Squashed 'third_party/flatbuffers/' content from commit acc9990ab
Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/.appveyor/check-generate-code.bat b/.appveyor/check-generate-code.bat
new file mode 100644
index 0000000..ba7398a
--- /dev/null
+++ b/.appveyor/check-generate-code.bat
@@ -0,0 +1,41 @@
+:: Copyright 2018 Google Inc. All rights reserved.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+set buildtype=Release
+if "%1"=="-b" set buildtype=%2
+
+cd tests
+call generate_code.bat -b %buildtype% || goto FAIL
+
+:: TODO: Release and Debug builds produce differences here for some reason.
+git checkout HEAD -- monster_test.bfbs
+git checkout HEAD -- arrays_test.bfbs
+
+git -c core.autocrlf=true diff --exit-code --quiet || goto :DIFFFOUND
+goto SUCCESS
+
+:DIFFFOUND
+@echo "" >&2
+@echo "ERROR: ********************************************************" >&2
+@echo "ERROR: The following differences were found after running the" >&2
+@echo "ERROR: tests/generate_code.sh script. Maybe you forgot to run" >&2
+@echo "ERROR: it after making changes in a generator or schema?" >&2
+@echo "ERROR: ********************************************************" >&2
+@echo "" >&2
+@git -c core.autocrlf=true --no-pager diff --binary
+
+:FAIL
+set EXITCODE=1
+:SUCCESS
+cd ..
+EXIT /B %EXITCODE%
\ No newline at end of file
diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml
new file mode 100644
index 0000000..a6e38fd
--- /dev/null
+++ b/.bazelci/presubmit.yml
@@ -0,0 +1,18 @@
+---
+buildifier: latest
+platforms:
+ ubuntu1604:
+ build_targets:
+ - "..."
+ test_targets:
+ - "..."
+ ubuntu1804:
+ build_targets:
+ - "..."
+ test_targets:
+ - "..."
+ macos:
+ build_targets:
+ - "..."
+ test_targets:
+ - "..."
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..7da2b43
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+---
+Language: Cpp
+BasedOnStyle: Google
+DerivePointerAlignment: false
+PointerAlignment: Right
+IndentPPDirectives: AfterHash
+Cpp11BracedListStyle: false
+AlwaysBreakTemplateDeclarations: false
+AllowShortCaseLabelsOnASingleLine: true
+SpaceAfterTemplateKeyword: false
+AllowShortBlocksOnASingleLine: true
+...
+
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..6c54966
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,7 @@
+root = true
+# Don't set line endings to avoid conflict with core.autocrlf flag.
+# Line endings on checkout/checkin are controlled by .gitattributes file.
+[*]
+indent_style = space
+indent_size = 2
+insert_final_newline = true
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..4cab1f4
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..a053fe4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,12 @@
+Thank you for submitting an issue!
+
+Please make sure you include the names of the affected language(s), compiler version(s), operating system version(s), and FlatBuffers version(s) in your issue title.
+
+This helps us get the correct maintainers to look at your issue. Here are examples of good titles:
+
+- Crash when accessing FlatBuffer [C++, gcc 4.8, OS X, master]
+- Flatc converts a protobuf 'bytes' field to 'string' in fbs schema file [all languages, FlatBuffers 1.4]
+
+Include other details as appropriate.
+
+Thanks!
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..8199465
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,16 @@
+Thank you for submitting a PR!
+
+Please make sure you include the names of the affected language(s) in your PR title.
+This helps us get the correct maintainers to look at your issue.
+
+If you make changes to any of the code generators, be sure to run
+`cd tests && sh generate_code.sh` (or equivalent .bat) and include the generated
+code changes in the PR. This allows us to better see the effect of the PR.
+
+If your PR includes C++ code, please adhere to the Google C++ Style Guide,
+and don't forget we try to support older compilers (e.g. VS2010, GCC 4.6.3),
+so only some C++11 support is available.
+
+Include other details as appropriate.
+
+Thanks!
diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 0000000..84ff87b
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,18 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 365
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 14
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - pinned
+ - security
+# Label to use when marking an issue as stale
+staleLabel: stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ activity for 1 year. It will be automatically closed if no further activity occurs.
+ To keep it open, simply post a new comment. Maintainers will re-open on
+ new activity. Thank you for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b7b41ac
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,118 @@
+*_wire.txt
+*_wire.bin
+.DS_Store
+*.o
+*.o.d
+*.class
+*.a
+*.swp
+*~
+*.vcxproj
+*.vcxproj.filters
+*.vcxproj.user
+*.sln
+*.suo
+*.opendb
+*.keystore
+**/.vs/**
+**/bin/**
+!tests/rust_usage_test/bin/**
+**/gen/**
+**/libs/**
+**/obj/**
+**/*.dir/**
+**/CMakeFiles/**
+**/cmake_install.cmake
+**/install_manifest.txt
+**/CMakeCache.txt
+**/CMakeTestfile.cmake
+**/CPackConfig.cmake
+**/CPackSourceConfig.cmake
+**/compile_commands.json
+**/Debug/**
+**/Release/**
+**/RelWithDebInfo/**
+**/x64/ #build artifacts from VS
+build.xml
+local.properties
+project.properties
+proguard-project.txt
+linklint_results
+Makefile
+flatc
+flatc.exe
+flathash
+flathash.exe
+flattests
+flattests.exe
+flatsamplebinary
+flatsamplebinary.exe
+flatsampletext
+flatsampletext.exe
+flatsamplebfbs
+flatsamplebfbs.exe
+grpctest
+grpctest.exe
+snapshot.sh
+tags
+tests/dart_gen
+tests/go_gen
+tests/monsterdata_java_wire.mon
+tests/monsterdata_java_wire_sp.mon
+tests/monsterdata_go_wire.mon
+tests/monsterdata_javascript_wire.mon
+tests/monsterdata_lobster_wire.mon
+tests/monsterdata_rust_wire.mon
+tests/unicode_test.mon
+tests/ts/
+tests/php/
+CMakeLists.txt.user
+CMakeScripts/**
+CTestTestfile.cmake
+FlatbuffersConfigVersion.cmake
+FlatBuffers.cbp
+build/Xcode/FlatBuffers.xcodeproj/project.xcworkspace/**
+build/Xcode/FlatBuffers.xcodeproj/xcuserdata/**
+FlatBuffers.xcodeproj/
+java/.idea
+java/*.iml
+.idea
+*.iml
+target
+**/*.pyc
+build/VS2010/FlatBuffers.sdf
+build/VS2010/FlatBuffers.opensdf
+build/VS2010/ipch/**/*.ipch
+*.so
+Testing/Temporary
+.cproject
+.settings/
+.project
+net/**/obj
+node_modules/
+android/.externalNativeBuild/
+android/.gradle/
+android/build/
+samples/android/.externalNativeBuild/
+samples/android/.gradle/
+samples/android/build/
+js/flatbuffers.mjs
+/bazel-bin
+/bazel-flatbuffers
+/bazel-genfiles
+/bazel-out
+/bazel-testlogs
+.ninja_deps
+.ninja_log
+build.ninja
+rules.ninja
+.vscode
+dart/.pub/
+dart/.packages
+dart/pubspec.lock
+dart/.dart_tool/
+dart/build/
+dart/doc/api/
+Cargo.lock
+.corpus**
+.seed**
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..fd2959f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,221 @@
+env:
+ global:
+ # Set at the root level as this is ignored when set under matrix.env.
+ - GCC_VERSION="4.9"
+ # Fail on first error if UBSAN or ASAN enabled for a target
+ - UBSAN_OPTIONS=halt_on_error=1
+ - ASAN_OPTIONS=halt_on_error=1
+ # Travis machines have 2 cores
+ - JOBS=2
+ - MAKEFLAGS="-j 2"
+
+conan-linux: &conan-linux
+ os: linux
+ dist: xenial
+ language: python
+ python: "3.7"
+ services:
+ - docker
+ install:
+ - ./conan/travis/install.sh
+ script:
+ - ./conan/travis/build.sh
+ if: tag IS present
+
+conan-linux-master: &conan-linux-master
+ os: linux
+ dist: xenial
+ language: python
+ python: "3.7"
+ services:
+ - docker
+ install:
+ - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./conan/travis/install.sh; fi'
+ script:
+ - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash ./conan/travis/build.sh; fi'
+ branches:
+ only:
+ - master
+
+conan-osx: &conan-osx
+ os: osx
+ language: generic
+ install:
+ - ./conan/travis/install.sh
+ script:
+ - ./conan/travis/build.sh
+ if: tag IS present
+
+matrix:
+ include:
+ #- language: python
+ # python: "2.7"
+ # install:
+ # - "pip install wheel twine"
+ # script:
+ # - "cd python/"
+ # - 'VERSION="$TRAVIS_TAG" python setup.py sdist bdist_wheel'
+ # - "cd ../"
+ # deploy:
+ # # Checkpointed release builds.
+ # - provider: script
+ # script: .travis/deploy-python.sh
+ # skip_cleanup: true
+ # on:
+ # tags: true
+ # # all_branches must be set with tags: true. See below post:
+ # # https://stackoverflow.com/a/27775257/1076585
+ # all_branches: true
+ # # Produce a new build for the cutting edge when master changes.
+ # - provider: script
+ # script: .travis/deploy-python.sh
+ # skip_cleanup: true
+ # on:
+ # branch: master
+ - language: cpp
+ os:
+ - linux
+
+ addons:
+ apt:
+ packages:
+ - docker-ce
+ script:
+ - bash .travis/build-and-run-docker-test-containers.sh
+
+ - language: cpp
+ os:
+ - linux
+
+ compiler:
+ - gcc
+
+ env:
+ matrix:
+ - BUILD_TYPE=Debug
+ - BUILD_TYPE=Release
+
+ before_install:
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
+
+ script:
+ - bash .travis/check-sources.sh
+ - bash grpc/build_grpc.sh
+ - cmake .
+ -DCMAKE_BUILD_TYPE=$BUILD_TYPE
+ -DFLATBUFFERS_BUILD_GRPCTEST=ON
+ -DGRPC_INSTALL_PATH=$TRAVIS_BUILD_DIR/google/grpc/install
+ -DPROTOBUF_DOWNLOAD_PATH=$TRAVIS_BUILD_DIR/google/grpc/third_party/protobuf
+ -DFLATBUFFERS_CODE_SANITIZE=ON
+ - cmake --build . -- -j${JOBS}
+ - LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib ctest --extra-verbose --output-on-failure
+ - bash .travis/check-generate-code.sh
+
+ - language: cpp
+ os: osx
+ osx_image: xcode9.3
+ env:
+ matrix:
+ - BUILD_TYPE=Debug
+ - BUILD_TYPE=Release
+
+ script:
+ - bash grpc/build_grpc.sh
+ - cmake .
+ -DCMAKE_BUILD_TYPE=$BUILD_TYPE
+ -DFLATBUFFERS_BUILD_GRPCTEST=ON
+ -DGRPC_INSTALL_PATH=$TRAVIS_BUILD_DIR/google/grpc/install
+ -DPROTOBUF_DOWNLOAD_PATH=$TRAVIS_BUILD_DIR/google/grpc/third_party/protobuf
+ -DFLATBUFFERS_CODE_SANITIZE=ON
+ - cmake --build . -- -j${JOBS}
+ - DYLD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/google/grpc/install/lib ctest --extra-verbose --output-on-failure
+ - bash .travis/check-generate-code.sh
+
+ - <<: *conan-linux-master
+ env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8
+ - <<: *conan-linux
+ env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=conanio/gcc49
+ - <<: *conan-linux
+ env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=conanio/gcc5
+ - <<: *conan-linux
+ env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=conanio/gcc6
+ - <<: *conan-linux
+ env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=conanio/gcc7
+ - <<: *conan-linux
+ env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8
+ - <<: *conan-linux
+ env: CONAN_GCC_VERSIONS=9 CONAN_DOCKER_IMAGE=conanio/gcc9
+ - <<: *conan-linux
+ env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=conanio/clang39
+ - <<: *conan-linux
+ env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=conanio/clang40
+ - <<: *conan-linux
+ env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=conanio/clang50
+ - <<: *conan-linux
+ env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=conanio/clang60
+ - <<: *conan-linux
+ env: CONAN_CLANG_VERSIONS=7.0 CONAN_DOCKER_IMAGE=conanio/clang7
+ - <<: *conan-linux
+ env: CONAN_CLANG_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/clang8
+ - <<: *conan-osx
+ osx_image: xcode7.3
+ env: CONAN_APPLE_CLANG_VERSIONS=7.3
+ - <<: *conan-osx
+ osx_image: xcode8.3
+ env: CONAN_APPLE_CLANG_VERSIONS=8.1
+ - <<: *conan-osx
+ osx_image: xcode9
+ env: CONAN_APPLE_CLANG_VERSIONS=9.0
+ - <<: *conan-osx
+ osx_image: xcode9.4
+ env: CONAN_APPLE_CLANG_VERSIONS=9.1
+ - <<: *conan-osx
+ osx_image: xcode10.2
+ env: CONAN_APPLE_CLANG_VERSIONS=10.0
+
+ - language: android
+ sudo: true
+ dist: trusty
+ android:
+ components:
+ - tools
+ - platform-tools
+ - build-tools-25.0.2
+ - android-25
+ - extra-android-m2repository
+ compiler:
+ - gcc
+
+ before_install:
+ # Output something every 10 minutes or Travis kills the job
+ - while sleep 540; do echo "=====[ $SECONDS seconds still running ]====="; done &
+ # Install the r17c version of the NDK that still so that we can continue to test with gnustl
+ # and stlport.
+ - export ANDROID_NDK_HOME=$HOME/android-ndk
+ - NDK_ZIP=$ANDROID_NDK_HOME/ndk.zip
+ - mkdir -p $ANDROID_NDK_HOME
+ - curl -o $NDK_ZIP https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip
+ - unzip -q -d $ANDROID_NDK_HOME $NDK_ZIP
+ - rm $NDK_ZIP
+ - mv $ANDROID_NDK_HOME/android-ndk-*/* $ANDROID_NDK_HOME
+ - rmdir $ANDROID_NDK_HOME/android-ndk-*
+ - export CMAKE=$(which cmake)
+ # libc required for prebuilt llvm toolchain the NDK r17c.
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq libc6; fi
+ # Setup environment for Linux build which is required to build the sample.
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
+ - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
+ script:
+ - failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))
+ # Kill the sleep loop
+ - kill %1
diff --git a/.travis/build-and-run-docker-test-containers.sh b/.travis/build-and-run-docker-test-containers.sh
new file mode 100755
index 0000000..e6039bf
--- /dev/null
+++ b/.travis/build-and-run-docker-test-containers.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+
+# build flatc on debian once to speed up the test loop below
+docker build -t build_flatc_debian_stretch -f tests/docker/Dockerfile.testing.build_flatc_debian_stretch .
+BUILD_CONTAINER_ID=$(docker create --read-only build_flatc_debian_stretch)
+docker cp ${BUILD_CONTAINER_ID}:/code/flatc flatc_debian_stretch
+
+for f in $(ls tests/docker/languages | sort)
+do
+ # docker pull sometimes fails for unknown reasons, probably travisci-related. this retries the pull we need a few times.
+ REQUIRED_BASE_IMAGE=$(cat tests/docker/languages/${f} | head -n 1 | awk ' { print $2 } ')
+
+ set +e
+ n=0
+ until [ $n -ge 5 ]
+ do
+ docker pull $REQUIRED_BASE_IMAGE && break
+ n=$[$n+1]
+ sleep 1
+ done
+ set -e
+
+ docker build -t $(echo ${f} | cut -f 3- -d .) -f tests/docker/languages/${f} .
+ echo "TEST OK: ${f}"
+done
diff --git a/.travis/check-generate-code.sh b/.travis/check-generate-code.sh
new file mode 100755
index 0000000..37d81bb
--- /dev/null
+++ b/.travis/check-generate-code.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+
+cd tests
+./generate_code.sh
+cd ..
+
+# TODO: Linux and macos builds produce differences here for some reason.
+git checkout HEAD -- tests/monster_test.bfbs
+git checkout HEAD -- tests/arrays_test.bfbs
+
+if ! git diff --quiet; then
+ echo >&2
+ echo "ERROR: ********************************************************" >&2
+ echo "ERROR: The following differences were found after running the" >&2
+ echo "ERROR: tests/generate_code.sh script. Maybe you forgot to run" >&2
+ echo "ERROR: it after making changes in a generator or schema?" >&2
+ echo "ERROR: ********************************************************" >&2
+ echo >&2
+ git diff --binary --exit-code
+fi
diff --git a/.travis/check-sources.sh b/.travis/check-sources.sh
new file mode 100644
index 0000000..3e6dbf1
--- /dev/null
+++ b/.travis/check-sources.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+
+if [ -n "$1" ]; then
+ scan_dir="$1"
+else
+ scan_dir="$( pwd )"
+fi
+
+py_checker="$0.py"
+
+echo "scan root directory = '$scan_dir'"
+python3 --version
+# Scan recursively and search all *.cpp and *.h files using regex patterns.
+# Assume that script running from a root of Flatbuffers working dir.
+python3 $py_checker "ascii" "$scan_dir/include" "\.h$"
+python3 $py_checker "ascii" "$scan_dir/src" "\.cpp$"
+python3 $py_checker "ascii" "$scan_dir/tests" "\.h$"
+python3 $py_checker "utf-8" "$scan_dir/tests" "\.cpp$"
diff --git a/.travis/check-sources.sh.py b/.travis/check-sources.sh.py
new file mode 100644
index 0000000..2b001d7
--- /dev/null
+++ b/.travis/check-sources.sh.py
@@ -0,0 +1,35 @@
+import os
+import re
+import sys
+
+def check_encoding(encoding, scan_dir, regex_pattern):
+ fname = None
+ try:
+ assert encoding in ['ascii', 'utf-8'], "unexpected encoding"
+ cmp = re.compile(regex_pattern)
+ for root, dirs, files in os.walk(scan_dir):
+ fname = root
+ cmp_list = [f for f in files if cmp.search(f) is not None]
+ for f in cmp_list:
+ fname = os.path.join(root, f)
+ with open(fname, mode='rb') as test_file:
+ btext = test_file.read()
+ # check encoding
+ btext.decode(encoding=encoding, errors="strict")
+ if encoding == "utf-8" and btext.startswith(b'\xEF\xBB\xBF'):
+ raise ValueError("unexpected BOM in file")
+ # check LF line endings
+ LF = btext.count(b'\n')
+ CR = btext.count(b'\r')
+ if CR!=0:
+ raise ValueError("invalid line endings: LF({})/CR({})".format(LF, CR))
+ except Exception as err:
+ print("ERROR with [{}]: {}".format(fname, err))
+ return -1
+ else:
+ return 0
+
+if __name__ == "__main__":
+ # python check-sources.sh.py 'ascii' '.' '.*\.(cpp|h)$'
+ res = check_encoding(sys.argv[1], sys.argv[2], sys.argv[3])
+ sys.exit(0 if res == 0 else -1)
diff --git a/.travis/deploy-python.sh b/.travis/deploy-python.sh
new file mode 100755
index 0000000..4cc0346
--- /dev/null
+++ b/.travis/deploy-python.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PROD_REPOSITORY="https://upload.pypi.org/legacy/"
+TEST_REPOSITORY="https://test.pypi.org/legacy/"
+
+twine upload \
+ --username "$PYPI_USERNAME" \
+ --password "$PYPI_PASSWORD" \
+ --repository-url "$PROD_REPOSITORY" \
+ "$DIR/../python/dist/"*
+
diff --git a/BUILD b/BUILD
new file mode 100644
index 0000000..520f98a
--- /dev/null
+++ b/BUILD
@@ -0,0 +1,225 @@
+licenses(["notice"])
+
+package(
+ default_visibility = ["//visibility:public"],
+ features = [
+ "-layering_check",
+ "-parse_headers",
+ ],
+)
+
+exports_files([
+ "LICENSE",
+])
+
+load(":build_defs.bzl", "flatbuffer_cc_library")
+
+# Public flatc library to compile flatbuffer files at runtime.
+cc_library(
+ name = "flatbuffers",
+ srcs = [
+ "src/code_generators.cpp",
+ "src/idl_gen_fbs.cpp",
+ "src/idl_gen_general.cpp",
+ "src/idl_gen_text.cpp",
+ "src/idl_parser.cpp",
+ "src/reflection.cpp",
+ "src/util.cpp",
+ ],
+ hdrs = [":public_headers"],
+ includes = ["include/"],
+ linkstatic = 1,
+)
+
+# Public C++ headers for the Flatbuffers library.
+filegroup(
+ name = "public_headers",
+ srcs = [
+ "include/flatbuffers/base.h",
+ "include/flatbuffers/code_generators.h",
+ "include/flatbuffers/flatbuffers.h",
+ "include/flatbuffers/flexbuffers.h",
+ "include/flatbuffers/hash.h",
+ "include/flatbuffers/idl.h",
+ "include/flatbuffers/minireflect.h",
+ "include/flatbuffers/reflection.h",
+ "include/flatbuffers/reflection_generated.h",
+ "include/flatbuffers/stl_emulation.h",
+ "include/flatbuffers/util.h",
+ ],
+)
+
+# Public flatc compiler library.
+cc_library(
+ name = "flatc_library",
+ srcs = [
+ "src/code_generators.cpp",
+ "src/flatc.cpp",
+ "src/idl_gen_fbs.cpp",
+ "src/idl_parser.cpp",
+ "src/reflection.cpp",
+ "src/util.cpp",
+ ],
+ hdrs = [
+ "include/flatbuffers/flatc.h",
+ ":public_headers",
+ ],
+ includes = [
+ "grpc/",
+ "include/",
+ ],
+)
+
+# Public flatc compiler.
+cc_binary(
+ name = "flatc",
+ srcs = [
+ "grpc/src/compiler/config.h",
+ "grpc/src/compiler/cpp_generator.cc",
+ "grpc/src/compiler/cpp_generator.h",
+ "grpc/src/compiler/go_generator.cc",
+ "grpc/src/compiler/go_generator.h",
+ "grpc/src/compiler/java_generator.cc",
+ "grpc/src/compiler/java_generator.h",
+ "grpc/src/compiler/schema_interface.h",
+ "src/flatc_main.cpp",
+ "src/idl_gen_cpp.cpp",
+ "src/idl_gen_dart.cpp",
+ "src/idl_gen_general.cpp",
+ "src/idl_gen_kotlin.cpp",
+ "src/idl_gen_go.cpp",
+ "src/idl_gen_grpc.cpp",
+ "src/idl_gen_js_ts.cpp",
+ "src/idl_gen_json_schema.cpp",
+ "src/idl_gen_lobster.cpp",
+ "src/idl_gen_lua.cpp",
+ "src/idl_gen_php.cpp",
+ "src/idl_gen_python.cpp",
+ "src/idl_gen_rust.cpp",
+ "src/idl_gen_text.cpp",
+ "src/util.cpp",
+ ],
+ includes = [
+ "grpc/",
+ "include/",
+ ],
+ deps = [
+ ":flatc_library",
+ ],
+)
+
+cc_library(
+ name = "runtime_cc",
+ hdrs = [
+ "include/flatbuffers/base.h",
+ "include/flatbuffers/flatbuffers.h",
+ "include/flatbuffers/flexbuffers.h",
+ "include/flatbuffers/stl_emulation.h",
+ "include/flatbuffers/util.h",
+ ],
+ includes = ["include/"],
+ linkstatic = 1,
+)
+
+# Test binary.
+cc_test(
+ name = "flatbuffers_test",
+ testonly = 1,
+ srcs = [
+ "include/flatbuffers/minireflect.h",
+ "include/flatbuffers/registry.h",
+ "src/code_generators.cpp",
+ "src/idl_gen_fbs.cpp",
+ "src/idl_gen_general.cpp",
+ "src/idl_gen_text.cpp",
+ "src/idl_parser.cpp",
+ "src/reflection.cpp",
+ "src/util.cpp",
+ "tests/namespace_test/namespace_test1_generated.h",
+ "tests/namespace_test/namespace_test2_generated.h",
+ "tests/native_type_test_impl.h",
+ "tests/native_type_test_impl.cpp",
+ "tests/test.cpp",
+ "tests/test_assert.cpp",
+ "tests/test_assert.h",
+ "tests/test_builder.cpp",
+ "tests/test_builder.h",
+ "tests/union_vector/union_vector_generated.h",
+ ":public_headers",
+ ],
+ copts = [
+ "-DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE",
+ "-DBAZEL_TEST_DATA_PATH",
+ ],
+ data = [
+ ":tests/include_test/include_test1.fbs",
+ ":tests/include_test/sub/include_test2.fbs",
+ ":tests/monster_test.bfbs",
+ ":tests/monster_test.fbs",
+ ":tests/monsterdata_test.golden",
+ ":tests/monsterdata_test.json",
+ ":tests/prototest/imported.proto",
+ ":tests/prototest/test.golden",
+ ":tests/prototest/test.proto",
+ ":tests/prototest/test_union.golden",
+ ":tests/unicode_test.json",
+ ":tests/union_vector/union_vector.fbs",
+ ":tests/union_vector/union_vector.json",
+ ":tests/monster_extra.fbs",
+ ":tests/monsterdata_extra.json",
+ ":tests/arrays_test.bfbs",
+ ":tests/arrays_test.fbs",
+ ":tests/arrays_test.golden",
+ ":tests/native_type_test.fbs",
+ ],
+ includes = [
+ "include/",
+ "tests/",
+ ],
+ deps = [
+ ":monster_extra_cc_fbs",
+ ":monster_test_cc_fbs",
+ ":arrays_test_cc_fbs",
+ ":native_type_test_cc_fbs",
+ ],
+)
+
+# Test bzl rules
+
+flatbuffer_cc_library(
+ name = "monster_test_cc_fbs",
+ srcs = ["tests/monster_test.fbs"],
+ include_paths = ["tests/include_test"],
+ includes = [
+ "tests/include_test/include_test1.fbs",
+ "tests/include_test/sub/include_test2.fbs",
+ ],
+)
+
+flatbuffer_cc_library(
+ name = "monster_extra_cc_fbs",
+ srcs = ["tests/monster_extra.fbs"],
+)
+
+flatbuffer_cc_library(
+ name = "arrays_test_cc_fbs",
+ srcs = ["tests/arrays_test.fbs"],
+ flatc_args = [
+ "--gen-object-api",
+ "--gen-compare",
+ "--no-includes",
+ "--gen-mutable",
+ "--reflect-names",
+ "--cpp-ptr-type flatbuffers::unique_ptr",
+ "--scoped-enums" ],
+)
+
+flatbuffer_cc_library(
+ name = "native_type_test_cc_fbs",
+ srcs = ["tests/native_type_test.fbs"],
+ flatc_args = [
+ "--gen-object-api",
+ "--gen-mutable",
+ "--cpp-ptr-type flatbuffers::unique_ptr" ],
+)
+
diff --git a/CMake/BuildFlatBuffers.cmake b/CMake/BuildFlatBuffers.cmake
new file mode 100644
index 0000000..835f4b8
--- /dev/null
+++ b/CMake/BuildFlatBuffers.cmake
@@ -0,0 +1,152 @@
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# General function to create FlatBuffer build rules for the given list of
+# schemas.
+#
+# flatbuffers_schemas: A list of flatbuffer schema files to process.
+#
+# schema_include_dirs: A list of schema file include directories, which will be
+# passed to flatc via the -I parameter.
+#
+# custom_target_name: The generated files will be added as dependencies for a
+# new custom target with this name. You should add that target as a dependency
+# for your main target to ensure these files are built. You can also retrieve
+# various properties from this target, such as GENERATED_INCLUDES_DIR,
+# BINARY_SCHEMAS_DIR, and COPY_TEXT_SCHEMAS_DIR.
+#
+# additional_dependencies: A list of additional dependencies that you'd like
+# all generated files to depend on. Pass in a blank string if you have none.
+#
+# generated_includes_dir: Where to generate the C++ header files for these
+# schemas. The generated includes directory will automatically be added to
+# CMake's include directories, and will be where generated header files are
+# placed. This parameter is optional; pass in empty string if you don't want to
+# generate include files for these schemas.
+#
+# binary_schemas_dir: If you specify an optional binary schema directory, binary
+# schemas will be generated for these schemas as well, and placed into the given
+# directory.
+#
+# copy_text_schemas_dir: If you want all text schemas (including schemas from
+# all schema include directories) copied into a directory (for example, if you
+# need them within your project to build JSON files), you can specify that
+# folder here. All text schemas will be copied to that folder.
+#
+# IMPORTANT: Make sure you quote all list arguments you pass to this function!
+# Otherwise CMake will only pass in the first element.
+# Example: build_flatbuffers("${fb_files}" "${include_dirs}" target_name ...)
+function(build_flatbuffers flatbuffers_schemas
+ schema_include_dirs
+ custom_target_name
+ additional_dependencies
+ generated_includes_dir
+ binary_schemas_dir
+ copy_text_schemas_dir)
+
+ # Test if including from FindFlatBuffers
+ if(FLATBUFFERS_FLATC_EXECUTABLE)
+ set(FLATC_TARGET "")
+ set(FLATC ${FLATBUFFERS_FLATC_EXECUTABLE})
+ else()
+ set(FLATC_TARGET flatc)
+ set(FLATC flatc)
+ endif()
+ set(FLATC_SCHEMA_ARGS --gen-mutable)
+ if(FLATBUFFERS_FLATC_SCHEMA_EXTRA_ARGS)
+ set(FLATC_SCHEMA_ARGS
+ ${FLATBUFFERS_FLATC_SCHEMA_EXTRA_ARGS}
+ ${FLATC_SCHEMA_ARGS}
+ )
+ endif()
+
+ set(working_dir "${CMAKE_CURRENT_SOURCE_DIR}")
+
+ set(schema_glob "*.fbs")
+ # Generate the include files parameters.
+ set(include_params "")
+ set(all_generated_files "")
+ foreach (include_dir ${schema_include_dirs})
+ set(include_params -I ${include_dir} ${include_params})
+ if (NOT ${copy_text_schemas_dir} STREQUAL "")
+ # Copy text schemas from dependent folders.
+ file(GLOB_RECURSE dependent_schemas ${include_dir}/${schema_glob})
+ foreach (dependent_schema ${dependent_schemas})
+ file(COPY ${dependent_schema} DESTINATION ${copy_text_schemas_dir})
+ endforeach()
+ endif()
+ endforeach()
+
+ foreach(schema ${flatbuffers_schemas})
+ get_filename_component(filename ${schema} NAME_WE)
+ # For each schema, do the things we requested.
+ if (NOT ${generated_includes_dir} STREQUAL "")
+ set(generated_include ${generated_includes_dir}/${filename}_generated.h)
+ add_custom_command(
+ OUTPUT ${generated_include}
+ COMMAND ${FLATC} ${FLATC_SCHEMA_ARGS}
+ -o ${generated_includes_dir}
+ ${include_params}
+ -c ${schema}
+ DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies}
+ WORKING_DIRECTORY "${working_dir}")
+ list(APPEND all_generated_files ${generated_include})
+ endif()
+
+ if (NOT ${binary_schemas_dir} STREQUAL "")
+ set(binary_schema ${binary_schemas_dir}/${filename}.bfbs)
+ add_custom_command(
+ OUTPUT ${binary_schema}
+ COMMAND ${FLATC} -b --schema
+ -o ${binary_schemas_dir}
+ ${include_params}
+ ${schema}
+ DEPENDS ${FLATC_TARGET} ${schema} ${additional_dependencies}
+ WORKING_DIRECTORY "${working_dir}")
+ list(APPEND all_generated_files ${binary_schema})
+ endif()
+
+ if (NOT ${copy_text_schemas_dir} STREQUAL "")
+ file(COPY ${schema} DESTINATION ${copy_text_schemas_dir})
+ endif()
+ endforeach()
+
+ # Create a custom target that depends on all the generated files.
+ # This is the target that you can depend on to trigger all these
+ # to be built.
+ add_custom_target(${custom_target_name}
+ DEPENDS ${all_generated_files} ${additional_dependencies})
+
+ # Register the include directory we are using.
+ if (NOT ${generated_includes_dir} STREQUAL "")
+ include_directories(${generated_includes_dir})
+ set_property(TARGET ${custom_target_name}
+ PROPERTY GENERATED_INCLUDES_DIR
+ ${generated_includes_dir})
+ endif()
+
+ # Register the binary schemas dir we are using.
+ if (NOT ${binary_schemas_dir} STREQUAL "")
+ set_property(TARGET ${custom_target_name}
+ PROPERTY BINARY_SCHEMAS_DIR
+ ${binary_schemas_dir})
+ endif()
+
+ # Register the text schema copy dir we are using.
+ if (NOT ${copy_text_schemas_dir} STREQUAL "")
+ set_property(TARGET ${custom_target_name}
+ PROPERTY COPY_TEXT_SCHEMAS_DIR
+ ${copy_text_schemas_dir})
+ endif()
+endfunction()
diff --git a/CMake/DESCRIPTION.txt b/CMake/DESCRIPTION.txt
new file mode 100644
index 0000000..3698b03
--- /dev/null
+++ b/CMake/DESCRIPTION.txt
@@ -0,0 +1,4 @@
+FlatBuffers is a cross platform serialization library architected for
+maximum memory efficiency. It allows you to directly access serialized
+data without parsing/unpacking it first, while still having great
+forwards/backwards compatibility.
diff --git a/CMake/FindFlatBuffers.cmake b/CMake/FindFlatBuffers.cmake
new file mode 100644
index 0000000..aad9a6b
--- /dev/null
+++ b/CMake/FindFlatBuffers.cmake
@@ -0,0 +1,61 @@
+# Copyright 2014 Stefan.Eilemann@epfl.ch
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Find the flatbuffers schema compiler
+#
+# Output Variables:
+# * FLATBUFFERS_FLATC_EXECUTABLE the flatc compiler executable
+# * FLATBUFFERS_FOUND
+#
+# Provides:
+# * FLATBUFFERS_GENERATE_C_HEADERS(Name <files>) creates the C++ headers
+# for the given flatbuffer schema files.
+# Returns the header files in ${Name}_OUTPUTS
+
+set(FLATBUFFERS_CMAKE_DIR ${CMAKE_CURRENT_LIST_DIR})
+
+find_program(FLATBUFFERS_FLATC_EXECUTABLE NAMES flatc)
+find_path(FLATBUFFERS_INCLUDE_DIR NAMES flatbuffers/flatbuffers.h)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(flatbuffers
+ DEFAULT_MSG FLATBUFFERS_FLATC_EXECUTABLE FLATBUFFERS_INCLUDE_DIR)
+
+if(FLATBUFFERS_FOUND)
+ function(FLATBUFFERS_GENERATE_C_HEADERS Name)
+ set(FLATC_OUTPUTS)
+ foreach(FILE ${ARGN})
+ get_filename_component(FLATC_OUTPUT ${FILE} NAME_WE)
+ set(FLATC_OUTPUT
+ "${CMAKE_CURRENT_BINARY_DIR}/${FLATC_OUTPUT}_generated.h")
+ list(APPEND FLATC_OUTPUTS ${FLATC_OUTPUT})
+
+ add_custom_command(OUTPUT ${FLATC_OUTPUT}
+ COMMAND ${FLATBUFFERS_FLATC_EXECUTABLE}
+ ARGS -c -o "${CMAKE_CURRENT_BINARY_DIR}/" ${FILE}
+ DEPENDS ${FILE}
+ COMMENT "Building C++ header for ${FILE}"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+ endforeach()
+ set(${Name}_OUTPUTS ${FLATC_OUTPUTS} PARENT_SCOPE)
+ endfunction()
+
+ set(FLATBUFFERS_INCLUDE_DIRS ${FLATBUFFERS_INCLUDE_DIR})
+ include_directories(${CMAKE_BINARY_DIR})
+else()
+ set(FLATBUFFERS_INCLUDE_DIR)
+endif()
+
+include("${FLATBUFFERS_CMAKE_DIR}/BuildFlatBuffers.cmake")
\ No newline at end of file
diff --git a/CMake/FlatbuffersConfig.cmake b/CMake/FlatbuffersConfig.cmake
new file mode 100644
index 0000000..107d78e
--- /dev/null
+++ b/CMake/FlatbuffersConfig.cmake
@@ -0,0 +1,4 @@
+include("${CMAKE_CURRENT_LIST_DIR}/FlatbuffersTargets.cmake" OPTIONAL)
+include("${CMAKE_CURRENT_LIST_DIR}/FlatcTargets.cmake" OPTIONAL)
+include("${CMAKE_CURRENT_LIST_DIR}/FlatbuffersSharedTargets.cmake" OPTIONAL)
+
diff --git a/CMake/FlatbuffersConfigVersion.cmake.in b/CMake/FlatbuffersConfigVersion.cmake.in
new file mode 100644
index 0000000..a553ab1
--- /dev/null
+++ b/CMake/FlatbuffersConfigVersion.cmake.in
@@ -0,0 +1,11 @@
+set(PACKAGE_VERSION "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@")
+
+# Check whether the requested PACKAGE_FIND_VERSION is compatible
+if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_COMPATIBLE FALSE)
+else()
+ set(PACKAGE_VERSION_COMPATIBLE TRUE)
+ if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
+ set(PACKAGE_VERSION_EXACT TRUE)
+ endif()
+endif()
diff --git a/CMake/PackageDebian.cmake b/CMake/PackageDebian.cmake
new file mode 100644
index 0000000..f587ff7
--- /dev/null
+++ b/CMake/PackageDebian.cmake
@@ -0,0 +1,39 @@
+# ------------------- Debianization ---------------------
+if (UNIX)
+
+ # Set build environment
+ SET(CPACK_GENERATOR "TGZ;DEB")
+ SET(CPACK_SOURCE_TGZ "ON")
+
+ # Common package information
+ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY
+ "FlatBuffers is an efficient cross platform serialization library for C++, with support for Java, C# and Go. It was created at Google specifically for game development and other performance-critical applications.")
+ SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/google/flatbuffers")
+ SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "Vitaly Isaev <vitalyisaev2@gmail.com>")
+
+ SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
+ SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
+ SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
+ SET(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_COMMIT}")
+ SET(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
+
+ # Derive architecture
+ IF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+ FIND_PROGRAM(DPKG_CMD dpkg)
+ IF(NOT DPKG_CMD)
+ MESSAGE(STATUS "Can not find dpkg in your path, default to i386.")
+ SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE i386)
+ ENDIF(NOT DPKG_CMD)
+ EXECUTE_PROCESS(COMMAND "${DPKG_CMD}" --print-architecture
+ OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ ENDIF(NOT CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
+
+ # Package name
+ SET(CPACK_DEBIAN_PACKAGE_NAME "flatbuffers")
+ SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt)
+ SET(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}")
+
+endif(UNIX)
diff --git a/CMake/PackageRedhat.cmake b/CMake/PackageRedhat.cmake
new file mode 100644
index 0000000..4545e72
--- /dev/null
+++ b/CMake/PackageRedhat.cmake
@@ -0,0 +1,34 @@
+if (UNIX)
+ set(CPACK_GENERATOR "RPM")
+ set(CPACK_SOURCE_TGZ "ON")
+
+ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "FlatBuffers serialization library and schema compiler.")
+
+ set(CPACK_RPM_PACKAGE_HOMEPAGE "https://github.com/google/flatbuffers")
+ set(CPACK_RPM_PACKAGE_MAINTAINER "Marc Butler <mockbutler@gmail.com>")
+
+ set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
+ set(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
+ set(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH})
+ set(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_COMMIT}")
+ set(CPACK_RPM_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}")
+
+ set(CPACK_RPM_PACKAGE_NAME "flatbuffers")
+
+ # Assume this is not a cross complation build.
+ if(NOT CPACK_RPM_PACKAGE_ARCHITECTURE)
+ set(CPACK_RPM_PACKAGE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
+ endif(NOT CPACK_RPM_PACKAGE_ARCHITECTURE)
+
+ set(CPACK_RPM_PACKAGE_VENDOR "Google, Inc.")
+ set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0")
+ set(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt)
+ set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/CMake/DESCRIPTION.txt)
+
+ # This may reduce rpm compatiblity with very old systems.
+ set(CPACK_RPM_COMPRESSION_TYPE lzma)
+
+ set(CPACK_RPM_PACKAGE_NAME "flatbuffers")
+ set(CPACK_PACKAGE_FILE_NAME
+ "${CPACK_RPM_PACKAGE_NAME}_${CPACK_RPM_PACKAGE_VERSION}_${CPACK_RPM_PACKAGE_ARCHITECTURE}")
+endif(UNIX)
diff --git a/CMake/Version.cmake b/CMake/Version.cmake
new file mode 100644
index 0000000..db6613b
--- /dev/null
+++ b/CMake/Version.cmake
@@ -0,0 +1,11 @@
+find_program(GIT git)
+execute_process(
+ COMMAND ${GIT} describe
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_DESCRIBE_DIRTY
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_DESCRIBE_DIRTY}")
+string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GIT_DESCRIBE_DIRTY}")
+string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${GIT_DESCRIBE_DIRTY}")
+string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" VERSION_COMMIT "${GIT_DESCRIBE_DIRTY}")
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..7da75f4
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,482 @@
+cmake_minimum_required(VERSION 2.8)
+# generate compile_commands.json
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+include(CheckCXXSymbolExists)
+
+project(FlatBuffers)
+
+# NOTE: Code coverage only works on Linux & OSX.
+option(FLATBUFFERS_CODE_COVERAGE "Enable the code coverage build option." OFF)
+option(FLATBUFFERS_BUILD_TESTS "Enable the build of tests and samples." ON)
+option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON)
+option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library"
+ ON)
+option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler"
+ ON)
+option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
+option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
+option(FLATBUFFERS_BUILD_SHAREDLIB
+ "Enable the build of the flatbuffers shared library"
+ OFF)
+option(FLATBUFFERS_LIBCXX_WITH_CLANG "Force libc++ when using Clang" ON)
+# NOTE: Sanitizer check only works on Linux & OSX (gcc & llvm).
+option(FLATBUFFERS_CODE_SANITIZE
+ "Add '-fsanitize' flags to 'flattests' and 'flatc' targets."
+ OFF)
+option(FLATBUFFERS_PACKAGE_REDHAT
+ "Build an rpm using the 'package' target."
+ OFF)
+option(FLATBUFFERS_PACKAGE_DEBIAN
+ "Build an deb using the 'package' target."
+ OFF)
+
+if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
+ message(WARNING
+ "Cannot build tests without building the compiler. Tests will be disabled.")
+ set(FLATBUFFERS_BUILD_TESTS OFF)
+endif()
+
+if(DEFINED FLATBUFFERS_MAX_PARSING_DEPTH)
+ # Override the default recursion depth limit.
+ add_definitions(-DFLATBUFFERS_MAX_PARSING_DEPTH=${FLATBUFFERS_MAX_PARSING_DEPTH})
+ message(STATUS "FLATBUFFERS_MAX_PARSING_DEPTH: ${FLATBUFFERS_MAX_PARSING_DEPTH}")
+endif()
+
+# Auto-detect locale-narrow 'strtod_l' and 'strtoull_l' functions.
+if(NOT DEFINED FLATBUFFERS_LOCALE_INDEPENDENT)
+ set(FLATBUFFERS_LOCALE_INDEPENDENT 0)
+ if(MSVC)
+ check_cxx_symbol_exists(_strtof_l stdlib.h FLATBUFFERS_HAS_STRTOF_L)
+ check_cxx_symbol_exists(_strtoui64_l stdlib.h FLATBUFFERS_HAS_STRTOULL_L)
+ else()
+ check_cxx_symbol_exists(strtof_l stdlib.h FLATBUFFERS_HAS_STRTOF_L)
+ check_cxx_symbol_exists(strtoull_l stdlib.h FLATBUFFERS_HAS_STRTOULL_L)
+ endif()
+ if(FLATBUFFERS_HAS_STRTOF_L AND FLATBUFFERS_HAS_STRTOULL_L)
+ set(FLATBUFFERS_LOCALE_INDEPENDENT 1)
+ endif()
+endif()
+add_definitions(-DFLATBUFFERS_LOCALE_INDEPENDENT=$<BOOL:${FLATBUFFERS_LOCALE_INDEPENDENT}>)
+
+set(FlatBuffers_Library_SRCS
+ include/flatbuffers/code_generators.h
+ include/flatbuffers/base.h
+ include/flatbuffers/flatbuffers.h
+ include/flatbuffers/hash.h
+ include/flatbuffers/idl.h
+ include/flatbuffers/util.h
+ include/flatbuffers/reflection.h
+ include/flatbuffers/reflection_generated.h
+ include/flatbuffers/stl_emulation.h
+ include/flatbuffers/flexbuffers.h
+ include/flatbuffers/registry.h
+ include/flatbuffers/minireflect.h
+ src/code_generators.cpp
+ src/idl_parser.cpp
+ src/idl_gen_text.cpp
+ src/reflection.cpp
+ src/util.cpp
+)
+
+set(FlatBuffers_Compiler_SRCS
+ ${FlatBuffers_Library_SRCS}
+ src/idl_gen_cpp.cpp
+ src/idl_gen_dart.cpp
+ src/idl_gen_general.cpp
+ src/idl_gen_kotlin.cpp
+ src/idl_gen_go.cpp
+ src/idl_gen_js_ts.cpp
+ src/idl_gen_php.cpp
+ src/idl_gen_python.cpp
+ src/idl_gen_lobster.cpp
+ src/idl_gen_lua.cpp
+ src/idl_gen_rust.cpp
+ src/idl_gen_fbs.cpp
+ src/idl_gen_grpc.cpp
+ src/idl_gen_json_schema.cpp
+ src/flatc.cpp
+ src/flatc_main.cpp
+ grpc/src/compiler/schema_interface.h
+ grpc/src/compiler/cpp_generator.h
+ grpc/src/compiler/cpp_generator.cc
+ grpc/src/compiler/go_generator.h
+ grpc/src/compiler/go_generator.cc
+ grpc/src/compiler/java_generator.h
+ grpc/src/compiler/java_generator.cc
+)
+
+set(FlatHash_SRCS
+ include/flatbuffers/hash.h
+ src/flathash.cpp
+)
+
+set(FlatBuffers_Tests_SRCS
+ ${FlatBuffers_Library_SRCS}
+ src/idl_gen_fbs.cpp
+ tests/test.cpp
+ tests/test_assert.h
+ tests/test_assert.cpp
+ tests/test_builder.h
+ tests/test_builder.cpp
+ tests/native_type_test_impl.h
+ tests/native_type_test_impl.cpp
+ # file generate by running compiler on tests/monster_test.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
+ # file generate by running compiler on tests/arrays_test.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/tests/arrays_test_generated.h
+ # file generate by running compiler on tests/native_type_test.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/tests/native_type_test_generated.h
+)
+
+set(FlatBuffers_Sample_Binary_SRCS
+ include/flatbuffers/flatbuffers.h
+ samples/sample_binary.cpp
+ # file generated by running compiler on samples/monster.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
+)
+
+set(FlatBuffers_Sample_Text_SRCS
+ ${FlatBuffers_Library_SRCS}
+ samples/sample_text.cpp
+ # file generated by running compiler on samples/monster.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
+)
+
+set(FlatBuffers_Sample_BFBS_SRCS
+ ${FlatBuffers_Library_SRCS}
+ src/idl_gen_general.cpp
+ samples/sample_bfbs.cpp
+ # file generated by running compiler on samples/monster.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
+)
+
+set(FlatBuffers_GRPCTest_SRCS
+ include/flatbuffers/flatbuffers.h
+ include/flatbuffers/grpc.h
+ include/flatbuffers/util.h
+ src/util.cpp
+ tests/monster_test.grpc.fb.h
+ tests/test_assert.h
+ tests/test_builder.h
+ tests/monster_test.grpc.fb.cc
+ tests/test_assert.cpp
+ tests/test_builder.cpp
+ grpc/tests/grpctest.cpp
+ grpc/tests/message_builder_test.cpp
+ # file generated by running compiler on samples/monster.fbs
+ ${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
+)
+
+# source_group(Compiler FILES ${FlatBuffers_Compiler_SRCS})
+# source_group(Tests FILES ${FlatBuffers_Tests_SRCS})
+
+if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+ # do not apply any global settings if the toolchain
+ # is being configured externally
+ message(STATUS "Using toolchain file: ${CMAKE_TOOLCHAIN_FILE}.")
+elseif(APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
+ set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast")
+elseif(CMAKE_COMPILER_IS_GNUCXX)
+ if(CYGWIN)
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -std=gnu++11")
+ else(CYGWIN)
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -std=c++0x")
+ endif(CYGWIN)
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Werror=shadow")
+ set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.4)
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 7.0)
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -faligned-new -Werror=implicit-fallthrough=2")
+ endif()
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -Wunused-result -Werror=unused-result -Wunused-parameter -Werror=unused-parameter")
+ endif()
+
+ # Certain platforms such as ARM do not use signed chars by default
+ # which causes issues with certain bounds checks.
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -fsigned-char")
+
+elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
+ set(FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wold-style-cast")
+ if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.8)
+ list(APPEND FLATBUFFERS_PRIVATE_CXX_FLAGS "-Wimplicit-fallthrough" "-Wextra-semi" "-Werror=unused-private-field") # enable warning
+ endif()
+ if(FLATBUFFERS_LIBCXX_WITH_CLANG)
+ if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ endif()
+ if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
+ "${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
+ set(CMAKE_EXE_LINKER_FLAGS
+ "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
+ endif()
+ endif()
+
+ # Certain platforms such as ARM do not use signed chars by default
+ # which causes issues with certain bounds checks.
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -fsigned-char")
+
+elseif(MSVC)
+ # Visual Studio pedantic build settings
+ # warning C4512: assignment operator could not be generated
+ # warning C4316: object allocated on the heap may not be aligned
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /wd4512 /wd4316")
+endif()
+
+if(FLATBUFFERS_CODE_COVERAGE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fprofile-arcs -ftest-coverage")
+ set(CMAKE_EXE_LINKER_FLAGS
+ "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+endif()
+
+function(add_fsanitize_to_target _target _sanitizer)
+ # FLATBUFFERS_CODE_SANITIZE: boolean {ON,OFF,YES,NO} or string with list of sanitizer.
+ # List of sanitizer is string starts with '=': "=address,undefined,thread,memory".
+ if((${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") OR
+ ((${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9"))
+ )
+ set(_sanitizer_flags "=address,undefined")
+ if(_sanitizer MATCHES "=.*")
+ # override default by user-defined sanitizer list
+ set(_sanitizer_flags ${_sanitizer})
+ endif()
+ target_compile_options(${_target} PRIVATE
+ -g -fsigned-char -fno-omit-frame-pointer
+ "-fsanitize${_sanitizer_flags}")
+ target_link_libraries(${_target} PRIVATE
+ "-fsanitize${_sanitizer_flags}")
+ set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ON)
+ message(STATUS "Sanitizer ${_sanitizer_flags} added to ${_target}")
+ endif()
+endfunction()
+
+if(BIICODE)
+ include(biicode/cmake/biicode.cmake)
+ return()
+endif()
+
+include_directories(include)
+include_directories(grpc)
+
+if(FLATBUFFERS_BUILD_FLATLIB)
+ add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
+ # CMake > 2.8.11: Attach header directory for when build via add_subdirectory().
+ target_include_directories(flatbuffers INTERFACE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
+ target_compile_options(flatbuffers PRIVATE "${FLATBUFFERS_PRIVATE_CXX_FLAGS}")
+endif()
+
+if(FLATBUFFERS_BUILD_FLATC)
+ add_executable(flatc ${FlatBuffers_Compiler_SRCS})
+ target_compile_options(flatc PRIVATE "${FLATBUFFERS_PRIVATE_CXX_FLAGS}")
+ if(FLATBUFFERS_CODE_SANITIZE AND NOT WIN32)
+ add_fsanitize_to_target(flatc ${FLATBUFFERS_CODE_SANITIZE})
+ endif()
+ if(NOT FLATBUFFERS_FLATC_EXECUTABLE)
+ set(FLATBUFFERS_FLATC_EXECUTABLE $<TARGET_FILE:flatc>)
+ endif()
+ if(MSVC)
+ # Make flatc.exe not depend on runtime dlls for easy distribution.
+ target_compile_options(flatc PUBLIC $<$<CONFIG:Release>:/MT>)
+ endif()
+endif()
+
+if(FLATBUFFERS_BUILD_FLATHASH)
+ add_executable(flathash ${FlatHash_SRCS})
+endif()
+
+if(FLATBUFFERS_BUILD_SHAREDLIB)
+ add_library(flatbuffers_shared SHARED ${FlatBuffers_Library_SRCS})
+
+ # Shared object version: "major.minor.micro"
+ # - micro updated every release when there is no API/ABI changes
+ # - minor updated when there are additions in API/ABI
+ # - major (ABI number) updated when there are changes in ABI (or removals)
+ set(FlatBuffers_Library_SONAME_MAJOR "1")
+ set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.11.0")
+ set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers
+ SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}"
+ VERSION "${FlatBuffers_Library_SONAME_FULL}")
+endif()
+
+function(compile_flatbuffers_schema_to_cpp_opt SRC_FBS OPT)
+ get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
+ string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
+ add_custom_command(
+ OUTPUT ${GEN_HEADER}
+ COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --gen-mutable
+ --gen-object-api -o "${SRC_FBS_DIR}"
+ --cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
+ --reflect-names ${OPT}
+ -I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
+ DEPENDS flatc)
+endfunction()
+
+function(compile_flatbuffers_schema_to_cpp SRC_FBS)
+ compile_flatbuffers_schema_to_cpp_opt(${SRC_FBS} "--no-includes;--gen-compare")
+endfunction()
+
+function(compile_flatbuffers_schema_to_binary SRC_FBS)
+ get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
+ string(REGEX REPLACE "\\.fbs$" ".bfbs" GEN_BINARY_SCHEMA ${SRC_FBS})
+ add_custom_command(
+ OUTPUT ${GEN_BINARY_SCHEMA}
+ COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -b --schema -o "${SRC_FBS_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
+ DEPENDS flatc)
+endfunction()
+
+if(FLATBUFFERS_BUILD_TESTS)
+ compile_flatbuffers_schema_to_cpp(tests/monster_test.fbs)
+ compile_flatbuffers_schema_to_cpp_opt(tests/native_type_test.fbs "")
+ compile_flatbuffers_schema_to_cpp_opt(tests/arrays_test.fbs --scoped-enums)
+ include_directories(${CMAKE_CURRENT_BINARY_DIR}/tests)
+ add_executable(flattests ${FlatBuffers_Tests_SRCS})
+ set_property(TARGET flattests
+ PROPERTY COMPILE_DEFINITIONS FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ FLATBUFFERS_DEBUG_VERIFICATION_FAILURE=1)
+ if(FLATBUFFERS_CODE_SANITIZE)
+ if(WIN32)
+ target_compile_definitions(flattests PRIVATE FLATBUFFERS_MEMORY_LEAK_TRACKING)
+ message(STATUS "Sanitizer MSVC::_CrtDumpMemoryLeaks added to flattests")
+ else()
+ add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE})
+ endif()
+ endif()
+
+ compile_flatbuffers_schema_to_cpp(samples/monster.fbs)
+ include_directories(${CMAKE_CURRENT_BINARY_DIR}/samples)
+ add_executable(flatsamplebinary ${FlatBuffers_Sample_Binary_SRCS})
+ add_executable(flatsampletext ${FlatBuffers_Sample_Text_SRCS})
+ add_executable(flatsamplebfbs ${FlatBuffers_Sample_BFBS_SRCS})
+endif()
+
+if(FLATBUFFERS_BUILD_GRPCTEST)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
+ endif()
+ if(NOT GRPC_INSTALL_PATH)
+ message(SEND_ERROR "GRPC_INSTALL_PATH variable is not defined. See grpc/README.md")
+ endif()
+ if(NOT PROTOBUF_DOWNLOAD_PATH)
+ message(SEND_ERROR "PROTOBUF_DOWNLOAD_PATH variable is not defined. See grpc/README.md")
+ endif()
+ INCLUDE_DIRECTORIES(${GRPC_INSTALL_PATH}/include)
+ INCLUDE_DIRECTORIES(${PROTOBUF_DOWNLOAD_PATH}/src)
+ LINK_DIRECTORIES(${GRPC_INSTALL_PATH}/lib)
+ add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
+ target_link_libraries(grpctest grpc++_unsecure grpc_unsecure gpr pthread dl)
+endif()
+
+include(CMake/Version.cmake)
+
+if(FLATBUFFERS_INSTALL)
+ include(GNUInstallDirs)
+
+ install(DIRECTORY include/flatbuffers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+ set(FB_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/flatbuffers")
+
+ configure_file(CMake/FlatbuffersConfigVersion.cmake.in FlatbuffersConfigVersion.cmake @ONLY)
+ install(
+ FILES "CMake/FlatbuffersConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/FlatbuffersConfigVersion.cmake"
+ DESTINATION ${FB_CMAKE_DIR}
+ )
+
+ if(FLATBUFFERS_BUILD_FLATLIB)
+ if(CMAKE_VERSION VERSION_LESS 3.0)
+ install(
+ TARGETS flatbuffers EXPORT FlatbuffersTargets
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ else()
+ install(
+ TARGETS flatbuffers EXPORT FlatbuffersTargets
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ )
+ endif()
+
+ install(EXPORT FlatbuffersTargets
+ FILE FlatbuffersTargets.cmake
+ NAMESPACE flatbuffers::
+ DESTINATION ${FB_CMAKE_DIR}
+ )
+ endif()
+
+ if(FLATBUFFERS_BUILD_FLATC)
+ install(
+ TARGETS flatc EXPORT FlatcTargets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ )
+
+ install(
+ EXPORT FlatcTargets
+ FILE FlatcTargets.cmake
+ NAMESPACE flatbuffers::
+ DESTINATION ${FB_CMAKE_DIR}
+ )
+ endif()
+
+ if(FLATBUFFERS_BUILD_SHAREDLIB)
+ if(CMAKE_VERSION VERSION_LESS 3.0)
+ install(
+ TARGETS flatbuffers_shared EXPORT FlatbuffersSharedTargets
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+ else()
+ install(
+ TARGETS flatbuffers_shared EXPORT FlatbuffersSharedTargets
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ )
+ endif()
+
+ install(
+ EXPORT FlatbuffersSharedTargets
+ FILE FlatbuffersSharedTargets.cmake
+ NAMESPACE flatbuffers::
+ DESTINATION ${FB_CMAKE_DIR}
+ )
+ endif()
+endif()
+
+if(FLATBUFFERS_BUILD_TESTS)
+ enable_testing()
+
+ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests" DESTINATION
+ "${CMAKE_CURRENT_BINARY_DIR}")
+ add_test(NAME flattests COMMAND flattests)
+ if(FLATBUFFERS_BUILD_GRPCTEST)
+ add_test(NAME grpctest COMMAND grpctest)
+ endif()
+endif()
+
+include(CMake/BuildFlatBuffers.cmake)
+
+if(UNIX)
+ # Use of CPack only supported on Linux systems.
+ if(FLATBUFFERS_PACKAGE_DEBIAN)
+ include(CMake/PackageDebian.cmake)
+ endif()
+ if (FLATBUFFERS_PACKAGE_REDHAT)
+ include(CMake/PackageRedhat.cmake)
+ endif()
+ include(CPack)
+endif()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..17428ad
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,42 @@
+Contributing {#contributing}
+============
+
+Want to contribute? Great! First, read this page (including the small print at
+the end).
+
+# Before you contribute
+Before we can use your code, you must sign the
+[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things—for instance that you'll tell us if you
+know that your code infringes on other people's patents. You don't have to sign
+the CLA until after you've submitted your code for review and a member has
+approved it, but you must do it before we can put your code into our codebase.
+Before you start working on a larger contribution, you should get in touch with
+us first through the issue tracker with your idea so that we can help out and
+possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+# Code reviews
+All submissions, including submissions by project members, require review. We
+use Github pull requests for this purpose.
+
+Some tips for good pull requests:
+* Use our code
+ [style guide](https://google.github.io/styleguide/cppguide.html).
+ When in doubt, try to stay true to the existing code of the project.
+* Write a descriptive commit message. What problem are you solving and what
+ are the consequences? Where and what did you test? Some good tips:
+ [here](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message)
+ and [here](https://www.kernel.org/doc/Documentation/SubmittingPatches).
+* If your PR consists of multiple commits which are successive improvements /
+ fixes to your first commit, consider squashing them into a single commit
+ (`git rebase -i`) such that your PR is a single commit on top of the current
+ HEAD. This make reviewing the code so much easier, and our history more
+ readable.
+
+# The small print
+Contributions made by corporations are covered by a different agreement than
+the one above, the Software Grant and Corporate Contributor License Agreement.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..a4c5efd
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..2ccde84
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,18 @@
+workspace(name = "com_github_google_flatbuffers")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+ name = "io_bazel_rules_go",
+ urls = [
+ "https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.18.6/rules_go-0.18.6.tar.gz",
+ "https://github.com/bazelbuild/rules_go/releases/download/0.18.6/rules_go-0.18.6.tar.gz",
+ ],
+ sha256 = "f04d2373bcaf8aa09bccb08a98a57e721306c8f6043a2a0ee610fd6853dcde3d",
+)
+
+load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
+
+go_rules_dependencies()
+
+go_register_toolchains()
diff --git a/android/.project b/android/.project
new file mode 100644
index 0000000..e7d5931
--- /dev/null
+++ b/android/.project
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) 2014 Google, Inc.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ -->
+<projectDescription>
+ <name>FlatBufferTest</name>
+</projectDescription>
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
new file mode 100644
index 0000000..846fd13
--- /dev/null
+++ b/android/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2013 Google, Inc.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ -->
+<!-- BEGIN_INCLUDE(manifest) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.FlatBufferTest">
+
+ <uses-feature android:glEsVersion="0x00020000"></uses-feature>
+
+ <!-- This .apk has no Java code itself, so set hasCode to false. -->
+ <application android:label="@string/app_name"
+ android:hasCode="false"
+ android:allowBackup="false">
+ <!-- Our activity is the built-in NativeActivity framework class.
+ This will take care of integrating with our NDK code. -->
+ <activity android:name="android.app.NativeActivity"
+ android:label="@string/app_name"
+ android:configChanges="orientation|keyboardHidden"
+ android:screenOrientation="landscape">
+ <!-- Tell NativeActivity the name of or .so -->
+ <meta-data android:name="android.app.lib_name"
+ android:value="FlatBufferTest" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+<!-- END_INCLUDE(manifest) -->
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..5e9809b
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,108 @@
+// Copyright (c) 2017 Google, Inc.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.0'
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion '25.0.2'
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res']
+ }
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ path "jni/Android.mk"
+ }
+ }
+
+ defaultConfig {
+ applicationId 'com.example.FlatBufferTest'
+ // This is the platform API where NativeActivity was introduced.
+ minSdkVersion 9
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ targets "FlatBufferTest"
+ arguments "-j" + Runtime.getRuntime().availableProcessors()
+ abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+ }
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ // Build with each STL variant.
+ productFlavors {
+ stlport {
+ applicationIdSuffix ".stlport"
+ versionNameSuffix "-stlport"
+ externalNativeBuild {
+ ndkBuild {
+ arguments "APP_STL=stlport_static"
+ }
+ }
+ }
+ gnustl {
+ applicationIdSuffix ".gnustl"
+ versionNameSuffix "-gnustl"
+ externalNativeBuild {
+ ndkBuild {
+ arguments "APP_STL=gnustl_static"
+ }
+ }
+ }
+ libcpp {
+ applicationIdSuffix ".libcpp"
+ versionNameSuffix "-libcpp"
+ externalNativeBuild {
+ ndkBuild {
+ arguments "APP_STL=c++_static"
+ }
+ }
+ }
+ }
+}
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..b4163b8
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1e1168c
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 19 11:54:59 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
diff --git a/android/gradlew b/android/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/android/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/android/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
new file mode 100644
index 0000000..e29c872
--- /dev/null
+++ b/android/jni/Android.mk
@@ -0,0 +1,65 @@
+# Copyright (c) 2013 Google, Inc.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+LOCAL_PATH := $(call my-dir)/../..
+
+include $(LOCAL_PATH)/android/jni/include.mk
+LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
+
+# Empty static library so that other projects can include just the basic
+# FlatBuffers headers as a module.
+include $(CLEAR_VARS)
+LOCAL_MODULE := flatbuffers
+LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_CPPFLAGS := -std=c++11 -fexceptions -Wall \
+ -DFLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+
+include $(BUILD_STATIC_LIBRARY)
+
+# static library that additionally includes text parsing/generation/reflection
+# for projects that want richer functionality.
+include $(CLEAR_VARS)
+LOCAL_MODULE := flatbuffers_extra
+LOCAL_SRC_FILES := src/idl_parser.cpp \
+ src/idl_gen_text.cpp \
+ src/reflection.cpp \
+ src/util.cpp \
+ src/code_generators.cpp
+LOCAL_STATIC_LIBRARIES := flatbuffers
+LOCAL_ARM_MODE := arm
+include $(BUILD_STATIC_LIBRARY)
+
+# FlatBuffers test
+include $(CLEAR_VARS)
+LOCAL_MODULE := FlatBufferTest
+LOCAL_SRC_FILES := android/jni/main.cpp \
+ tests/test.cpp \
+ tests/test_assert.h \
+ tests/test_builder.h \
+ tests/test_assert.cpp \
+ tests/test_builder.cpp \
+ tests/native_type_test_impl.h \
+ tests/native_type_test_impl.cpp \
+ src/idl_gen_fbs.cpp \
+ src/idl_gen_general.cpp
+LOCAL_LDLIBS := -llog -landroid -latomic
+LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers_extra
+LOCAL_ARM_MODE := arm
+include $(BUILD_SHARED_LIBRARY)
+
+$(call import-module,android/native_app_glue)
+
+$(call import-add-path,$(LOCAL_PATH)/../..)
diff --git a/android/jni/Application.mk b/android/jni/Application.mk
new file mode 100644
index 0000000..ca9e800
--- /dev/null
+++ b/android/jni/Application.mk
@@ -0,0 +1,20 @@
+# Copyright (c) 2014 Google, Inc.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+APP_PLATFORM := android-9
+APP_PROJECT_PATH := $(call my-dir)/..
+APP_STL ?= stlport_static
+APP_ABI := armeabi-v7a
+APP_CPPFLAGS += -std=c++11
diff --git a/android/jni/build_flatc.bat b/android/jni/build_flatc.bat
new file mode 100644
index 0000000..0b3f2ad
--- /dev/null
+++ b/android/jni/build_flatc.bat
@@ -0,0 +1,68 @@
+@rem Copyright (c) 2013 Google, Inc.
+@rem
+@rem This software is provided 'as-is', without any express or implied
+@rem warranty. In no event will the authors be held liable for any damages
+@rem arising from the use of this software.
+@rem Permission is granted to anyone to use this software for any purpose,
+@rem including commercial applications, and to alter it and redistribute it
+@rem freely, subject to the following restrictions:
+@rem 1. The origin of this software must not be misrepresented; you must not
+@rem claim that you wrote the original software. If you use this software
+@rem in a product, an acknowledgment in the product documentation would be
+@rem appreciated but is not required.
+@rem 2. Altered source versions must be plainly marked as such, and must not be
+@rem misrepresented as being the original software.
+@rem 3. This notice may not be removed or altered from any source distribution.
+@echo off
+
+setlocal enabledelayedexpansion
+
+set thispath=%~dp0
+
+rem Path to cmake passed in by caller.
+set cmake=%1
+rem Path to cmake project to build.
+set cmake_project_path=%2
+
+rem Newest and oldest version of Visual Studio that it's possible to select.
+set visual_studio_version_max=20
+set visual_studio_version_min=8
+
+rem Determine the newest version of Visual Studio installed on this machine.
+set visual_studio_version=
+for /L %%a in (%visual_studio_version_max%,-1,%visual_studio_version_min%) do (
+ echo Searching for Visual Studio %%a >&2
+ reg query HKLM\SOFTWARE\Microsoft\VisualStudio\%%a.0 /ve 1>NUL 2>NUL
+ if !ERRORLEVEL! EQU 0 (
+ set visual_studio_version=%%a
+ goto found_vs
+ )
+)
+echo Unable to determine whether Visual Studio is installed. >&2
+exit /B 1
+:found_vs
+
+rem Map Visual Studio version to cmake generator name.
+if "%visual_studio_version%"=="8" (
+ set cmake_generator=Visual Studio 8 2005
+)
+if "%visual_studio_version%"=="9" (
+ set cmake_generator=Visual Studio 9 2008
+)
+if %visual_studio_version% GEQ 10 (
+ set cmake_generator=Visual Studio %visual_studio_version%
+)
+rem Set visual studio version variable for msbuild.
+set VisualStudioVersion=%visual_studio_version%.0
+
+rem Generate Visual Studio solution.
+echo Generating solution for %cmake_generator%. >&2
+cd "%cmake_project_path%"
+%cmake% -G"%cmake_generator%"
+if %ERRORLEVEL% NEQ 0 (
+ exit /B %ERRORLEVEL%
+)
+
+rem Build flatc
+python %thispath%\msbuild.py flatc.vcxproj
+if ERRORLEVEL 1 exit /B 1
diff --git a/android/jni/include.mk b/android/jni/include.mk
new file mode 100644
index 0000000..b53e257
--- /dev/null
+++ b/android/jni/include.mk
@@ -0,0 +1,237 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file contains utility functions for Android projects using Flatbuffers.
+# To use this file, include it in your project's Android.mk by calling near the
+# top of your android makefile like so:
+#
+# include $(FLATBUFFERS_DIR)/android/jni/include.mk
+#
+# You will also need to import the flatbuffers module using the standard
+# import-module function.
+#
+# The main functionality this file provides are the following functions:
+# flatbuffers_fbs_to_h: Converts flatbuffer schema paths to header paths.
+# flatbuffers_header_build_rule:
+# Creates a build rule for a schema's generated header. This build rule
+# has a dependency on the flatc compiler which will be built if necessary.
+# flatbuffers_header_build_rules:
+# Creates build rules for generated headers for each schema listed and sets
+# up depenedendies.
+#
+# More information and example usage can be found in the comments preceeding
+# each function.
+
+# Targets to build the Flatbuffers compiler as well as some utility definitions
+ifeq (,$(FLATBUFFERS_INCLUDE_MK_))
+FLATBUFFERS_INCLUDE_MK_ := 1
+
+# Portable version of $(realpath) that omits drive letters on Windows.
+realpath-portable = $(join $(filter %:,$(subst :,: ,$1)),\
+ $(realpath $(filter-out %:,$(subst :,: ,$1))))
+
+PROJECT_OS := $(OS)
+ifeq (,$(OS))
+PROJECT_OS := $(shell uname -s)
+else
+ifneq ($(findstring Windows,$(PROJECT_OS)),)
+PROJECT_OS := Windows
+endif
+endif
+
+# The following block generates build rules which result in headers being
+# rebuilt from flatbuffers schemas.
+
+FLATBUFFERS_CMAKELISTS_DIR := \
+ $(call realpath-portable,$(dir $(lastword $(MAKEFILE_LIST)))/../..)
+
+# Directory that contains the FlatBuffers compiler.
+ifeq (Windows,$(PROJECT_OS))
+FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
+FLATBUFFERS_FLATC := $(lastword \
+ $(wildcard $(FLATBUFFERS_FLATC_PATH)/*/flatc.exe) \
+ $(wildcard $(FLATBUFFERS_FLATC_PATH)/flatc.exe))
+endif
+ifeq (Linux,$(PROJECT_OS))
+FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
+FLATBUFFERS_FLATC := $(FLATBUFFERS_FLATC_PATH)/flatc
+endif
+ifeq (Darwin,$(PROJECT_OS))
+FLATBUFFERS_FLATC_PATH?=$(FLATBUFFERS_CMAKELISTS_DIR)
+FLATBUFFERS_FLATC := $(lastword \
+ $(wildcard $(FLATBUFFERS_FLATC_PATH)/*/flatc) \
+ $(wildcard $(FLATBUFFERS_FLATC_PATH)/flatc))
+endif
+
+FLATBUFFERS_FLATC_ARGS?=
+
+# Search for cmake.
+CMAKE_ROOT := \
+ $(call realpath-portable,$(LOCAL_PATH)/../../../../../../prebuilts/cmake)
+ifeq (,$(CMAKE))
+ifeq (Linux,$(PROJECT_OS))
+CMAKE := $(wildcard $(CMAKE_ROOT)/linux-x86/current/bin/cmake*)
+endif
+ifeq (Darwin,$(PROJECT_OS))
+CMAKE := \
+ $(wildcard $(CMAKE_ROOT)/darwin-x86_64/current/*.app/Contents/bin/cmake)
+endif
+ifeq (Windows,$(PROJECT_OS))
+CMAKE := $(wildcard $(CMAKE_ROOT)/windows/current/bin/cmake*)
+endif
+endif
+ifeq (,$(CMAKE))
+CMAKE := cmake
+endif
+
+# Windows friendly portable local path.
+# GNU-make doesn't like : in paths, must use relative paths on Windows.
+ifeq (Windows,$(PROJECT_OS))
+PORTABLE_LOCAL_PATH =
+else
+PORTABLE_LOCAL_PATH = $(LOCAL_PATH)/
+endif
+
+# Generate a host build rule for the flatbuffers compiler.
+ifeq (Windows,$(PROJECT_OS))
+define build_flatc_recipe
+ $(FLATBUFFERS_CMAKELISTS_DIR)\android\jni\build_flatc.bat \
+ $(CMAKE) $(FLATBUFFERS_CMAKELISTS_DIR)
+endef
+endif
+ifeq (Linux,$(PROJECT_OS))
+define build_flatc_recipe
+ +cd $(FLATBUFFERS_CMAKELISTS_DIR) && \
+ $(CMAKE) . && \
+ $(MAKE) flatc
+endef
+endif
+ifeq (Darwin,$(PROJECT_OS))
+define build_flatc_recipe
+ cd $(FLATBUFFERS_CMAKELISTS_DIR) && "$(CMAKE)" -GXcode . && \
+ xcodebuild -target flatc
+endef
+endif
+ifeq (,$(build_flatc_recipe))
+ifeq (,$(FLATBUFFERS_FLATC))
+$(error flatc binary not found!)
+endif
+endif
+
+# Generate a build rule for flatc.
+ifeq ($(strip $(FLATBUFFERS_FLATC)),)
+flatc_target := build_flatc
+.PHONY: $(flatc_target)
+FLATBUFFERS_FLATC := \
+ python $(FLATBUFFERS_CMAKELISTS_DIR)/android/jni/run_flatc.py \
+ $(FLATBUFFERS_CMAKELISTS_DIR)
+else
+flatc_target := $(FLATBUFFERS_FLATC)
+endif
+$(flatc_target):
+ $(call build_flatc_recipe)
+
+# $(flatbuffers_fbs_to_h schema_dir,output_dir,path)
+#
+# Convert the specified schema path to a Flatbuffers generated header path.
+# For example:
+#
+# $(call flatbuffers_fbs_to_h,$(MY_PROJ_DIR)/schemas,\
+# $(MY_PROJ_DIR)/gen/include,$(MY_PROJ_DIR)/schemas/example.fbs)
+#
+# This will convert the file path `$(MY_PROJ_DIR)/schemas/example.fbs)` to
+# `$(MY_PROJ_DIR)/gen/include/example_generated.h`
+define flatbuffers_fbs_to_h
+$(subst $(1),$(2),$(patsubst %.fbs,%_generated.h,$(3)))
+endef
+
+# $(flatbuffers_header_build_rule schema_file,schema_dir,output_dir,\
+# schema_include_dirs)
+#
+# Generate a build rule that will convert a Flatbuffers schema to a generated
+# header derived from the schema filename using flatbuffers_fbs_to_h. For
+# example:
+#
+# $(call flatbuffers_header_build_rule,$(MY_PROJ_DIR)/schemas/example.fbs,\
+# $(MY_PROJ_DIR)/schemas,$(MY_PROJ_DIR)/gen/include)
+#
+# The final argument, schema_include_dirs, is optional and is only needed when
+# the schema files depend on other schema files outside their own directory.
+define flatbuffers_header_build_rule
+$(eval \
+ $(call flatbuffers_fbs_to_h,$(2),$(3),$(1)): $(1) $(flatc_target)
+ $(call host-echo-build-step,generic,Generate) \
+ $(subst $(LOCAL_PATH)/,,$(call flatbuffers_fbs_to_h,$(2),$(3),$(1)))
+ $(hide) $$(FLATBUFFERS_FLATC) $(FLATBUFFERS_FLATC_ARGS) \
+ $(foreach include,$(4),-I $(include)) -o $$(dir $$@) -c $$<)
+endef
+
+# TODO: Remove when the LOCAL_PATH expansion bug in the NDK is fixed.
+# Override the default behavior of local-source-file-path to workaround
+# a bug which prevents the build of deeply nested projects when NDK_OUT is
+# set.
+local-source-file-path=\
+$(if $(call host-path-is-absolute,$1),$1,$(call \
+ realpath-portable,$(LOCAL_PATH)/$1))
+
+
+# $(flatbuffers_header_build_rules schema_files,schema_dir,output_dir,\
+# schema_include_dirs,src_files,[build_target],[dependencies]))
+#
+# $(1) schema_files: Space separated list of flatbuffer schema files.
+# $(2) schema_dir: Directory containing the flatbuffer schemas.
+# $(3) output_dir: Where to place the generated files.
+# $(4) schema_include_dirs: Directories to include when generating schemas.
+# $(5) src_files: Files that should depend upon the headers generated from the
+# flatbuffer schemas.
+# $(6) build_target: Name of a build target that depends upon all generated
+# headers.
+# $(7) dependencies: Space seperated list of additional build targets src_files
+# should depend upon.
+#
+# Use this in your own Android.mk file to generate build rules that will
+# generate header files for your flatbuffer schemas as well as automatically
+# set your source files to be dependent on the generated headers. For example:
+#
+# $(call flatbuffers_header_build_rules,$(MY_PROJ_SCHEMA_FILES),\
+# $(MY_PROJ_SCHEMA_DIR),$(MY_PROJ_GENERATED_OUTPUT_DIR),
+# $(MY_PROJ_SCHEMA_INCLUDE_DIRS),$(LOCAL_SRC_FILES))
+#
+# NOTE: Due problesm with path processing in ndk-build when presented with
+# deeply nested projects must redefine LOCAL_PATH after include this makefile
+# using:
+#
+# LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
+#
+define flatbuffers_header_build_rules
+$(foreach schema,$(1),\
+ $(call flatbuffers_header_build_rule,\
+ $(schema),$(strip $(2)),$(strip $(3)),$(strip $(4))))\
+$(foreach src,$(strip $(5)),\
+ $(eval $(call local-source-file-path,$(src)): \
+ $(foreach schema,$(strip $(1)),\
+ $(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))))\
+$(if $(6),\
+ $(foreach schema,$(strip $(1)),\
+ $(eval $(6): \
+ $(call flatbuffers_fbs_to_h,$(strip $(2)),$(strip $(3)),$(schema)))),)\
+$(if $(7),\
+ $(foreach src,$(strip $(5)),\
+ $(eval $(call local-source-file-path,$(src)): $(strip $(7)))),)\
+$(if $(7),\
+ $(foreach dependency,$(strip $(7)),\
+ $(eval $(6): $(dependency))),)
+endef
+
+endif # FLATBUFFERS_INCLUDE_MK_
diff --git a/android/jni/main.cpp b/android/jni/main.cpp
new file mode 100644
index 0000000..0d64349
--- /dev/null
+++ b/android/jni/main.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android_native_app_glue.h>
+
+extern int main(int argc, char **argv);
+
+void android_main(android_app *app) {
+ // Make sure glue isn't stripped.
+ app_dummy();
+
+ main(0, NULL);
+}
diff --git a/android/jni/msbuild.py b/android/jni/msbuild.py
new file mode 100644
index 0000000..5f92d70
--- /dev/null
+++ b/android/jni/msbuild.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Simple script that locates the newest MSBuild in one of several locations.
+
+This script will find the highest version number of MSBuild and run it,
+passing its arguments through to MSBuild.
+"""
+
+import glob
+import os
+import re
+import string
+import subprocess
+import sys
+
+SYSTEMROOT = os.getenv("SYSTEMROOT", "c:\\windows")
+PROGRAM_FILES = os.getenv("ProgramFiles", "c:\\Program Files")
+PROGRAM_FILES_X86 = os.getenv("ProgramFiles(x86)", "c:\\Program Files (x86)")
+
+SEARCH_FOLDERS = [ PROGRAM_FILES + "\\MSBuild\\*\\Bin\\MSBuild.exe",
+ PROGRAM_FILES_X86 + "\\MSBuild\\*\\Bin\\MSBuild.exe",
+ SYSTEMROOT + "\\Microsoft.NET\Framework\\*\\MSBuild.exe" ]
+
+def compare_version(a, b):
+ """Compare two version number strings of the form W.X.Y.Z.
+
+ The numbers are compared most-significant to least-significant.
+ For example, 12.345.67.89 > 2.987.88.99.
+
+ Args:
+ a: First version number string to compare
+ b: Second version number string to compare
+
+ Returns:
+ 0 if the numbers are identical, a positive number if 'a' is larger, and
+ a negative number if 'b' is larger.
+ """
+ aa = string.split(a, ".")
+ bb = string.split(b, ".")
+ for i in range(0, 4):
+ if aa[i] != bb[i]:
+ return cmp(int(aa[i]), int(bb[i]))
+ return 0
+
+def main():
+ msbuilds = []
+
+ for folder in SEARCH_FOLDERS:
+ for file in glob.glob(folder):
+ p = subprocess.Popen([file, "/version"], stdout=subprocess.PIPE)
+ out, err = p.communicate()
+ match = re.search("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$", out, re.M)
+ if match:
+ msbuilds.append({ 'ver':match.group(), 'exe':file })
+ msbuilds.sort(lambda x, y: compare_version(x['ver'], y['ver']), reverse=True)
+ if len(msbuilds) == 0:
+ print "Unable to find MSBuild.\n"
+ return -1;
+ cmd = [msbuilds[0]['exe']]
+ cmd.extend(sys.argv[1:])
+ return subprocess.call(cmd)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/android/jni/run_flatc.py b/android/jni/run_flatc.py
new file mode 100755
index 0000000..cda13bb
--- /dev/null
+++ b/android/jni/run_flatc.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import platform
+import subprocess
+import sys
+
+EXECUTABLE_EXTENSION = '.exe' if platform.system() == 'Windows' else ''
+# Paths to search for flatc relative to the current working directory.
+FLATC_SEARCH_PATHS = [os.path.curdir, 'Release', 'Debug']
+
+def main():
+ """Script that finds and runs flatc built from source."""
+ if len(sys.argv) < 2:
+ sys.stderr.write('Usage: run_flatc.py flatbuffers_dir [flatc_args]\n')
+ return 1
+ cwd = os.getcwd()
+ flatc = ''
+ flatbuffers_dir = sys.argv[1]
+ for path in FLATC_SEARCH_PATHS:
+ current = os.path.join(flatbuffers_dir, path,
+ 'flatc' + EXECUTABLE_EXTENSION)
+ if os.path.exists(current):
+ flatc = current
+ break
+ if not flatc:
+ sys.stderr.write('flatc not found\n')
+ return 1
+ command = [flatc] + sys.argv[2:]
+ return subprocess.call(command)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
new file mode 100644
index 0000000..ec75239
--- /dev/null
+++ b/android/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2014 Google, Inc.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ -->
+<resources>
+ <string name="app_name">FlatBufferTest</string>
+</resources>
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..75a63c8
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,105 @@
+branches:
+ only:
+ - master
+
+os: Visual Studio 2015
+
+environment:
+
+ global:
+ # Workaround for https://github.com/conda/conda-build/issues/636
+ PYTHONIOENCODING: UTF-8
+ CONDA_INSTALL_LOCN: "C:\\Miniconda35-x64"
+
+ matrix:
+ - CMAKE_VS_VERSION: "10 2010"
+ MONSTER_EXTRA: "skip"
+
+ - CMAKE_VS_VERSION: "12 2013"
+ MONSTER_EXTRA: "skip"
+
+ - CMAKE_VS_VERSION: "14 2015"
+ MONSTER_EXTRA: ""
+
+platform:
+ - x86
+ - x64
+
+configuration:
+ - Debug
+ - Release
+
+before_build:
+ - set MONSTER_EXTRA=%MONSTER_EXTRA%
+ - cmake -G"Visual Studio %CMAKE_VS_VERSION%" -DFLATBUFFERS_CODE_SANITIZE=1 .
+ # This cuts down on a lot of noise generated by xamarin warnings.
+ - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
+
+build:
+ project: ALL_BUILD.vcxproj
+ verbosity: minimal
+
+after_build:
+ - python conan/appveyor/install.py
+ - python conan/appveyor/build.py
+
+install:
+ - set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%;
+ - curl -sSf -o rustup-init.exe https://win.rustup.rs/
+ - rustup-init.exe -y
+ - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
+ - rustc -V
+ - cargo -V
+
+test_script:
+ - call .appveyor\check-generate-code.bat -b %CONFIGURATION%
+ - "cd tests"
+ - rem "Building all code"
+ - generate_code.bat -b %CONFIGURATION%
+ - 7z a GeneratedMyGameCode.zip MyGame\
+ - rem "---------------- C++ -----------------"
+ - "cd .."
+ - "%CONFIGURATION%\\flattests.exe"
+ - "cd tests"
+ - rem "---------------- Java -----------------"
+ - "java -version"
+ - "JavaTest.bat"
+ - rem "---------------- Rust ----------------"
+ - "RustTest.bat"
+ - rem "---------------- JS -----------------"
+ - "node --version"
+ - "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
+ - "node JavaScriptTest ./monster_test_generated"
+ - rem "-------------- Python ---------------"
+ - where python
+ - python --version
+ - where pip
+ - pip --version
+ - where conda
+ - conda --version
+ - rem "installing flatbuffers python library"
+ - pip install ../python
+ - rem "testing without installing Numpy"
+ - python py_test.py 0 0 0
+ - rem "testing after installing Numpy - disabled"
+ # FIXME: This has a LOT of unnecessary dependencies and makes the tests fail
+ # with timeouts.
+ # - conda install --yes numpy
+ # - python py_test.py 0 0 0
+ - rem "---------------- C# -----------------"
+ # Have to compile this here rather than in "build" above because AppVeyor only
+ # supports building one project??
+ - "cd FlatBuffers.Test"
+ - "msbuild.exe /property:Configuration=Release;OutputPath=tempcs /verbosity:minimal FlatBuffers.Test.csproj"
+ - "tempcs\\FlatBuffers.Test.exe"
+ # Run tests with UNSAFE_BYTEBUFFER
+ - "msbuild.exe /property:Configuration=Release;UnsafeByteBuffer=true;OutputPath=tempcsUnsafe /verbosity:minimal FlatBuffers.Test.csproj"
+ - "tempcsUnsafe\\FlatBuffers.Test.exe"
+ # TODO: add more languages.
+ - "cd ..\\.."
+
+artifacts:
+ - path: $(CONFIGURATION)\flatc.exe
+ name: flatc.exe
+ - path: tests\GeneratedMyGameCode.zip
+ name: GeneratedMyGameCode.zip
diff --git a/build_defs.bzl b/build_defs.bzl
new file mode 100644
index 0000000..a92f0ed
--- /dev/null
+++ b/build_defs.bzl
@@ -0,0 +1,237 @@
+# Description:
+# BUILD rules for generating flatbuffer files in various languages.
+
+"""
+Rules for building C++ flatbuffers with Bazel.
+"""
+
+flatc_path = "@com_github_google_flatbuffers//:flatc"
+
+DEFAULT_INCLUDE_PATHS = [
+ "./",
+ "$(GENDIR)",
+ "$(BINDIR)",
+]
+
+DEFAULT_FLATC_ARGS = [
+ "--gen-object-api",
+ "--gen-compare",
+ "--no-includes",
+ "--gen-mutable",
+ "--reflect-names",
+ "--cpp-ptr-type flatbuffers::unique_ptr",
+]
+
+def flatbuffer_library_public(
+ name,
+ srcs,
+ outs,
+ language_flag,
+ out_prefix = "",
+ includes = [],
+ include_paths = DEFAULT_INCLUDE_PATHS,
+ flatc_args = DEFAULT_FLATC_ARGS,
+ reflection_name = "",
+ reflection_visibility = None,
+ output_to_bindir = False):
+ """Generates code files for reading/writing the given flatbuffers in the requested language using the public compiler.
+
+ Args:
+ name: Rule name.
+ srcs: Source .fbs files. Sent in order to the compiler.
+ outs: Output files from flatc.
+ language_flag: Target language flag. One of [-c, -j, -js].
+ out_prefix: Prepend this path to the front of all generated files except on
+ single source targets. Usually is a directory name.
+ includes: Optional, list of filegroups of schemas that the srcs depend on.
+ include_paths: Optional, list of paths the includes files can be found in.
+ flatc_args: Optional, list of additional arguments to pass to flatc.
+ reflection_name: Optional, if set this will generate the flatbuffer
+ reflection binaries for the schemas.
+ reflection_visibility: The visibility of the generated reflection Fileset.
+ output_to_bindir: Passed to genrule for output to bin directory.
+
+
+ This rule creates a filegroup(name) with all generated source files, and
+ optionally a Fileset([reflection_name]) with all generated reflection
+ binaries.
+ """
+ include_paths_cmd = ["-I %s" % (s) for s in include_paths]
+
+ # '$(@D)' when given a single source target will give the appropriate
+ # directory. Appending 'out_prefix' is only necessary when given a build
+ # target with multiple sources.
+ output_directory = (
+ ("-o $(@D)/%s" % (out_prefix)) if len(srcs) > 1 else ("-o $(@D)")
+ )
+ genrule_cmd = " ".join([
+ "SRCS=($(SRCS));",
+ "for f in $${SRCS[@]:0:%s}; do" % len(srcs),
+ "$(location %s)" % (flatc_path),
+ " ".join(include_paths_cmd),
+ " ".join(flatc_args),
+ language_flag,
+ output_directory,
+ "$$f;",
+ "done",
+ ])
+ native.genrule(
+ name = name,
+ srcs = srcs + includes,
+ outs = outs,
+ output_to_bindir = output_to_bindir,
+ tools = [flatc_path],
+ cmd = genrule_cmd,
+ message = "Generating flatbuffer files for %s:" % (name),
+ )
+ if reflection_name:
+ reflection_genrule_cmd = " ".join([
+ "SRCS=($(SRCS));",
+ "for f in $${SRCS[@]:0:%s}; do" % len(srcs),
+ "$(location %s)" % (flatc_path),
+ "-b --schema",
+ " ".join(flatc_args),
+ " ".join(include_paths_cmd),
+ language_flag,
+ output_directory,
+ "$$f;",
+ "done",
+ ])
+ reflection_outs = [
+ (out_prefix + "%s.bfbs") % (s.replace(".fbs", "").split("/")[-1])
+ for s in srcs
+ ]
+ native.genrule(
+ name = "%s_srcs" % reflection_name,
+ srcs = srcs + includes,
+ outs = reflection_outs,
+ output_to_bindir = output_to_bindir,
+ tools = [flatc_path],
+ cmd = reflection_genrule_cmd,
+ message = "Generating flatbuffer reflection binary for %s:" % (name),
+ )
+ native.Fileset(
+ name = reflection_name,
+ out = "%s_out" % reflection_name,
+ entries = [
+ native.FilesetEntry(files = reflection_outs),
+ ],
+ visibility = reflection_visibility,
+ )
+
+def flatbuffer_cc_library(
+ name,
+ srcs,
+ srcs_filegroup_name = "",
+ out_prefix = "",
+ includes = [],
+ include_paths = DEFAULT_INCLUDE_PATHS,
+ flatc_args = DEFAULT_FLATC_ARGS,
+ visibility = None,
+ srcs_filegroup_visibility = None,
+ gen_reflections = False):
+ '''A cc_library with the generated reader/writers for the given flatbuffer definitions.
+
+ Args:
+ name: Rule name.
+ srcs: Source .fbs files. Sent in order to the compiler.
+ srcs_filegroup_name: Name of the output filegroup that holds srcs. Pass this
+ filegroup into the `includes` parameter of any other
+ flatbuffer_cc_library that depends on this one's schemas.
+ out_prefix: Prepend this path to the front of all generated files. Usually
+ is a directory name.
+ includes: Optional, list of filegroups of schemas that the srcs depend on.
+ ** SEE REMARKS BELOW **
+ include_paths: Optional, list of paths the includes files can be found in.
+ flatc_args: Optional list of additional arguments to pass to flatc
+ (e.g. --gen-mutable).
+ visibility: The visibility of the generated cc_library. By default, use the
+ default visibility of the project.
+ srcs_filegroup_visibility: The visibility of the generated srcs filegroup.
+ By default, use the value of the visibility parameter above.
+ gen_reflections: Optional, if true this will generate the flatbuffer
+ reflection binaries for the schemas.
+
+ This produces:
+ filegroup([name]_srcs): all generated .h files.
+ filegroup(srcs_filegroup_name if specified, or [name]_includes if not):
+ Other flatbuffer_cc_library's can pass this in for their `includes`
+ parameter, if they depend on the schemas in this library.
+ Fileset([name]_reflection): (Optional) all generated reflection binaries.
+ cc_library([name]): library with sources and flatbuffers deps.
+
+ Remarks:
+ ** Because the genrule used to call flatc does not have any trivial way of
+ computing the output list of files transitively generated by includes and
+ --gen-includes (the default) being defined for flatc, the --gen-includes
+ flag will not work as expected. The way around this is to add a dependency
+ to the flatbuffer_cc_library defined alongside the flatc included Fileset.
+ For example you might define:
+
+ flatbuffer_cc_library(
+ name = "my_fbs",
+ srcs = [ "schemas/foo.fbs" ],
+ includes = [ "//third_party/bazz:bazz_fbs_includes" ],
+ )
+
+ In which foo.fbs includes a few files from the Fileset defined at
+ //third_party/bazz:bazz_fbs_includes. When compiling the library that
+ includes foo_generated.h, and therefore has my_fbs as a dependency, it
+ will fail to find any of the bazz *_generated.h files unless you also
+ add bazz's flatbuffer_cc_library to your own dependency list, e.g.:
+
+ cc_library(
+ name = "my_lib",
+ deps = [
+ ":my_fbs",
+ "//third_party/bazz:bazz_fbs"
+ ],
+ )
+
+ Happy dependent Flatbuffering!
+ '''
+ output_headers = [
+ (out_prefix + "%s_generated.h") % (s.replace(".fbs", "").split("/")[-1])
+ for s in srcs
+ ]
+ reflection_name = "%s_reflection" % name if gen_reflections else ""
+
+ srcs_lib = "%s_srcs" % (name)
+ flatbuffer_library_public(
+ name = srcs_lib,
+ srcs = srcs,
+ outs = output_headers,
+ language_flag = "-c",
+ out_prefix = out_prefix,
+ includes = includes,
+ include_paths = include_paths,
+ flatc_args = flatc_args,
+ reflection_name = reflection_name,
+ reflection_visibility = visibility,
+ )
+ native.cc_library(
+ name = name,
+ hdrs = [
+ ":" + srcs_lib,
+ ],
+ srcs = [
+ ":" + srcs_lib,
+ ],
+ features = [
+ "-parse_headers",
+ ],
+ deps = [
+ "@com_github_google_flatbuffers//:runtime_cc",
+ ],
+ includes = [],
+ linkstatic = 1,
+ visibility = visibility,
+ )
+
+ # A filegroup for the `srcs`. That is, all the schema files for this
+ # Flatbuffer set.
+ native.filegroup(
+ name = srcs_filegroup_name if srcs_filegroup_name else "%s_includes" % (name),
+ srcs = srcs,
+ visibility = srcs_filegroup_visibility if srcs_filegroup_visibility != None else visibility,
+ )
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..807709c
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,18 @@
+{
+ "name": "google/flatbuffers",
+ "type": "library",
+ "description": "FlatBuffers for PHP",
+ "keywords": ["google", "flatbuffers", "serialization"],
+ "homepage": "https://github.com/google/flatbuffers",
+ "license": "Apache-2.0",
+ "require": {
+ "php": ">=5.4"
+ },
+ "require-dev": {
+ },
+ "autoload": {
+ "psr-4": {
+ "Google\\FlatBuffers\\": "php"
+ }
+ }
+}
\ No newline at end of file
diff --git a/conan/CMakeLists.txt b/conan/CMakeLists.txt
new file mode 100644
index 0000000..d32a013
--- /dev/null
+++ b/conan/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.8)
+
+message(STATUS "Conan FlatBuffers Wrapper")
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+if (WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB)
+ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+endif(WIN32 AND MSVC AND FLATBUFFERS_BUILD_SHAREDLIB)
+
+include(${CMAKE_SOURCE_DIR}/CMakeListsOriginal.txt)
diff --git a/conan/appveyor/build.py b/conan/appveyor/build.py
new file mode 100644
index 0000000..9bac46d
--- /dev/null
+++ b/conan/appveyor/build.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os
+
+if os.getenv("APPVEYOR_REPO_TAG") != "true":
+ print("Skip build step. It's not TAG")
+else:
+ os.system("python conan/build.py")
diff --git a/conan/appveyor/install.py b/conan/appveyor/install.py
new file mode 100644
index 0000000..962c7da
--- /dev/null
+++ b/conan/appveyor/install.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os
+
+if os.getenv("APPVEYOR_REPO_TAG") != "true":
+ print("Skip step. It's not TAG")
+else:
+ os.system("pip install conan conan-package-tools")
diff --git a/conan/build.py b/conan/build.py
new file mode 100644
index 0000000..5545631
--- /dev/null
+++ b/conan/build.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os
+import re
+import subprocess
+from cpt.packager import ConanMultiPackager
+
+
+def set_appveyor_environment():
+ if os.getenv("APPVEYOR") is not None:
+ compiler_version = os.getenv("CMAKE_VS_VERSION").split(" ")[0].replace('"', '')
+ os.environ["CONAN_VISUAL_VERSIONS"] = compiler_version
+ os.environ["CONAN_STABLE_BRANCH_PATTERN"] = "master"
+ ci_platform = os.getenv("Platform").replace('"', '')
+ ci_platform = "x86" if ci_platform == "x86" else "x86_64"
+ os.environ["CONAN_ARCHS"] = ci_platform
+ os.environ["CONAN_BUILD_TYPES"] = os.getenv("Configuration").replace('"', '')
+
+
+def get_branch():
+ try:
+ for line in subprocess.check_output("git branch", shell=True).decode().splitlines():
+ line = line.strip()
+ if line.startswith("*") and " (HEAD detached" not in line:
+ return line.replace("*", "", 1).strip()
+ return ""
+ except Exception:
+ pass
+ return ""
+
+
+def get_version():
+ version = get_branch()
+ if os.getenv("TRAVIS", False):
+ version = os.getenv("TRAVIS_BRANCH")
+
+ if os.getenv("APPVEYOR", False):
+ version = os.getenv("APPVEYOR_REPO_BRANCH")
+ if os.getenv("APPVEYOR_REPO_TAG") == "true":
+ version = os.getenv("APPVEYOR_REPO_TAG_NAME")
+
+ match = re.search(r"v(\d+\.\d+\.\d+.*)", version)
+ if match:
+ return match.group(1)
+ return version
+
+
+def get_reference(username):
+ return "flatbuffers/{}@google/stable".format(get_version())
+
+
+if __name__ == "__main__":
+ login_username = os.getenv("CONAN_LOGIN_USERNAME", "aardappel")
+ username = os.getenv("CONAN_USERNAME", "google")
+ upload = os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/aardappel/flatbuffers")
+ stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*")
+ test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package"))
+ upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
+ set_appveyor_environment()
+
+ builder = ConanMultiPackager(reference=get_reference(username),
+ username=username,
+ login_username=login_username,
+ upload=upload,
+ stable_branch_pattern=stable_branch_pattern,
+ upload_only_when_stable=upload_only_when_stable,
+ test_folder=test_folder)
+ builder.add_common_builds(pure_c=False)
+ builder.run()
diff --git a/conan/test_package/CMakeLists.txt b/conan/test_package/CMakeLists.txt
new file mode 100644
index 0000000..9c1c78c
--- /dev/null
+++ b/conan/test_package/CMakeLists.txt
@@ -0,0 +1,9 @@
+project(test_package CXX)
+cmake_minimum_required(VERSION 2.8.11)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+add_executable(${PROJECT_NAME} test_package.cpp)
+target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
+set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)
diff --git a/conan/test_package/conanfile.py b/conan/test_package/conanfile.py
new file mode 100644
index 0000000..735e31d
--- /dev/null
+++ b/conan/test_package/conanfile.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from conans import ConanFile, CMake
+import os
+
+
+class TestPackageConan(ConanFile):
+ settings = "os", "compiler", "build_type", "arch"
+ generators = "cmake"
+
+ def build(self):
+ cmake = CMake(self)
+ cmake.configure()
+ cmake.build()
+
+ def test(self):
+ bin_path = os.path.join("bin", "test_package")
+ self.run(bin_path, run_environment=True)
+ self.run("flatc --version", run_environment=True)
+ self.run("flathash fnv1_16 conan", run_environment=True)
diff --git a/conan/test_package/test_package.cpp b/conan/test_package/test_package.cpp
new file mode 100644
index 0000000..df7d577
--- /dev/null
+++ b/conan/test_package/test_package.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+#include <iostream>
+#include "flatbuffers/util.h"
+
+// Test to validate Conan package generated
+
+int main(int /*argc*/, const char * /*argv*/ []) {
+
+ const std::string filename("conanbuildinfo.cmake");
+
+ if (flatbuffers::FileExists(filename.c_str())) {
+ std::cout << "File " << filename << " exists.\n";
+ } else {
+ std::cout << "File " << filename << " does not exist.\n";
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/conan/travis/build.sh b/conan/travis/build.sh
new file mode 100755
index 0000000..069ced2
--- /dev/null
+++ b/conan/travis/build.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ if which pyenv > /dev/null; then
+ eval "$(pyenv init -)"
+ fi
+ pyenv activate conan
+fi
+
+conan user
+python conan/build.py
diff --git a/conan/travis/install.sh b/conan/travis/install.sh
new file mode 100755
index 0000000..f4208d8
--- /dev/null
+++ b/conan/travis/install.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ brew update || brew update
+ brew outdated pyenv || brew upgrade pyenv
+ brew install pyenv-virtualenv
+ brew install cmake || true
+
+ if which pyenv > /dev/null; then
+ eval "$(pyenv init -)"
+ fi
+
+ pyenv install 2.7.10
+ pyenv virtualenv 2.7.10 conan
+ pyenv rehash
+ pyenv activate conan
+fi
+
+pip install -U conan_package_tools conan
diff --git a/conanfile.py b/conanfile.py
new file mode 100644
index 0000000..bdd832c
--- /dev/null
+++ b/conanfile.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""Conan recipe package for Google FlatBuffers
+"""
+import os
+import shutil
+from conans import ConanFile, CMake, tools
+
+
+class FlatbuffersConan(ConanFile):
+ name = "flatbuffers"
+ license = "Apache-2.0"
+ url = "https://github.com/google/flatbuffers"
+ homepage = "http://google.github.io/flatbuffers/"
+ author = "Wouter van Oortmerssen"
+ topics = ("conan", "flatbuffers", "serialization", "rpc", "json-parser")
+ description = "Memory Efficient Serialization Library"
+ settings = "os", "compiler", "build_type", "arch"
+ options = {"shared": [True, False], "fPIC": [True, False]}
+ default_options = {"shared": False, "fPIC": True}
+ generators = "cmake"
+ exports = "LICENSE.txt"
+ exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt", "conan/CMakeLists.txt"]
+
+ def source(self):
+ """Wrap the original CMake file to call conan_basic_setup
+ """
+ shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt")
+ shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt")
+
+ def config_options(self):
+ """Remove fPIC option on Windows platform
+ """
+ if self.settings.os == "Windows":
+ self.options.remove("fPIC")
+
+ def configure_cmake(self):
+ """Create CMake instance and execute configure step
+ """
+ cmake = CMake(self)
+ cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False
+ cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared
+ cmake.definitions["FLATBUFFERS_BUILD_FLATLIB"] = not self.options.shared
+ cmake.configure()
+ return cmake
+
+ def build(self):
+ """Configure, build and install FlatBuffers using CMake.
+ """
+ cmake = self.configure_cmake()
+ cmake.build()
+
+ def package(self):
+ """Copy Flatbuffers' artifacts to package folder
+ """
+ cmake = self.configure_cmake()
+ cmake.install()
+ self.copy(pattern="LICENSE.txt", dst="licenses")
+ self.copy(pattern="FindFlatBuffers.cmake", dst=os.path.join("lib", "cmake", "flatbuffers"), src="CMake")
+ self.copy(pattern="flathash*", dst="bin", src="bin")
+ self.copy(pattern="flatc*", dst="bin", src="bin")
+ if self.settings.os == "Windows" and self.options.shared:
+ if self.settings.compiler == "Visual Studio":
+ shutil.move(os.path.join(self.package_folder, "lib", "%s.dll" % self.name),
+ os.path.join(self.package_folder, "bin", "%s.dll" % self.name))
+ elif self.settings.compiler == "gcc":
+ shutil.move(os.path.join(self.package_folder, "lib", "lib%s.dll" % self.name),
+ os.path.join(self.package_folder, "bin", "lib%s.dll" % self.name))
+
+ def package_info(self):
+ """Collect built libraries names and solve flatc path.
+ """
+ self.cpp_info.libs = tools.collect_libs(self)
+ self.user_info.flatc = os.path.join(self.package_folder, "bin", "flatc")
diff --git a/dart/CHANGELOG.md b/dart/CHANGELOG.md
new file mode 100644
index 0000000..5e2d2de
--- /dev/null
+++ b/dart/CHANGELOG.md
@@ -0,0 +1,14 @@
+# CHANGELOG
+
+## 1.9.2
+
+- Ensure `_writeString` adds enough padding to null terminate strings.
+
+## 1.9.1
+
+- Changed constant identifiers to be compatible with Dart 2.x
+- No longer supports Dart 1.x
+
+## 1.9.0
+
+- Initial release, supports Dart 1.x and many dev versions of Dart 2.x
\ No newline at end of file
diff --git a/dart/LICENSE b/dart/LICENSE
new file mode 100644
index 0000000..b2ae013
--- /dev/null
+++ b/dart/LICENSE
@@ -0,0 +1,233 @@
+The code in lib/flat_buffers.dart is based on code that was releases under the
+following license:
+
+Copyright 2012, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+To the extent permissible, the changes to that code and the other assets in
+this package are licensed under the Apache2 license:
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2014 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/dart/README.md b/dart/README.md
new file mode 100644
index 0000000..11bc0c4
--- /dev/null
+++ b/dart/README.md
@@ -0,0 +1,13 @@
+# FlatBuffers for Dart
+
+This package is used to read and write FlatBuffer files in Dart.
+
+Most consumers will want to use the [`flatc`](https://github.com/google/flatbuffers)
+compiler to generate Dart code from a FlatBuffers IDL schema. For example, the
+`monster_my_game.sample_generated.dart` was generated with `flatc` from
+`monster.fbs` in the example folder. The generated classes can be used to read
+or write binary files that are interoperable with other languages and platforms
+supported by FlatBuffers, as illustrated in the `example.dart` in the
+examples folder.
+
+Additional documentation and examples are available [at the FlatBuffers site](https://google.github.io/flatbuffers/index.html)
\ No newline at end of file
diff --git a/dart/example/example.dart b/dart/example/example.dart
new file mode 100644
index 0000000..d95bb31
--- /dev/null
+++ b/dart/example/example.dart
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2018 Dan Field. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+import './monster_my_game.sample_generated.dart' as myGame;
+
+// Example how to use FlatBuffers to create and read binary buffers.
+
+void main() {
+ builderTest();
+ objectBuilderTest();
+}
+
+void builderTest() {
+ final builder = new fb.Builder(initialSize: 1024);
+ final int weaponOneName = builder.writeString("Sword");
+ final int weaponOneDamage = 3;
+
+ final int weaponTwoName = builder.writeString("Axe");
+ final int weaponTwoDamage = 5;
+
+ final swordBuilder = new myGame.WeaponBuilder(builder)
+ ..begin()
+ ..addNameOffset(weaponOneName)
+ ..addDamage(weaponOneDamage);
+ final int sword = swordBuilder.finish();
+
+ final axeBuilder = new myGame.WeaponBuilder(builder)
+ ..begin()
+ ..addNameOffset(weaponTwoName)
+ ..addDamage(weaponTwoDamage);
+ final int axe = axeBuilder.finish();
+
+ // Serialize a name for our monster, called "Orc".
+ final int name = builder.writeString('Orc');
+
+ // Create a list representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ final inventory = builder.writeListUint8(treasure);
+ final weapons = builder.writeList([sword, axe]);
+
+ // Struct builders are very easy to reuse.
+ final vec3Builder = new myGame.Vec3Builder(builder);
+
+ vec3Builder.finish(4.0, 5.0, 6.0);
+ vec3Builder.finish(1.0, 2.0, 3.0);
+ // Set his hit points to 300 and his mana to 150.
+ final int hp = 300;
+ final int mana = 150;
+
+ final monster = new myGame.MonsterBuilder(builder)
+ ..begin()
+ ..addNameOffset(name)
+ ..addInventoryOffset(inventory)
+ ..addWeaponsOffset(weapons)
+ ..addEquippedType(myGame.EquipmentTypeId.Weapon)
+ ..addEquippedOffset(axe)
+ ..addHp(hp)
+ ..addMana(mana)
+ ..addPos(vec3Builder.finish(1.0, 2.0, 3.0))
+ ..addColor(myGame.Color.Red);
+
+ final int monsteroff = monster.finish();
+ final buffer = builder.finish(monsteroff);
+ if (verify(buffer)) {
+ print(
+ "The FlatBuffer was successfully created with a builder and verified!");
+ }
+}
+
+void objectBuilderTest() {
+ // Create the builder here so we can use it for both weapons and equipped
+ // the actual data will only be written to the buffer once.
+ var axe = new myGame.WeaponObjectBuilder(name: 'Axe', damage: 5);
+
+ var monsterBuilder = new myGame.MonsterObjectBuilder(
+ pos: new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
+ mana: 150,
+ hp: 300,
+ name: 'Orc',
+ inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
+ color: myGame.Color.Red,
+ weapons: [new myGame.WeaponObjectBuilder(name: 'Sword', damage: 3), axe],
+ equippedType: myGame.EquipmentTypeId.Weapon,
+ equipped: axe,
+ );
+
+ var buffer = monsterBuilder.toBytes();
+
+ // We now have a FlatBuffer we can store on disk or send over a network.
+
+ // ** file/network code goes here :) **
+
+ // Instead, we're going to access it right away (as if we just received it).
+ if (verify(buffer)) {
+ print(
+ "The FlatBuffer was successfully created with an object builder and verified!");
+ }
+}
+
+bool verify(List<int> buffer) {
+ // Get access to the root:
+ var monster = new myGame.Monster(buffer);
+
+ // Get and test some scalar types from the FlatBuffer.
+ assert(monster.hp == 80);
+ assert(monster.mana == 150); // default
+ assert(monster.name == "MyMonster");
+
+ // Get and test a field of the FlatBuffer's `struct`.
+ var pos = monster.pos;
+ assert(pos != null);
+ assert(pos.z == 3.0);
+
+ // Get a test an element from the `inventory` FlatBuffer's `vector`.
+ var inv = monster.inventory;
+ assert(inv != null);
+ assert(inv.length == 10);
+ assert(inv[9] == 9);
+
+ // Get and test the `weapons` FlatBuffers's `vector`.
+ var expected_weapon_names = ["Sword", "Axe"];
+ var expected_weapon_damages = [3, 5];
+ var weps = monster.weapons;
+ for (int i = 0; i < weps.length; i++) {
+ assert(weps[i].name == expected_weapon_names[i]);
+ assert(weps[i].damage == expected_weapon_damages[i]);
+ }
+
+ // Get and test the `Equipment` union (`equipped` field).
+ assert(monster.equippedType.value == myGame.EquipmentTypeId.Weapon.value);
+ assert(monster.equippedType == myGame.EquipmentTypeId.Weapon);
+
+ assert(monster.equipped is myGame.Weapon);
+ var equipped = monster.equipped as myGame.Weapon;
+ assert(equipped.name == "Axe");
+ assert(equipped.damage == 5);
+
+ print(monster);
+ return true;
+}
diff --git a/dart/example/monster_my_game.sample_generated.dart b/dart/example/monster_my_game.sample_generated.dart
new file mode 100644
index 0000000..2c7c10d
--- /dev/null
+++ b/dart/example/monster_my_game.sample_generated.dart
@@ -0,0 +1,440 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, non_constant_identifier_names
+
+library my_game.sample;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+
+class Color {
+ final int value;
+ const Color._(this.value);
+
+ factory Color.fromValue(int value) {
+ if (value == null) return null;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum Color');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 2;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const Color Red = const Color._(0);
+ static const Color Green = const Color._(1);
+ static const Color Blue = const Color._(2);
+ static get values => {0: Red,1: Green,2: Blue,};
+
+ static const fb.Reader<Color> reader = const _ColorReader();
+
+ @override
+ String toString() {
+ return 'Color{value: $value}';
+ }
+}
+
+class _ColorReader extends fb.Reader<Color> {
+ const _ColorReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ Color read(fb.BufferContext bc, int offset) =>
+ new Color.fromValue(const fb.Int8Reader().read(bc, offset));
+}
+
+class EquipmentTypeId {
+ final int value;
+ const EquipmentTypeId._(this.value);
+
+ factory EquipmentTypeId.fromValue(int value) {
+ if (value == null) return null;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum EquipmentTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 1;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const EquipmentTypeId NONE = const EquipmentTypeId._(0);
+ static const EquipmentTypeId Weapon = const EquipmentTypeId._(1);
+ static get values => {0: NONE,1: Weapon,};
+
+ static const fb.Reader<EquipmentTypeId> reader = const _EquipmentTypeIdReader();
+
+ @override
+ String toString() {
+ return 'EquipmentTypeId{value: $value}';
+ }
+}
+
+class _EquipmentTypeIdReader extends fb.Reader<EquipmentTypeId> {
+ const _EquipmentTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ EquipmentTypeId read(fb.BufferContext bc, int offset) =>
+ new EquipmentTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class Vec3 {
+ Vec3._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Vec3> reader = const _Vec3Reader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
+ double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
+ double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
+
+ @override
+ String toString() {
+ return 'Vec3{x: $x, y: $y, z: $z}';
+ }
+}
+
+class _Vec3Reader extends fb.StructReader<Vec3> {
+ const _Vec3Reader();
+
+ @override
+ int get size => 12;
+
+ @override
+ Vec3 createObject(fb.BufferContext bc, int offset) =>
+ new Vec3._(bc, offset);
+}
+
+class Vec3Builder {
+ Vec3Builder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(double x, double y, double z) {
+ fbBuilder.putFloat32(z);
+ fbBuilder.putFloat32(y);
+ fbBuilder.putFloat32(x);
+ return fbBuilder.offset;
+ }
+
+}
+
+class Vec3ObjectBuilder extends fb.ObjectBuilder {
+ final double _x;
+ final double _y;
+ final double _z;
+
+ Vec3ObjectBuilder({
+ double x,
+ double y,
+ double z,
+ })
+ : _x = x,
+ _y = y,
+ _z = z;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.putFloat32(_z);
+ fbBuilder.putFloat32(_y);
+ fbBuilder.putFloat32(_x);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+ int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
+ int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
+ List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
+ Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
+ List<Weapon> get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGet(_bc, _bcOffset, 18, null);
+ EquipmentTypeId get equippedType => new EquipmentTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 20, null));
+ dynamic get equipped {
+ switch (equippedType?.value) {
+ case 1: return Weapon.reader.vTableGet(_bc, _bcOffset, 22, null);
+ default: return null;
+ }
+ }
+ List<Vec3> get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGet(_bc, _bcOffset, 24, null);
+
+ @override
+ String toString() {
+ return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, weapons: $weapons, equippedType: $equippedType, equipped: $equipped, path: $path}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterBuilder {
+ MonsterBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addPos(int offset) {
+ fbBuilder.addStruct(0, offset);
+ return fbBuilder.offset;
+ }
+ int addMana(int mana) {
+ fbBuilder.addInt16(1, mana);
+ return fbBuilder.offset;
+ }
+ int addHp(int hp) {
+ fbBuilder.addInt16(2, hp);
+ return fbBuilder.offset;
+ }
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(3, offset);
+ return fbBuilder.offset;
+ }
+ int addInventoryOffset(int offset) {
+ fbBuilder.addOffset(5, offset);
+ return fbBuilder.offset;
+ }
+ int addColor(Color color) {
+ fbBuilder.addInt8(6, color?.value);
+ return fbBuilder.offset;
+ }
+ int addWeaponsOffset(int offset) {
+ fbBuilder.addOffset(7, offset);
+ return fbBuilder.offset;
+ }
+ int addEquippedType(EquipmentTypeId equippedType) {
+ fbBuilder.addUint8(8, equippedType?.value);
+ return fbBuilder.offset;
+ }
+ int addEquippedOffset(int offset) {
+ fbBuilder.addOffset(9, offset);
+ return fbBuilder.offset;
+ }
+ int addPathOffset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+ final Vec3ObjectBuilder _pos;
+ final int _mana;
+ final int _hp;
+ final String _name;
+ final List<int> _inventory;
+ final Color _color;
+ final List<WeaponObjectBuilder> _weapons;
+ final EquipmentTypeId _equippedType;
+ final dynamic _equipped;
+ final List<Vec3ObjectBuilder> _path;
+
+ MonsterObjectBuilder({
+ Vec3ObjectBuilder pos,
+ int mana,
+ int hp,
+ String name,
+ List<int> inventory,
+ Color color,
+ List<WeaponObjectBuilder> weapons,
+ EquipmentTypeId equippedType,
+ dynamic equipped,
+ List<Vec3ObjectBuilder> path,
+ })
+ : _pos = pos,
+ _mana = mana,
+ _hp = hp,
+ _name = name,
+ _inventory = inventory,
+ _color = color,
+ _weapons = weapons,
+ _equippedType = equippedType,
+ _equipped = equipped,
+ _path = path;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+ final int inventoryOffset = _inventory?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_inventory)
+ : null;
+ final int weaponsOffset = _weapons?.isNotEmpty == true
+ ? fbBuilder.writeList(_weapons.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
+ final int pathOffset = _path?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_path)
+ : null;
+
+ fbBuilder.startTable();
+ if (_pos != null) {
+ fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+ }
+ fbBuilder.addInt16(1, _mana);
+ fbBuilder.addInt16(2, _hp);
+ if (nameOffset != null) {
+ fbBuilder.addOffset(3, nameOffset);
+ }
+ if (inventoryOffset != null) {
+ fbBuilder.addOffset(5, inventoryOffset);
+ }
+ fbBuilder.addInt8(6, _color?.value);
+ if (weaponsOffset != null) {
+ fbBuilder.addOffset(7, weaponsOffset);
+ }
+ fbBuilder.addUint8(8, _equippedType?.value);
+ if (equippedOffset != null) {
+ fbBuilder.addOffset(9, equippedOffset);
+ }
+ if (pathOffset != null) {
+ fbBuilder.addOffset(10, pathOffset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Weapon {
+ Weapon._(this._bc, this._bcOffset);
+ factory Weapon(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Weapon> reader = const _WeaponReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
+ int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, null);
+
+ @override
+ String toString() {
+ return 'Weapon{name: $name, damage: $damage}';
+ }
+}
+
+class _WeaponReader extends fb.TableReader<Weapon> {
+ const _WeaponReader();
+
+ @override
+ Weapon createObject(fb.BufferContext bc, int offset) =>
+ new Weapon._(bc, offset);
+}
+
+class WeaponBuilder {
+ WeaponBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addDamage(int damage) {
+ fbBuilder.addInt16(1, damage);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class WeaponObjectBuilder extends fb.ObjectBuilder {
+ final String _name;
+ final int _damage;
+
+ WeaponObjectBuilder({
+ String name,
+ int damage,
+ })
+ : _name = name,
+ _damage = damage;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+
+ fbBuilder.startTable();
+ if (nameOffset != null) {
+ fbBuilder.addOffset(0, nameOffset);
+ }
+ fbBuilder.addInt16(1, _damage);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/dart/lib/flat_buffers.dart b/dart/lib/flat_buffers.dart
new file mode 100644
index 0000000..e251260
--- /dev/null
+++ b/dart/lib/flat_buffers.dart
@@ -0,0 +1,1241 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:math';
+import 'dart:typed_data';
+
+const int _sizeofUint8 = 1;
+const int _sizeofUint16 = 2;
+const int _sizeofUint32 = 4;
+const int _sizeofUint64 = 8;
+const int _sizeofInt8 = 1;
+const int _sizeofInt16 = 2;
+const int _sizeofInt32 = 4;
+const int _sizeofInt64 = 8;
+const int _sizeofFloat32 = 4;
+const int _sizeofFloat64 = 8;
+
+/// Callback used to invoke a struct builder's finish method.
+///
+/// This callback is used by other struct's `finish` methods to write the nested
+/// struct's fields inline.
+typedef void StructBuilder();
+
+/// Buffer with data and some context about it.
+class BufferContext {
+ final ByteData _buffer;
+
+ factory BufferContext.fromBytes(List<int> byteList) {
+ Uint8List uint8List = _asUint8List(byteList);
+ ByteData buf = new ByteData.view(uint8List.buffer, uint8List.offsetInBytes);
+ return new BufferContext._(buf);
+ }
+
+ BufferContext._(this._buffer);
+
+ int derefObject(int offset) {
+ return offset + _getUint32(offset);
+ }
+
+ Uint8List _asUint8LIst(int offset, int length) =>
+ _buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length);
+
+ double _getFloat64(int offset) =>
+ _buffer.getFloat64(offset, Endian.little);
+
+ double _getFloat32(int offset) =>
+ _buffer.getFloat32(offset, Endian.little);
+
+ int _getInt64(int offset) =>
+ _buffer.getInt64(offset, Endian.little);
+
+ int _getInt32(int offset) =>
+ _buffer.getInt32(offset, Endian.little);
+
+ int _getInt16(int offset) =>
+ _buffer.getInt16(offset, Endian.little);
+
+ int _getInt8(int offset) => _buffer.getInt8(offset);
+
+ int _getUint64(int offset) =>
+ _buffer.getUint64(offset, Endian.little);
+
+ int _getUint32(int offset) =>
+ _buffer.getUint32(offset, Endian.little);
+
+ int _getUint16(int offset) =>
+ _buffer.getUint16(offset, Endian.little);
+
+ int _getUint8(int offset) => _buffer.getUint8(offset);
+
+ /// If the [byteList] is already a [Uint8List] return it.
+ /// Otherwise return a [Uint8List] copy of the [byteList].
+ static Uint8List _asUint8List(List<int> byteList) {
+ if (byteList is Uint8List) {
+ return byteList;
+ } else {
+ return new Uint8List.fromList(byteList);
+ }
+ }
+}
+
+/// Class implemented by typed builders generated by flatc.
+abstract class ObjectBuilder {
+ int _firstOffset;
+
+ /// Can be used to write the data represented by this builder to the [Builder]
+ /// and reuse the offset created in multiple tables.
+ ///
+ /// Note that this method assumes you call it using the same [Builder] instance
+ /// every time. The returned offset is only good for the [Builder] used in the
+ /// first call to this method.
+ int getOrCreateOffset(Builder fbBuilder) {
+ _firstOffset ??= finish(fbBuilder);
+ return _firstOffset;
+ }
+
+ /// Writes the data in this helper to the [Builder].
+ int finish(Builder fbBuilder);
+
+ /// Convenience method that will create a new [Builder], [finish]es the data,
+ /// and returns the buffer as a [Uint8List] of bytes.
+ Uint8List toBytes();
+}
+
+/// Class that helps building flat buffers.
+class Builder {
+ final int initialSize;
+
+ /// The list of existing VTable(s).
+ //final List<_VTable> _vTables = <_VTable>[];
+ final List<int> _vTables = <int>[];
+
+ ByteData _buf;
+
+ /// The maximum alignment that has been seen so far. If [_buf] has to be
+ /// reallocated in the future (to insert room at its start for more bytes) the
+ /// reallocation will need to be a multiple of this many bytes.
+ int _maxAlign;
+
+ /// The number of bytes that have been written to the buffer so far. The
+ /// most recently written byte is this many bytes from the end of [_buf].
+ int _tail;
+
+ /// The location of the end of the current table, measured in bytes from the
+ /// end of [_buf], or `null` if a table is not currently being built.
+ int _currentTableEndTail;
+
+ _VTable _currentVTable;
+
+ /// Map containing all strings that have been written so far. This allows us
+ /// to avoid duplicating strings.
+ ///
+ /// Allocated only if `internStrings` is set to true on the constructor.
+ Map<String, int> _strings;
+
+ /// Creates a new FlatBuffers Builder.
+ ///
+ /// `initialSize` is the initial array size in bytes. The [Builder] will
+ /// automatically grow the array if/as needed. `internStrings`, if set to
+ /// true, will cause [writeString] to pool strings in the buffer so that
+ /// identical strings will always use the same offset in tables.
+ Builder({this.initialSize: 1024, bool internStrings = false}) {
+ if (internStrings == true) {
+ _strings = new Map<String, int>();
+ }
+ reset();
+ }
+
+ /// Add the [field] with the given boolean [value]. The field is not added if
+ /// the [value] is equal to [def]. Booleans are stored as 8-bit fields with
+ /// `0` for `false` and `1` for `true`.
+ void addBool(int field, bool value, [bool def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint8, 1);
+ _trackField(field);
+ _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit signed integer [value]. The field is
+ /// not added if the [value] is equal to [def].
+ void addInt32(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt32, 1);
+ _trackField(field);
+ _setInt32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit signed integer [value]. The field is
+ /// not added if the [value] is equal to [def].
+ void addInt16(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt16, 1);
+ _trackField(field);
+ _setInt16AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 8-bit signed integer [value]. The field is
+ /// not added if the [value] is equal to [def].
+ void addInt8(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt8, 1);
+ _trackField(field);
+ _setInt8AtTail(_buf, _tail, value);
+ }
+ }
+
+ void addStruct(int field, int offset) {
+ _ensureCurrentVTable();
+ _trackField(field);
+ _currentVTable.addField(field, offset);
+ }
+
+ /// Add the [field] referencing an object with the given [offset].
+ void addOffset(int field, int offset) {
+ _ensureCurrentVTable();
+ if (offset != null) {
+ _prepare(_sizeofUint32, 1);
+ _trackField(field);
+ _setUint32AtTail(_buf, _tail, _tail - offset);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint32(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint32, 1);
+ _trackField(field);
+ _setUint32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint16(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint16, 1);
+ _trackField(field);
+ _setUint16AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 8-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint8(int field, int value, [int def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint8, 1);
+ _trackField(field);
+ _setUint8AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 32-bit float [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addFloat32(int field, double value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofFloat32, 1);
+ _trackField(field);
+ _setFloat32AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 64-bit double [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addFloat64(int field, double value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofFloat64, 1);
+ _trackField(field);
+ _setFloat64AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 64-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addUint64(int field, int value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofUint64, 1);
+ _trackField(field);
+ _setUint64AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// Add the [field] with the given 64-bit unsigned integer [value]. The field
+ /// is not added if the [value] is equal to [def].
+ void addInt64(int field, int value, [double def]) {
+ _ensureCurrentVTable();
+ if (value != null && value != def) {
+ _prepare(_sizeofInt64, 1);
+ _trackField(field);
+ _setInt64AtTail(_buf, _tail, value);
+ }
+ }
+
+ /// End the current table and return its offset.
+ int endTable() {
+ if (_currentVTable == null) {
+ throw new StateError('Start a table before ending it.');
+ }
+ // Prepare for writing the VTable.
+ _prepare(_sizeofInt32, 1);
+ int tableTail = _tail;
+ // Prepare the size of the current table.
+ _currentVTable.tableSize = tableTail - _currentTableEndTail;
+ // Prepare the VTable to use for the current table.
+ int vTableTail;
+ {
+ _currentVTable.computeFieldOffsets(tableTail);
+ // Try to find an existing compatible VTable.
+ // Search backward - more likely to have recently used one
+ for (int i = _vTables.length - 1; i >= 0; i--) {
+ final int vt2Offset = _vTables[i];
+ final int vt2Start = _buf.lengthInBytes - vt2Offset;
+ final int vt2Size = _buf.getUint16(vt2Start, Endian.little);
+
+ if (_currentVTable._vTableSize == vt2Size &&
+ _currentVTable._offsetsMatch(vt2Start, _buf)) {
+ vTableTail = vt2Offset;
+ break;
+ }
+ }
+ // Write a new VTable.
+ if (vTableTail == null) {
+ _prepare(_sizeofUint16, _currentVTable.numOfUint16);
+ vTableTail = _tail;
+ _currentVTable.tail = vTableTail;
+ _currentVTable.output(_buf, _buf.lengthInBytes - _tail);
+ _vTables.add(_currentVTable.tail);
+ }
+ }
+ // Set the VTable offset.
+ _setInt32AtTail(_buf, tableTail, vTableTail - tableTail);
+ // Done with this table.
+ _currentVTable = null;
+ return tableTail;
+ }
+
+ /// This method low level method can be used to return a raw piece of the buffer
+ /// after using the the put* methods.
+ ///
+ /// Most clients should prefer calling [finish].
+ Uint8List lowFinish() {
+ int alignedTail = _tail + ((-_tail) % _maxAlign);
+ return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
+ }
+
+ /// Finish off the creation of the buffer. The given [offset] is used as the
+ /// root object offset, and usually references directly or indirectly every
+ /// written object. If [fileIdentifier] is specified (and not `null`), it is
+ /// interpreted as a 4-byte Latin-1 encoded string that should be placed at
+ /// bytes 4-7 of the file.
+ Uint8List finish(int offset, [String fileIdentifier]) {
+ _prepare(max(_sizeofUint32, _maxAlign), fileIdentifier == null ? 1 : 2);
+ int alignedTail = _tail + ((-_tail) % _maxAlign);
+ _setUint32AtTail(_buf, alignedTail, alignedTail - offset);
+ if (fileIdentifier != null) {
+ for (int i = 0; i < 4; i++) {
+ _setUint8AtTail(_buf, alignedTail - _sizeofUint32 - i,
+ fileIdentifier.codeUnitAt(i));
+ }
+ }
+ return _buf.buffer.asUint8List(_buf.lengthInBytes - alignedTail);
+ }
+
+ /// Writes a Float64 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putFloat64(double value) {
+ _prepare(_sizeofFloat64, 1);
+ _setFloat32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Float32 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putFloat32(double value) {
+ _prepare(_sizeofFloat32, 1);
+ _setFloat32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Int64 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt64(int value) {
+ _prepare(_sizeofInt64, 1);
+ _setInt64AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint32 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt32(int value) {
+ _prepare(_sizeofInt32, 1);
+ _setInt32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint16 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt16(int value) {
+ _prepare(_sizeofInt16, 1);
+ _setInt16AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint8 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putInt8(int value) {
+ _prepare(_sizeofInt8, 1);
+ _buf.setInt8(_buf.lengthInBytes - _tail, value);
+ }
+
+ /// Writes a Uint64 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint64(int value) {
+ _prepare(_sizeofUint64, 1);
+ _setUint64AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint32 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint32(int value) {
+ _prepare(_sizeofUint32, 1);
+ _setUint32AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint16 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint16(int value) {
+ _prepare(_sizeofUint16, 1);
+ _setUint16AtTail(_buf, _tail, value);
+ }
+
+ /// Writes a Uint8 to the tail of the buffer after preparing space for it.
+ ///
+ /// Updates the [offset] pointer. This method is intended for use when writing structs to the buffer.
+ void putUint8(int value) {
+ _prepare(_sizeofUint8, 1);
+ _buf.setUint8(_buf.lengthInBytes - _tail, value);
+ }
+
+ /// Reset the builder and make it ready for filling a new buffer.
+ void reset() {
+ _buf = new ByteData(initialSize);
+ _maxAlign = 1;
+ _tail = 0;
+ _currentVTable = null;
+ if (_strings != null) {
+ _strings = new Map<String, int>();
+ }
+ }
+
+ /// Start a new table. Must be finished with [endTable] invocation.
+ void startTable() {
+ if (_currentVTable != null) {
+ throw new StateError('Inline tables are not supported.');
+ }
+ _currentVTable = new _VTable();
+ _currentTableEndTail = _tail;
+ }
+
+ /// Finish a Struct vector. Most callers should preferto use [writeListOfStructs].
+ ///
+ /// Most callers should prefer [writeListOfStructs].
+ int endStructVector(int count) {
+ putUint32(count);
+ return _tail;
+ }
+
+ /// Writes a list of Structs to the buffer, returning the offset
+ int writeListOfStructs(List<ObjectBuilder> structBuilders) {
+ _ensureNoVTable();
+ for (int i = structBuilders.length - 1; i >= 0; i--) {
+ structBuilders[i].finish(this);
+ }
+ return endStructVector(structBuilders.length);
+ }
+
+ /// Write the given list of [values].
+ int writeList(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint32AtTail(_buf, tail, tail - value);
+ tail -= _sizeofUint32;
+ }
+ return result;
+ }
+
+ /// Write the given list of 64-bit float [values].
+ int writeListFloat64(List<double> values) {
+ _ensureNoVTable();
+ _prepare(4, 1 + (2 * values.length));
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (double value in values) {
+ _setFloat64AtTail(_buf, tail, value);
+ tail -= _sizeofFloat64;
+ }
+ return result;
+ }
+
+ /// Write the given list of 32-bit float [values].
+ int writeListFloat32(List<double> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofFloat32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (double value in values) {
+ _setFloat32AtTail(_buf, tail, value);
+ tail -= _sizeofFloat32;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 64-bit integer [values].
+ int writeListInt64(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt64AtTail(_buf, tail, value);
+ tail -= _sizeofInt64;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 64-bit integer [values].
+ int writeListUint64(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint64AtTail(_buf, tail, value);
+ tail -= _sizeofUint64;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 32-bit integer [values].
+ int writeListInt32(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt32AtTail(_buf, tail, value);
+ tail -= _sizeofInt32;
+ }
+ return result;
+ }
+
+ /// Write the given list of unsigned 32-bit integer [values].
+ int writeListUint32(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1 + values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint32AtTail(_buf, tail, value);
+ tail -= _sizeofUint32;
+ }
+ return result;
+ }
+
+ /// Write the given list of signed 16-bit integer [values].
+ int writeListInt16(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt16AtTail(_buf, tail, value);
+ tail -= _sizeofInt16;
+ }
+ return result;
+ }
+
+ /// Write the given list of unsigned 16-bit integer [values].
+ int writeListUint16(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint16AtTail(_buf, tail, value);
+ tail -= _sizeofUint16;
+ }
+ return result;
+ }
+
+ /// Write the given list of bools as unsigend 8-bit integer [values].
+ int writeListBool(List<bool> values) {
+ return writeListUint8(values?.map((b) => b ? 1 : 0)?.toList());
+ }
+
+ /// Write the given list of signed 8-bit integer [values].
+ int writeListInt8(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setInt8AtTail(_buf, tail, value);
+ tail -= _sizeofUint8;
+ }
+ return result;
+ }
+
+ /// Write the given list of unsigned 8-bit integer [values].
+ int writeListUint8(List<int> values) {
+ _ensureNoVTable();
+ _prepare(_sizeofUint32, 1, additionalBytes: values.length);
+ final int result = _tail;
+ int tail = _tail;
+ _setUint32AtTail(_buf, tail, values.length);
+ tail -= _sizeofUint32;
+ for (int value in values) {
+ _setUint8AtTail(_buf, tail, value);
+ tail -= _sizeofUint8;
+ }
+ return result;
+ }
+
+ /// Write the given string [value] and return its offset, or `null` if
+ /// the [value] is `null`.
+ int writeString(String value) {
+ _ensureNoVTable();
+ if (value != null) {
+ if (_strings != null) {
+ return _strings.putIfAbsent(value, () => _writeString(value));
+ } else {
+ return _writeString(value);
+ }
+ }
+ return null;
+ }
+
+ int _writeString(String value) {
+ // TODO(scheglov) optimize for ASCII strings
+ List<int> bytes = utf8.encode(value);
+ int length = bytes.length;
+ _prepare(4, 1, additionalBytes: length + 1);
+ final int result = _tail;
+ _setUint32AtTail(_buf, _tail, length);
+ int offset = _buf.lengthInBytes - _tail + 4;
+ for (int i = 0; i < length; i++) {
+ _buf.setUint8(offset++, bytes[i]);
+ }
+ return result;
+ }
+
+ /// Throw an exception if there is not currently a vtable.
+ void _ensureCurrentVTable() {
+ if (_currentVTable == null) {
+ throw new StateError('Start a table before adding values.');
+ }
+ }
+
+ /// Throw an exception if there is currently a vtable.
+ void _ensureNoVTable() {
+ if (_currentVTable != null) {
+ throw new StateError(
+ 'Cannot write a non-scalar value while writing a table.');
+ }
+ }
+
+ /// The number of bytes that have been written to the buffer so far. The
+ /// most recently written byte is this many bytes from the end of the buffer.
+ int get offset => _tail;
+
+ /// Zero-pads the buffer, which may be required for some struct layouts.
+ void pad(int howManyBytes) {
+ for (int i = 0; i < howManyBytes; i++) putUint8(0);
+ }
+
+ /// Prepare for writing the given `count` of scalars of the given `size`.
+ /// Additionally allocate the specified `additionalBytes`. Update the current
+ /// tail pointer to point at the allocated space.
+ void _prepare(int size, int count, {int additionalBytes = 0}) {
+ // Update the alignment.
+ if (_maxAlign < size) {
+ _maxAlign = size;
+ }
+ // Prepare amount of required space.
+ int dataSize = size * count + additionalBytes;
+ int alignDelta = (-(_tail + dataSize)) % size;
+ int bufSize = alignDelta + dataSize;
+ // Ensure that we have the required amount of space.
+ {
+ int oldCapacity = _buf.lengthInBytes;
+ if (_tail + bufSize > oldCapacity) {
+ int desiredNewCapacity = (oldCapacity + bufSize) * 2;
+ int deltaCapacity = desiredNewCapacity - oldCapacity;
+ deltaCapacity += (-deltaCapacity) % _maxAlign;
+ int newCapacity = oldCapacity + deltaCapacity;
+ ByteData newBuf = new ByteData(newCapacity);
+ newBuf.buffer
+ .asUint8List()
+ .setAll(deltaCapacity, _buf.buffer.asUint8List());
+ _buf = newBuf;
+ }
+ }
+ // Update the tail pointer.
+ _tail += bufSize;
+ }
+
+ /// Record the offset of the given [field].
+ void _trackField(int field) {
+ _currentVTable.addField(field, _tail);
+ }
+
+ static void _setFloat64AtTail(ByteData _buf, int tail, double x) {
+ _buf.setFloat64(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setFloat32AtTail(ByteData _buf, int tail, double x) {
+ _buf.setFloat32(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setUint64AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint64(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setInt64AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt64(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setInt32AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt32(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setUint32AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint32(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setInt16AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt16(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setUint16AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint16(_buf.lengthInBytes - tail, x, Endian.little);
+ }
+
+ static void _setInt8AtTail(ByteData _buf, int tail, int x) {
+ _buf.setInt8(_buf.lengthInBytes - tail, x);
+ }
+
+ static void _setUint8AtTail(ByteData _buf, int tail, int x) {
+ _buf.setUint8(_buf.lengthInBytes - tail, x);
+ }
+}
+
+/// Reader of lists of boolean values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class BoolListReader extends Reader<List<bool>> {
+ const BoolListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<bool> read(BufferContext bc, int offset) =>
+ new _FbBoolList(bc, bc.derefObject(offset));
+}
+
+/// The reader of booleans.
+class BoolReader extends Reader<bool> {
+ const BoolReader() : super();
+
+ @override
+ int get size => _sizeofUint8;
+
+ @override
+ bool read(BufferContext bc, int offset) => bc._getInt8(offset) != 0;
+}
+
+/// The reader of lists of 64-bit float values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Float64ListReader extends Reader<List<double>> {
+ const Float64ListReader();
+
+ @override
+ int get size => _sizeofFloat64;
+
+ @override
+ List<double> read(BufferContext bc, int offset) =>
+ new _FbFloat64List(bc, bc.derefObject(offset));
+}
+
+class Float32ListReader extends Reader<List<double>> {
+ const Float32ListReader();
+
+ @override
+ int get size => _sizeofFloat32;
+
+ @override
+ List<double> read(BufferContext bc, int offset) =>
+ new _FbFloat32List(bc, bc.derefObject(offset));
+}
+
+class Float64Reader extends Reader<double> {
+ const Float64Reader();
+
+ @override
+ int get size => _sizeofFloat64;
+
+ @override
+ double read(BufferContext bc, int offset) => bc._getFloat64(offset);
+}
+
+class Float32Reader extends Reader<double> {
+ const Float32Reader();
+
+ @override
+ int get size => _sizeofFloat32;
+
+ @override
+ double read(BufferContext bc, int offset) => bc._getFloat32(offset);
+}
+
+class Int64Reader extends Reader<int> {
+ const Int64Reader() : super();
+ @override
+ int get size => _sizeofInt64;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt64(offset);
+}
+
+/// The reader of signed 32-bit integers.
+class Int32Reader extends Reader<int> {
+ const Int32Reader() : super();
+
+ @override
+ int get size => _sizeofInt32;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt32(offset);
+}
+
+/// The reader of signed 32-bit integers.
+class Int16Reader extends Reader<int> {
+ const Int16Reader() : super();
+
+ @override
+ int get size => _sizeofInt16;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt16(offset);
+}
+
+/// The reader of 8-bit signed integers.
+class Int8Reader extends Reader<int> {
+ const Int8Reader() : super();
+
+ @override
+ int get size => _sizeofInt8;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getInt8(offset);
+}
+
+/// The reader of lists of objects.
+///
+/// The returned unmodifiable lists lazily read objects on access.
+class ListReader<E> extends Reader<List<E>> {
+ final Reader<E> _elementReader;
+
+ const ListReader(this._elementReader);
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<E> read(BufferContext bc, int offset) =>
+ new _FbGenericList<E>(_elementReader, bc, bc.derefObject(offset));
+}
+
+/// Object that can read a value at a [BufferContext].
+abstract class Reader<T> {
+ const Reader();
+
+ /// The size of the value in bytes.
+ int get size;
+
+ /// Read the value at the given [offset] in [bc].
+ T read(BufferContext bc, int offset);
+
+ /// Read the value of the given [field] in the given [object].
+ T vTableGet(BufferContext object, int offset, int field, [T defaultValue]) {
+ int vTableSOffset = object._getInt32(offset);
+ int vTableOffset = offset - vTableSOffset;
+ int vTableSize = object._getUint16(vTableOffset);
+ int vTableFieldOffset = field;
+ if (vTableFieldOffset < vTableSize) {
+ int fieldOffsetInObject =
+ object._getUint16(vTableOffset + vTableFieldOffset);
+ if (fieldOffsetInObject != 0) {
+ return read(object, offset + fieldOffsetInObject);
+ }
+ }
+ return defaultValue;
+ }
+}
+
+/// The reader of string values.
+class StringReader extends Reader<String> {
+ const StringReader() : super();
+
+ @override
+ int get size => 4;
+
+ @override
+ String read(BufferContext bc, int offset) {
+ int strOffset = bc.derefObject(offset);
+ int length = bc._getUint32(strOffset);
+ Uint8List bytes = bc._asUint8LIst(strOffset + 4, length);
+ if (_isLatin(bytes)) {
+ return new String.fromCharCodes(bytes);
+ }
+ return utf8.decode(bytes);
+ }
+
+ static bool _isLatin(Uint8List bytes) {
+ int length = bytes.length;
+ for (int i = 0; i < length; i++) {
+ if (bytes[i] > 127) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+/// An abstract reader for structs.
+abstract class StructReader<T> extends Reader<T> {
+ const StructReader();
+
+ /// Return the object at `offset`.
+ T createObject(BufferContext bc, int offset);
+
+ T read(BufferContext bp, int offset) {
+ return createObject(bp, offset);
+ }
+}
+
+/// An abstract reader for tables.
+abstract class TableReader<T> extends Reader<T> {
+ const TableReader();
+
+ @override
+ int get size => 4;
+
+ /// Return the object at [offset].
+ T createObject(BufferContext bc, int offset);
+
+ @override
+ T read(BufferContext bp, int offset) {
+ int objectOffset = bp.derefObject(offset);
+ return createObject(bp, objectOffset);
+ }
+}
+
+/// Reader of lists of unsigned 32-bit integer values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Uint32ListReader extends Reader<List<int>> {
+ const Uint32ListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<int> read(BufferContext bc, int offset) =>
+ new _FbUint32List(bc, bc.derefObject(offset));
+}
+
+/// The reader of unsigned 64-bit integers.
+///
+/// WARNING: May have compatibility issues with JavaScript
+class Uint64Reader extends Reader<int> {
+ const Uint64Reader() : super();
+
+ @override
+ int get size => _sizeofUint64;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint64(offset);
+}
+
+/// The reader of unsigned 32-bit integers.
+class Uint32Reader extends Reader<int> {
+ const Uint32Reader() : super();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint32(offset);
+}
+
+/// Reader of lists of unsigned 32-bit integer values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Uint16ListReader extends Reader<List<int>> {
+ const Uint16ListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<int> read(BufferContext bc, int offset) =>
+ new _FbUint16List(bc, bc.derefObject(offset));
+}
+
+/// The reader of unsigned 32-bit integers.
+class Uint16Reader extends Reader<int> {
+ const Uint16Reader() : super();
+
+ @override
+ int get size => _sizeofUint16;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint16(offset);
+}
+
+/// Reader of lists of unsigned 8-bit integer values.
+///
+/// The returned unmodifiable lists lazily read values on access.
+class Uint8ListReader extends Reader<List<int>> {
+ const Uint8ListReader();
+
+ @override
+ int get size => _sizeofUint32;
+
+ @override
+ List<int> read(BufferContext bc, int offset) =>
+ new _FbUint8List(bc, bc.derefObject(offset));
+}
+
+/// The reader of unsigned 8-bit integers.
+class Uint8Reader extends Reader<int> {
+ const Uint8Reader() : super();
+
+ @override
+ int get size => _sizeofUint8;
+
+ @override
+ int read(BufferContext bc, int offset) => bc._getUint8(offset);
+}
+
+/// The list backed by 64-bit values - Uint64 length and Float64.
+class _FbFloat64List extends _FbList<double> {
+ _FbFloat64List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ double operator [](int i) {
+ return bc._getFloat64(offset + 4 + 8 * i);
+ }
+}
+
+/// The list backed by 32-bit values - Float32.
+class _FbFloat32List extends _FbList<double> {
+ _FbFloat32List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ double operator [](int i) {
+ return bc._getFloat32(offset + 4 + 4 * i);
+ }
+}
+
+/// List backed by a generic object which may have any size.
+class _FbGenericList<E> extends _FbList<E> {
+ final Reader<E> elementReader;
+
+ List<E> _items;
+
+ _FbGenericList(this.elementReader, BufferContext bp, int offset)
+ : super(bp, offset);
+
+ @override
+ E operator [](int i) {
+ _items ??= new List<E>(length);
+ E item = _items[i];
+ if (item == null) {
+ item = elementReader.read(bc, offset + 4 + elementReader.size * i);
+ _items[i] = item;
+ }
+ return item;
+ }
+}
+
+/// The base class for immutable lists read from flat buffers.
+abstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
+ final BufferContext bc;
+ final int offset;
+ int _length;
+
+ _FbList(this.bc, this.offset);
+
+ @override
+ int get length {
+ _length ??= bc._getUint32(offset);
+ return _length;
+ }
+
+ @override
+ void set length(int i) =>
+ throw new StateError('Attempt to modify immutable list');
+
+ @override
+ void operator []=(int i, E e) =>
+ throw new StateError('Attempt to modify immutable list');
+}
+
+/// List backed by 32-bit unsigned integers.
+class _FbUint32List extends _FbList<int> {
+ _FbUint32List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ int operator [](int i) {
+ return bc._getUint32(offset + 4 + 4 * i);
+ }
+}
+
+/// List backed by 16-bit unsigned integers.
+class _FbUint16List extends _FbList<int> {
+ _FbUint16List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ int operator [](int i) {
+ return bc._getUint16(offset + 4 + 2 * i);
+ }
+}
+
+/// List backed by 8-bit unsigned integers.
+class _FbUint8List extends _FbList<int> {
+ _FbUint8List(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ int operator [](int i) {
+ return bc._getUint8(offset + 4 + i);
+ }
+}
+
+/// List backed by 8-bit unsigned integers.
+class _FbBoolList extends _FbList<bool> {
+ _FbBoolList(BufferContext bc, int offset) : super(bc, offset);
+
+ @override
+ bool operator [](int i) {
+ return bc._getUint8(offset + 4 + i) == 1 ? true : false;
+ }
+}
+
+/// Class that describes the structure of a table.
+class _VTable {
+ static const int _metadataLength = 4;
+
+ final List<int> fieldTails = <int>[];
+ final List<int> fieldOffsets = <int>[];
+
+ /// The size of the table that uses this VTable.
+ int tableSize;
+
+ /// The tail of this VTable. It is used to share the same VTable between
+ /// multiple tables of identical structure.
+ int tail;
+
+ int get _vTableSize => numOfUint16 * _sizeofUint16;
+
+ int get numOfUint16 => 1 + 1 + fieldTails.length;
+
+ void addField(int field, int offset) {
+ while (fieldTails.length <= field) {
+ fieldTails.add(null);
+ }
+ fieldTails[field] = offset;
+ }
+
+ bool _offsetsMatch(int vt2Start, ByteData buf) {
+ for (int i = 0; i < fieldOffsets.length; i++) {
+ if (fieldOffsets[i] !=
+ buf.getUint16(
+ vt2Start + _metadataLength + (2 * i), Endian.little)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// Fill the [fieldOffsets] field.
+ void computeFieldOffsets(int tableTail) {
+ assert(fieldOffsets.isEmpty);
+ for (int fieldTail in fieldTails) {
+ int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
+ fieldOffsets.add(fieldOffset);
+ }
+ }
+
+ /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
+ /// and have at least [numOfUint16] 16-bit words available.
+ void output(ByteData buf, int bufOffset) {
+ // VTable size.
+ buf.setUint16(bufOffset, numOfUint16 * 2, Endian.little);
+ bufOffset += 2;
+ // Table size.
+ buf.setUint16(bufOffset, tableSize, Endian.little);
+ bufOffset += 2;
+ // Field offsets.
+ for (int fieldOffset in fieldOffsets) {
+ buf.setUint16(bufOffset, fieldOffset, Endian.little);
+ bufOffset += 2;
+ }
+ }
+}
diff --git a/dart/publish.sh b/dart/publish.sh
new file mode 100755
index 0000000..167a4a3
--- /dev/null
+++ b/dart/publish.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note to pub consumers: this file is used to assist with publishing the
+# pub package from the flatbuffers repository and is not meant for general use.
+# As pub does not currently provide a way to exclude files, it is included here.
+
+command -v pub >/dev/null 2>&1 || { echo >&2 "Require `pub` but it's not installed. Aborting."; exit 1; }
+
+cp ../samples/monster.fbs example/
+cp ../tests/monster_test.fbs test/
+pub publish
+
+rm example/monster.fbs
+rm test/monster_test.fbs
\ No newline at end of file
diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml
new file mode 100644
index 0000000..4761ffc
--- /dev/null
+++ b/dart/pubspec.yaml
@@ -0,0 +1,20 @@
+name: flat_buffers
+version: 1.11.0
+description: >
+ FlatBuffers reading and writing library for Dart. Use the flatc compiler to
+ generate Dart classes for a FlatBuffers schema, and this library to assist with
+ reading and writing the binary format.
+
+ Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
+authors:
+- Dan Field <dfield@gmail.com>
+- Konstantin Scheglov
+- Paul Berry
+homepage: https://github.com/google/flatbuffers
+documentation: https://google.github.io/flatbuffers/index.html
+dev_dependencies:
+ test: ^1.3.0
+ test_reflective_loader: ^0.1.4
+ path: ^1.5.1
+environment:
+ sdk: '>=2.0.0-dev.28.0 <3.0.0'
\ No newline at end of file
diff --git a/dart/test/flat_buffers_test.dart b/dart/test/flat_buffers_test.dart
new file mode 100644
index 0000000..f9c5e01
--- /dev/null
+++ b/dart/test/flat_buffers_test.dart
@@ -0,0 +1,573 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+import 'dart:io' as io;
+
+import 'package:path/path.dart' as path;
+
+import 'package:flat_buffers/flat_buffers.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import './monster_test_my_game.example_generated.dart' as example;
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(BuilderTest);
+ defineReflectiveTests(CheckOtherLangaugesData);
+ });
+}
+
+int indexToField(int index) {
+ return (1 + 1 + index) * 2;
+}
+
+@reflectiveTest
+class CheckOtherLangaugesData {
+ test_cppData() async {
+ List<int> data = await new io.File(path.join(
+ path.dirname(io.Platform.script.path),
+ 'monsterdata_test.mon',
+ ))
+ .readAsBytes();
+ example.Monster mon = new example.Monster(data);
+ expect(mon.hp, 80);
+ expect(mon.mana, 150);
+ expect(mon.name, 'MyMonster');
+ expect(mon.pos.x, 1.0);
+ expect(mon.pos.y, 2.0);
+ expect(mon.pos.z, 3.0);
+ expect(mon.pos.test1, 3.0);
+ expect(mon.pos.test2.value, 2.0);
+ expect(mon.pos.test3.a, 5);
+ expect(mon.pos.test3.b, 6);
+ expect(mon.testType.value, example.AnyTypeId.Monster.value);
+ expect(mon.test is example.Monster, true);
+ final monster2 = mon.test as example.Monster;
+ expect(monster2.name, "Fred");
+
+ expect(mon.inventory.length, 5);
+ expect(mon.inventory.reduce((cur, next) => cur + next), 10);
+ expect(mon.test4.length, 2);
+ expect(
+ mon.test4[0].a + mon.test4[0].b + mon.test4[1].a + mon.test4[1].b, 100);
+ expect(mon.testarrayofstring.length, 2);
+ expect(mon.testarrayofstring[0], "test1");
+ expect(mon.testarrayofstring[1], "test2");
+
+ // this will fail if accessing any field fails.
+ expect(mon.toString(),
+ 'Monster{pos: Vec3{x: 1.0, y: 2.0, z: 3.0, test1: 3.0, test2: Color{value: 2}, test3: Test{a: 5, b: 6}}, mana: 150, hp: 80, name: MyMonster, inventory: [0, 1, 2, 3, 4], color: Color{value: 8}, testType: AnyTypeId{value: 1}, test: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], testarrayofstring: [test1, test2], testarrayoftables: null, enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, inventory: null, color: Color{value: 8}, testType: AnyTypeId{value: 0}, test: null, test4: null, testarrayofstring: null, testarrayoftables: null, enemy: null, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: 0, testhashu32Fnv1: 0, testhashs64Fnv1: 0, testhashu64Fnv1: 0, testhashs32Fnv1a: 0, testhashu32Fnv1a: 0, testhashs64Fnv1a: 0, testhashu64Fnv1a: 0, testarrayofbools: null, testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: null, vectorOfLongs: null, vectorOfDoubles: null, parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}, testnestedflatbuffer: null, testempty: null, testbool: false, testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, testhashs64Fnv1: 7930699090847568257, testhashu64Fnv1: 7930699090847568257, testhashs32Fnv1a: -1904106383, testhashu32Fnv1a: 2390860913, testhashs64Fnv1a: 4898026182817603057, testhashu64Fnv1a: 4898026182817603057, testarrayofbools: [true, false, true], testf: 3.14159, testf2: 3.0, testf3: 0.0, testarrayofstring2: null, testarrayofsortedstruct: null, flex: null, test5: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], vectorOfLongs: [1, 100, 10000, 1000000, 100000000], vectorOfDoubles: [-1.7976931348623157e+308, 0.0, 1.7976931348623157e+308], parentNamespaceTest: null, vectorOfReferrables: null, singleWeakReference: 0, vectorOfWeakReferences: null, vectorOfStrongReferrables: null, coOwningReference: 0, vectorOfCoOwningReferences: null, nonOwningReference: 0, vectorOfNonOwningReferences: null}');
+ }
+}
+
+@reflectiveTest
+class BuilderTest {
+ void test_monsterBuilder() {
+ final fbBuilder = new Builder();
+ final str = fbBuilder.writeString('MyMonster');
+
+ fbBuilder.writeString('test1');
+ fbBuilder.writeString('test2');
+ final testArrayOfString = fbBuilder.endStructVector(2);
+
+ final fred = fbBuilder.writeString('Fred');
+
+ final List<int> treasure = [0, 1, 2, 3, 4];
+ final inventory = fbBuilder.writeListUint8(treasure);
+
+ final monBuilder = new example.MonsterBuilder(fbBuilder)
+ ..begin()
+ ..addNameOffset(fred);
+ final mon2 = monBuilder.finish();
+
+ final testBuilder = new example.TestBuilder(fbBuilder);
+ testBuilder.finish(10, 20);
+ testBuilder.finish(30, 40);
+ final test4 = fbBuilder.endStructVector(2);
+
+
+ monBuilder
+ ..begin()
+ ..addPos(
+ new example.Vec3Builder(fbBuilder).finish(
+ 1.0,
+ 2.0,
+ 3.0,
+ 3.0,
+ example.Color.Green,
+ () => testBuilder.finish(5, 6),
+ ),
+ )
+ ..addHp(80)
+ ..addNameOffset(str)
+ ..addInventoryOffset(inventory)
+ ..addTestType(example.AnyTypeId.Monster)
+ ..addTestOffset(mon2)
+ ..addTest4Offset(test4)
+ ..addTestarrayofstringOffset(testArrayOfString);
+ final mon = monBuilder.finish();
+ fbBuilder.finish(mon);
+ }
+
+ void test_error_addInt32_withoutStartTable() {
+ Builder builder = new Builder();
+ expect(() {
+ builder.addInt32(0, 0);
+ }, throwsStateError);
+ }
+
+ void test_error_addOffset_withoutStartTable() {
+ Builder builder = new Builder();
+ expect(() {
+ builder.addOffset(0, 0);
+ }, throwsStateError);
+ }
+
+ void test_error_endTable_withoutStartTable() {
+ Builder builder = new Builder();
+ expect(() {
+ builder.endTable();
+ }, throwsStateError);
+ }
+
+ void test_error_startTable_duringTable() {
+ Builder builder = new Builder();
+ builder.startTable();
+ expect(() {
+ builder.startTable();
+ }, throwsStateError);
+ }
+
+ void test_error_writeString_duringTable() {
+ Builder builder = new Builder();
+ builder.startTable();
+ expect(() {
+ builder.writeString('12345');
+ }, throwsStateError);
+ }
+
+ void test_file_identifier() {
+ Uint8List byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ int offset = builder.endTable();
+ byteList = builder.finish(offset, 'Az~ÿ');
+ }
+ // Convert byteList to a ByteData so that we can read data from it.
+ ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
+ // First 4 bytes are an offset to the table data.
+ int tableDataLoc = byteData.getUint32(0, Endian.little);
+ // Next 4 bytes are the file identifier.
+ expect(byteData.getUint8(4), 65); // 'a'
+ expect(byteData.getUint8(5), 122); // 'z'
+ expect(byteData.getUint8(6), 126); // '~'
+ expect(byteData.getUint8(7), 255); // 'ÿ'
+ // First 4 bytes of the table data are a backwards offset to the vtable.
+ int vTableLoc = tableDataLoc -
+ byteData.getInt32(tableDataLoc, Endian.little);
+ // First 2 bytes of the vtable are the size of the vtable in bytes, which
+ // should be 4.
+ expect(byteData.getUint16(vTableLoc, Endian.little), 4);
+ // Next 2 bytes are the size of the object in bytes (including the vtable
+ // pointer), which should be 4.
+ expect(byteData.getUint16(vTableLoc + 2, Endian.little), 4);
+ }
+
+ void test_low() {
+ Builder builder = new Builder(initialSize: 0);
+ expect((builder..putUint8(1)).lowFinish(), [1]);
+ expect((builder..putUint32(2)).lowFinish(), [2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint8(3)).lowFinish(),
+ [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint8(4)).lowFinish(),
+ [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint8(5)).lowFinish(),
+ [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ expect((builder..putUint32(6)).lowFinish(),
+ [6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]);
+ }
+
+ void test_table_default() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ builder.addInt32(0, 10, 10);
+ builder.addInt32(1, 20, 10);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buffer = new BufferContext.fromBytes(byteList);
+ int objectOffset = buffer.derefObject(0);
+ // was not written, so uses the new default value
+ expect(
+ const Int32Reader()
+ .vTableGet(buffer, objectOffset, indexToField(0), 15),
+ 15);
+ // has the written value
+ expect(
+ const Int32Reader()
+ .vTableGet(buffer, objectOffset, indexToField(1), 15),
+ 20);
+ }
+
+ void test_table_format() {
+ Uint8List byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ builder.startTable();
+ builder.addInt32(0, 10);
+ builder.addInt32(1, 20);
+ builder.addInt32(2, 30);
+ byteList = builder.finish(builder.endTable());
+ }
+ // Convert byteList to a ByteData so that we can read data from it.
+ ByteData byteData = byteList.buffer.asByteData(byteList.offsetInBytes);
+ // First 4 bytes are an offset to the table data.
+ int tableDataLoc = byteData.getUint32(0, Endian.little);
+ // First 4 bytes of the table data are a backwards offset to the vtable.
+ int vTableLoc = tableDataLoc -
+ byteData.getInt32(tableDataLoc, Endian.little);
+ // First 2 bytes of the vtable are the size of the vtable in bytes, which
+ // should be 10.
+ expect(byteData.getUint16(vTableLoc, Endian.little), 10);
+ // Next 2 bytes are the size of the object in bytes (including the vtable
+ // pointer), which should be 16.
+ expect(byteData.getUint16(vTableLoc + 2, Endian.little), 16);
+ // Remaining 6 bytes are the offsets within the object where the ints are
+ // located.
+ for (int i = 0; i < 3; i++) {
+ int offset =
+ byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
+ expect(byteData.getInt32(tableDataLoc + offset, Endian.little),
+ 10 + 10 * i);
+ }
+ }
+
+ void test_table_string() {
+ String latinString = 'test';
+ String unicodeString = 'Проба пера';
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int latinStringOffset = builder.writeString(latinString);
+ int unicodeStringOffset = builder.writeString(unicodeString);
+ builder.startTable();
+ builder.addOffset(0, latinStringOffset);
+ builder.addOffset(1, unicodeStringOffset);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ int objectOffset = buf.derefObject(0);
+ expect(const StringReader().vTableGet(buf, objectOffset, indexToField(0)),
+ latinString);
+ expect(const StringReader().vTableGet(buf, objectOffset, indexToField(1)),
+ unicodeString);
+ }
+
+ void test_table_types() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int stringOffset = builder.writeString('12345');
+ builder.startTable();
+ builder.addBool(0, true);
+ builder.addInt8(1, 10);
+ builder.addInt32(2, 20);
+ builder.addOffset(3, stringOffset);
+ builder.addInt32(4, 40);
+ builder.addUint32(5, 0x9ABCDEF0);
+ builder.addUint8(6, 0x9A);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ int objectOffset = buf.derefObject(0);
+ expect(
+ const BoolReader().vTableGet(buf, objectOffset, indexToField(0)), true);
+ expect(
+ const Int8Reader().vTableGet(buf, objectOffset, indexToField(1)), 10);
+ expect(
+ const Int32Reader().vTableGet(buf, objectOffset, indexToField(2)), 20);
+ expect(const StringReader().vTableGet(buf, objectOffset, indexToField(3)),
+ '12345');
+ expect(
+ const Int32Reader().vTableGet(buf, objectOffset, indexToField(4)), 40);
+ expect(const Uint32Reader().vTableGet(buf, objectOffset, indexToField(5)),
+ 0x9ABCDEF0);
+ expect(const Uint8Reader().vTableGet(buf, objectOffset, indexToField(6)),
+ 0x9A);
+ }
+
+ void test_writeList_of_Uint32() {
+ List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint32(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint32ListReader().read(buf, 0);
+ expect(items, hasLength(4));
+ expect(items, orderedEquals(values));
+ }
+
+ void test_writeList_ofBool() {
+ void verifyListBooleans(int len, List<int> trueBits) {
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ List<bool> values = new List<bool>.filled(len, false);
+ for (int bit in trueBits) {
+ values[bit] = true;
+ }
+ int offset = builder.writeListBool(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<bool> items = const BoolListReader().read(buf, 0);
+ expect(items, hasLength(len));
+ for (int i = 0; i < items.length; i++) {
+ expect(items[i], trueBits.contains(i), reason: 'bit $i of $len');
+ }
+ }
+
+ verifyListBooleans(0, <int>[]);
+ verifyListBooleans(1, <int>[]);
+ verifyListBooleans(1, <int>[0]);
+ verifyListBooleans(31, <int>[0, 1]);
+ verifyListBooleans(31, <int>[1, 2, 24, 25, 30]);
+ verifyListBooleans(31, <int>[0, 30]);
+ verifyListBooleans(32, <int>[1, 2, 24, 25, 31]);
+ verifyListBooleans(33, <int>[1, 2, 24, 25, 32]);
+ verifyListBooleans(33, <int>[1, 2, 24, 25, 31, 32]);
+ verifyListBooleans(63, <int>[]);
+ verifyListBooleans(63, <int>[0, 1, 2, 61, 62]);
+ verifyListBooleans(63, new List<int>.generate(63, (i) => i));
+ verifyListBooleans(64, <int>[]);
+ verifyListBooleans(64, <int>[0, 1, 2, 61, 62, 63]);
+ verifyListBooleans(64, <int>[1, 2, 62]);
+ verifyListBooleans(64, <int>[0, 1, 2, 63]);
+ verifyListBooleans(64, new List<int>.generate(64, (i) => i));
+ verifyListBooleans(100, <int>[0, 3, 30, 60, 90, 99]);
+ }
+
+ void test_writeList_ofInt32() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListInt32(<int>[1, 2, 3, 4, 5]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const ListReader<int>(const Int32Reader()).read(buf, 0);
+ expect(items, hasLength(5));
+ expect(items, orderedEquals(<int>[1, 2, 3, 4, 5]));
+ }
+
+ void test_writeList_ofFloat64() {
+ List<double> values = <double>[-1.234567, 3.4E+9, -5.6E-13, 7.8, 12.13];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListFloat64(values);
+ byteList = builder.finish(offset);
+ }
+
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<double> items = const Float64ListReader().read(buf, 0);
+
+ expect(items, hasLength(values.length));
+ for (int i = 0; i < values.length; i++) {
+ expect(values[i], closeTo(items[i], .001));
+ }
+ }
+
+ void test_writeList_ofFloat32() {
+ List<double> values = [1.0, 2.23, -3.213, 7.8, 12.13];
+ // write
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListFloat32(values);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<double> items = const Float32ListReader().read(buf, 0);
+ expect(items, hasLength(5));
+ for (int i = 0; i < values.length; i++) {
+ expect(values[i], closeTo(items[i], .001));
+ }
+ }
+
+ void test_writeList_ofObjects() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ // write the object #1
+ int object1;
+ {
+ builder.startTable();
+ builder.addInt32(0, 10);
+ builder.addInt32(1, 20);
+ object1 = builder.endTable();
+ }
+ // write the object #1
+ int object2;
+ {
+ builder.startTable();
+ builder.addInt32(0, 100);
+ builder.addInt32(1, 200);
+ object2 = builder.endTable();
+ }
+ // write the list
+ int offset = builder.writeList([object1, object2]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<TestPointImpl> items =
+ const ListReader<TestPointImpl>(const TestPointReader()).read(buf, 0);
+ expect(items, hasLength(2));
+ expect(items[0].x, 10);
+ expect(items[0].y, 20);
+ expect(items[1].x, 100);
+ expect(items[1].y, 200);
+ }
+
+ void test_writeList_ofStrings_asRoot() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int str1 = builder.writeString('12345');
+ int str2 = builder.writeString('ABC');
+ int offset = builder.writeList([str1, str2]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<String> items =
+ const ListReader<String>(const StringReader()).read(buf, 0);
+ expect(items, hasLength(2));
+ expect(items, contains('12345'));
+ expect(items, contains('ABC'));
+ }
+
+ void test_writeList_ofStrings_inObject() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int listOffset = builder.writeList(
+ [builder.writeString('12345'), builder.writeString('ABC')]);
+ builder.startTable();
+ builder.addOffset(0, listOffset);
+ int offset = builder.endTable();
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ StringListWrapperImpl reader = new StringListWrapperReader().read(buf, 0);
+ List<String> items = reader.items;
+ expect(items, hasLength(2));
+ expect(items, contains('12345'));
+ expect(items, contains('ABC'));
+ }
+
+ void test_writeList_ofUint32() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint32ListReader().read(buf, 0);
+ expect(items, hasLength(3));
+ expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
+ }
+
+ void test_writeList_ofUint16() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint16(<int>[1, 2, 60000]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint16ListReader().read(buf, 0);
+ expect(items, hasLength(3));
+ expect(items, orderedEquals(<int>[1, 2, 60000]));
+ }
+
+ void test_writeList_ofUint8() {
+ List<int> byteList;
+ {
+ Builder builder = new Builder(initialSize: 0);
+ int offset = builder.writeListUint8(<int>[1, 2, 3, 4, 0x9A]);
+ byteList = builder.finish(offset);
+ }
+ // read and verify
+ BufferContext buf = new BufferContext.fromBytes(byteList);
+ List<int> items = const Uint8ListReader().read(buf, 0);
+ expect(items, hasLength(5));
+ expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
+ }
+}
+
+class StringListWrapperImpl {
+ final BufferContext bp;
+ final int offset;
+
+ StringListWrapperImpl(this.bp, this.offset);
+
+ List<String> get items => const ListReader<String>(const StringReader())
+ .vTableGet(bp, offset, indexToField(0));
+}
+
+class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
+ const StringListWrapperReader();
+
+ @override
+ StringListWrapperImpl createObject(BufferContext object, int offset) {
+ return new StringListWrapperImpl(object, offset);
+ }
+}
+
+class TestPointImpl {
+ final BufferContext bp;
+ final int offset;
+
+ TestPointImpl(this.bp, this.offset);
+
+ int get x => const Int32Reader().vTableGet(bp, offset, indexToField(0), 0);
+
+ int get y => const Int32Reader().vTableGet(bp, offset, indexToField(1), 0);
+}
+
+class TestPointReader extends TableReader<TestPointImpl> {
+ const TestPointReader();
+
+ @override
+ TestPointImpl createObject(BufferContext object, int offset) {
+ return new TestPointImpl(object, offset);
+ }
+}
diff --git a/dart/test/monster_test_my_game.example2_generated.dart b/dart/test/monster_test_my_game.example2_generated.dart
new file mode 100644
index 0000000..9a3ab66
--- /dev/null
+++ b/dart/test/monster_test_my_game.example2_generated.dart
@@ -0,0 +1,62 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game.example2;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import 'include_test1_my_game.example2_generated.dart';
+import 'include_test2_my_game.example2_generated.dart';
+import './monster_test_my_game_generated.dart' as my_game;
+import './monster_test_my_game.example_generated.dart' as my_game_example;
+
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+
+ @override
+ String toString() {
+ return 'Monster{}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+
+ MonsterObjectBuilder();
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/dart/test/monster_test_my_game.example_generated.dart b/dart/test/monster_test_my_game.example_generated.dart
new file mode 100644
index 0000000..49e2ec1
--- /dev/null
+++ b/dart/test/monster_test_my_game.example_generated.dart
@@ -0,0 +1,1486 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game.example;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import 'include_test1_my_game.example_generated.dart';
+import 'include_test2_my_game.example_generated.dart';
+import './monster_test_my_game_generated.dart' as my_game;
+import './monster_test_my_game.example2_generated.dart' as my_game_example2;
+
+class Color {
+ final int value;
+ const Color._(this.value);
+
+ factory Color.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum Color');
+ }
+ return values[value];
+ }
+
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const Color Red = const Color._(1);
+ static const Color Green = const Color._(2);
+ static const Color Blue = const Color._(8);
+ static get values => {1: Red,2: Green,8: Blue,};
+
+ static const fb.Reader<Color> reader = const _ColorReader();
+
+ @override
+ String toString() {
+ return 'Color{value: $value}';
+ }
+}
+
+class _ColorReader extends fb.Reader<Color> {
+ const _ColorReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ Color read(fb.BufferContext bc, int offset) =>
+ new Color.fromValue(const fb.Int8Reader().read(bc, offset));
+}
+
+class AnyTypeId {
+ final int value;
+ const AnyTypeId._(this.value);
+
+ factory AnyTypeId.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyTypeId NONE = const AnyTypeId._(0);
+ static const AnyTypeId Monster = const AnyTypeId._(1);
+ static const AnyTypeId TestSimpleTableWithEnum = const AnyTypeId._(2);
+ static const AnyTypeId MyGame_Example2_Monster = const AnyTypeId._(3);
+ static get values => {0: NONE,1: Monster,2: TestSimpleTableWithEnum,3: MyGame_Example2_Monster,};
+
+ static const fb.Reader<AnyTypeId> reader = const _AnyTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyTypeId{value: $value}';
+ }
+}
+
+class _AnyTypeIdReader extends fb.Reader<AnyTypeId> {
+ const _AnyTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class AnyUniqueAliasesTypeId {
+ final int value;
+ const AnyUniqueAliasesTypeId._(this.value);
+
+ factory AnyUniqueAliasesTypeId.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyUniqueAliasesTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyUniqueAliasesTypeId NONE = const AnyUniqueAliasesTypeId._(0);
+ static const AnyUniqueAliasesTypeId M = const AnyUniqueAliasesTypeId._(1);
+ static const AnyUniqueAliasesTypeId T = const AnyUniqueAliasesTypeId._(2);
+ static const AnyUniqueAliasesTypeId M2 = const AnyUniqueAliasesTypeId._(3);
+ static get values => {0: NONE,1: M,2: T,3: M2,};
+
+ static const fb.Reader<AnyUniqueAliasesTypeId> reader = const _AnyUniqueAliasesTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyUniqueAliasesTypeId{value: $value}';
+ }
+}
+
+class _AnyUniqueAliasesTypeIdReader extends fb.Reader<AnyUniqueAliasesTypeId> {
+ const _AnyUniqueAliasesTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyUniqueAliasesTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class AnyAmbiguousAliasesTypeId {
+ final int value;
+ const AnyAmbiguousAliasesTypeId._(this.value);
+
+ factory AnyAmbiguousAliasesTypeId.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyAmbiguousAliasesTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyAmbiguousAliasesTypeId NONE = const AnyAmbiguousAliasesTypeId._(0);
+ static const AnyAmbiguousAliasesTypeId M1 = const AnyAmbiguousAliasesTypeId._(1);
+ static const AnyAmbiguousAliasesTypeId M2 = const AnyAmbiguousAliasesTypeId._(2);
+ static const AnyAmbiguousAliasesTypeId M3 = const AnyAmbiguousAliasesTypeId._(3);
+ static get values => {0: NONE,1: M1,2: M2,3: M3,};
+
+ static const fb.Reader<AnyAmbiguousAliasesTypeId> reader = const _AnyAmbiguousAliasesTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyAmbiguousAliasesTypeId{value: $value}';
+ }
+}
+
+class _AnyAmbiguousAliasesTypeIdReader extends fb.Reader<AnyAmbiguousAliasesTypeId> {
+ const _AnyAmbiguousAliasesTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyAmbiguousAliasesTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class Test {
+ Test._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Test> reader = const _TestReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get a => const fb.Int16Reader().read(_bc, _bcOffset + 0);
+ int get b => const fb.Int8Reader().read(_bc, _bcOffset + 2);
+
+ @override
+ String toString() {
+ return 'Test{a: $a, b: $b}';
+ }
+}
+
+class _TestReader extends fb.StructReader<Test> {
+ const _TestReader();
+
+ @override
+ int get size => 4;
+
+ @override
+ Test createObject(fb.BufferContext bc, int offset) =>
+ new Test._(bc, offset);
+}
+
+class TestBuilder {
+ TestBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int a, int b) {
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(b);
+ fbBuilder.putInt16(a);
+ return fbBuilder.offset;
+ }
+
+}
+
+class TestObjectBuilder extends fb.ObjectBuilder {
+ final int _a;
+ final int _b;
+
+ TestObjectBuilder({
+ int a,
+ int b,
+ })
+ : _a = a,
+ _b = b;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(_b);
+ fbBuilder.putInt16(_a);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class TestSimpleTableWithEnum {
+ TestSimpleTableWithEnum._(this._bc, this._bcOffset);
+ factory TestSimpleTableWithEnum(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TestSimpleTableWithEnum> reader = const _TestSimpleTableWithEnumReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 4, 2));
+
+ @override
+ String toString() {
+ return 'TestSimpleTableWithEnum{color: $color}';
+ }
+}
+
+class _TestSimpleTableWithEnumReader extends fb.TableReader<TestSimpleTableWithEnum> {
+ const _TestSimpleTableWithEnumReader();
+
+ @override
+ TestSimpleTableWithEnum createObject(fb.BufferContext bc, int offset) =>
+ new TestSimpleTableWithEnum._(bc, offset);
+}
+
+class TestSimpleTableWithEnumBuilder {
+ TestSimpleTableWithEnumBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addColor(Color color) {
+ fbBuilder.addInt8(0, color?.value);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TestSimpleTableWithEnumObjectBuilder extends fb.ObjectBuilder {
+ final Color _color;
+
+ TestSimpleTableWithEnumObjectBuilder({
+ Color color,
+ })
+ : _color = color;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addInt8(0, _color?.value);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Vec3 {
+ Vec3._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Vec3> reader = const _Vec3Reader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
+ double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
+ double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
+ double get test1 => const fb.Float64Reader().read(_bc, _bcOffset + 16);
+ Color get test2 => new Color.fromValue(const fb.Int8Reader().read(_bc, _bcOffset + 24));
+ Test get test3 => Test.reader.read(_bc, _bcOffset + 26);
+
+ @override
+ String toString() {
+ return 'Vec3{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}';
+ }
+}
+
+class _Vec3Reader extends fb.StructReader<Vec3> {
+ const _Vec3Reader();
+
+ @override
+ int get size => 32;
+
+ @override
+ Vec3 createObject(fb.BufferContext bc, int offset) =>
+ new Vec3._(bc, offset);
+}
+
+class Vec3Builder {
+ Vec3Builder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(double x, double y, double z, double test1, Color test2, fb.StructBuilder test3) {
+ fbBuilder.pad(2);
+ test3();
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(test2?.value);
+ fbBuilder.putFloat64(test1);
+ fbBuilder.pad(4);
+ fbBuilder.putFloat32(z);
+ fbBuilder.putFloat32(y);
+ fbBuilder.putFloat32(x);
+ return fbBuilder.offset;
+ }
+
+}
+
+class Vec3ObjectBuilder extends fb.ObjectBuilder {
+ final double _x;
+ final double _y;
+ final double _z;
+ final double _test1;
+ final Color _test2;
+ final TestObjectBuilder _test3;
+
+ Vec3ObjectBuilder({
+ double x,
+ double y,
+ double z,
+ double test1,
+ Color test2,
+ TestObjectBuilder test3,
+ })
+ : _x = x,
+ _y = y,
+ _z = z,
+ _test1 = test1,
+ _test2 = test2,
+ _test3 = test3;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.pad(2);
+ _test3.finish(fbBuilder);
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(_test2?.value);
+ fbBuilder.putFloat64(_test1);
+ fbBuilder.pad(4);
+ fbBuilder.putFloat32(_z);
+ fbBuilder.putFloat32(_y);
+ fbBuilder.putFloat32(_x);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Ability {
+ Ability._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Ability> reader = const _AbilityReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get id => const fb.Uint32Reader().read(_bc, _bcOffset + 0);
+ int get distance => const fb.Uint32Reader().read(_bc, _bcOffset + 4);
+
+ @override
+ String toString() {
+ return 'Ability{id: $id, distance: $distance}';
+ }
+}
+
+class _AbilityReader extends fb.StructReader<Ability> {
+ const _AbilityReader();
+
+ @override
+ int get size => 8;
+
+ @override
+ Ability createObject(fb.BufferContext bc, int offset) =>
+ new Ability._(bc, offset);
+}
+
+class AbilityBuilder {
+ AbilityBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int id, int distance) {
+ fbBuilder.putUint32(distance);
+ fbBuilder.putUint32(id);
+ return fbBuilder.offset;
+ }
+
+}
+
+class AbilityObjectBuilder extends fb.ObjectBuilder {
+ final int _id;
+ final int _distance;
+
+ AbilityObjectBuilder({
+ int id,
+ int distance,
+ })
+ : _id = id,
+ _distance = distance;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.putUint32(_distance);
+ fbBuilder.putUint32(_id);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Stat {
+ Stat._(this._bc, this._bcOffset);
+ factory Stat(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Stat> reader = const _StatReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ String get id => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
+ int get val => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 6, 0);
+ int get count => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 8, 0);
+
+ @override
+ String toString() {
+ return 'Stat{id: $id, val: $val, count: $count}';
+ }
+}
+
+class _StatReader extends fb.TableReader<Stat> {
+ const _StatReader();
+
+ @override
+ Stat createObject(fb.BufferContext bc, int offset) =>
+ new Stat._(bc, offset);
+}
+
+class StatBuilder {
+ StatBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addIdOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addVal(int val) {
+ fbBuilder.addInt64(1, val);
+ return fbBuilder.offset;
+ }
+ int addCount(int count) {
+ fbBuilder.addUint16(2, count);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class StatObjectBuilder extends fb.ObjectBuilder {
+ final String _id;
+ final int _val;
+ final int _count;
+
+ StatObjectBuilder({
+ String id,
+ int val,
+ int count,
+ })
+ : _id = id,
+ _val = val,
+ _count = count;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int idOffset = fbBuilder.writeString(_id);
+
+ fbBuilder.startTable();
+ if (idOffset != null) {
+ fbBuilder.addOffset(0, idOffset);
+ }
+ fbBuilder.addInt64(1, _val);
+ fbBuilder.addUint16(2, _count);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Referrable {
+ Referrable._(this._bc, this._bcOffset);
+ factory Referrable(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Referrable> reader = const _ReferrableReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get id => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 4, 0);
+
+ @override
+ String toString() {
+ return 'Referrable{id: $id}';
+ }
+}
+
+class _ReferrableReader extends fb.TableReader<Referrable> {
+ const _ReferrableReader();
+
+ @override
+ Referrable createObject(fb.BufferContext bc, int offset) =>
+ new Referrable._(bc, offset);
+}
+
+class ReferrableBuilder {
+ ReferrableBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addId(int id) {
+ fbBuilder.addUint64(0, id);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class ReferrableObjectBuilder extends fb.ObjectBuilder {
+ final int _id;
+
+ ReferrableObjectBuilder({
+ int id,
+ })
+ : _id = id;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addUint64(0, _id);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+/// an example documentation comment: monster object
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+ int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
+ int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
+ List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
+ Color get color => new Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 8));
+ AnyTypeId get testType => new AnyTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 18, 0));
+ dynamic get test {
+ switch (testType?.value) {
+ case 1: return Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+ case 2: return TestSimpleTableWithEnum.reader.vTableGet(_bc, _bcOffset, 20, null);
+ case 3: return my_game_example2.Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+ default: return null;
+ }
+ }
+ List<Test> get test4 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 22, null);
+ List<String> get testarrayofstring => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 24, null);
+/// an example documentation comment: this will end up in the generated code
+/// multiline too
+ List<Monster> get testarrayoftables => const fb.ListReader<Monster>(Monster.reader).vTableGet(_bc, _bcOffset, 26, null);
+ Monster get enemy => Monster.reader.vTableGet(_bc, _bcOffset, 28, null);
+ List<int> get testnestedflatbuffer => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 30, null);
+ Stat get testempty => Stat.reader.vTableGet(_bc, _bcOffset, 32, null);
+ bool get testbool => const fb.BoolReader().vTableGet(_bc, _bcOffset, 34, false);
+ int get testhashs32Fnv1 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 36, 0);
+ int get testhashu32Fnv1 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 38, 0);
+ int get testhashs64Fnv1 => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 40, 0);
+ int get testhashu64Fnv1 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 42, 0);
+ int get testhashs32Fnv1a => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 44, 0);
+ int get testhashu32Fnv1a => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 46, 0);
+ int get testhashs64Fnv1a => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 48, 0);
+ int get testhashu64Fnv1a => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 50, 0);
+ List<bool> get testarrayofbools => const fb.ListReader<bool>(const fb.BoolReader()).vTableGet(_bc, _bcOffset, 52, null);
+ double get testf => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 54, 3.14159);
+ double get testf2 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 56, 3.0);
+ double get testf3 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 58, 0.0);
+ List<String> get testarrayofstring2 => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 60, null);
+ List<Ability> get testarrayofsortedstruct => const fb.ListReader<Ability>(Ability.reader).vTableGet(_bc, _bcOffset, 62, null);
+ List<int> get flex => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 64, null);
+ List<Test> get test5 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 66, null);
+ List<int> get vectorOfLongs => const fb.ListReader<int>(const fb.Int64Reader()).vTableGet(_bc, _bcOffset, 68, null);
+ List<double> get vectorOfDoubles => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 70, null);
+ my_game.InParentNamespace get parentNamespaceTest => my_game.InParentNamespace.reader.vTableGet(_bc, _bcOffset, 72, null);
+ List<Referrable> get vectorOfReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 74, null);
+ int get singleWeakReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 76, 0);
+ List<int> get vectorOfWeakReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 78, null);
+ List<Referrable> get vectorOfStrongReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 80, null);
+ int get coOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 82, 0);
+ List<int> get vectorOfCoOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 84, null);
+ int get nonOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 86, 0);
+ List<int> get vectorOfNonOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 88, null);
+ AnyUniqueAliasesTypeId get anyUniqueType => new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 90, 0));
+ dynamic get anyUnique {
+ switch (anyUniqueType?.value) {
+ case 1: return M.reader.vTableGet(_bc, _bcOffset, 92, null);
+ case 2: return T.reader.vTableGet(_bc, _bcOffset, 92, null);
+ case 3: return M2.reader.vTableGet(_bc, _bcOffset, 92, null);
+ default: return null;
+ }
+ }
+ AnyAmbiguousAliasesTypeId get anyAmbiguousType => new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 94, 0));
+ dynamic get anyAmbiguous {
+ switch (anyAmbiguousType?.value) {
+ case 1: return M1.reader.vTableGet(_bc, _bcOffset, 96, null);
+ case 2: return M2.reader.vTableGet(_bc, _bcOffset, 96, null);
+ case 3: return M3.reader.vTableGet(_bc, _bcOffset, 96, null);
+ default: return null;
+ }
+ }
+ List<Color> get vectorOfEnums => const fb.ListReader<Color>(Color.reader).vTableGet(_bc, _bcOffset, 98, null);
+
+ @override
+ String toString() {
+ return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterBuilder {
+ MonsterBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addPos(int offset) {
+ fbBuilder.addStruct(0, offset);
+ return fbBuilder.offset;
+ }
+ int addMana(int mana) {
+ fbBuilder.addInt16(1, mana);
+ return fbBuilder.offset;
+ }
+ int addHp(int hp) {
+ fbBuilder.addInt16(2, hp);
+ return fbBuilder.offset;
+ }
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(3, offset);
+ return fbBuilder.offset;
+ }
+ int addInventoryOffset(int offset) {
+ fbBuilder.addOffset(5, offset);
+ return fbBuilder.offset;
+ }
+ int addColor(Color color) {
+ fbBuilder.addInt8(6, color?.value);
+ return fbBuilder.offset;
+ }
+ int addTestType(AnyTypeId testType) {
+ fbBuilder.addUint8(7, testType?.value);
+ return fbBuilder.offset;
+ }
+ int addTestOffset(int offset) {
+ fbBuilder.addOffset(8, offset);
+ return fbBuilder.offset;
+ }
+ int addTest4Offset(int offset) {
+ fbBuilder.addOffset(9, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofstringOffset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayoftablesOffset(int offset) {
+ fbBuilder.addOffset(11, offset);
+ return fbBuilder.offset;
+ }
+ int addEnemyOffset(int offset) {
+ fbBuilder.addOffset(12, offset);
+ return fbBuilder.offset;
+ }
+ int addTestnestedflatbufferOffset(int offset) {
+ fbBuilder.addOffset(13, offset);
+ return fbBuilder.offset;
+ }
+ int addTestemptyOffset(int offset) {
+ fbBuilder.addOffset(14, offset);
+ return fbBuilder.offset;
+ }
+ int addTestbool(bool testbool) {
+ fbBuilder.addBool(15, testbool);
+ return fbBuilder.offset;
+ }
+ int addTesthashs32Fnv1(int testhashs32Fnv1) {
+ fbBuilder.addInt32(16, testhashs32Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashu32Fnv1(int testhashu32Fnv1) {
+ fbBuilder.addUint32(17, testhashu32Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashs64Fnv1(int testhashs64Fnv1) {
+ fbBuilder.addInt64(18, testhashs64Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashu64Fnv1(int testhashu64Fnv1) {
+ fbBuilder.addUint64(19, testhashu64Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashs32Fnv1a(int testhashs32Fnv1a) {
+ fbBuilder.addInt32(20, testhashs32Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashu32Fnv1a(int testhashu32Fnv1a) {
+ fbBuilder.addUint32(21, testhashu32Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashs64Fnv1a(int testhashs64Fnv1a) {
+ fbBuilder.addInt64(22, testhashs64Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashu64Fnv1a(int testhashu64Fnv1a) {
+ fbBuilder.addUint64(23, testhashu64Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofboolsOffset(int offset) {
+ fbBuilder.addOffset(24, offset);
+ return fbBuilder.offset;
+ }
+ int addTestf(double testf) {
+ fbBuilder.addFloat32(25, testf);
+ return fbBuilder.offset;
+ }
+ int addTestf2(double testf2) {
+ fbBuilder.addFloat32(26, testf2);
+ return fbBuilder.offset;
+ }
+ int addTestf3(double testf3) {
+ fbBuilder.addFloat32(27, testf3);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofstring2Offset(int offset) {
+ fbBuilder.addOffset(28, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofsortedstructOffset(int offset) {
+ fbBuilder.addOffset(29, offset);
+ return fbBuilder.offset;
+ }
+ int addFlexOffset(int offset) {
+ fbBuilder.addOffset(30, offset);
+ return fbBuilder.offset;
+ }
+ int addTest5Offset(int offset) {
+ fbBuilder.addOffset(31, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfLongsOffset(int offset) {
+ fbBuilder.addOffset(32, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfDoublesOffset(int offset) {
+ fbBuilder.addOffset(33, offset);
+ return fbBuilder.offset;
+ }
+ int addParentNamespaceTestOffset(int offset) {
+ fbBuilder.addOffset(34, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfReferrablesOffset(int offset) {
+ fbBuilder.addOffset(35, offset);
+ return fbBuilder.offset;
+ }
+ int addSingleWeakReference(int singleWeakReference) {
+ fbBuilder.addUint64(36, singleWeakReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfWeakReferencesOffset(int offset) {
+ fbBuilder.addOffset(37, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfStrongReferrablesOffset(int offset) {
+ fbBuilder.addOffset(38, offset);
+ return fbBuilder.offset;
+ }
+ int addCoOwningReference(int coOwningReference) {
+ fbBuilder.addUint64(39, coOwningReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfCoOwningReferencesOffset(int offset) {
+ fbBuilder.addOffset(40, offset);
+ return fbBuilder.offset;
+ }
+ int addNonOwningReference(int nonOwningReference) {
+ fbBuilder.addUint64(41, nonOwningReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfNonOwningReferencesOffset(int offset) {
+ fbBuilder.addOffset(42, offset);
+ return fbBuilder.offset;
+ }
+ int addAnyUniqueType(AnyUniqueAliasesTypeId anyUniqueType) {
+ fbBuilder.addUint8(43, anyUniqueType?.value);
+ return fbBuilder.offset;
+ }
+ int addAnyUniqueOffset(int offset) {
+ fbBuilder.addOffset(44, offset);
+ return fbBuilder.offset;
+ }
+ int addAnyAmbiguousType(AnyAmbiguousAliasesTypeId anyAmbiguousType) {
+ fbBuilder.addUint8(45, anyAmbiguousType?.value);
+ return fbBuilder.offset;
+ }
+ int addAnyAmbiguousOffset(int offset) {
+ fbBuilder.addOffset(46, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfEnumsOffset(int offset) {
+ fbBuilder.addOffset(47, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+ final Vec3ObjectBuilder _pos;
+ final int _mana;
+ final int _hp;
+ final String _name;
+ final List<int> _inventory;
+ final Color _color;
+ final AnyTypeId _testType;
+ final dynamic _test;
+ final List<TestObjectBuilder> _test4;
+ final List<String> _testarrayofstring;
+ final List<MonsterObjectBuilder> _testarrayoftables;
+ final MonsterObjectBuilder _enemy;
+ final List<int> _testnestedflatbuffer;
+ final StatObjectBuilder _testempty;
+ final bool _testbool;
+ final int _testhashs32Fnv1;
+ final int _testhashu32Fnv1;
+ final int _testhashs64Fnv1;
+ final int _testhashu64Fnv1;
+ final int _testhashs32Fnv1a;
+ final int _testhashu32Fnv1a;
+ final int _testhashs64Fnv1a;
+ final int _testhashu64Fnv1a;
+ final List<bool> _testarrayofbools;
+ final double _testf;
+ final double _testf2;
+ final double _testf3;
+ final List<String> _testarrayofstring2;
+ final List<AbilityObjectBuilder> _testarrayofsortedstruct;
+ final List<int> _flex;
+ final List<TestObjectBuilder> _test5;
+ final List<int> _vectorOfLongs;
+ final List<double> _vectorOfDoubles;
+ final my_game.InParentNamespaceObjectBuilder _parentNamespaceTest;
+ final List<ReferrableObjectBuilder> _vectorOfReferrables;
+ final int _singleWeakReference;
+ final List<int> _vectorOfWeakReferences;
+ final List<ReferrableObjectBuilder> _vectorOfStrongReferrables;
+ final int _coOwningReference;
+ final List<int> _vectorOfCoOwningReferences;
+ final int _nonOwningReference;
+ final List<int> _vectorOfNonOwningReferences;
+ final AnyUniqueAliasesTypeId _anyUniqueType;
+ final dynamic _anyUnique;
+ final AnyAmbiguousAliasesTypeId _anyAmbiguousType;
+ final dynamic _anyAmbiguous;
+ final List<Color> _vectorOfEnums;
+
+ MonsterObjectBuilder({
+ Vec3ObjectBuilder pos,
+ int mana,
+ int hp,
+ String name,
+ List<int> inventory,
+ Color color,
+ AnyTypeId testType,
+ dynamic test,
+ List<TestObjectBuilder> test4,
+ List<String> testarrayofstring,
+ List<MonsterObjectBuilder> testarrayoftables,
+ MonsterObjectBuilder enemy,
+ List<int> testnestedflatbuffer,
+ StatObjectBuilder testempty,
+ bool testbool,
+ int testhashs32Fnv1,
+ int testhashu32Fnv1,
+ int testhashs64Fnv1,
+ int testhashu64Fnv1,
+ int testhashs32Fnv1a,
+ int testhashu32Fnv1a,
+ int testhashs64Fnv1a,
+ int testhashu64Fnv1a,
+ List<bool> testarrayofbools,
+ double testf,
+ double testf2,
+ double testf3,
+ List<String> testarrayofstring2,
+ List<AbilityObjectBuilder> testarrayofsortedstruct,
+ List<int> flex,
+ List<TestObjectBuilder> test5,
+ List<int> vectorOfLongs,
+ List<double> vectorOfDoubles,
+ my_game.InParentNamespaceObjectBuilder parentNamespaceTest,
+ List<ReferrableObjectBuilder> vectorOfReferrables,
+ int singleWeakReference,
+ List<int> vectorOfWeakReferences,
+ List<ReferrableObjectBuilder> vectorOfStrongReferrables,
+ int coOwningReference,
+ List<int> vectorOfCoOwningReferences,
+ int nonOwningReference,
+ List<int> vectorOfNonOwningReferences,
+ AnyUniqueAliasesTypeId anyUniqueType,
+ dynamic anyUnique,
+ AnyAmbiguousAliasesTypeId anyAmbiguousType,
+ dynamic anyAmbiguous,
+ List<Color> vectorOfEnums,
+ })
+ : _pos = pos,
+ _mana = mana,
+ _hp = hp,
+ _name = name,
+ _inventory = inventory,
+ _color = color,
+ _testType = testType,
+ _test = test,
+ _test4 = test4,
+ _testarrayofstring = testarrayofstring,
+ _testarrayoftables = testarrayoftables,
+ _enemy = enemy,
+ _testnestedflatbuffer = testnestedflatbuffer,
+ _testempty = testempty,
+ _testbool = testbool,
+ _testhashs32Fnv1 = testhashs32Fnv1,
+ _testhashu32Fnv1 = testhashu32Fnv1,
+ _testhashs64Fnv1 = testhashs64Fnv1,
+ _testhashu64Fnv1 = testhashu64Fnv1,
+ _testhashs32Fnv1a = testhashs32Fnv1a,
+ _testhashu32Fnv1a = testhashu32Fnv1a,
+ _testhashs64Fnv1a = testhashs64Fnv1a,
+ _testhashu64Fnv1a = testhashu64Fnv1a,
+ _testarrayofbools = testarrayofbools,
+ _testf = testf,
+ _testf2 = testf2,
+ _testf3 = testf3,
+ _testarrayofstring2 = testarrayofstring2,
+ _testarrayofsortedstruct = testarrayofsortedstruct,
+ _flex = flex,
+ _test5 = test5,
+ _vectorOfLongs = vectorOfLongs,
+ _vectorOfDoubles = vectorOfDoubles,
+ _parentNamespaceTest = parentNamespaceTest,
+ _vectorOfReferrables = vectorOfReferrables,
+ _singleWeakReference = singleWeakReference,
+ _vectorOfWeakReferences = vectorOfWeakReferences,
+ _vectorOfStrongReferrables = vectorOfStrongReferrables,
+ _coOwningReference = coOwningReference,
+ _vectorOfCoOwningReferences = vectorOfCoOwningReferences,
+ _nonOwningReference = nonOwningReference,
+ _vectorOfNonOwningReferences = vectorOfNonOwningReferences,
+ _anyUniqueType = anyUniqueType,
+ _anyUnique = anyUnique,
+ _anyAmbiguousType = anyAmbiguousType,
+ _anyAmbiguous = anyAmbiguous,
+ _vectorOfEnums = vectorOfEnums;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+ final int inventoryOffset = _inventory?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_inventory)
+ : null;
+ final int testOffset = _test?.getOrCreateOffset(fbBuilder);
+ final int test4Offset = _test4?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_test4)
+ : null;
+ final int testarrayofstringOffset = _testarrayofstring?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayofstring.map((b) => fbBuilder.writeString(b)).toList())
+ : null;
+ final int testarrayoftablesOffset = _testarrayoftables?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayoftables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int enemyOffset = _enemy?.getOrCreateOffset(fbBuilder);
+ final int testnestedflatbufferOffset = _testnestedflatbuffer?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_testnestedflatbuffer)
+ : null;
+ final int testemptyOffset = _testempty?.getOrCreateOffset(fbBuilder);
+ final int testarrayofboolsOffset = _testarrayofbools?.isNotEmpty == true
+ ? fbBuilder.writeListBool(_testarrayofbools)
+ : null;
+ final int testarrayofstring2Offset = _testarrayofstring2?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayofstring2.map((b) => fbBuilder.writeString(b)).toList())
+ : null;
+ final int testarrayofsortedstructOffset = _testarrayofsortedstruct?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_testarrayofsortedstruct)
+ : null;
+ final int flexOffset = _flex?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_flex)
+ : null;
+ final int test5Offset = _test5?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_test5)
+ : null;
+ final int vectorOfLongsOffset = _vectorOfLongs?.isNotEmpty == true
+ ? fbBuilder.writeListInt64(_vectorOfLongs)
+ : null;
+ final int vectorOfDoublesOffset = _vectorOfDoubles?.isNotEmpty == true
+ ? fbBuilder.writeListFloat64(_vectorOfDoubles)
+ : null;
+ final int parentNamespaceTestOffset = _parentNamespaceTest?.getOrCreateOffset(fbBuilder);
+ final int vectorOfReferrablesOffset = _vectorOfReferrables?.isNotEmpty == true
+ ? fbBuilder.writeList(_vectorOfReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int vectorOfWeakReferencesOffset = _vectorOfWeakReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfWeakReferences)
+ : null;
+ final int vectorOfStrongReferrablesOffset = _vectorOfStrongReferrables?.isNotEmpty == true
+ ? fbBuilder.writeList(_vectorOfStrongReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int vectorOfCoOwningReferencesOffset = _vectorOfCoOwningReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfCoOwningReferences)
+ : null;
+ final int vectorOfNonOwningReferencesOffset = _vectorOfNonOwningReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfNonOwningReferences)
+ : null;
+ final int anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder);
+ final int anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder);
+ final int vectorOfEnumsOffset = _vectorOfEnums?.isNotEmpty == true
+ ? fbBuilder.writeListInt8(_vectorOfEnums.map((f) => f.value))
+ : null;
+
+ fbBuilder.startTable();
+ if (_pos != null) {
+ fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+ }
+ fbBuilder.addInt16(1, _mana);
+ fbBuilder.addInt16(2, _hp);
+ if (nameOffset != null) {
+ fbBuilder.addOffset(3, nameOffset);
+ }
+ if (inventoryOffset != null) {
+ fbBuilder.addOffset(5, inventoryOffset);
+ }
+ fbBuilder.addInt8(6, _color?.value);
+ fbBuilder.addUint8(7, _testType?.value);
+ if (testOffset != null) {
+ fbBuilder.addOffset(8, testOffset);
+ }
+ if (test4Offset != null) {
+ fbBuilder.addOffset(9, test4Offset);
+ }
+ if (testarrayofstringOffset != null) {
+ fbBuilder.addOffset(10, testarrayofstringOffset);
+ }
+ if (testarrayoftablesOffset != null) {
+ fbBuilder.addOffset(11, testarrayoftablesOffset);
+ }
+ if (enemyOffset != null) {
+ fbBuilder.addOffset(12, enemyOffset);
+ }
+ if (testnestedflatbufferOffset != null) {
+ fbBuilder.addOffset(13, testnestedflatbufferOffset);
+ }
+ if (testemptyOffset != null) {
+ fbBuilder.addOffset(14, testemptyOffset);
+ }
+ fbBuilder.addBool(15, _testbool);
+ fbBuilder.addInt32(16, _testhashs32Fnv1);
+ fbBuilder.addUint32(17, _testhashu32Fnv1);
+ fbBuilder.addInt64(18, _testhashs64Fnv1);
+ fbBuilder.addUint64(19, _testhashu64Fnv1);
+ fbBuilder.addInt32(20, _testhashs32Fnv1a);
+ fbBuilder.addUint32(21, _testhashu32Fnv1a);
+ fbBuilder.addInt64(22, _testhashs64Fnv1a);
+ fbBuilder.addUint64(23, _testhashu64Fnv1a);
+ if (testarrayofboolsOffset != null) {
+ fbBuilder.addOffset(24, testarrayofboolsOffset);
+ }
+ fbBuilder.addFloat32(25, _testf);
+ fbBuilder.addFloat32(26, _testf2);
+ fbBuilder.addFloat32(27, _testf3);
+ if (testarrayofstring2Offset != null) {
+ fbBuilder.addOffset(28, testarrayofstring2Offset);
+ }
+ if (testarrayofsortedstructOffset != null) {
+ fbBuilder.addOffset(29, testarrayofsortedstructOffset);
+ }
+ if (flexOffset != null) {
+ fbBuilder.addOffset(30, flexOffset);
+ }
+ if (test5Offset != null) {
+ fbBuilder.addOffset(31, test5Offset);
+ }
+ if (vectorOfLongsOffset != null) {
+ fbBuilder.addOffset(32, vectorOfLongsOffset);
+ }
+ if (vectorOfDoublesOffset != null) {
+ fbBuilder.addOffset(33, vectorOfDoublesOffset);
+ }
+ if (parentNamespaceTestOffset != null) {
+ fbBuilder.addOffset(34, parentNamespaceTestOffset);
+ }
+ if (vectorOfReferrablesOffset != null) {
+ fbBuilder.addOffset(35, vectorOfReferrablesOffset);
+ }
+ fbBuilder.addUint64(36, _singleWeakReference);
+ if (vectorOfWeakReferencesOffset != null) {
+ fbBuilder.addOffset(37, vectorOfWeakReferencesOffset);
+ }
+ if (vectorOfStrongReferrablesOffset != null) {
+ fbBuilder.addOffset(38, vectorOfStrongReferrablesOffset);
+ }
+ fbBuilder.addUint64(39, _coOwningReference);
+ if (vectorOfCoOwningReferencesOffset != null) {
+ fbBuilder.addOffset(40, vectorOfCoOwningReferencesOffset);
+ }
+ fbBuilder.addUint64(41, _nonOwningReference);
+ if (vectorOfNonOwningReferencesOffset != null) {
+ fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
+ }
+ fbBuilder.addUint8(43, _anyUniqueType?.value);
+ if (anyUniqueOffset != null) {
+ fbBuilder.addOffset(44, anyUniqueOffset);
+ }
+ fbBuilder.addUint8(45, _anyAmbiguousType?.value);
+ if (anyAmbiguousOffset != null) {
+ fbBuilder.addOffset(46, anyAmbiguousOffset);
+ }
+ if (vectorOfEnumsOffset != null) {
+ fbBuilder.addOffset(47, vectorOfEnumsOffset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class TypeAliases {
+ TypeAliases._(this._bc, this._bcOffset);
+ factory TypeAliases(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TypeAliases> reader = const _TypeAliasesReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get i8 => const fb.Int8Reader().vTableGet(_bc, _bcOffset, 4, 0);
+ int get u8 => const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 6, 0);
+ int get i16 => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 0);
+ int get u16 => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 10, 0);
+ int get i32 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 12, 0);
+ int get u32 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 14, 0);
+ int get i64 => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 16, 0);
+ int get u64 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 18, 0);
+ double get f32 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 20, 0.0);
+ double get f64 => const fb.Float64Reader().vTableGet(_bc, _bcOffset, 22, 0.0);
+ List<int> get v8 => const fb.ListReader<int>(const fb.Int8Reader()).vTableGet(_bc, _bcOffset, 24, null);
+ List<double> get vf64 => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 26, null);
+
+ @override
+ String toString() {
+ return 'TypeAliases{i8: $i8, u8: $u8, i16: $i16, u16: $u16, i32: $i32, u32: $u32, i64: $i64, u64: $u64, f32: $f32, f64: $f64, v8: $v8, vf64: $vf64}';
+ }
+}
+
+class _TypeAliasesReader extends fb.TableReader<TypeAliases> {
+ const _TypeAliasesReader();
+
+ @override
+ TypeAliases createObject(fb.BufferContext bc, int offset) =>
+ new TypeAliases._(bc, offset);
+}
+
+class TypeAliasesBuilder {
+ TypeAliasesBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addI8(int i8) {
+ fbBuilder.addInt8(0, i8);
+ return fbBuilder.offset;
+ }
+ int addU8(int u8) {
+ fbBuilder.addUint8(1, u8);
+ return fbBuilder.offset;
+ }
+ int addI16(int i16) {
+ fbBuilder.addInt16(2, i16);
+ return fbBuilder.offset;
+ }
+ int addU16(int u16) {
+ fbBuilder.addUint16(3, u16);
+ return fbBuilder.offset;
+ }
+ int addI32(int i32) {
+ fbBuilder.addInt32(4, i32);
+ return fbBuilder.offset;
+ }
+ int addU32(int u32) {
+ fbBuilder.addUint32(5, u32);
+ return fbBuilder.offset;
+ }
+ int addI64(int i64) {
+ fbBuilder.addInt64(6, i64);
+ return fbBuilder.offset;
+ }
+ int addU64(int u64) {
+ fbBuilder.addUint64(7, u64);
+ return fbBuilder.offset;
+ }
+ int addF32(double f32) {
+ fbBuilder.addFloat32(8, f32);
+ return fbBuilder.offset;
+ }
+ int addF64(double f64) {
+ fbBuilder.addFloat64(9, f64);
+ return fbBuilder.offset;
+ }
+ int addV8Offset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+ int addVf64Offset(int offset) {
+ fbBuilder.addOffset(11, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TypeAliasesObjectBuilder extends fb.ObjectBuilder {
+ final int _i8;
+ final int _u8;
+ final int _i16;
+ final int _u16;
+ final int _i32;
+ final int _u32;
+ final int _i64;
+ final int _u64;
+ final double _f32;
+ final double _f64;
+ final List<int> _v8;
+ final List<double> _vf64;
+
+ TypeAliasesObjectBuilder({
+ int i8,
+ int u8,
+ int i16,
+ int u16,
+ int i32,
+ int u32,
+ int i64,
+ int u64,
+ double f32,
+ double f64,
+ List<int> v8,
+ List<double> vf64,
+ })
+ : _i8 = i8,
+ _u8 = u8,
+ _i16 = i16,
+ _u16 = u16,
+ _i32 = i32,
+ _u32 = u32,
+ _i64 = i64,
+ _u64 = u64,
+ _f32 = f32,
+ _f64 = f64,
+ _v8 = v8,
+ _vf64 = vf64;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int v8Offset = _v8?.isNotEmpty == true
+ ? fbBuilder.writeListInt8(_v8)
+ : null;
+ final int vf64Offset = _vf64?.isNotEmpty == true
+ ? fbBuilder.writeListFloat64(_vf64)
+ : null;
+
+ fbBuilder.startTable();
+ fbBuilder.addInt8(0, _i8);
+ fbBuilder.addUint8(1, _u8);
+ fbBuilder.addInt16(2, _i16);
+ fbBuilder.addUint16(3, _u16);
+ fbBuilder.addInt32(4, _i32);
+ fbBuilder.addUint32(5, _u32);
+ fbBuilder.addInt64(6, _i64);
+ fbBuilder.addUint64(7, _u64);
+ fbBuilder.addFloat32(8, _f32);
+ fbBuilder.addFloat64(9, _f64);
+ if (v8Offset != null) {
+ fbBuilder.addOffset(10, v8Offset);
+ }
+ if (vf64Offset != null) {
+ fbBuilder.addOffset(11, vf64Offset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/dart/test/monster_test_my_game_generated.dart b/dart/test/monster_test_my_game_generated.dart
new file mode 100644
index 0000000..26bb73b
--- /dev/null
+++ b/dart/test/monster_test_my_game_generated.dart
@@ -0,0 +1,62 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import 'include_test1_my_game_generated.dart';
+import 'include_test2_my_game_generated.dart';
+import './monster_test_my_game.example_generated.dart' as my_game_example;
+import './monster_test_my_game.example2_generated.dart' as my_game_example2;
+
+class InParentNamespace {
+ InParentNamespace._(this._bc, this._bcOffset);
+ factory InParentNamespace(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<InParentNamespace> reader = const _InParentNamespaceReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+
+ @override
+ String toString() {
+ return 'InParentNamespace{}';
+ }
+}
+
+class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
+ const _InParentNamespaceReader();
+
+ @override
+ InParentNamespace createObject(fb.BufferContext bc, int offset) =>
+ new InParentNamespace._(bc, offset);
+}
+
+class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
+
+ InParentNamespaceObjectBuilder();
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/docs/footer.html b/docs/footer.html
new file mode 100644
index 0000000..42bc5f2
--- /dev/null
+++ b/docs/footer.html
@@ -0,0 +1,14 @@
+<!-- Google Analytics -->
+<script>
+ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+ })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
+
+ ga('create', 'UA-49880327-7', 'auto');
+ ga('send', 'pageview');
+
+</script>
+
+</body>
+</html>
diff --git a/docs/header.html b/docs/header.html
new file mode 100644
index 0000000..0266e7c
--- /dev/null
+++ b/docs/header.html
@@ -0,0 +1,62 @@
+<!-- HTML header for doxygen 1.8.6-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,700" rel="stylesheet">
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea" style="height: 110px;">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <!--BEGIN PROJECT_LOGO-->
+ <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+ <!--END PROJECT_LOGO-->
+ <td id="commonprojectlogo">
+ <img alt="Logo" src="$relpath^fpl_logo_small.png"/>
+ </td>
+ <!--BEGIN PROJECT_NAME-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectname">$projectname
+ <!--BEGIN PROJECT_NUMBER--> <span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+ </div>
+ <div style="font-size:12px;">
+ An open source project by <a href="https://developers.google.com/games/#Tools">FPL</a>.
+ </div>
+ <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+ </td>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectbrief">$projectbrief</div>
+ </td>
+ <!--END PROJECT_BRIEF-->
+ <!--END !PROJECT_NAME-->
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/docs/images/fpl_logo_small.png b/docs/images/fpl_logo_small.png
new file mode 100644
index 0000000..2c728f3
--- /dev/null
+++ b/docs/images/fpl_logo_small.png
Binary files differ
diff --git a/docs/images/ftv2mnode.png b/docs/images/ftv2mnode.png
new file mode 100644
index 0000000..3caf47d
--- /dev/null
+++ b/docs/images/ftv2mnode.png
Binary files differ
diff --git a/docs/images/ftv2pnode.png b/docs/images/ftv2pnode.png
new file mode 100644
index 0000000..f1aaad3
--- /dev/null
+++ b/docs/images/ftv2pnode.png
Binary files differ
diff --git a/docs/source/Benchmarks.md b/docs/source/Benchmarks.md
new file mode 100644
index 0000000..848f4e3
--- /dev/null
+++ b/docs/source/Benchmarks.md
@@ -0,0 +1,63 @@
+C++ Benchmarks {#flatbuffers_benchmarks}
+==========
+
+Comparing against other serialization solutions, running on Windows 7
+64bit. We use the LITE runtime for Protocol Buffers (less code / lower
+overhead), Rapid JSON (one of the fastest C++ JSON parsers around),
+and pugixml, also one of the fastest XML parsers.
+
+We also compare against code that doesn't use a serialization library
+at all (the column "Raw structs"), which is what you get if you write
+hardcoded code that just writes structs. This is the fastest possible,
+but of course is not cross platform nor has any kind of forwards /
+backwards compatibility.
+
+We compare against Flatbuffers with the binary wire format (as
+intended), and also with JSON as the wire format with the optional JSON
+parser (which, using a schema, parses JSON into a binary buffer that can
+then be accessed as before).
+
+The benchmark object is a set of about 10 objects containing an array, 4
+strings, and a large variety of int/float scalar values of all sizes,
+meant to be representative of game data, e.g. a scene format.
+
+| | FlatBuffers (binary) | Protocol Buffers LITE | Rapid JSON | FlatBuffers (JSON) | pugixml | Raw structs |
+|--------------------------------------------------------|-----------------------|-----------------------|-----------------------|------------------------| ----------------------| ----------------------|
+| Decode + Traverse + Dealloc (1 million times, seconds) | 0.08 | 302 | 583 | 105 | 196 | 0.02 |
+| Decode / Traverse / Dealloc (breakdown) | 0 / 0.08 / 0 | 220 / 0.15 / 81 | 294 / 0.9 / 287 | 70 / 0.08 / 35 | 41 / 3.9 / 150 | 0 / 0.02 / 0 |
+| Encode (1 million times, seconds) | 3.2 | 185 | 650 | 169 | 273 | 0.15 |
+| Wire format size (normal / zlib, bytes) | 344 / 220 | 228 / 174 | 1475 / 322 | 1029 / 298 | 1137 / 341 | 312 / 187 |
+| Memory needed to store decoded wire (bytes / blocks) | 0 / 0 | 760 / 20 | 65689 / 4 | 328 / 1 | 34194 / 3 | 0 / 0 |
+| Transient memory allocated during decode (KB) | 0 | 1 | 131 | 4 | 34 | 0 |
+| Generated source code size (KB) | 4 | 61 | 0 | 4 | 0 | 0 |
+| Field access in handwritten traversal code | typed accessors | typed accessors | manual error checking | typed accessors | manual error checking | typed but no safety |
+| Library source code (KB) | 15 | some subset of 3800 | 87 | 43 | 327 | 0 |
+
+### Some other serialization systems we compared against but did not benchmark (yet), in rough order of applicability:
+
+- Cap'n'Proto promises to reduce Protocol Buffers much like FlatBuffers does,
+ though with a more complicated binary encoding and less flexibility (no
+ optional fields to allow deprecating fields or serializing with missing
+ fields for which defaults exist).
+ It currently also isn't fully cross-platform portable (lack of VS support).
+- msgpack: has very minimal forwards/backwards compatibility support when used
+ with the typed C++ interface. Also lacks VS2010 support.
+- Thrift: very similar to Protocol Buffers, but appears to be less efficient,
+ and have more dependencies.
+- YAML: a superset of JSON and otherwise very similar. Used by e.g. Unity.
+- C# comes with built-in serialization functionality, as used by Unity also.
+ Being tied to the language, and having no automatic versioning support
+ limits its applicability.
+- Project Anarchy (the free mobile engine by Havok) comes with a serialization
+ system, that however does no automatic versioning (have to code around new
+ fields manually), is very much tied to the rest of the engine, and works
+ without a schema to generate code (tied to your C++ class definition).
+
+### Code for benchmarks
+
+Code for these benchmarks sits in `benchmarks/` in git branch `benchmarks`.
+It sits in its own branch because it has submodule dependencies that the main
+project doesn't need, and the code standards do not meet those of the main
+project. Please read `benchmarks/cpp/README.txt` before working with the code.
+
+<br>
diff --git a/docs/source/Building.md b/docs/source/Building.md
new file mode 100644
index 0000000..a896711
--- /dev/null
+++ b/docs/source/Building.md
@@ -0,0 +1,100 @@
+Building {#flatbuffers_guide_building}
+========
+
+## Building with CMake
+
+The distribution comes with a `cmake` file that should allow
+you to build project/make files for any platform. For details on `cmake`, see
+<https://www.cmake.org>. In brief, depending on your platform, use one of
+e.g.:
+
+ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
+ cmake -G "Visual Studio 10" -DCMAKE_BUILD_TYPE=Release
+ cmake -G "Xcode" -DCMAKE_BUILD_TYPE=Release
+
+Then, build as normal for your platform. This should result in a `flatc`
+executable, essential for the next steps.
+Note that to use clang instead of gcc, you may need to set up your environment
+variables, e.g.
+`CC=/usr/bin/clang CXX=/usr/bin/clang++ cmake -G "Unix Makefiles"`.
+
+Optionally, run the `flattests` executable from the root `flatbuffers/`
+directory to ensure everything is working correctly on your system. If this
+fails, please contact us!
+
+Building should also produce two sample executables, `flatsamplebinary` and
+`flatsampletext`, see the corresponding `.cpp` files in the
+`flatbuffers/samples` directory.
+
+*Note that you MUST be in the root of the FlatBuffers distribution when you
+run 'flattests' or `flatsampletext`, or it will fail to load its files.*
+
+## Building for Android
+
+There is a `flatbuffers/android` directory that contains all you need to build
+the test executable on android (use the included `build_apk.sh` script, or use
+`ndk_build` / `adb` etc. as usual). Upon running, it will output to the log
+if tests succeeded or not.
+
+You may also run an android sample from inside the `flatbuffers/samples`, by
+running the `android_sample.sh` script. Optionally, you may go to the
+`flatbuffers/samples/android` folder and build the sample with the
+`build_apk.sh` script or `ndk_build` / `adb` etc.
+
+## Using FlatBuffers in your own projects
+
+For C++, there is usually no runtime to compile, as the code consists of a
+single header, `include/flatbuffers/flatbuffers.h`. You should add the
+`include` folder to your include paths. If you wish to be
+able to load schemas and/or parse text into binary buffers at runtime,
+you additionally need the other headers in `include/flatbuffers`. You must
+also compile/link `src/idl_parser.cpp` (and `src/idl_gen_text.cpp` if you
+also want to be able convert binary to text).
+
+To see how to include FlatBuffers in any of our supported languages, please
+view the [Tutorial](@ref flatbuffers_guide_tutorial) and select your appropriate
+language using the radio buttons.
+
+### Using in CMake-based projects
+If you want to use FlatBuffers in a project which already uses CMake, then a more
+robust and flexible approach is to build FlatBuffers as part of that project directly.
+This is done by making the FlatBuffers source code available to the main build
+and adding it using CMake's `add_subdirectory()` command. This has the
+significant advantage that the same compiler and linker settings are used
+between FlatBuffers and the rest of your project, so issues associated with using
+incompatible libraries (eg debug/release), etc. are avoided. This is
+particularly useful on Windows.
+
+Suppose you put FlatBuffers source code in directory `${FLATBUFFERS_SRC_DIR}`.
+To build it as part of your project, add following code to your `CMakeLists.txt` file:
+```cmake
+# Add FlatBuffers directly to our build. This defines the `flatbuffers` target.
+add_subdirectory(${FLATBUFFERS_SRC_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build
+ EXCLUDE_FROM_ALL)
+
+# Now simply link against flatbuffers as needed to your already declared target.
+# The flatbuffers target carry header search path automatically if CMake > 2.8.11.
+target_link_libraries(own_project_target PRIVATE flatbuffers)
+```
+When build your project the `flatbuffers` library will be compiled and linked
+to a target as part of your project.
+
+#### Override default depth limit of nested objects
+To override [the depth limit of recursion](@ref flatbuffers_guide_use_cpp),
+add this directive:
+```cmake
+set(FLATBUFFERS_MAX_PARSING_DEPTH 16)
+```
+to `CMakeLists.txt` file before `add_subdirectory(${FLATBUFFERS_SRC_DIR})` line.
+
+#### For Google Play apps
+
+For applications on Google Play that integrate this library, usage is tracked.
+This tracking is done automatically using the embedded version string
+(flatbuffer_version_string), and helps us continue to optimize it.
+Aside from consuming a few extra bytes in your application binary, it shouldn't
+affect your application at all. We use this information to let us know if
+FlatBuffers is useful and if we should continue to invest in it. Since this is
+open source, you are free to remove the version string but we would appreciate
+if you would leave it in.
diff --git a/docs/source/CONTRIBUTING.md b/docs/source/CONTRIBUTING.md
new file mode 120000
index 0000000..f939e75
--- /dev/null
+++ b/docs/source/CONTRIBUTING.md
@@ -0,0 +1 @@
+../../CONTRIBUTING.md
\ No newline at end of file
diff --git a/docs/source/CUsage.md b/docs/source/CUsage.md
new file mode 100644
index 0000000..9aafa6f
--- /dev/null
+++ b/docs/source/CUsage.md
@@ -0,0 +1,224 @@
+Use in C {#flatbuffers_guide_use_c}
+==========
+
+The C language binding exists in a separate project named [FlatCC](https://github.com/dvidelabs/flatcc).
+
+The `flatcc` C schema compiler can generate code offline as well as
+online via a C library. It can also generate buffer verifiers and fast
+JSON parsers, printers.
+
+Great care has been taken to ensure compatibily with the main `flatc`
+project.
+
+## General Documention
+
+- [Tutorial](@ref flatbuffers_guide_tutorial) - select C as language
+ when scrolling down
+- [FlatCC Guide](https://github.com/dvidelabs/flatcc#flatcc-flatbuffers-in-c-for-c)
+- [The C Builder Interface](https://github.com/dvidelabs/flatcc/blob/master/doc/builder.md#the-builder-interface)
+- [The Monster Sample in C](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c)
+- [GitHub](https://github.com/dvidelabs/flatcc)
+
+
+## Supported Platforms
+
+- Ubuntu (clang / gcc, ninja / gnu make)
+- OS-X (clang / gcc, ninja / gnu make)
+- Windows MSVC 2010, 2013, 2015
+
+CI builds recent versions of gcc, clang and MSVC on OS-X, Ubuntu, and
+Windows, and occasionally older compiler versions. See main project [Status](https://github.com/dvidelabs/flatcc#status).
+
+Other platforms may well work, including Centos, but are not tested
+regularly.
+
+The monster sample project was specifically written for C99 in order to
+follow the C++ version and for that reason it will not work with MSVC
+2010.
+
+## Modular Object Creation
+
+In the tutorial we used the call `Monster_create_as_root` to create the
+root buffer object since this is easier in simple use cases. Sometimes
+we need more modularity so we can reuse a function to create nested
+tables and root tables the same way. For this we need the
+`flatcc_builder_buffer_create_call`. It is best to keep `flatcc_builder`
+calls isolated at the top driver level, so we get:
+
+<div class="language-c">
+~~~{.c}
+ ns(Monster_ref_t) create_orc(flatcc_builder_t *B)
+ {
+ // ... same as in the tutorial.
+ return s(Monster_create(B, ...));
+ }
+
+ void create_monster_buffer()
+ {
+ uint8_t *buf;
+ size_t size;
+ flatcc_builder_t builder, *B;
+
+ // Initialize the builder object.
+ B = &builder;
+ flatcc_builder_init(B);
+ // Only use `buffer_create` without `create/start/end_as_root`.
+ flatcc_builder_buffer_create(create_orc(B));
+ // Allocate and copy buffer to user memory.
+ buf = flatcc_builder_finalize_buffer(B, &size);
+ // ... write the buffer to disk or network, or something.
+
+ free(buf);
+ flatcc_builder_clear(B);
+ }
+~~~
+</div>
+
+The same principle applies with `start/end` vs `start/end_as_root` in
+the top-down approach.
+
+
+## Top Down Example
+
+The tutorial uses a bottom up approach. In C it is also possible to use
+a top-down approach by starting and ending objects nested within each
+other. In the tutorial there is no deep nesting, so the difference is
+limited, but it shows the idea:
+
+<div class="language-c">
+<br>
+~~~{.c}
+ uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ size_t treasure_count = c_vec_len(treasure);
+ ns(Weapon_ref_t) axe;
+
+ // NOTE: if we use end_as_root, we MUST also start as root.
+ ns(Monster_start_as_root(B));
+ ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
+ ns(Monster_hp_add(B, 300));
+ ns(Monster_mana_add(B, 150));
+ // We use create_str instead of add because we have no existing string reference.
+ ns(Monster_name_create_str(B, "Orc"));
+ // Again we use create because we no existing vector object, only a C-array.
+ ns(Monster_inventory_create(B, treasure, treasure_count));
+ ns(Monster_color_add(B, ns(Color_Red)));
+ if (1) {
+ ns(Monster_weapons_start(B));
+ ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Sword"), 3));
+ // We reuse the axe object later. Note that we dereference a pointer
+ // because push always returns a short-term pointer to the stored element.
+ // We could also have created the axe object first and simply pushed it.
+ axe = *ns(Monster_weapons_push_create(B, flatbuffers_string_create_str(B, "Axe"), 5));
+ ns(Monster_weapons_end(B));
+ } else {
+ // We can have more control with the table elements added to a vector:
+ //
+ ns(Monster_weapons_start(B));
+ ns(Monster_weapons_push_start(B));
+ ns(Weapon_name_create_str(B, "Sword"));
+ ns(Weapon_damage_add(B, 3));
+ ns(Monster_weapons_push_end(B));
+ ns(Monster_weapons_push_start(B));
+ ns(Monster_weapons_push_start(B));
+ ns(Weapon_name_create_str(B, "Axe"));
+ ns(Weapon_damage_add(B, 5));
+ axe = *ns(Monster_weapons_push_end(B));
+ ns(Monster_weapons_end(B));
+ }
+ // Unions can get their type by using a type-specific add/create/start method.
+ ns(Monster_equipped_Weapon_add(B, axe));
+
+ ns(Monster_end_as_root(B));
+~~~
+</div>
+
+
+## Basic Reflection
+
+The C-API does support reading binary schema (.bfbs)
+files via code generated from the `reflection.fbs` schema, and an
+[example usage](https://github.com/dvidelabs/flatcc/tree/master/samples/reflection)
+shows how to use this. The reflection schema files are pre-generated
+in the [runtime distribution](https://github.com/dvidelabs/flatcc/tree/master/include/flatcc/reflection).
+
+
+## Mutations and Reflection
+
+The C-API does not support mutating reflection like C++ does, nor does
+the reader interface support mutating scalars (and it is generally
+unsafe to do so even after verification).
+
+The generated reader interface supports sorting vectors in-place after
+casting them to a mutating type because it is not practical to do so
+while building a buffer. This is covered in the builder documentation.
+The reflection example makes use of this feature to look up objects by
+name.
+
+It is possible to build new buffers using complex objects from existing
+buffers as source. This can be very efficient due to direct copy
+semantics without endian conversion or temporary stack allocation.
+
+Scalars, structs and strings can be used as source, as well vectors of
+these.
+
+It is currently not possible to use an existing table or vector of table
+as source, but it would be possible to add support for this at some
+point.
+
+
+## Namespaces
+
+The `FLATBUFFERS_WRAP_NAMESPACE` approach used in the tutorial is convenient
+when each function has a very long namespace prefix. But it isn't always
+the best approach. If the namespace is absent, or simple and
+informative, we might as well use the prefix directly. The
+[reflection example](https://github.com/dvidelabs/flatcc/blob/master/samples/reflection/bfbs2json.c)
+mentioned above uses this approach.
+
+
+## Checking for Present Members
+
+Not all languages support testing if a field is present, but in C we can
+elaborate the reader section of the tutorial with tests for this. Recall
+that `mana` was set to the default value `150` and therefore shouldn't
+be present.
+
+<div class="language-c">
+~~~{.c}
+ int hp_present = ns(Monster_hp_is_present(monster)); // 1
+ int mana_present = ns(Monster_mana_is_present(monster)); // 0
+~~~
+</div>
+
+## Alternative ways to add a Union
+
+In the tutorial we used a single call to add a union. Here we show
+different ways to accomplish the same thing. The last form is rarely
+used, but is the low-level way to do it. It can be used to group small
+values together in the table by adding type and data at different
+points in time.
+
+<div class="language-c">
+~~~{.c}
+ ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
+ ns(Monster_equipped_add(B, equipped));
+ // or alternatively
+ ns(Monster_equipped_Weapon_add(B, axe);
+ // or alternatively
+ ns(Monster_equipped_add_type(B, ns(Equipment_Weapon));
+ ns(Monster_equipped_add_member(B, axe));
+~~~
+</div>
+
+## Why not integrate with the `flatc` tool?
+
+[It was considered how the C code generator could be integrated into the
+`flatc` tool](https://github.com/dvidelabs/flatcc/issues/1), but it
+would either require that the standalone C implementation of the schema
+compiler was dropped, or it would lead to excessive code duplication, or
+a complicated intermediate representation would have to be invented.
+Neither of these alternatives are very attractive, and it isn't a big
+deal to use the `flatcc` tool instead of `flatc` given that the
+FlatBuffers C runtime library needs to be made available regardless.
+
+
diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md
new file mode 100644
index 0000000..7889abd
--- /dev/null
+++ b/docs/source/Compiler.md
@@ -0,0 +1,207 @@
+Using the schema compiler {#flatbuffers_guide_using_schema_compiler}
+=========================
+
+Usage:
+
+ flatc [ GENERATOR OPTIONS ] [ -o PATH ] [ -I PATH ] FILES...
+ [ -- FILES...]
+
+The files are read and parsed in order, and can contain either schemas
+or data (see below). Data files are processed according to the definitions of
+the most recent schema specified.
+
+`--` indicates that the following files are binary files in
+FlatBuffer format conforming to the schema indicated before it.
+
+Depending on the flags passed, additional files may
+be generated for each file processed:
+
+For any schema input files, one or more generators can be specified:
+
+- `--cpp`, `-c` : Generate a C++ header for all definitions in this file (as
+ `filename_generated.h`).
+
+- `--java`, `-j` : Generate Java code.
+
+- `--kotlin`, `-k` : Generate Kotlin code.
+
+- `--csharp`, `-n` : Generate C# code.
+
+- `--go`, `-g` : Generate Go code.
+
+- `--python`, `-p`: Generate Python code.
+
+- `--js`, `-s`: Generate JavaScript code.
+
+- `--ts`: Generate TypeScript code.
+
+- `--php`: Generate PHP code.
+
+- `--grpc`: Generate RPC stub code for GRPC.
+
+- `--dart`: Generate Dart code.
+
+- `--lua`: Generate Lua code.
+
+- `--lobster`: Generate Lobster code.
+
+- `--rust`, `-r` : Generate Rust code.
+
+For any data input files:
+
+- `--binary`, `-b` : If data is contained in this file, generate a
+ `filename.bin` containing the binary flatbuffer (or a different extension
+ if one is specified in the schema).
+
+- `--json`, `-t` : If data is contained in this file, generate a
+ `filename.json` representing the data in the flatbuffer.
+
+Additional options:
+
+- `-o PATH` : Output all generated files to PATH (either absolute, or
+ relative to the current directory). If omitted, PATH will be the
+ current directory. PATH should end in your systems path separator,
+ e.g. `/` or `\`.
+
+- `-I PATH` : when encountering `include` statements, attempt to load the
+ files from this path. Paths will be tried in the order given, and if all
+ fail (or none are specified) it will try to load relative to the path of
+ the schema file being parsed.
+
+- `-M` : Print make rules for generated files.
+
+- `--strict-json` : Require & generate strict JSON (field names are enclosed
+ in quotes, no trailing commas in tables/vectors). By default, no quotes are
+ required/generated, and trailing commas are allowed.
+
+- `--allow-non-utf8` : Pass non-UTF-8 input through parser and emit nonstandard
+ \x escapes in JSON. (Default is to raise parse error on non-UTF-8 input.)
+
+- `--natural-utf8` : Output strings with UTF-8 as human-readable strings.
+ By default, UTF-8 characters are printed as \uXXXX escapes."
+
+- `--defaults-json` : Output fields whose value is equal to the default value
+ when writing JSON text.
+
+- `--no-prefix` : Don't prefix enum values in generated C++ by their enum
+ type.
+
+- `--scoped-enums` : Use C++11 style scoped and strongly typed enums in
+ generated C++. This also implies `--no-prefix`.
+
+- `--gen-includes` : (deprecated), this is the default behavior.
+ If the original behavior is required (no include
+ statements) use `--no-includes.`
+
+- `--no-includes` : Don't generate include statements for included schemas the
+ generated file depends on (C++).
+
+- `--gen-mutable` : Generate additional non-const accessors for mutating
+ FlatBuffers in-place.
+
+- `--gen-onefile` : Generate single output file for C# and Go.
+
+- `--gen-name-strings` : Generate type name functions for C++.
+
+- `--gen-object-api` : Generate an additional object-based API. This API is
+ more convenient for object construction and mutation than the base API,
+ at the cost of efficiency (object allocation). Recommended only to be used
+ if other options are insufficient.
+
+- `--gen-compare` : Generate operator== for object-based API types.
+
+- `--gen-nullable` : Add Clang _Nullable for C++ pointer. or @Nullable for Java.
+
+- `--gen-generated` : Add @Generated annotation for Java.
+
+- `--gen-all` : Generate not just code for the current schema files, but
+ for all files it includes as well. If the language uses a single file for
+ output (by default the case for C++ and JS), all code will end up in
+ this one file.
+
+- `--cpp-include` : Adds an #include in generated file
+
+- `--cpp-ptr-type T` : Set object API pointer type (default std::unique_ptr)
+
+- `--cpp-str-type T` : Set object API string type (default std::string)
+ T::c_str(), T::length() and T::empty() must be supported.
+ The custom type also needs to be constructible from std::string (see the
+ --cpp-str-flex-ctor option to change this behavior).
+
+- `--cpp-str-flex-ctor` : Don't construct custom string types by passing
+ std::string from Flatbuffers, but (char* + length). This allows efficient
+ construction of custom string types, including zero-copy construction.
+
+- `--object-prefix` : Customise class prefix for C++ object-based API.
+
+- `--object-suffix` : Customise class suffix for C++ object-based API.
+
+- `--no-js-exports` : Removes Node.js style export lines (useful for JS)
+
+- `--goog-js-export` : Uses goog.exportsSymbol and goog.exportsProperty
+ instead of Node.js style exporting. Needed for compatibility with the
+ Google closure compiler (useful for JS).
+
+- `--es6-js-export` : Generates ECMAScript v6 style export definitions
+ instead of Node.js style exporting. Useful when integrating flatbuffers
+ with modern Javascript projects.
+
+- `--go-namespace` : Generate the overrided namespace in Golang.
+
+- `--go-import` : Generate the overrided import for flatbuffers in Golang.
+ (default is "github.com/google/flatbuffers/go").
+
+- `--raw-binary` : Allow binaries without a file_indentifier to be read.
+ This may crash flatc given a mismatched schema.
+
+- `--size-prefixed` : Input binaries are size prefixed buffers.
+
+- `--proto`: Expect input files to be .proto files (protocol buffers).
+ Output the corresponding .fbs file.
+ Currently supports: `package`, `message`, `enum`, nested declarations,
+ `import` (use `-I` for paths), `extend`, `oneof`, `group`.
+ Does not support, but will skip without error: `option`, `service`,
+ `extensions`, and most everything else.
+
+- `--oneof-union` : Translate .proto oneofs to flatbuffer unions.
+
+- `--grpc` : Generate GRPC interfaces for the specified languages.
+
+- `--schema`: Serialize schemas instead of JSON (use with -b). This will
+ output a binary version of the specified schema that itself corresponds
+ to the reflection/reflection.fbs schema. Loading this binary file is the
+ basis for reflection functionality.
+
+- `--bfbs-comments`: Add doc comments to the binary schema files.
+
+- `--conform FILE` : Specify a schema the following schemas should be
+ an evolution of. Gives errors if not. Useful to check if schema
+ modifications don't break schema evolution rules.
+
+- `--conform-includes PATH` : Include path for the schema given with
+ `--conform PATH`.
+
+- `--include-prefix PATH` : Prefix this path to any generated include
+ statements.
+
+- `--keep-prefix` : Keep original prefix of schema include statement.
+
+- `--no-fb-impor` : Don't include flatbuffers import statement for TypeScript.
+
+- `--no-ts-reexpor` : Don't re-export imported dependencies for TypeScript.
+
+- `--short-name` : Use short function names for JS and TypeScript.
+
+- `--reflect-types` : Add minimal type reflection to code generation.
+
+- `--reflect-names` : Add minimal type/name reflection.
+
+- `--root-type T` : Select or override the default root_type.
+
+- `--force-defaults` : Emit default values in binary output from JSON.
+
+- `--force-empty` : When serializing from object API representation, force
+ strings and vectors to empty rather than null.
+
+NOTE: short-form options for generators are deprecated, use the long form
+whenever possible.
diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md
new file mode 100644
index 0000000..7867f4b
--- /dev/null
+++ b/docs/source/CppUsage.md
@@ -0,0 +1,608 @@
+Use in C++ {#flatbuffers_guide_use_cpp}
+==========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in C++, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
+to general FlatBuffers usage in all of the supported languages (including C++).
+This page is designed to cover the nuances of FlatBuffers usage, specific to
+C++.
+
+#### Prerequisites
+
+This page assumes you have written a FlatBuffers schema and compiled it
+with the Schema Compiler. If you have not, please see
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
+and [Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
+matter), you've generated a C++ header called `mygame_generated.h` using the
+compiler (e.g. `flatc -c mygame.fbs`), you can now start using this in
+your program by including the header. As noted, this header relies on
+`flatbuffers/flatbuffers.h`, which should be in your include path.
+
+## FlatBuffers C++ library code location
+
+The code for the FlatBuffers C++ library can be found at
+`flatbuffers/include/flatbuffers`. You can browse the library code on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/include/flatbuffers).
+
+## Testing the FlatBuffers C++ library
+
+The code to test the C++ library can be found at `flatbuffers/tests`.
+The test code itself is located in
+[test.cpp](https://github.com/google/flatbuffers/blob/master/tests/test.cpp).
+
+This test file is built alongside `flatc`. To review how to build the project,
+please read the [Building](@ref flatbuffers_guide_building) documentation.
+
+To run the tests, execute `flattests` from the root `flatbuffers/` directory.
+For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
+run: `./flattests`.
+
+## Using the FlatBuffers C++ library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in C++.*
+
+FlatBuffers supports both reading and writing FlatBuffers in C++.
+
+To use FlatBuffers in your code, first generate the C++ classes from your
+schema with the `--cpp` option to `flatc`. Then you can include both FlatBuffers
+and the generated code to read or write FlatBuffers.
+
+For example, here is how you would read a FlatBuffer binary file in C++:
+First, include the library and generated code. Then read the file into
+a `char *` array, which you pass to `GetMonster()`.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ #include "flatbuffers/flatbuffers.h"
+ #include "monster_test_generate.h"
+ #include <iostream> // C++ header file for printing
+ #include <fstream> // C++ header file for file access
+
+
+ std::ifstream infile;
+ infile.open("monsterdata_test.mon", std::ios::binary | std::ios::in);
+ infile.seekg(0,std::ios::end);
+ int length = infile.tellg();
+ infile.seekg(0,std::ios::beg);
+ char *data = new char[length];
+ infile.read(data, length);
+ infile.close();
+
+ auto monster = GetMonster(data);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`monster` is of type `Monster *`, and points to somewhere *inside* your
+buffer (root object pointers are not the same as `buffer_pointer` !).
+If you look in your generated header, you'll see it has
+convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ std::cout << "hp : " << monster->hp() << std::endl; // `80`
+ std::cout << "mana : " << monster->mana() << std::endl; // default value of `150`
+ std::cout << "name : " << monster->name()->c_str() << std::endl; // "MyMonster"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*Note: That we never stored a `mana` value, so it will return the default.*
+
+The following attributes are supported:
+
+- `shared` (on a field): For string fields, this enables the usage of string
+ pooling (i.e. `CreateSharedString`) as default serialization behavior.
+
+ Specifically, `CreateXxxDirect` functions and `Pack` functions for object
+ based API (see below) will use `CreateSharedString` to create strings.
+
+## Object based API. {#flatbuffers_cpp_object_based_api}
+
+FlatBuffers is all about memory efficiency, which is why its base API is written
+around using as little as possible of it. This does make the API clumsier
+(requiring pre-order construction of all data, and making mutation harder).
+
+For times when efficiency is less important a more convenient object based API
+can be used (through `--gen-object-api`) that is able to unpack & pack a
+FlatBuffer into objects and standard STL containers, allowing for convenient
+construction, access and mutation.
+
+To use:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ // Autogenerated class from table Monster.
+ MonsterT monsterobj;
+
+ // Deserialize from buffer into object.
+ UnPackTo(&monsterobj, flatbuffer);
+
+ // Update object directly like a C++ class instance.
+ cout << monsterobj->name; // This is now a std::string!
+ monsterobj->name = "Bob"; // Change the name.
+
+ // Serialize into new flatbuffer.
+ FlatBufferBuilder fbb;
+ Pack(fbb, &monsterobj);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following attributes are specific to the object-based API code generation:
+
+- `native_inline` (on a field): Because FlatBuffer tables and structs are
+ optionally present in a given buffer, they are best represented as pointers
+ (specifically std::unique_ptrs) in the native class since they can be null.
+ This attribute changes the member declaration to use the type directly
+ rather than wrapped in a unique_ptr.
+
+- `native_default`: "value" (on a field): For members that are declared
+ "native_inline", the value specified with this attribute will be included
+ verbatim in the class constructor initializer list for this member.
+
+- `native_custom_alloc`:"custom_allocator" (on a table or struct): When using the
+ object-based API all generated NativeTables that are allocated when unpacking
+ your flatbuffer will use "custom allocator". The allocator is also used by
+ any std::vector that appears in a table defined with `native_custom_alloc`.
+ This can be used to provide allocation from a pool for example, for faster
+ unpacking when using the object-based API.
+
+ Minimal Example:
+
+ schema:
+
+ table mytable(native_custom_alloc:"custom_allocator") {
+ ...
+ }
+
+ with custom_allocator defined before flatbuffers.h is included, as:
+
+ template <typename T> struct custom_allocator : public std::allocator<T> {
+
+ typedef T *pointer;
+
+ template <class U>
+ struct rebind {
+ typedef custom_allocator<U> other;
+ };
+
+ pointer allocate(const std::size_t n) {
+ return std::allocator<T>::allocate(n);
+ }
+
+ void deallocate(T* ptr, std::size_t n) {
+ return std::allocator<T>::deallocate(ptr,n);
+ }
+
+ custom_allocator() throw() {}
+ template <class U>
+ custom_allocator(const custom_allocator<U>&) throw() {}
+ };
+
+- `native_type`' "type" (on a struct): In some cases, a more optimal C++ data
+ type exists for a given struct. For example, the following schema:
+
+ struct Vec2 {
+ x: float;
+ y: float;
+ }
+
+ generates the following Object-Based API class:
+
+ struct Vec2T : flatbuffers::NativeTable {
+ float x;
+ float y;
+ };
+
+ However, it can be useful to instead use a user-defined C++ type since it
+ can provide more functionality, eg.
+
+ struct vector2 {
+ float x = 0, y = 0;
+ vector2 operator+(vector2 rhs) const { ... }
+ vector2 operator-(vector2 rhs) const { ... }
+ float length() const { ... }
+ // etc.
+ };
+
+ The `native_type` attribute will replace the usage of the generated class
+ with the given type. So, continuing with the example, the generated
+ code would use |vector2| in place of |Vec2T| for all generated code.
+
+ However, becuase the native_type is unknown to flatbuffers, the user must
+ provide the following functions to aide in the serialization process:
+
+ namespace flatbuffers {
+ FlatbufferStruct Pack(const native_type& obj);
+ native_type UnPack(const FlatbufferStruct& obj);
+ }
+
+Finally, the following top-level attribute
+
+- `native_include`: "path" (at file level): Because the `native_type` attribute
+ can be used to introduce types that are unknown to flatbuffers, it may be
+ necessary to include "external" header files in the generated code. This
+ attribute can be used to directly add an #include directive to the top of
+ the generated code that includes the specified path directly.
+
+- `force_align`: this attribute may not be respected in the object API,
+ depending on the aligned of the allocator used with `new`.
+
+# External references.
+
+An additional feature of the object API is the ability to allow you to load
+multiple independent FlatBuffers, and have them refer to eachothers objects
+using hashes which are then represented as typed pointers in the object API.
+
+To make this work have a field in the objects you want to referred to which is
+using the string hashing feature (see `hash` attribute in the
+[schema](@ref flatbuffers_guide_writing_schema) documentation). Then you have
+a similar hash in the field referring to it, along with a `cpp_type`
+attribute specifying the C++ type this will refer to (this can be any C++
+type, and will get a `*` added).
+
+Then, in JSON or however you create these buffers, make sure they use the
+same string (or hash).
+
+When you call `UnPack` (or `Create`), you'll need a function that maps from
+hash to the object (see `resolver_function_t` for details).
+
+# Using different pointer types.
+
+By default the object tree is built out of `std::unique_ptr`, but you can
+influence this either globally (using the `--cpp-ptr-type` argument to
+`flatc`) or per field (using the `cpp_ptr_type` attribute) to by any smart
+pointer type (`my_ptr<T>`), or by specifying `naked` as the type to get `T *`
+pointers. Unlike the smart pointers, naked pointers do not manage memory for
+you, so you'll have to manage their lifecycles manually. To reference the
+pointer type specified by the `--cpp-ptr-type` argument to `flatc` from a
+flatbuffer field set the `cpp_ptr_type` attribute to `default_ptr_type`.
+
+# Using different string type.
+
+By default the object tree is built out of `std::string`, but you can
+influence this either globally (using the `--cpp-str-type` argument to
+`flatc`) or per field using the `cpp_str_type` attribute.
+
+The type must support T::c_str(), T::length() and T::empty() as member functions.
+
+Further, the type must be constructible from std::string, as by default a
+std::string instance is constructed and then used to initialize the custom
+string type. This behavior impedes efficient and zero-copy construction of
+custom string types; the `--cpp-str-flex-ctor` argument to `flatc` or the
+per field attribute `cpp_str_flex_ctor` can be used to change this behavior,
+so that the custom string type is constructed by passing the pointer and
+length of the FlatBuffers String. The custom string class will require a
+constructor in the following format: custom_str_class(const char *, size_t).
+Please note that the character array is not guaranteed to be NULL terminated,
+you should always use the provided size to determine end of string.
+
+## Reflection (& Resizing)
+
+There is experimental support for reflection in FlatBuffers, allowing you to
+read and write data even if you don't know the exact format of a buffer, and
+even allows you to change sizes of strings and vectors in-place.
+
+The way this works is very elegant; there is actually a FlatBuffer schema that
+describes schemas (!) which you can find in `reflection/reflection.fbs`.
+The compiler, `flatc`, can write out any schemas it has just parsed as a binary
+FlatBuffer, corresponding to this meta-schema.
+
+Loading in one of these binary schemas at runtime allows you traverse any
+FlatBuffer data that corresponds to it without knowing the exact format. You
+can query what fields are present, and then read/write them after.
+
+For convenient field manipulation, you can include the header
+`flatbuffers/reflection.h` which includes both the generated code from the meta
+schema, as well as a lot of helper functions.
+
+And example of usage, for the time being, can be found in
+`test.cpp/ReflectionTest()`.
+
+## Mini Reflection
+
+A more limited form of reflection is available for direct inclusion in
+generated code, which doesn't any (binary) schema access at all. It was designed
+to keep the overhead of reflection as low as possible (on the order of 2-6
+bytes per field added to your executable), but doesn't contain all the
+information the (binary) schema contains.
+
+You add this information to your generated code by specifying `--reflect-types`
+(or instead `--reflect-names` if you also want field / enum names).
+
+You can now use this information, for example to print a FlatBuffer to text:
+
+ auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
+
+`MonsterTypeTable()` is declared in the generated code for each type. The
+string produced is very similar to the JSON produced by the `Parser` based
+text generator.
+
+You'll need `flatbuffers/minireflect.h` for this functionality. In there is also
+a convenient visitor/iterator so you can write your own output / functionality
+based on the mini reflection tables without having to know the FlatBuffers or
+reflection encoding.
+
+## Storing maps / dictionaries in a FlatBuffer
+
+FlatBuffers doesn't support maps natively, but there is support to
+emulate their behavior with vectors and binary search, which means you
+can have fast lookups directly from a FlatBuffer without having to unpack
+your data into a `std::map` or similar.
+
+To use it:
+- Designate one of the fields in a table as they "key" field. You do this
+ by setting the `key` attribute on this field, e.g.
+ `name:string (key)`.
+ You may only have one key field, and it must be of string or scalar type.
+- Write out tables of this type as usual, collect their offsets in an
+ array or vector.
+- Instead of `CreateVector`, call `CreateVectorOfSortedTables`,
+ which will first sort all offsets such that the tables they refer to
+ are sorted by the key field, then serialize it.
+- Now when you're accessing the FlatBuffer, you can use `Vector::LookupByKey`
+ instead of just `Vector::Get` to access elements of the vector, e.g.:
+ `myvector->LookupByKey("Fred")`, which returns a pointer to the
+ corresponding table type, or `nullptr` if not found.
+ `LookupByKey` performs a binary search, so should have a similar speed to
+ `std::map`, though may be faster because of better caching. `LookupByKey`
+ only works if the vector has been sorted, it will likely not find elements
+ if it hasn't been sorted.
+
+## Direct memory access
+
+As you can see from the above examples, all elements in a buffer are
+accessed through generated accessors. This is because everything is
+stored in little endian format on all platforms (the accessor
+performs a swap operation on big endian machines), and also because
+the layout of things is generally not known to the user.
+
+For structs, layout is deterministic and guaranteed to be the same
+across platforms (scalars are aligned to their
+own size, and structs themselves to their largest member), and you
+are allowed to access this memory directly by using `sizeof()` and
+`memcpy` on the pointer to a struct, or even an array of structs.
+
+To compute offsets to sub-elements of a struct, make sure they
+are a structs themselves, as then you can use the pointers to
+figure out the offset without having to hardcode it. This is
+handy for use of arrays of structs with calls like `glVertexAttribPointer`
+in OpenGL or similar APIs.
+
+It is important to note is that structs are still little endian on all
+machines, so only use tricks like this if you can guarantee you're not
+shipping on a big endian machine (an `assert(FLATBUFFERS_LITTLEENDIAN)`
+would be wise).
+
+## Access of untrusted buffers
+
+The generated accessor functions access fields over offsets, which is
+very quick. These offsets are not verified at run-time, so a malformed
+buffer could cause a program to crash by accessing random memory.
+
+When you're processing large amounts of data from a source you know (e.g.
+your own generated data on disk), this is acceptable, but when reading
+data from the network that can potentially have been modified by an
+attacker, this is undesirable.
+
+For this reason, you can optionally use a buffer verifier before you
+access the data. This verifier will check all offsets, all sizes of
+fields, and null termination of strings to ensure that when a buffer
+is accessed, all reads will end up inside the buffer.
+
+Each root type will have a verification function generated for it,
+e.g. for `Monster`, you can call:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ bool ok = VerifyMonsterBuffer(Verifier(buf, len));
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+if `ok` is true, the buffer is safe to read.
+
+Besides untrusted data, this function may be useful to call in debug
+mode, as extra insurance against data being corrupted somewhere along
+the way.
+
+While verifying a buffer isn't "free", it is typically faster than
+a full traversal (since any scalar data is not actually touched),
+and since it may cause the buffer to be brought into cache before
+reading, the actual overhead may be even lower than expected.
+
+In specialized cases where a denial of service attack is possible,
+the verifier has two additional constructor arguments that allow
+you to limit the nesting depth and total amount of tables the
+verifier may encounter before declaring the buffer malformed. The default is
+`Verifier(buf, len, 64 /* max depth */, 1000000, /* max tables */)` which
+should be sufficient for most uses.
+
+## Text & schema parsing
+
+Using binary buffers with the generated header provides a super low
+overhead use of FlatBuffer data. There are, however, times when you want
+to use text formats, for example because it interacts better with source
+control, or you want to give your users easy access to data.
+
+Another reason might be that you already have a lot of data in JSON
+format, or a tool that generates JSON, and if you can write a schema for
+it, this will provide you an easy way to use that data directly.
+
+(see the schema documentation for some specifics on the JSON format
+accepted).
+
+There are two ways to use text formats:
+
+#### Using the compiler as a conversion tool
+
+This is the preferred path, as it doesn't require you to add any new
+code to your program, and is maximally efficient since you can ship with
+binary data. The disadvantage is that it is an extra step for your
+users/developers to perform, though you might be able to automate it.
+
+ flatc -b myschema.fbs mydata.json
+
+This will generate the binary file `mydata_wire.bin` which can be loaded
+as before.
+
+#### Making your program capable of loading text directly
+
+This gives you maximum flexibility. You could even opt to support both,
+i.e. check for both files, and regenerate the binary from text when
+required, otherwise just load the binary.
+
+This option is currently only available for C++, or Java through JNI.
+
+As mentioned in the section "Building" above, this technique requires
+you to link a few more files into your program, and you'll want to include
+`flatbuffers/idl.h`.
+
+Load text (either a schema or json) into an in-memory buffer (there is a
+convenient `LoadFile()` utility function in `flatbuffers/util.h` if you
+wish). Construct a parser:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ flatbuffers::Parser parser;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can parse any number of text files in sequence:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+ parser.Parse(text_file.c_str());
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This works similarly to how the command-line compiler works: a sequence
+of files parsed by the same `Parser` object allow later files to
+reference definitions in earlier files. Typically this means you first
+load a schema file (which populates `Parser` with definitions), followed
+by one or more JSON files.
+
+As optional argument to `Parse`, you may specify a null-terminated list of
+include paths. If not specified, any include statements try to resolve from
+the current directory.
+
+If there were any parsing errors, `Parse` will return `false`, and
+`Parser::err` contains a human readable error string with a line number
+etc, which you should present to the creator of that file.
+
+After each JSON file, the `Parser::fbb` member variable is the
+`FlatBufferBuilder` that contains the binary buffer version of that
+file, that you can access as described above.
+
+`samples/sample_text.cpp` is a code sample showing the above operations.
+
+## Threading
+
+Reading a FlatBuffer does not touch any memory outside the original buffer,
+and is entirely read-only (all const), so is safe to access from multiple
+threads even without synchronisation primitives.
+
+Creating a FlatBuffer is not thread safe. All state related to building
+a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
+outside of it is touched. To make this thread safe, either do not
+share instances of FlatBufferBuilder between threads (recommended), or
+manually wrap it in synchronisation primites. There's no automatic way to
+accomplish this, by design, as we feel multithreaded construction
+of a single buffer will be rare, and synchronisation overhead would be costly.
+
+## Advanced union features
+
+The C++ implementation currently supports vectors of unions (i.e. you can
+declare a field as `[T]` where `T` is a union type instead of a table type). It
+also supports structs and strings in unions, besides tables.
+
+For an example of these features, see `tests/union_vector`, and
+`UnionVectorTest` in `test.cpp`.
+
+Since these features haven't been ported to other languages yet, if you
+choose to use them, you won't be able to use these buffers in other languages
+(`flatc` will refuse to compile a schema that uses these features).
+
+These features reduce the amount of "table wrapping" that was previously
+needed to use unions.
+
+To use scalars, simply wrap them in a struct.
+
+## Depth limit of nested objects and stack-overflow control
+The parser of Flatbuffers schema or json-files is kind of recursive parser.
+To avoid stack-overflow problem the parser has a built-in limiter of
+recursion depth. Number of nested declarations in a schema or number of
+nested json-objects is limited. By default, this depth limit set to `64`.
+It is possible to override this limit with `FLATBUFFERS_MAX_PARSING_DEPTH`
+definition. This definition can be helpful for testing purposes or embedded
+applications. For details see [build](@ref flatbuffers_guide_building) of
+CMake-based projects.
+
+## Dependence from C-locale {#flatbuffers_locale_cpp}
+The Flatbuffers [grammar](@ref flatbuffers grammar) uses ASCII
+character set for identifiers, alphanumeric literals, reserved words.
+
+Internal implementation of the Flatbuffers depends from functions which
+depend from C-locale: `strtod()` or `strtof()`, for example.
+The library expects the dot `.` symbol as the separator of an integer
+part from the fractional part of a float number.
+Another separator symbols (`,` for example) will break the compatibility
+and may lead to an error while parsing a Flatbuffers schema or a json file.
+
+The Standard C locale is a global resource, there is only one locale for
+the entire application. Some modern compilers and platforms have
+locale-independent or locale-narrow functions `strtof_l`, `strtod_l`,
+`strtoll_l`, `strtoull_l` to resolve this dependency.
+These functions use specified locale rather than the global or per-thread
+locale instead. They are part of POSIX-2008 but not part of the C/C++
+standard library, therefore, may be missing on some platforms.
+The Flatbuffers library try to detect these functions at configuration and
+compile time:
+- CMake `"CMakeLists.txt"`:
+ - Check existence of `strtol_l` and `strtod_l` in the `<stdlib.h>`.
+- Compile-time `"/include/base.h"`:
+ - `_MSC_VER >= 1900`: MSVC2012 or higher if build with MSVC.
+ - `_XOPEN_SOURCE>=700`: POSIX-2008 if build with GCC/Clang.
+
+After detection, the definition `FLATBUFFERS_LOCALE_INDEPENDENT` will be
+set to `0` or `1`.
+To override or stop this detection use CMake `-DFLATBUFFERS_LOCALE_INDEPENDENT={0|1}`
+or predefine `FLATBUFFERS_LOCALE_INDEPENDENT` symbol.
+
+To test the compatibility of the Flatbuffers library with
+a specific locale use the environment variable `FLATBUFFERS_TEST_LOCALE`:
+```sh
+>FLATBUFFERS_TEST_LOCALE="" ./flattests
+>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./flattests
+```
+
+## Support of floating-point numbers
+The Flatbuffers library assumes that a C++ compiler and a CPU are
+compatible with the `IEEE-754` floating-point standard.
+The schema and json parser may fail if `fast-math` or `/fp:fast` mode is active.
+
+### Support of hexadecimal and special floating-point numbers
+According to the [grammar](@ref flatbuffers_grammar) `fbs` and `json` files
+may use hexadecimal and special (`NaN`, `Inf`) floating-point literals.
+The Flatbuffers uses `strtof` and `strtod` functions to parse floating-point
+literals. The Flatbuffers library has a code to detect a compiler compatibility
+with the literals. If necessary conditions are met the preprocessor constant
+`FLATBUFFERS_HAS_NEW_STRTOD` will be set to `1`.
+The support of floating-point literals will be limited at compile time
+if `FLATBUFFERS_HAS_NEW_STRTOD` constant is less than `1`.
+In this case, schemas with hexadecimal or special literals cannot be used.
+
+### Comparison of floating-point NaN values
+The floating-point `NaN` (`not a number`) is special value which
+representing an undefined or unrepresentable value.
+`NaN` may be explicitly assigned to variables, typically as a representation
+for missing values or may be a result of a mathematical operation.
+The `IEEE-754` defines two kind of `NaNs`:
+- Quiet NaNs, or `qNaNs`.
+- Signaling NaNs, or `sNaNs`.
+
+According to the `IEEE-754`, a comparison with `NaN` always returns
+an unordered result even when compared with itself. As a result, a whole
+Flatbuffers object will be not equal to itself if has one or more `NaN`.
+Flatbuffers scalar fields that have the default value are not actually stored
+in the serialized data but are generated in code (see [Writing a schema](@ref flatbuffers_guide_writing_schema)).
+Scalar fields with `NaN` defaults break this behavior.
+If a schema has a lot of `NaN` defaults the Flatbuffers can override
+the unordered comparison by the ordered: `(NaN==NaN)->true`.
+This ordered comparison is enabled when compiling a program with the symbol
+`FLATBUFFERS_NAN_DEFAULTS` defined.
+Additional computations added by `FLATBUFFERS_NAN_DEFAULTS` are very cheap
+if GCC or Clang used. These compilers have a compile-time implementation
+of `isnan` checking which MSVC does not.
+
+<br>
diff --git a/docs/source/DartUsage.md b/docs/source/DartUsage.md
new file mode 100644
index 0000000..6670cc5
--- /dev/null
+++ b/docs/source/DartUsage.md
@@ -0,0 +1,108 @@
+Use in Dart {#flatbuffers_guide_use_dart}
+===========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Dart, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
+to general FlatBuffers usage in all of the supported languages (including Dart).
+This page is designed to cover the nuances of FlatBuffers usage, specific to
+Dart.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Dart library code location
+
+The code for the FlatBuffers Dart library can be found at
+`flatbuffers/dart`. You can browse the library code on the [FlatBuffers
+GitHub page](https://github.com/google/flatbuffers/tree/master/dart).
+
+## Testing the FlatBuffers Dart library
+
+The code to test the Dart library can be found at `flatbuffers/tests`.
+The test code itself is located in [dart_test.dart](https://github.com/google/
+flatbuffers/blob/master/tests/dart_test.dart).
+
+To run the tests, use the [DartTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/DartTest.sh) shell script.
+
+*Note: The shell script requires the [Dart SDK](https://www.dartlang.org/tools/sdk)
+to be installed.*
+
+## Using the FlatBuffers Dart library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Dart.*
+
+FlatBuffers supports reading and writing binary FlatBuffers in Dart.
+
+To use FlatBuffers in your own code, first generate Dart classes from your
+schema with the `--dart` option to `flatc`. Then you can include both FlatBuffers
+and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Dart: First,
+include the library and generated code. Then read a FlatBuffer binary file into
+a `List<int>`, which you pass to the factory constructor for `Monster`:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
+import 'dart:io' as io;
+
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+import './monster_my_game.sample_generated.dart' as myGame;
+
+List<int> data = await new io.File('monster.dat').readAsBytes();
+var monster = new myGame.Monster(data);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.dart}
+var hp = monster.hp;
+var pos = monster.pos;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+## Differences from the Dart SDK Front End flat_buffers
+
+The work in this repository is signfiicantly based on the implementation used
+internally by the Dart SDK in the front end/analyzer package. Several
+significant changes have been made.
+
+1. Support for packed boolean lists has been removed. This is not standard
+ in other implementations and is not compatible with them. Do note that,
+ like in the JavaScript implementation, __null values in boolean lists
+ will be treated as false__. It is also still entirely possible to pack data
+ in a single scalar field, but that would have to be done on the application
+ side.
+2. The SDK implementation supports enums with regular Dart enums, which
+ works if enums are always indexed at 1; however, FlatBuffers does not
+ require that. This implementation uses specialized enum-like classes to
+ ensure proper mapping from FlatBuffers to Dart and other platforms.
+3. The SDK implementation does not appear to support FlatBuffer structs or
+ vectors of structs - it treated everything as a built-in scalar or a table.
+ This implementation treats structs in a way that is compatible with other
+ non-Dart implementations, and properly handles vectors of structs. Many of
+ the methods prefixed with 'low' have been prepurposed to support this.
+4. The SDK implementation treats int64 and uint64 as float64s. This
+ implementation does not. This may cause problems with JavaScript
+ compatibility - however, it should be possible to use the JavaScript
+ implementation, or to do a customized implementation that treats all 64 bit
+ numbers as floats. Supporting the Dart VM and Flutter was a more important
+ goal of this implementation. Support for 16 bit integers was also added.
+5. The code generation in this offers an "ObjectBuilder", which generates code
+ very similar to the SDK classes that consume FlatBuffers, as well as Builder
+ classes, which produces code which more closely resembles the builders in
+ other languages. The ObjectBuilder classes are easier to use, at the cost of
+ additional references allocated.
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Dart, though you could use the C++ parser through Dart Native Extensions.
+Please see the C++ documentation for more on text parsing (note that this is
+not currently an option in Flutter - follow [this issue](https://github.com/flutter/flutter/issues/7053)
+for the latest).
+
+<br>
diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md
new file mode 100644
index 0000000..dc77500
--- /dev/null
+++ b/docs/source/FlatBuffers.md
@@ -0,0 +1,180 @@
+FlatBuffers {#flatbuffers_index}
+===========
+
+# Overview {#flatbuffers_overview}
+
+[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
+serialization library for C++, C#, C, Go, Java, Kotlin, JavaScript, Lobster, Lua, TypeScript, PHP, Python, and Rust.
+It was originally created at Google for game development and other
+performance-critical applications.
+
+It is available as Open Source on [GitHub](http://github.com/google/flatbuffers)
+under the Apache license, v2 (see LICENSE.txt).
+
+## Why use FlatBuffers?
+
+- **Access to serialized data without parsing/unpacking** - What sets
+ FlatBuffers apart is that it represents hierarchical data in a flat
+ binary buffer in such a way that it can still be accessed directly
+ without parsing/unpacking, while also still supporting data
+ structure evolution (forwards/backwards compatibility).
+
+- **Memory efficiency and speed** - The only memory needed to access
+ your data is that of the buffer. It requires 0 additional allocations
+ (in C++, other languages may vary). FlatBuffers is also very
+ suitable for use with mmap (or streaming), requiring only part of the
+ buffer to be in memory. Access is close to the speed of raw
+ struct access with only one extra indirection (a kind of vtable) to
+ allow for format evolution and optional fields. It is aimed at
+ projects where spending time and space (many memory allocations) to
+ be able to access or construct serialized data is undesirable, such
+ as in games or any other performance sensitive applications. See the
+ [benchmarks](@ref flatbuffers_benchmarks) for details.
+
+- **Flexible** - Optional fields means not only do you get great
+ forwards and backwards compatibility (increasingly important for
+ long-lived games: don't have to update all data with each new
+ version!). It also means you have a lot of choice in what data you
+ write and what data you don't, and how you design data structures.
+
+- **Tiny code footprint** - Small amounts of generated code, and just
+ a single small header as the minimum dependency, which is very easy
+ to integrate. Again, see the benchmark section for details.
+
+- **Strongly typed** - Errors happen at compile time rather than
+ manually having to write repetitive and error prone run-time checks.
+ Useful code can be generated for you.
+
+- **Convenient to use** - Generated C++ code allows for terse access
+ & construction code. Then there's optional functionality for parsing
+ schemas and JSON-like text representations at runtime efficiently if
+ needed (faster and more memory efficient than other JSON
+ parsers).
+
+ Java, Kotlin and Go code supports object-reuse. C# has efficient struct based
+ accessors.
+
+- **Cross platform code with no dependencies** - C++ code will work
+ with any recent gcc/clang and VS2010. Comes with build files for the tests &
+ samples (Android .mk files, and cmake for all other platforms).
+
+### Why not use Protocol Buffers, or .. ?
+
+Protocol Buffers is indeed relatively similar to FlatBuffers,
+with the primary difference being that FlatBuffers does not need a parsing/
+unpacking step to a secondary representation before you can
+access data, often coupled with per-object memory allocation. The code
+is an order of magnitude bigger, too. Protocol Buffers has neither optional
+text import/export nor schema language features like unions.
+
+### But all the cool kids use JSON!
+
+JSON is very readable (which is why we use it as our optional text
+format) and very convenient when used together with dynamically typed
+languages (such as JavaScript). When serializing data from statically
+typed languages, however, JSON not only has the obvious drawback of runtime
+inefficiency, but also forces you to write *more* code to access data
+(counterintuitively) due to its dynamic-typing serialization system.
+In this context, it is only a better choice for systems that have very
+little to no information ahead of time about what data needs to be stored.
+
+If you do need to store data that doesn't fit a schema, FlatBuffers also
+offers a schema-less (self-describing) version!
+
+Read more about the "why" of FlatBuffers in the
+[white paper](@ref flatbuffers_white_paper).
+
+### Who uses FlatBuffers?
+- [Cocos2d-x](http://www.cocos2d-x.org/), the #1 open source mobile game
+ engine, uses it to serialize all their
+ [game data](http://www.cocos2d-x.org/reference/native-cpp/V3.5/d7/d2d/namespaceflatbuffers.html).
+- [Facebook](http://facebook.com/) uses it for client-server communication in
+ their Android app. They have a nice
+ [article](https://code.facebook.com/posts/872547912839369/improving-facebook-s-performance-on-android-with-flatbuffers/)
+ explaining how it speeds up loading their posts.
+- [Fun Propulsion Labs](https://developers.google.com/games/#Tools)
+ at Google uses it extensively in all their libraries and games.
+
+## Usage in brief
+
+This section is a quick rundown of how to use this system. Subsequent
+sections provide a more in-depth usage guide.
+
+- Write a schema file that allows you to define the data structures
+ you may want to serialize. Fields can have a scalar type
+ (ints/floats of all sizes), or they can be a: string; array of any type;
+ reference to yet another object; or, a set of possible objects (unions).
+ Fields are optional and have defaults, so they don't need to be
+ present for every object instance.
+
+- Use `flatc` (the FlatBuffer compiler) to generate a C++ header (or
+ Java/Kotlin/C#/Go/Python.. classes) with helper classes to access and construct
+ serialized data. This header (say `mydata_generated.h`) only depends on
+ `flatbuffers.h`, which defines the core functionality.
+
+- Use the `FlatBufferBuilder` class to construct a flat binary buffer.
+ The generated functions allow you to add objects to this
+ buffer recursively, often as simply as making a single function call.
+
+- Store or send your buffer somewhere!
+
+- When reading it back, you can obtain the pointer to the root object
+ from the binary buffer, and from there traverse it conveniently
+ in-place with `object->field()`.
+
+## In-depth documentation
+
+- How to [build the compiler](@ref flatbuffers_guide_building) and samples on
+ various platforms.
+- How to [use the compiler](@ref flatbuffers_guide_using_schema_compiler).
+- How to [write a schema](@ref flatbuffers_guide_writing_schema).
+- How to [use the generated C++ code](@ref flatbuffers_guide_use_cpp) in your
+ own programs.
+- How to [use the generated Java/C# code](@ref flatbuffers_guide_use_java_c-sharp)
+ in your own programs.
+- How to [use the generated Kotlin code](@ref flatbuffers_guide_use_kotlin)
+ in your own programs.
+- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
+ own programs.
+- How to [use the generated Lua code](@ref flatbuffers_guide_use_lua) in your
+ own programs.
+- How to [use the generated JavaScript code](@ref flatbuffers_guide_use_javascript) in your
+ own programs.
+- How to [use the generated TypeScript code](@ref flatbuffers_guide_use_typescript) in your
+ own programs.
+- How to [use FlatBuffers in C with `flatcc`](@ref flatbuffers_guide_use_c) in your
+ own programs.
+- How to [use the generated Lobster code](@ref flatbuffers_guide_use_lobster) in your
+ own programs.
+- How to [use the generated Rust code](@ref flatbuffers_guide_use_rust) in your
+ own programs.
+- [Support matrix](@ref flatbuffers_support) for platforms/languages/features.
+- Some [benchmarks](@ref flatbuffers_benchmarks) showing the advantage of
+ using FlatBuffers.
+- A [white paper](@ref flatbuffers_white_paper) explaining the "why" of
+ FlatBuffers.
+- How to use the [schema-less](@ref flexbuffers) version of
+ FlatBuffers.
+- A description of the [internals](@ref flatbuffers_internals) of FlatBuffers.
+- A formal [grammar](@ref flatbuffers_grammar) of the schema language.
+
+## Online resources
+
+- [GitHub repository](http://github.com/google/flatbuffers)
+- [Landing page](http://google.github.io/flatbuffers)
+- [FlatBuffers Google Group](https://groups.google.com/forum/#!forum/flatbuffers)
+- [FlatBuffers Issues Tracker](http://github.com/google/flatbuffers/issues)
+- Independent implementations & tools:
+ - [FlatCC](https://github.com/dvidelabs/flatcc) Alternative FlatBuffers
+ parser, code generator and runtime all in C.
+- Videos:
+ - Colt's [DevByte](https://www.youtube.com/watch?v=iQTxMkSJ1dQ).
+ - GDC 2015 [Lightning Talk](https://www.youtube.com/watch?v=olmL1fUnQAQ).
+ - FlatBuffers for [Go](https://www.youtube.com/watch?v=-BPVId_lA5w).
+ - Evolution of FlatBuffers
+ [visualization](https://www.youtube.com/watch?v=a0QE0xS8rKM).
+- Useful documentation created by others:
+ - [FlatBuffers in Go](https://rwinslow.com/tags/flatbuffers/)
+ - [FlatBuffers in Android](http://frogermcs.github.io/flatbuffers-in-android-introdution/)
+ - [Parsing JSON to FlatBuffers in Java](http://frogermcs.github.io/json-parsing-with-flatbuffers-in-android/)
+ - [FlatBuffers in Unity](http://exiin.com/blog/flatbuffers-for-unity-sample-code/)
diff --git a/docs/source/FlexBuffers.md b/docs/source/FlexBuffers.md
new file mode 100644
index 0000000..a089df3
--- /dev/null
+++ b/docs/source/FlexBuffers.md
@@ -0,0 +1,166 @@
+FlexBuffers {#flexbuffers}
+==========
+
+FlatBuffers was designed around schemas, because when you want maximum
+performance and data consistency, strong typing is helpful.
+
+There are however times when you want to store data that doesn't fit a
+schema, because you can't know ahead of time what all needs to be stored.
+
+For this, FlatBuffers has a dedicated format, called FlexBuffers.
+This is a binary format that can be used in conjunction
+with FlatBuffers (by storing a part of a buffer in FlexBuffers
+format), or also as its own independent serialization format.
+
+While it loses the strong typing, you retain the most unique advantage
+FlatBuffers has over other serialization formats (schema-based or not):
+FlexBuffers can also be accessed without parsing / copying / object allocation.
+This is a huge win in efficiency / memory friendly-ness, and allows unique
+use cases such as mmap-ing large amounts of free-form data.
+
+FlexBuffers' design and implementation allows for a very compact encoding,
+combining automatic pooling of strings with automatic sizing of containers to
+their smallest possible representation (8/16/32/64 bits). Many values and
+offsets can be encoded in just 8 bits. While a schema-less representation is
+usually more bulky because of the need to be self-descriptive, FlexBuffers
+generates smaller binaries for many cases than regular FlatBuffers.
+
+FlexBuffers is still slower than regular FlatBuffers though, so we recommend to
+only use it if you need it.
+
+
+# Usage
+
+This is for C++, other languages may follow.
+
+Include the header `flexbuffers.h`, which in turn depends on `flatbuffers.h`
+and `util.h`.
+
+To create a buffer:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+flexbuffers::Builder fbb;
+fbb.Int(13);
+fbb.Finish();
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You create any value, followed by `Finish`. Unlike FlatBuffers which requires
+the root value to be a table, here any value can be the root, including a lonely
+int value.
+
+You can now access the `std::vector<uint8_t>` that contains the encoded value
+as `fbb.GetBuffer()`. Write it, send it, or store it in a parent FlatBuffer. In
+this case, the buffer is just 3 bytes in size.
+
+To read this value back, you could just say:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+auto root = flexbuffers::GetRoot(my_buffer);
+int64_t i = root.AsInt64();
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+FlexBuffers stores ints only as big as needed, so it doesn't differentiate
+between different sizes of ints. You can ask for the 64 bit version,
+regardless of what you put in. In fact, since you demand to read the root
+as an int, if you supply a buffer that actually contains a float, or a
+string with numbers in it, it will convert it for you on the fly as well,
+or return 0 if it can't. If instead you actually want to know what is inside
+the buffer before you access it, you can call `root.GetType()` or `root.IsInt()`
+etc.
+
+Here's a slightly more complex value you could write instead of `fbb.Int` above:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+fbb.Map([&]() {
+ fbb.Vector("vec", [&]() {
+ fbb.Int(-100);
+ fbb.String("Fred");
+ fbb.IndirectFloat(4.0f);
+ });
+ fbb.UInt("foo", 100);
+});
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This stores the equivalent of the JSON value
+`{ vec: [ -100, "Fred", 4.0 ], foo: 100 }`. The root is a dictionary that has
+just two key-value pairs, with keys `vec` and `foo`. Unlike FlatBuffers, it
+actually has to store these keys in the buffer (which it does only once if
+you store multiple such objects, by pooling key values), but also unlike
+FlatBuffers it has no restriction on the keys (fields) that you use.
+
+The map constructor uses a C++11 Lambda to group its children, but you can
+also use more conventional start/end calls if you prefer.
+
+The first value in the map is a vector. You'll notice that unlike FlatBuffers,
+you can use mixed types. There is also a `TypedVector` variant that only
+allows a single type, and uses a bit less memory.
+
+`IndirectFloat` is an interesting feature that allows you to store values
+by offset rather than inline. Though that doesn't make any visible change
+to the user, the consequence is that large values (especially doubles or
+64 bit ints) that occur more than once can be shared. Another use case is
+inside of vectors, where the largest element makes up the size of all elements
+(e.g. a single double forces all elements to 64bit), so storing a lot of small
+integers together with a double is more efficient if the double is indirect.
+
+Accessing it:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
+auto map = flexbuffers::GetRoot(my_buffer).AsMap();
+map.size(); // 2
+auto vec = map["vec"].AsVector();
+vec.size(); // 3
+vec[0].AsInt64(); // -100;
+vec[1].AsString().c_str(); // "Fred";
+vec[1].AsInt64(); // 0 (Number parsing failed).
+vec[2].AsDouble(); // 4.0
+vec[2].AsString().IsTheEmptyString(); // true (Wrong Type).
+vec[2].AsString().c_str(); // "" (This still works though).
+vec[2].ToString().c_str(); // "4" (Or have it converted).
+map["foo"].AsUInt8(); // 100
+map["unknown"].IsNull(); // true
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+# Binary encoding
+
+A description of how FlexBuffers are encoded is in the
+[internals](@ref flatbuffers_internals) document.
+
+
+# Nesting inside a FlatBuffer
+
+You can mark a field as containing a FlexBuffer, e.g.
+
+ a:[ubyte] (flexbuffer);
+
+A special accessor will be generated that allows you to access the root value
+directly, e.g. `a_flexbuffer_root().AsInt64()`.
+
+
+# Efficiency tips
+
+* Vectors generally are a lot more efficient than maps, so prefer them over maps
+ when possible for small objects. Instead of a map with keys `x`, `y` and `z`,
+ use a vector. Better yet, use a typed vector. Or even better, use a fixed
+ size typed vector.
+* Maps are backwards compatible with vectors, and can be iterated as such.
+ You can iterate either just the values (`map.Values()`), or in parallel with
+ the keys vector (`map.Keys()`). If you intend
+ to access most or all elements, this is faster than looking up each element
+ by key, since that involves a binary search of the key vector.
+* When possible, don't mix values that require a big bit width (such as double)
+ in a large vector of smaller values, since all elements will take on this
+ width. Use `IndirectDouble` when this is a possibility. Note that
+ integers automatically use the smallest width possible, i.e. if you ask
+ to serialize an int64_t whose value is actually small, you will use less
+ bits. Doubles are represented as floats whenever possible losslessly, but
+ this is only possible for few values.
+ Since nested vectors/maps are stored over offsets, they typically don't
+ affect the vector width.
+* To store large arrays of byte data, use a blob. If you'd use a typed
+ vector, the bit width of the size field may make it use more space than
+ expected, and may not be compatible with `memcpy`.
+ Similarly, large arrays of (u)int16_t may be better off stored as a
+ binary blob if their size could exceed 64k elements.
+ Construction and use are otherwise similar to strings.
diff --git a/docs/source/GoApi.md b/docs/source/GoApi.md
new file mode 100644
index 0000000..98be2b6
--- /dev/null
+++ b/docs/source/GoApi.md
@@ -0,0 +1,26 @@
+Go API
+======
+
+\addtogroup flatbuffers_go_api
+
+<!-- Note: The `GoApi_generate.txt` code snippet was generated using `godoc` and
+ customized for use with this markdown file. To regenerate the file, use the
+ `godoc` tool (http://godoc.org) with the files in the `flatbuffers/go`
+ folder.
+
+ You may need to ensure that copies of the files exist in the `src/`
+ subfolder at the path set by the `$GOROOT` environment variable. You can
+ either move the files to `$GOROOT/src/flatbuffers` manually, if `$GOROOT`
+ is already set, otherwise you will need to manually set the `$GOROOT`
+ variable to a path and create `src/flatbuffers` subfolders at that path.
+ Then copy the flatbuffers files into `$GOROOT/src/flatbuffers`. (Some
+ versions of `godoc` include a `-path` flag. This could be used instead, if
+ available).
+
+ Once the files exist at the `$GOROOT/src/flatbuffers` location, you can
+ regenerate this doc using the following command:
+ `godoc flatbuffers > GoApi_generated.txt`.
+
+ After the documentation is generated, you will have to manually remove any
+ non-user facing documentation from this file. -->
+\snippet GoApi_generated.txt Go API
diff --git a/docs/source/GoApi_generated.txt b/docs/source/GoApi_generated.txt
new file mode 100644
index 0000000..3d4e0fc
--- /dev/null
+++ b/docs/source/GoApi_generated.txt
@@ -0,0 +1,125 @@
+// This file was generated using `godoc` and customized for use with the
+// API Reference documentation. To recreate this file, use the `godoc` tool
+// (http://godoc.org) with the files in the `flatbuffers/go` folder.
+//
+// Note: You may need to ensure that copies of the files exist in the
+// `src/` subfolder at the path set by the `$GOROOT` environment variable.
+// You can either move the files to `$GOROOT/src/flatbuffers` manually, if
+// `$GOROOT` is already set, otherwise you will need to manually set the
+// `$GOROOT` variable to a path and create `src/flatbuffers` subfolders at that
+// path. Then copy these files into `$GOROOT/src/flatbuffers`. (Some versions of
+// `godoc` include a `-path` flag. This could be used instead, if available).
+//
+// Once the files exist at the `$GOROOT/src/flatbuffers` location, you can
+// regenerate this doc using the following command:
+// `godoc flatbuffers > GoApi_generated.txt`.
+//
+// After the documentation is generated, you will have to manually remove any
+// non-user facing documentation from this file.
+
+/// [Go API]
+PACKAGE DOCUMENTATION
+
+package flatbuffers
+ Package flatbuffers provides facilities to read and write flatbuffers
+ objects.
+
+TYPES
+
+type Builder struct {
+ // `Bytes` gives raw access to the buffer. Most users will want to use
+ // FinishedBytes() instead.
+ Bytes []byte
+}
+ Builder is a state machine for creating FlatBuffer objects. Use a
+ Builder to construct object(s) starting from leaf nodes.
+
+ A Builder constructs byte buffers in a last-first manner for simplicity
+ and performance.
+
+FUNCTIONS
+
+func NewBuilder(initialSize int) *Builder
+ NewBuilder initializes a Builder of size `initial_size`. The internal
+ buffer is grown as needed.
+
+func (b *Builder) CreateByteString(s []byte) UOffsetT
+ CreateByteString writes a byte slice as a string (null-terminated).
+
+func (b *Builder) CreateByteVector(v []byte) UOffsetT
+ CreateByteVector writes a ubyte vector
+
+func (b *Builder) CreateString(s string) UOffsetT
+ CreateString writes a null-terminated string as a vector.
+
+func (b *Builder) EndVector(vectorNumElems int) UOffsetT
+ EndVector writes data necessary to finish vector construction.
+
+func (b *Builder) Finish(rootTable UOffsetT)
+ Finish finalizes a buffer, pointing to the given `rootTable`.
+
+func (b *Builder) FinishedBytes() []byte
+ FinishedBytes returns a pointer to the written data in the byte buffer.
+ Panics if the builder is not in a finished state (which is caused by
+ calling `Finish()`).
+
+func (b *Builder) Head() UOffsetT
+ Head gives the start of useful data in the underlying byte buffer. Note:
+ unlike other functions, this value is interpreted as from the left.
+
+func (b *Builder) PrependBool(x bool)
+ PrependBool prepends a bool to the Builder buffer. Aligns and checks for
+ space.
+
+func (b *Builder) PrependByte(x byte)
+ PrependByte prepends a byte to the Builder buffer. Aligns and checks for
+ space.
+
+func (b *Builder) PrependFloat32(x float32)
+ PrependFloat32 prepends a float32 to the Builder buffer. Aligns and
+ checks for space.
+
+func (b *Builder) PrependFloat64(x float64)
+ PrependFloat64 prepends a float64 to the Builder buffer. Aligns and
+ checks for space.
+
+func (b *Builder) PrependInt16(x int16)
+ PrependInt16 prepends a int16 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) PrependInt32(x int32)
+ PrependInt32 prepends a int32 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) PrependInt64(x int64)
+ PrependInt64 prepends a int64 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) PrependInt8(x int8)
+ PrependInt8 prepends a int8 to the Builder buffer. Aligns and checks for
+ space.
+
+func (b *Builder) PrependUOffsetT(off UOffsetT)
+ PrependUOffsetT prepends an UOffsetT, relative to where it will be
+ written.
+
+func (b *Builder) PrependUint16(x uint16)
+ PrependUint16 prepends a uint16 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) PrependUint32(x uint32)
+ PrependUint32 prepends a uint32 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) PrependUint64(x uint64)
+ PrependUint64 prepends a uint64 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) PrependUint8(x uint8)
+ PrependUint8 prepends a uint8 to the Builder buffer. Aligns and checks
+ for space.
+
+func (b *Builder) Reset()
+ Reset truncates the underlying Builder buffer, facilitating alloc-free
+ reuse of a Builder. It also resets bookkeeping data.
+/// [Go API]
diff --git a/docs/source/GoUsage.md b/docs/source/GoUsage.md
new file mode 100644
index 0000000..ab6ddbd
--- /dev/null
+++ b/docs/source/GoUsage.md
@@ -0,0 +1,99 @@
+Use in Go {#flatbuffers_guide_use_go}
+=========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Go, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
+to general FlatBuffers usage in all of the supported languages (including Go).
+This page is designed to cover the nuances of FlatBuffers usage, specific to
+Go.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Go library code location
+
+The code for the FlatBuffers Go library can be found at
+`flatbuffers/go`. You can browse the library code on the [FlatBuffers
+GitHub page](https://github.com/google/flatbuffers/tree/master/go).
+
+## Testing the FlatBuffers Go library
+
+The code to test the Go library can be found at `flatbuffers/tests`.
+The test code itself is located in [go_test.go](https://github.com/google/
+flatbuffers/blob/master/tests/go_test.go).
+
+To run the tests, use the [GoTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/GoTest.sh) shell script.
+
+*Note: The shell script requires [Go](https://golang.org/doc/install) to
+be installed.*
+
+## Using the FlatBuffers Go library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Go.*
+
+FlatBuffers supports reading and writing binary FlatBuffers in Go.
+
+To use FlatBuffers in your own code, first generate Go classes from your
+schema with the `--go` option to `flatc`. Then you can include both FlatBuffers
+and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Go: First,
+include the library and generated code. Then read a FlatBuffer binary file into
+a `[]byte`, which you pass to the `GetRootAsMonster` function:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
+ import (
+ example "MyGame/Example"
+ flatbuffers "github.com/google/flatbuffers/go"
+
+ io/ioutil
+ )
+
+ buf, err := ioutil.ReadFile("monster.dat")
+ // handle err
+ monster := example.GetRootAsMonster(buf, 0)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
+ hp := monster.Hp()
+ pos := monster.Pos(nil)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+In some cases it's necessary to modify values in an existing FlatBuffer in place (without creating a copy). For this reason, scalar fields of a Flatbuffer table or struct can be mutated.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.go}
+ monster := example.GetRootAsMonster(buf, 0)
+
+ // Set table field.
+ if ok := monster.MutateHp(10); !ok {
+ panic("failed to mutate Hp")
+ }
+
+ // Set struct field.
+ monster.Pos().MutateZ(4)
+
+ // This mutation will fail because the mana field is not available in
+ // the buffer. It should be set when creating the buffer.
+ if ok := monster.MutateMana(20); !ok {
+ panic("failed to mutate Hp")
+ }
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The term `mutate` is used instead of `set` to indicate that this is a special use case. All mutate functions return a boolean value which is false if the field we're trying to mutate is not available in the buffer.
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Go, though you could use the C++ parser through cgo. Please see the
+C++ documentation for more on text parsing.
+
+<br>
diff --git a/docs/source/Grammar.md b/docs/source/Grammar.md
new file mode 100644
index 0000000..51cc5f0
--- /dev/null
+++ b/docs/source/Grammar.md
@@ -0,0 +1,74 @@
+Grammar of the schema language {#flatbuffers_grammar}
+==============================
+
+schema = include*
+ ( namespace\_decl | type\_decl | enum\_decl | root\_decl |
+ file_extension_decl | file_identifier_decl |
+ attribute\_decl | rpc\_decl | object )*
+
+include = `include` string\_constant `;`
+
+namespace\_decl = `namespace` ident ( `.` ident )* `;`
+
+attribute\_decl = `attribute` ident | `"`ident`"` `;`
+
+type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`
+
+enum\_decl = ( `enum` ident `:` type | `union` ident ) metadata `{`
+commasep( enumval\_decl ) `}`
+
+root\_decl = `root_type` ident `;`
+
+field\_decl = ident `:` type [ `=` scalar ] metadata `;`
+
+rpc\_decl = `rpc_service` ident `{` rpc\_method+ `}`
+
+rpc\_method = ident `(` ident `)` `:` ident metadata `;`
+
+type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
+`float` | `long` | `ulong` | `double` |
+`int8` | `uint8` | `int16` | `uint16` | `int32` | `uint32`| `int64` | `uint64` |
+`float32` | `float64` |
+`string` | `[` type `]` | ident
+
+enumval\_decl = ident [ `=` integer\_constant ]
+
+metadata = [ `(` commasep( ident [ `:` single\_value ] ) `)` ]
+
+scalar = integer\_constant | float\_constant
+
+object = { commasep( ident `:` value ) }
+
+single\_value = scalar | string\_constant
+
+value = single\_value | object | `[` commasep( value ) `]`
+
+commasep(x) = [ x ( `,` x )\* ]
+
+file_extension_decl = `file_extension` string\_constant `;`
+
+file_identifier_decl = `file_identifier` string\_constant `;`
+
+string\_constant = `\".*?\"`
+
+ident = `[a-zA-Z_][a-zA-Z0-9_]*`
+
+`[:digit:]` = `[0-9]`
+
+`[:xdigit:]` = `[0-9a-fA-F]`
+
+dec\_integer\_constant = `[-+]?[:digit:]+`
+
+hex\_integer\_constant = `[-+]?0[xX][:xdigit:]+`
+
+integer\_constant = dec\_integer\_constant | hex\_integer\_constant
+
+dec\_float\_constant = `[-+]?(([.][:digit:]+)|([:digit:]+[.][:digit:]*)|([:digit:]+))([eE][-+]?[:digit:]+)?`
+
+hex\_float\_constant = `[-+]?0[xX](([.][:xdigit:]+)|([:xdigit:]+[.][:xdigit:]*)|([:xdigit:]+))([pP][-+]?[:digit:]+)`
+
+special\_float\_constant = `[-+]?(nan|inf|infinity)`
+
+float\_constant = decimal\_float\_constant | hexadecimal\_float\_constant | special\_float\_constant
+
+boolean\_constant = `(true|false)` | (integer\_constant ? `true` : `false`)
diff --git a/docs/source/Internals.md b/docs/source/Internals.md
new file mode 100644
index 0000000..d2064ca
--- /dev/null
+++ b/docs/source/Internals.md
@@ -0,0 +1,455 @@
+FlatBuffer Internals {#flatbuffers_internals}
+====================
+
+This section is entirely optional for the use of FlatBuffers. In normal
+usage, you should never need the information contained herein. If you're
+interested however, it should give you more of an appreciation of why
+FlatBuffers is both efficient and convenient.
+
+### Format components
+
+A FlatBuffer is a binary file and in-memory format consisting mostly of
+scalars of various sizes, all aligned to their own size. Each scalar is
+also always represented in little-endian format, as this corresponds to
+all commonly used CPUs today. FlatBuffers will also work on big-endian
+machines, but will be slightly slower because of additional
+byte-swap intrinsics.
+
+It is assumed that the following conditions are met, to ensure
+cross-platform interoperability:
+- The binary `IEEE-754` format is used for floating-point numbers.
+- The `two's complemented` representation is used for signed integers.
+- The endianness is the same for floating-point numbers as for integers.
+
+On purpose, the format leaves a lot of details about where exactly
+things live in memory undefined, e.g. fields in a table can have any
+order, and objects to some extent can be stored in many orders. This is
+because the format doesn't need this information to be efficient, and it
+leaves room for optimization and extension (for example, fields can be
+packed in a way that is most compact). Instead, the format is defined in
+terms of offsets and adjacency only. This may mean two different
+implementations may produce different binaries given the same input
+values, and this is perfectly valid.
+
+### Format identification
+
+The format also doesn't contain information for format identification
+and versioning, which is also by design. FlatBuffers is a statically typed
+system, meaning the user of a buffer needs to know what kind of buffer
+it is. FlatBuffers can of course be wrapped inside other containers
+where needed, or you can use its union feature to dynamically identify
+multiple possible sub-objects stored. Additionally, it can be used
+together with the schema parser if full reflective capabilities are
+desired.
+
+Versioning is something that is intrinsically part of the format (the
+optionality / extensibility of fields), so the format itself does not
+need a version number (it's a meta-format, in a sense). We're hoping
+that this format can accommodate all data needed. If format breaking
+changes are ever necessary, it would become a new kind of format rather
+than just a variation.
+
+### Offsets
+
+The most important and generic offset type (see `flatbuffers.h`) is
+`uoffset_t`, which is currently always a `uint32_t`, and is used to
+refer to all tables/unions/strings/vectors (these are never stored
+in-line). 32bit is
+intentional, since we want to keep the format binary compatible between
+32 and 64bit systems, and a 64bit offset would bloat the size for almost
+all uses. A version of this format with 64bit (or 16bit) offsets is easy to set
+when needed. Unsigned means they can only point in one direction, which
+typically is forward (towards a higher memory location). Any backwards
+offsets will be explicitly marked as such.
+
+The format starts with an `uoffset_t` to the root object in the buffer.
+
+We have two kinds of objects, structs and tables.
+
+### Structs
+
+These are the simplest, and as mentioned, intended for simple data that
+benefits from being extra efficient and doesn't need versioning /
+extensibility. They are always stored inline in their parent (a struct,
+table, or vector) for maximum compactness. Structs define a consistent
+memory layout where all components are aligned to their size, and
+structs aligned to their largest scalar member. This is done independent
+of the alignment rules of the underlying compiler to guarantee a cross
+platform compatible layout. This layout is then enforced in the generated
+code.
+
+### Tables
+
+Unlike structs, these are not stored in inline in their parent, but are
+referred to by offset.
+
+They start with an `soffset_t` to a vtable. This is a signed version of
+`uoffset_t`, since vtables may be stored anywhere relative to the object.
+This offset is substracted (not added) from the object start to arrive at
+the vtable start. This offset is followed by all the
+fields as aligned scalars (or offsets). Unlike structs, not all fields
+need to be present. There is no set order and layout.
+
+To be able to access fields regardless of these uncertainties, we go
+through a vtable of offsets. Vtables are shared between any objects that
+happen to have the same vtable values.
+
+The elements of a vtable are all of type `voffset_t`, which is
+a `uint16_t`. The first element is the size of the vtable in bytes,
+including the size element. The second one is the size of the object, in bytes
+(including the vtable offset). This size could be used for streaming, to know
+how many bytes to read to be able to access all *inline* fields of the object.
+The remaining elements are the N offsets, where N is the amount of fields
+declared in the schema when the code that constructed this buffer was
+compiled (thus, the size of the table is N + 2).
+
+All accessor functions in the generated code for tables contain the
+offset into this table as a constant. This offset is checked against the
+first field (the number of elements), to protect against newer code
+reading older data. If this offset is out of range, or the vtable entry
+is 0, that means the field is not present in this object, and the
+default value is return. Otherwise, the entry is used as offset to the
+field to be read.
+
+### Strings and Vectors
+
+Strings are simply a vector of bytes, and are always
+null-terminated. Vectors are stored as contiguous aligned scalar
+elements prefixed by a 32bit element count (not including any
+null termination). Neither is stored inline in their parent, but are referred to
+by offset.
+
+### Construction
+
+The current implementation constructs these buffers backwards (starting
+at the highest memory address of the buffer), since
+that significantly reduces the amount of bookkeeping and simplifies the
+construction API.
+
+### Code example
+
+Here's an example of the code that gets generated for the `samples/monster.fbs`.
+What follows is the entire file, broken up by comments:
+
+ // automatically generated, do not modify
+
+ #include "flatbuffers/flatbuffers.h"
+
+ namespace MyGame {
+ namespace Sample {
+
+Nested namespace support.
+
+ enum {
+ Color_Red = 0,
+ Color_Green = 1,
+ Color_Blue = 2,
+ };
+
+ inline const char **EnumNamesColor() {
+ static const char *names[] = { "Red", "Green", "Blue", nullptr };
+ return names;
+ }
+
+ inline const char *EnumNameColor(int e) { return EnumNamesColor()[e]; }
+
+Enums and convenient reverse lookup.
+
+ enum {
+ Any_NONE = 0,
+ Any_Monster = 1,
+ };
+
+ inline const char **EnumNamesAny() {
+ static const char *names[] = { "NONE", "Monster", nullptr };
+ return names;
+ }
+
+ inline const char *EnumNameAny(int e) { return EnumNamesAny()[e]; }
+
+Unions share a lot with enums.
+
+ struct Vec3;
+ struct Monster;
+
+Predeclare all data types since circular references between types are allowed
+(circular references between object are not, though).
+
+ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 {
+ private:
+ float x_;
+ float y_;
+ float z_;
+
+ public:
+ Vec3(float x, float y, float z)
+ : x_(flatbuffers::EndianScalar(x)), y_(flatbuffers::EndianScalar(y)), z_(flatbuffers::EndianScalar(z)) {}
+
+ float x() const { return flatbuffers::EndianScalar(x_); }
+ float y() const { return flatbuffers::EndianScalar(y_); }
+ float z() const { return flatbuffers::EndianScalar(z_); }
+ };
+ FLATBUFFERS_STRUCT_END(Vec3, 12);
+
+These ugly macros do a couple of things: they turn off any padding the compiler
+might normally do, since we add padding manually (though none in this example),
+and they enforce alignment chosen by FlatBuffers. This ensures the layout of
+this struct will look the same regardless of compiler and platform. Note that
+the fields are private: this is because these store little endian scalars
+regardless of platform (since this is part of the serialized data).
+`EndianScalar` then converts back and forth, which is a no-op on all current
+mobile and desktop platforms, and a single machine instruction on the few
+remaining big endian platforms.
+
+ struct Monster : private flatbuffers::Table {
+ const Vec3 *pos() const { return GetStruct<const Vec3 *>(4); }
+ int16_t mana() const { return GetField<int16_t>(6, 150); }
+ int16_t hp() const { return GetField<int16_t>(8, 100); }
+ const flatbuffers::String *name() const { return GetPointer<const flatbuffers::String *>(10); }
+ const flatbuffers::Vector<uint8_t> *inventory() const { return GetPointer<const flatbuffers::Vector<uint8_t> *>(14); }
+ int8_t color() const { return GetField<int8_t>(16, 2); }
+ };
+
+Tables are a bit more complicated. A table accessor struct is used to point at
+the serialized data for a table, which always starts with an offset to its
+vtable. It derives from `Table`, which contains the `GetField` helper functions.
+GetField takes a vtable offset, and a default value. It will look in the vtable
+at that offset. If the offset is out of bounds (data from an older version) or
+the vtable entry is 0, the field is not present and the default is returned.
+Otherwise, it uses the entry as an offset into the table to locate the field.
+
+ struct MonsterBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_pos(const Vec3 *pos) { fbb_.AddStruct(4, pos); }
+ void add_mana(int16_t mana) { fbb_.AddElement<int16_t>(6, mana, 150); }
+ void add_hp(int16_t hp) { fbb_.AddElement<int16_t>(8, hp, 100); }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) { fbb_.AddOffset(10, name); }
+ void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) { fbb_.AddOffset(14, inventory); }
+ void add_color(int8_t color) { fbb_.AddElement<int8_t>(16, color, 2); }
+ MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
+ flatbuffers::Offset<Monster> Finish() { return flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 7)); }
+ };
+
+`MonsterBuilder` is the base helper struct to construct a table using a
+`FlatBufferBuilder`. You can add the fields in any order, and the `Finish`
+call will ensure the correct vtable gets generated.
+
+ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
+ const Vec3 *pos, int16_t mana,
+ int16_t hp,
+ flatbuffers::Offset<flatbuffers::String> name,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory,
+ int8_t color) {
+ MonsterBuilder builder_(_fbb);
+ builder_.add_inventory(inventory);
+ builder_.add_name(name);
+ builder_.add_pos(pos);
+ builder_.add_hp(hp);
+ builder_.add_mana(mana);
+ builder_.add_color(color);
+ return builder_.Finish();
+ }
+
+`CreateMonster` is a convenience function that calls all functions in
+`MonsterBuilder` above for you. Note that if you pass values which are
+defaults as arguments, it will not actually construct that field, so
+you can probably use this function instead of the builder class in
+almost all cases.
+
+ inline const Monster *GetMonster(const void *buf) { return flatbuffers::GetRoot<Monster>(buf); }
+
+This function is only generated for the root table type, to be able to
+start traversing a FlatBuffer from a raw buffer pointer.
+
+ }; // namespace MyGame
+ }; // namespace Sample
+
+### Encoding example.
+
+Below is a sample encoding for the following JSON corresponding to the above
+schema:
+
+ { pos: { x: 1, y: 2, z: 3 }, name: "fred", hp: 50 }
+
+Resulting in this binary buffer:
+
+ // Start of the buffer:
+ uint32_t 20 // Offset to the root table.
+
+ // Start of the vtable. Not shared in this example, but could be:
+ uint16_t 16 // Size of table, starting from here.
+ uint16_t 22 // Size of object inline data.
+ uint16_t 4, 0, 20, 16, 0, 0 // Offsets to fields from start of (root) table, 0 for not present.
+
+ // Start of the root table:
+ int32_t 16 // Offset to vtable used (default negative direction)
+ float 1, 2, 3 // the Vec3 struct, inline.
+ uint32_t 8 // Offset to the name string.
+ int16_t 50 // hp field.
+ int16_t 0 // Padding for alignment.
+
+ // Start of name string:
+ uint32_t 4 // Length of string.
+ int8_t 'f', 'r', 'e', 'd', 0, 0, 0, 0 // Text + 0 termination + padding.
+
+Note that this not the only possible encoding, since the writer has some
+flexibility in which of the children of root object to write first (though in
+this case there's only one string), and what order to write the fields in.
+Different orders may also cause different alignments to happen.
+
+### Additional reading.
+
+The author of the C language implementation has made a similar
+[document](https://github.com/dvidelabs/flatcc/blob/master/doc/binary-format.md#flatbuffers-binary-format)
+that may further help clarify the format.
+
+# FlexBuffers
+
+The [schema-less](@ref flexbuffers) version of FlatBuffers have their
+own encoding, detailed here.
+
+It shares many properties mentioned above, in that all data is accessed
+over offsets, all scalars are aligned to their own size, and
+all data is always stored in little endian format.
+
+One difference is that FlexBuffers are built front to back, so children are
+stored before parents, and the root of the data starts at the last byte.
+
+Another difference is that scalar data is stored with a variable number of bits
+(8/16/32/64). The current width is always determined by the *parent*, i.e. if
+the scalar sits in a vector, the vector determines the bit width for all
+elements at once. Selecting the minimum bit width for a particular vector is
+something the encoder does automatically and thus is typically of no concern
+to the user, though being aware of this feature (and not sticking a double in
+the same vector as a bunch of byte sized elements) is helpful for efficiency.
+
+Unlike FlatBuffers there is only one kind of offset, and that is an unsigned
+integer indicating the number of bytes in a negative direction from the address
+of itself (where the offset is stored).
+
+### Vectors
+
+The representation of the vector is at the core of how FlexBuffers works (since
+maps are really just a combination of 2 vectors), so it is worth starting there.
+
+As mentioned, a vector is governed by a single bit width (supplied by its
+parent). This includes the size field. For example, a vector that stores the
+integer values `1, 2, 3` is encoded as follows:
+
+ uint8_t 3, 1, 2, 3, 4, 4, 4
+
+The first `3` is the size field, and is placed before the vector (an offset
+from the parent to this vector points to the first element, not the size
+field, so the size field is effectively at index -1).
+Since this is an untyped vector `SL_VECTOR`, it is followed by 3 type
+bytes (one per element of the vector), which are always following the vector,
+and are always a uint8_t even if the vector is made up of bigger scalars.
+
+### Types
+
+A type byte is made up of 2 components (see flexbuffers.h for exact values):
+
+* 2 lower bits representing the bit-width of the child (8, 16, 32, 64).
+ This is only used if the child is accessed over an offset, such as a child
+ vector. It is ignored for inline types.
+* 6 bits representing the actual type (see flexbuffers.h).
+
+Thus, in this example `4` means 8 bit child (value 0, unused, since the value is
+in-line), type `SL_INT` (value 1).
+
+### Typed Vectors
+
+These are like the Vectors above, but omit the type bytes. The type is instead
+determined by the vector type supplied by the parent. Typed vectors are only
+available for a subset of types for which these savings can be significant,
+namely inline signed/unsigned integers (`TYPE_VECTOR_INT` / `TYPE_VECTOR_UINT`),
+floats (`TYPE_VECTOR_FLOAT`), and keys (`TYPE_VECTOR_KEY`, see below).
+
+Additionally, for scalars, there are fixed length vectors of sizes 2 / 3 / 4
+that don't store the size (`TYPE_VECTOR_INT2` etc.), for an additional savings
+in space when storing common vector or color data.
+
+### Scalars
+
+FlexBuffers supports integers (`TYPE_INT` and `TYPE_UINT`) and floats
+(`TYPE_FLOAT`), available in the bit-widths mentioned above. They can be stored
+both inline and over an offset (`TYPE_INDIRECT_*`).
+
+The offset version is useful to encode costly 64bit (or even 32bit) quantities
+into vectors / maps of smaller sizes, and to share / repeat a value multiple
+times.
+
+### Booleans and Nulls
+
+Booleans (`TYPE_BOOL`) and nulls (`TYPE_NULL`) are encoded as inlined unsigned integers.
+
+### Blobs, Strings and Keys.
+
+A blob (`TYPE_BLOB`) is encoded similar to a vector, with one difference: the
+elements are always `uint8_t`. The parent bit width only determines the width of
+the size field, allowing blobs to be large without the elements being large.
+
+Strings (`TYPE_STRING`) are similar to blobs, except they have an additional 0
+termination byte for convenience, and they MUST be UTF-8 encoded (since an
+accessor in a language that does not support pointers to UTF-8 data may have to
+convert them to a native string type).
+
+A "Key" (`TYPE_KEY`) is similar to a string, but doesn't store the size
+field. They're so named because they are used with maps, which don't care
+for the size, and can thus be even more compact. Unlike strings, keys cannot
+contain bytes of value 0 as part of their data (size can only be determined by
+`strlen`), so while you can use them outside the context of maps if you so
+desire, you're usually better off with strings.
+
+### Maps
+
+A map (`TYPE_MAP`) is like an (untyped) vector, but with 2 prefixes before the
+size field:
+
+| index | field |
+| ----: | :----------------------------------------------------------- |
+| -3 | An offset to the keys vector (may be shared between tables). |
+| -2 | Byte width of the keys vector. |
+| -1 | Size (from here on it is compatible with `TYPE_VECTOR`) |
+| 0 | Elements. |
+| Size | Types. |
+
+Since a map is otherwise the same as a vector, it can be iterated like
+a vector (which is probably faster than lookup by key).
+
+The keys vector is a typed vector of keys. Both the keys and corresponding
+values *have* to be stored in sorted order (as determined by `strcmp`), such
+that lookups can be made using binary search.
+
+The reason the key vector is a seperate structure from the value vector is
+such that it can be shared between multiple value vectors, and also to
+allow it to be treated as its own individual vector in code.
+
+An example map { foo: 13, bar: 14 } would be encoded as:
+
+ 0 : uint8_t 'b', 'a', 'r', 0
+ 4 : uint8_t 'f', 'o', 'o', 0
+ 8 : uint8_t 2 // key vector of size 2
+ // key vector offset points here
+ 9 : uint8_t 9, 6 // offsets to bar_key and foo_key
+ 11: uint8_t 2, 1 // offset to key vector, and its byte width
+ 13: uint8_t 2 // value vector of size
+ // value vector offset points here
+ 14: uint8_t 14, 13 // values
+ 16: uint8_t 4, 4 // types
+
+### The root
+
+As mentioned, the root starts at the end of the buffer.
+The last uint8_t is the width in bytes of the root (normally the parent
+determines the width, but the root has no parent). The uint8_t before this is
+the type of the root, and the bytes before that are the root value (of the
+number of bytes specified by the last byte).
+
+So for example, the integer value `13` as root would be:
+
+ uint8_t 13, 4, 1 // Value, type, root byte width.
+
+
+<br>
diff --git a/docs/source/JavaCsharpUsage.md b/docs/source/JavaCsharpUsage.md
new file mode 100644
index 0000000..102ce37
--- /dev/null
+++ b/docs/source/JavaCsharpUsage.md
@@ -0,0 +1,172 @@
+Use in Java/C# {#flatbuffers_guide_use_java_c-sharp}
+==============
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Java or C#, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
+general FlatBuffers usage in all of the supported languages (including both Java
+and C#). This page is designed to cover the nuances of FlatBuffers usage,
+specific to Java and C#.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Java and C-sharp code location
+
+#### Java
+
+The code for the FlatBuffers Java library can be found at
+`flatbuffers/java/com/google/flatbuffers`. You can browse the library on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
+java/com/google/flatbuffers).
+
+#### C-sharp
+
+The code for the FlatBuffers C# library can be found at
+`flatbuffers/net/FlatBuffers`. You can browse the library on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/net/
+FlatBuffers).
+
+## Testing the FlatBuffers Java and C-sharp libraries
+
+The code to test the libraries can be found at `flatbuffers/tests`.
+
+#### Java
+
+The test code for Java is located in [JavaTest.java](https://github.com/google
+/flatbuffers/blob/master/tests/JavaTest.java).
+
+To run the tests, use either [JavaTest.sh](https://github.com/google/
+flatbuffers/blob/master/tests/JavaTest.sh) or [JavaTest.bat](https://github.com/
+google/flatbuffers/blob/master/tests/JavaTest.bat), depending on your operating
+system.
+
+*Note: These scripts require that [Java](https://www.oracle.com/java/index.html)
+is installed.*
+
+#### C-sharp
+
+The test code for C# is located in the [FlatBuffers.Test](https://github.com/
+google/flatbuffers/tree/master/tests/FlatBuffers.Test) subfolder. To run the
+tests, open `FlatBuffers.Test.csproj` in [Visual Studio](
+https://www.visualstudio.com), and compile/run the project.
+
+Optionally, you can run this using [Mono](http://www.mono-project.com/) instead.
+Once you have installed `Mono`, you can run the tests from the command line
+by running the following commands from inside the `FlatBuffers.Test` folder:
+
+~~~{.sh}
+ mcs *.cs ../MyGame/Example/*.cs ../../net/FlatBuffers/*.cs
+ mono Assert.exe
+~~~
+
+## Using the FlatBuffers Java (and C#) library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Java or C#.*
+
+FlatBuffers supports reading and writing binary FlatBuffers in Java and C#.
+
+To use FlatBuffers in your own code, first generate Java classes from your
+schema with the `--java` option to `flatc`. (Or for C# with `--csharp`).
+Then you can include both FlatBuffers and the generated code to read
+or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Java:
+First, import the library and generated code. Then, you read a FlatBuffer binary
+file into a `byte[]`. You then turn the `byte[]` into a `ByteBuffer`, which you
+pass to the `getRootAsMyRootType` function:
+
+*Note: The code here is written from the perspective of Java. Code for both
+languages is both generated and used in nearly the exact same way, with only
+minor differences. These differences are
+[explained in a section below](#differences_in_c-sharp).*
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java}
+ import MyGame.Example.*;
+ import com.google.flatbuffers.FlatBufferBuilder;
+
+ // This snippet ignores exceptions for brevity.
+ File file = new File("monsterdata_test.mon");
+ RandomAccessFile f = new RandomAccessFile(file, "r");
+ byte[] data = new byte[(int)f.length()];
+ f.readFully(data);
+ f.close();
+
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ Monster monster = Monster.getRootAsMonster(bb);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access the data from the `Monster monster`:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.java}
+ short hp = monster.hp();
+ Vec3 pos = monster.pos();
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+<a name="differences_in_c-sharp">
+#### Differences in C-sharp
+</a>
+
+C# code works almost identically to Java, with only a few minor differences.
+You can see an example of C# code in
+`tests/FlatBuffers.Test/FlatBuffersExampleTests.cs` or
+`samples/SampleBinary.cs`.
+
+First of all, naming follows standard C# style with `PascalCasing` identifiers,
+e.g. `GetRootAsMyRootType`. Also, values (except vectors and unions) are
+available as properties instead of parameterless accessor methods as in Java.
+The performance-enhancing methods to which you can pass an already created
+object are prefixed with `Get`, e.g.:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cs}
+ // property
+ var pos = monster.Pos;
+
+ // method filling a preconstructed object
+ var preconstructedPos = new Vec3();
+ monster.GetPos(preconstructedPos);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+## Storing dictionaries in a FlatBuffer
+
+FlatBuffers doesn't support dictionaries natively, but there is support to
+emulate their behavior with vectors and binary search, which means you
+can have fast lookups directly from a FlatBuffer without having to unpack
+your data into a `Dictionary` or similar.
+
+To use it:
+- Designate one of the fields in a table as the "key" field. You do this
+ by setting the `key` attribute on this field, e.g.
+ `name:string (key)`.
+ You may only have one key field, and it must be of string or scalar type.
+- Write out tables of this type as usual, collect their offsets in an
+ array.
+- Instead of calling standard generated method,
+ e.g.: `Monster.createTestarrayoftablesVector`,
+ call `CreateSortedVectorOfMonster` in C# or
+ `createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
+ which will first sort all offsets such that the tables they refer to
+ are sorted by the key field, then serialize it.
+- Now when you're accessing the FlatBuffer, you can use
+ the `ByKey` accessor to access elements of the vector, e.g.:
+ `monster.testarrayoftablesByKey("Frodo")` in Java or
+ `monster.TestarrayoftablesByKey("Frodo")` in C#,
+ which returns an object of the corresponding table type,
+ or `null` if not found.
+ `ByKey` performs a binary search, so should have a similar
+ speed to `Dictionary`, though may be faster because of better caching.
+ `ByKey` only works if the vector has been sorted, it will
+ likely not find elements if it hasn't been sorted.
+
+## Text parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Java or C#, though you could use the C++ parser through native call
+interfaces available to each language. Please see the
+C++ documentation for more on text parsing.
+
+<br>
diff --git a/docs/source/JavaScriptUsage.md b/docs/source/JavaScriptUsage.md
new file mode 100644
index 0000000..c321c95
--- /dev/null
+++ b/docs/source/JavaScriptUsage.md
@@ -0,0 +1,105 @@
+Use in JavaScript {#flatbuffers_guide_use_javascript}
+=================
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in JavaScript, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
+general FlatBuffers usage in all of the supported languages
+(including JavaScript). This page is specifically designed to cover the nuances
+of FlatBuffers usage in JavaScript.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers JavaScript library code location
+
+The code for the FlatBuffers JavaScript library can be found at
+`flatbuffers/js`. You can browse the library code on the [FlatBuffers
+GitHub page](https://github.com/google/flatbuffers/tree/master/js).
+
+## Testing the FlatBuffers JavaScript library
+
+The code to test the JavaScript library can be found at `flatbuffers/tests`.
+The test code itself is located in [JavaScriptTest.js](https://github.com/
+google/flatbuffers/blob/master/tests/JavaScriptTest.js).
+
+To run the tests, use the [JavaScriptTest.sh](https://github.com/google/
+flatbuffers/blob/master/tests/JavaScriptTest.sh) shell script.
+
+*Note: The JavaScript test file requires [Node.js](https://nodejs.org/en/).*
+
+## Using the FlatBuffers JavaScript libary
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in JavaScript.*
+
+FlatBuffers supports both reading and writing FlatBuffers in JavaScript.
+
+To use FlatBuffers in your own code, first generate JavaScript classes from your
+schema with the `--js` option to `flatc`. Then you can include both FlatBuffers
+and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Javascript:
+First, include the library and generated code. Then read the file into an
+`Uint8Array`. Make a `flatbuffers.ByteBuffer` out of the `Uint8Array`, and pass
+the ByteBuffer to the `getRootAsMonster` function.
+
+*Note: Both JavaScript module loaders (e.g. Node.js) and browser-based
+HTML/JavaScript code segments are shown below in the following snippet:*
+
+~~~{.js}
+ // Note: These require functions are specific to JavaScript module loaders
+ // (namely, Node.js). See below for a browser-based example.
+ var fs = require('fs');
+
+ var flatbuffers = require('../flatbuffers').flatbuffers;
+ var MyGame = require('./monster_generated').MyGame;
+
+ var data = new Uint8Array(fs.readFileSync('monster.dat'));
+ var buf = new flatbuffers.ByteBuffer(data);
+
+ var monster = MyGame.Example.Monster.getRootAsMonster(buf);
+
+ //--------------------------------------------------------------------------//
+
+ // Note: This code is specific to browser-based HTML/JavaScript. See above
+ // for the code using JavaScript module loaders (e.g. Node.js).
+ <script src="../js/flatbuffers.js"></script>
+ <script src="monster_generated.js"></script>
+ <script>
+ function readFile() {
+ var reader = new FileReader(); // This example uses the HTML5 FileReader.
+ var file = document.getElementById(
+ 'file_input').files[0]; // "monster.dat" from the HTML <input> field.
+
+ reader.onload = function() { // Executes after the file is read.
+ var data = new Uint8Array(reader.result);
+
+ var buf = new flatbuffers.ByteBuffer(data);
+
+ var monster = MyGame.Example.Monster.getRootAsMonster(buf);
+ }
+
+ reader.readAsArrayBuffer(file);
+ }
+ </script>
+
+ // Open the HTML file in a browser and select "monster.dat" from with the
+ // <input> field.
+ <input type="file" id="file_input" onchange="readFile();">
+~~~
+
+Now you can access values like this:
+
+~~~{.js}
+ var hp = monster.hp();
+ var pos = monster.pos();
+~~~
+
+## Text parsing FlatBuffers in JavaScript
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from JavaScript.
diff --git a/docs/source/KotlinUsage.md b/docs/source/KotlinUsage.md
new file mode 100644
index 0000000..092fcd7
--- /dev/null
+++ b/docs/source/KotlinUsage.md
@@ -0,0 +1,84 @@
+Use in Kotlin {#flatbuffers_guide_use_kotlin}
+==============
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Kotlin, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
+general FlatBuffers usage in all of the supported languages (including K).
+
+This page is designed to cover the nuances of FlatBuffers usage, specific to Kotlin.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## Kotlin and FlatBuffers Java code location
+
+Code generated for Kotlin currently uses the flatbuffers java runtime library. That means that Kotlin generated code can only have Java virtual machine as target architecture (which includes Android). Kotlin Native and Kotlin.js are currently not supported.
+
+The code for the FlatBuffers Java library can be found at
+`flatbuffers/java/com/google/flatbuffers`. You can browse the library on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
+java/com/google/flatbuffers).
+
+## Testing FlatBuffers Kotlin
+
+The test code for Java is located in [KotlinTest.java](https://github.com/google
+/flatbuffers/blob/master/tests/KotlinTest.kt).
+
+To run the tests, use [KotlinTest.sh](https://github.com/google/
+flatbuffers/blob/master/tests/KotlinTest.sh) shell script.
+
+*Note: These scripts require that [Kotlin](https://kotlinlang.org/) is installed.*
+
+## Using the FlatBuffers Kotlin library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Kotlin.*
+
+FlatBuffers supports reading and writing binary FlatBuffers in Kotlin.
+
+To use FlatBuffers in your own code, first generate Java classes from your
+schema with the `--kotlin` option to `flatc`.
+Then you can include both FlatBuffers and the generated code to read
+or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Kotlin:
+First, import the library and generated code. Then, you read a FlatBuffer binary
+file into a `ByteArray`. You then turn the `ByteArray` into a `ByteBuffer`, which you
+pass to the `getRootAsMyRootType` function:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.kt}
+ import MyGame.Example.*
+ import com.google.flatbuffers.FlatBufferBuilder
+
+ // This snippet ignores exceptions for brevity.
+ val data = RandomAccessFile(File("monsterdata_test.mon"), "r").use {
+ val temp = ByteArray(it.length().toInt())
+ it.readFully(temp)
+ temp
+ }
+
+ val bb = ByteBuffer.wrap(data)
+ val monster = Monster.getRootAsMonster(bb)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access the data from the `Monster monster`:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.kt}
+ val hp = monster.hp
+ val pos = monster.pos!!;
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+
+## Differences between Kotlin and Java code
+
+Kotlin generated code was designed to be as close as possible to the java counterpart, as for now, we only support kotlin on java virtual machine. So the differences in implementation and usage are basically the ones introduced by the Kotlin language itself. You can find more in-depth information [here](https://kotlinlang.org/docs/reference/comparison-to-java.html).
+
+The most obvious ones are:
+
+* Fields as accessed as Kotlin [properties](https://kotlinlang.org/docs/reference/properties.html)
+* Static methods are accessed in [companion object](https://kotlinlang.org/docs/reference/classes.html#companion-objects)
\ No newline at end of file
diff --git a/docs/source/LobsterUsage.md b/docs/source/LobsterUsage.md
new file mode 100644
index 0000000..9d69caf
--- /dev/null
+++ b/docs/source/LobsterUsage.md
@@ -0,0 +1,85 @@
+Use in Lobster {#flatbuffers_guide_use_lobster}
+==============
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Lobster, it should be noted that the
+[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
+FlatBuffers usage in all of the supported languages (including Lobster). This
+page is designed to cover the nuances of FlatBuffers usage, specific to
+Lobster.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Lobster library code location
+
+The code for the FlatBuffers Lobster library can be found at
+`flatbuffers/lobster`. You can browse the library code on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
+lobster).
+
+## Testing the FlatBuffers Lobster library
+
+The code to test the Lobster library can be found at `flatbuffers/tests`.
+The test code itself is located in [lobstertest.lobster](https://github.com/google/
+flatbuffers/blob/master/tests/lobstertest.lobster).
+
+To run the tests, run `lobster lobstertest.lobster`. To obtain Lobster itself,
+go to the [Lobster homepage](http://strlen.com/lobster) or
+[github](https://github.com/aardappel/lobster) to learn how to build it for your
+platform.
+
+## Using the FlatBuffers Lobster library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Lobster.*
+
+There is support for both reading and writing FlatBuffers in Lobster.
+
+To use FlatBuffers in your own code, first generate Lobster classes from your
+schema with the `--lobster` option to `flatc`. Then you can include both
+FlatBuffers and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Lobster:
+First, import the library and the generated code. Then read a FlatBuffer binary
+file into a string, which you pass to the `GetRootAsMonster` function:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
+ include "monster_generated.lobster"
+
+ let fb = read_file("monsterdata_test.mon")
+ assert fb
+ let monster = MyGame_Example_GetRootAsMonster(fb)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lobster}
+ let hp = monster.hp
+ let pos = monster.pos
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As you can see, even though `hp` and `pos` are functions that access FlatBuffer
+data in-place in the string buffer, they appear as field accesses.
+
+## Speed
+
+Using FlatBuffers in Lobster should be relatively fast, as the implementation
+makes use of native support for writing binary values, and access of vtables.
+Both generated code and the runtime library are therefore small and fast.
+
+Actual speed will depend on wether you use Lobster as bytecode VM or compiled to
+C++.
+
+## Text Parsing
+
+Lobster has full support for parsing JSON into FlatBuffers, or generating
+JSON from FlatBuffers. See `samples/sample_test.lobster` for an example.
+
+This uses the C++ parser and generator underneath, so should be both fast and
+conformant.
+
+<br>
diff --git a/docs/source/LuaUsage.md b/docs/source/LuaUsage.md
new file mode 100644
index 0000000..75b1f3b
--- /dev/null
+++ b/docs/source/LuaUsage.md
@@ -0,0 +1,81 @@
+Use in Lua {#flatbuffers_guide_use_lua}
+=============
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Lua, it should be noted that the
+[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
+FlatBuffers usage in all of the supported languages (including Lua). This
+page is designed to cover the nuances of FlatBuffers usage, specific to
+Lua.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Lua library code location
+
+The code for the FlatBuffers Lua library can be found at
+`flatbuffers/lua`. You can browse the library code on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/lua).
+
+## Testing the FlatBuffers Lua library
+
+The code to test the Lua library can be found at `flatbuffers/tests`.
+The test code itself is located in [luatest.lua](https://github.com/google/
+flatbuffers/blob/master/tests/luatest.lua).
+
+To run the tests, use the [LuaTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/LuaTest.sh) shell script.
+
+*Note: This script requires [Lua 5.3](https://www.lua.org/) to be
+installed.*
+
+## Using the FlatBuffers Lua library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Lua.*
+
+There is support for both reading and writing FlatBuffers in Lua.
+
+To use FlatBuffers in your own code, first generate Lua classes from your
+schema with the `--lua` option to `flatc`. Then you can include both
+FlatBuffers and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Lua:
+First, require the module and the generated code. Then read a FlatBuffer binary
+file into a `string`, which you pass to the `GetRootAsMonster` function:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
+ -- require the library
+ local flatbuffers = require("flatbuffers")
+
+ -- require the generated code
+ local monster = require("MyGame.Sample.Monster")
+
+ -- read the flatbuffer from a file into a string
+ local f = io.open('monster.dat', 'rb')
+ local buf = f:read('*a')
+ f:close()
+
+ -- parse the flatbuffer to get an instance to the root monster
+ local monster1 = monster.GetRootAsMonster(buf, 0)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
+ -- use the : notation to access member data
+ local hp = monster1:Hp()
+ local pos = monster1:Pos()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Lua, though you could use the C++ parser through SWIG or ctypes. Please
+see the C++ documentation for more on text parsing.
+
+<br>
diff --git a/docs/source/PHPUsage.md b/docs/source/PHPUsage.md
new file mode 100644
index 0000000..cdff449
--- /dev/null
+++ b/docs/source/PHPUsage.md
@@ -0,0 +1,89 @@
+Use in PHP {#flatbuffers_guide_use_php}
+==========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in PHP, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
+general FlatBuffers usage in all of the supported languages
+(including PHP). This page is specifically designed to cover the nuances of
+FlatBuffers usage in PHP.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers PHP library code location
+
+The code for FlatBuffers PHP library can be found at `flatbuffers/php`. You
+can browse the library code on the [FlatBuffers
+GitHub page](https://github.com/google/flatbuffers/tree/master/php).
+
+## Testing the FlatBuffers JavaScript library
+
+The code to test the PHP library can be found at `flatbuffers/tests`.
+The test code itself is located in [phpTest.php](https://github.com/google/
+flatbuffers/blob/master/tests/phpTest.php).
+
+You can run the test with `php phpTest.php` from the command line.
+
+*Note: The PHP test file requires
+[PHP](http://php.net/manual/en/install.php) to be installed.*
+
+## Using theFlatBuffers PHP library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in PHP.*
+
+FlatBuffers supports both reading and writing FlatBuffers in PHP.
+
+To use FlatBuffers in your own code, first generate PHP classes from your schema
+with the `--php` option to `flatc`. Then you can include both FlatBuffers and
+the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in PHP:
+First, include the library and generated code (using the PSR `autoload`
+function). Then you can read a FlatBuffer binary file, which you
+pass the contents of to the `GetRootAsMonster` function:
+
+~~~{.php}
+ // It is recommended that your use PSR autoload when using FlatBuffers in PHP.
+ // Here is an example:
+ function __autoload($class_name) {
+ // The last segment of the class name matches the file name.
+ $class = substr($class_name, strrpos($class_name, "\\") + 1);
+ $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root.
+
+ // Contains the `*.php` files for the FlatBuffers library and the `flatc` generated files.
+ $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")),
+ join(DIRECTORY_SEPARATOR, array($root_dir, "tests", "MyGame", "Example")));
+ foreach ($paths as $path) {
+ $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
+ if (file_exists($file)) {
+ require($file);
+ break;
+ }
+ }
+
+ // Read the contents of the FlatBuffer binary file.
+ $filename = "monster.dat";
+ $handle = fopen($filename, "rb");
+ $contents = $fread($handle, filesize($filename));
+ fclose($handle);
+
+ // Pass the contents to `GetRootAsMonster`.
+ $monster = \MyGame\Example\Monster::GetRootAsMonster($contents);
+~~~
+
+Now you can access values like this:
+
+~~~{.php}
+ $hp = $monster->GetHp();
+ $pos = $monster->GetPos();
+~~~
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from PHP.
diff --git a/docs/source/PythonUsage.md b/docs/source/PythonUsage.md
new file mode 100644
index 0000000..f338cda
--- /dev/null
+++ b/docs/source/PythonUsage.md
@@ -0,0 +1,100 @@
+Use in Python {#flatbuffers_guide_use_python}
+=============
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Python, it should be noted that the
+[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
+FlatBuffers usage in all of the supported languages (including Python). This
+page is designed to cover the nuances of FlatBuffers usage, specific to
+Python.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Python library code location
+
+The code for the FlatBuffers Python library can be found at
+`flatbuffers/python/flatbuffers`. You can browse the library code on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/
+python).
+
+## Testing the FlatBuffers Python library
+
+The code to test the Python library can be found at `flatbuffers/tests`.
+The test code itself is located in [py_test.py](https://github.com/google/
+flatbuffers/blob/master/tests/py_test.py).
+
+To run the tests, use the [PythonTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/PythonTest.sh) shell script.
+
+*Note: This script requires [python](https://www.python.org/) to be
+installed.*
+
+## Using the FlatBuffers Python library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Python.*
+
+There is support for both reading and writing FlatBuffers in Python.
+
+To use FlatBuffers in your own code, first generate Python classes from your
+schema with the `--python` option to `flatc`. Then you can include both
+FlatBuffers and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Python:
+First, import the library and the generated code. Then read a FlatBuffer binary
+file into a `bytearray`, which you pass to the `GetRootAsMonster` function:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+ import MyGame.Example as example
+ import flatbuffers
+
+ buf = open('monster.dat', 'rb').read()
+ buf = bytearray(buf)
+ monster = example.GetRootAsMonster(buf, 0)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+ hp = monster.Hp()
+ pos = monster.Pos()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+## Support for Numpy arrays
+
+The Flatbuffers python library also has support for accessing scalar
+vectors as numpy arrays. This can be orders of magnitude faster than
+iterating over the vector one element at a time, and is particularly
+useful when unpacking large nested flatbuffers. The generated code for
+a scalar vector will have a method `<vector name>AsNumpy()`. In the
+case of the Monster example, you could access the inventory vector
+like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+ inventory = monster.InventoryAsNumpy()
+ # inventory is a numpy array of type np.dtype('uint8')
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+instead of
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+ inventory = []
+ for i in range(monster.InventoryLength()):
+ inventory.append(int(monster.Inventory(i)))
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Numpy is not a requirement. If numpy is not installed on your system,
+then attempting to access one of the `*asNumpy()` methods will result
+in a `NumpyRequiredForThisFeature` exception.
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Python, though you could use the C++ parser through SWIG or ctypes. Please
+see the C++ documentation for more on text parsing.
+
+<br>
diff --git a/docs/source/README_TO_GENERATE_DOCS.md b/docs/source/README_TO_GENERATE_DOCS.md
new file mode 100644
index 0000000..5df0b6a
--- /dev/null
+++ b/docs/source/README_TO_GENERATE_DOCS.md
@@ -0,0 +1,32 @@
+## Prerequisites
+
+To generate the docs for FlatBuffers from the source files, you
+will first need to install two programs.
+
+1. You will need to install `doxygen`. See
+ [Download Doxygen](http://www.stack.nl/~dimitri/doxygen/download.html).
+
+2. You will need to install `doxypypy` to format python comments appropriately.
+ Install it from [here](https://github.com/Feneric/doxypypy).
+
+*Note: You will need both `doxygen` and `doxypypy` to be in your
+[PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable.*
+
+After you have both of those files installed and in your path, you need to
+set up the `py_filter` to invoke `doxypypy` from `doxygen`.
+
+Follow the steps
+[here](https://github.com/Feneric/doxypypy#invoking-doxypypy-from-doxygen).
+
+## Generating Docs
+
+Run the following commands to generate the docs:
+
+`cd flatbuffers/docs/source`
+`doxygen`
+
+The output is placed in `flatbuffers/docs/html`.
+
+*Note: The Go API Reference code must be generated ahead of time. For
+instructions on how to regenerated this file, please read the comments
+in `GoApi.md`.*
diff --git a/docs/source/RustUsage.md b/docs/source/RustUsage.md
new file mode 100644
index 0000000..6819117
--- /dev/null
+++ b/docs/source/RustUsage.md
@@ -0,0 +1,174 @@
+Use in Rust {#flatbuffers_guide_use_rust}
+==========
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Rust, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide
+to general FlatBuffers usage in all of the supported languages (including Rust).
+This page is designed to cover the nuances of FlatBuffers usage, specific to
+Rust.
+
+#### Prerequisites
+
+This page assumes you have written a FlatBuffers schema and compiled it
+with the Schema Compiler. If you have not, please see
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
+and [Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+Assuming you wrote a schema, say `mygame.fbs` (though the extension doesn't
+matter), you've generated a Rust file called `mygame_generated.rs` using the
+compiler (e.g. `flatc --rust mygame.fbs` or via helpers listed in "Useful
+tools created by others" section bellow), you can now start using this in
+your program by including the file. As noted, this header relies on the crate
+`flatbuffers`, which should be in your include `Cargo.toml`.
+
+## FlatBuffers Rust library code location
+
+The code for the FlatBuffers Rust library can be found at
+`flatbuffers/rust`. You can browse the library code on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/rust).
+
+## Testing the FlatBuffers Rust library
+
+The code to test the Rust library can be found at `flatbuffers/tests/rust_usage_test`.
+The test code itself is located in
+[integration_test.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/tests/integration_test.rs)
+
+This test file requires `flatc` to be present. To review how to build the project,
+please read the [Building](@ref flatbuffers_guide_building) documenation.
+
+To run the tests, execute `RustTest.sh` from the `flatbuffers/tests` directory.
+For example, on [Linux](https://en.wikipedia.org/wiki/Linux), you would simply
+run: `cd tests && ./RustTest.sh`.
+
+*Note: The shell script requires [Rust](https://www.rust-lang.org) to
+be installed.*
+
+## Using the FlatBuffers Rust library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Rust.*
+
+FlatBuffers supports both reading and writing FlatBuffers in Rust.
+
+To use FlatBuffers in your code, first generate the Rust modules from your
+schema with the `--rust` option to `flatc`. Then you can import both FlatBuffers
+and the generated code to read or write FlatBuffers.
+
+For example, here is how you would read a FlatBuffer binary file in Rust:
+First, include the library and generated code. Then read the file into
+a `u8` vector, which you pass, as a byte slice, to `get_root_as_monster()`.
+
+This full example program is available in the Rust test suite:
+[monster_example.rs](https://github.com/google/flatbuffers/blob/master/tests/rust_usage_test/bin/monster_example.rs)
+
+It can be run by `cd`ing to the `rust_usage_test` directory and executing: `cargo run monster_example`.
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
+ extern crate flatbuffers;
+
+ #[allow(dead_code, unused_imports)]
+ #[path = "../../monster_test_generated.rs"]
+ mod monster_test_generated;
+ pub use monster_test_generated::my_game;
+
+ use std::io::Read;
+
+ fn main() {
+ let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap();
+ let mut buf = Vec::new();
+ f.read_to_end(&mut buf).expect("file reading failed");
+
+ let monster = my_game::example::get_root_as_monster(&buf[..]);
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`monster` is of type `Monster`, and points to somewhere *inside* your
+buffer (root object pointers are not the same as `buffer_pointer` !).
+If you look in your generated header, you'll see it has
+convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
+ println!("{}", monster.hp()); // `80`
+ println!("{}", monster.mana()); // default value of `150`
+ println!("{:?}", monster.name()); // Some("MyMonster")
+ }
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*Note: That we never stored a `mana` value, so it will return the default.*
+
+## Direct memory access
+
+As you can see from the above examples, all elements in a buffer are
+accessed through generated accessors. This is because everything is
+stored in little endian format on all platforms (the accessor
+performs a swap operation on big endian machines), and also because
+the layout of things is generally not known to the user.
+
+For structs, layout is deterministic and guaranteed to be the same
+across platforms (scalars are aligned to their
+own size, and structs themselves to their largest member), and you
+are allowed to access this memory directly by using `safe_slice` and
+on the reference to a struct, or even an array of structs.
+
+To compute offsets to sub-elements of a struct, make sure they
+are structs themselves, as then you can use the pointers to
+figure out the offset without having to hardcode it. This is
+handy for use of arrays of structs with calls like `glVertexAttribPointer`
+in OpenGL or similar APIs.
+
+It is important to note is that structs are still little endian on all
+machines, so only use tricks like this if you can guarantee you're not
+shipping on a big endian machine (using an `#[cfg(target_endian = "little")]`
+attribute would be wise).
+
+The special function `safe_slice` is implemented on Vector objects that are
+represented in memory the same way as they are represented on the wire. This
+function is always available on vectors of struct, bool, u8, and i8. It is
+conditionally-compiled on little-endian systems for all the remaining scalar
+types.
+
+The FlatBufferBuilder function `create_vector_direct` is implemented for all
+types that are endian-safe to write with a `memcpy`. It is the write-equivalent
+of `safe_slice`.
+
+## Access of untrusted buffers
+
+The generated accessor functions access fields over offsets, which is
+very quick. These offsets are used to index into Rust slices, so they are
+bounds-checked by the Rust runtime. However, our Rust implementation may
+change: we may convert access functions to use direct pointer dereferencing, to
+improve lookup speed. As a result, users should not rely on the aforementioned
+bounds-checking behavior.
+
+When you're processing large amounts of data from a source you know (e.g.
+your own generated data on disk), this is acceptable, but when reading
+data from the network that can potentially have been modified by an
+attacker, this is undesirable.
+
+The C++ port provides a buffer verifier. At this time, Rust does not. Rust may
+provide a verifier in a future version. In the meantime, Rust users can access
+the buffer verifier generated by the C++ port through a foreign function
+interface (FFI).
+
+## Threading
+
+Reading a FlatBuffer does not touch any memory outside the original buffer,
+and is entirely read-only (all immutable), so is safe to access from multiple
+threads even without synchronisation primitives.
+
+Creating a FlatBuffer is not thread safe. All state related to building
+a FlatBuffer is contained in a FlatBufferBuilder instance, and no memory
+outside of it is touched. To make this thread safe, either do not
+share instances of FlatBufferBuilder between threads (recommended), or
+manually wrap it in synchronisation primitives. There's no automatic way to
+accomplish this, by design, as we feel multithreaded construction
+of a single buffer will be rare, and synchronisation overhead would be costly.
+
+## Useful tools created by others
+
+* [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler
+(flatc) as API for transparent `.fbs` to `.rs` code-generation via Cargo
+build scripts integration.
+
+<br>
diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md
new file mode 100644
index 0000000..403aebb
--- /dev/null
+++ b/docs/source/Schemas.md
@@ -0,0 +1,629 @@
+Writing a schema {#flatbuffers_guide_writing_schema}
+================
+
+The syntax of the schema language (aka IDL, [Interface Definition Language][])
+should look quite familiar to users of any of the C family of
+languages, and also to users of other IDLs. Let's look at an example
+first:
+
+ // example IDL file
+
+ namespace MyGame;
+
+ attribute "priority";
+
+ enum Color : byte { Red = 1, Green, Blue }
+
+ union Any { Monster, Weapon, Pickup }
+
+ struct Vec3 {
+ x:float;
+ y:float;
+ z:float;
+ }
+
+ table Monster {
+ pos:Vec3;
+ mana:short = 150;
+ hp:short = 100;
+ name:string;
+ friendly:bool = false (deprecated, priority: 1);
+ inventory:[ubyte];
+ color:Color = Blue;
+ test:Any;
+ }
+
+ root_type Monster;
+
+(`Weapon` & `Pickup` not defined as part of this example).
+
+### Tables
+
+Tables are the main way of defining objects in FlatBuffers, and consist
+of a name (here `Monster`) and a list of fields. Each field has a name,
+a type, and optionally a default value (if omitted, it defaults to `0` /
+`NULL`).
+
+Each field is optional: It does not have to appear in the wire
+representation, and you can choose to omit fields for each individual
+object. As a result, you have the flexibility to add fields without fear of
+bloating your data. This design is also FlatBuffer's mechanism for forward
+and backwards compatibility. Note that:
+
+- You can add new fields in the schema ONLY at the end of a table
+ definition. Older data will still
+ read correctly, and give you the default value when read. Older code
+ will simply ignore the new field.
+ If you want to have flexibility to use any order for fields in your
+ schema, you can manually assign ids (much like Protocol Buffers),
+ see the `id` attribute below.
+
+- You cannot delete fields you don't use anymore from the schema,
+ but you can simply
+ stop writing them into your data for almost the same effect.
+ Additionally you can mark them as `deprecated` as in the example
+ above, which will prevent the generation of accessors in the
+ generated C++, as a way to enforce the field not being used any more.
+ (careful: this may break code!).
+
+- You may change field names and table names, if you're ok with your
+ code breaking until you've renamed them there too.
+
+See "Schema evolution examples" below for more on this
+topic.
+
+### Structs
+
+Similar to a table, only now none of the fields are optional (so no defaults
+either), and fields may not be added or be deprecated. Structs may only contain
+scalars or other structs. Use this for
+simple objects where you are very sure no changes will ever be made
+(as quite clear in the example `Vec3`). Structs use less memory than
+tables and are even faster to access (they are always stored in-line in their
+parent object, and use no virtual table).
+
+### Types
+
+Built-in scalar types are
+
+- 8 bit: `byte` (`int8`), `ubyte` (`uint8`), `bool`
+
+- 16 bit: `short` (`int16`), `ushort` (`uint16`)
+
+- 32 bit: `int` (`int32`), `uint` (`uint32`), `float` (`float32`)
+
+- 64 bit: `long` (`int64`), `ulong` (`uint64`), `double` (`float64`)
+
+The type names in parentheses are alias names such that for example
+`uint8` can be used in place of `ubyte`, and `int32` can be used in
+place of `int` without affecting code generation.
+
+Built-in non-scalar types:
+
+- Vector of any other type (denoted with `[type]`). Nesting vectors
+ is not supported, instead you can wrap the inner vector in a table.
+
+- `string`, which may only hold UTF-8 or 7-bit ASCII. For other text encodings
+ or general binary data use vectors (`[byte]` or `[ubyte]`) instead.
+
+- References to other tables or structs, enums or unions (see
+ below).
+
+You can't change types of fields once they're used, with the exception
+of same-size data where a `reinterpret_cast` would give you a desirable result,
+e.g. you could change a `uint` to an `int` if no values in current data use the
+high bit yet.
+
+### Arrays
+
+Arrays are a convenience short-hand for a fixed-length collection of elements.
+Arrays can be used to replace the following schema:
+
+ struct Vec3 {
+ x:float;
+ y:float;
+ z:float;
+ }
+
+with the following schema:
+
+ struct Vec3 {
+ v:[float:3];
+ }
+
+Both representations are binary equivalent.
+
+Arrays are currently only supported in a `struct`.
+
+### (Default) Values
+
+Values are a sequence of digits. Values may be optionally followed by a decimal
+point (`.`) and more digits, for float constants, or optionally prefixed by
+a `-`. Floats may also be in scientific notation; optionally ending with an `e`
+or `E`, followed by a `+` or `-` and more digits.
+
+Only scalar values can have defaults, non-scalar (string/vector/table) fields
+default to `NULL` when not present.
+
+You generally do not want to change default values after they're initially
+defined. Fields that have the default value are not actually stored in the
+serialized data (see also Gotchas below) but are generated in code,
+so when you change the default, you'd
+now get a different value than from code generated from an older version of
+the schema. There are situations, however, where this may be
+desirable, especially if you can ensure a simultaneous rebuild of
+all code.
+
+### Enums
+
+Define a sequence of named constants, each with a given value, or
+increasing by one from the previous one. The default first value
+is `0`. As you can see in the enum declaration, you specify the underlying
+integral type of the enum with `:` (in this case `byte`), which then determines
+the type of any fields declared with this enum type.
+
+Only integer types are allowed, i.e. `byte`, `ubyte`, `short` `ushort`, `int`,
+`uint`, `long` and `ulong`.
+
+Typically, enum values should only ever be added, never removed (there is no
+deprecation for enums). This requires code to handle forwards compatibility
+itself, by handling unknown enum values.
+
+### Unions
+
+Unions share a lot of properties with enums, but instead of new names
+for constants, you use names of tables. You can then declare
+a union field, which can hold a reference to any of those types, and
+additionally a field with the suffix `_type` is generated that holds
+the corresponding enum value, allowing you to know which type to cast
+to at runtime.
+
+It's possible to give an alias name to a type union. This way a type can even be
+used to mean different things depending on the name used:
+
+ table PointPosition { x:uint; y:uint; }
+ table MarkerPosition {}
+ union Position {
+ Start:MarkerPosition,
+ Point:PointPosition,
+ Finish:MarkerPosition
+ }
+
+Unions contain a special `NONE` marker to denote that no value is stored so that
+name cannot be used as an alias.
+
+Unions are a good way to be able to send multiple message types as a FlatBuffer.
+Note that because a union field is really two fields, it must always be
+part of a table, it cannot be the root of a FlatBuffer by itself.
+
+If you have a need to distinguish between different FlatBuffers in a more
+open-ended way, for example for use as files, see the file identification
+feature below.
+
+There is an experimental support only in C++ for a vector of unions
+(and types). In the example IDL file above, use [Any] to add a
+vector of Any to Monster table.
+
+### Namespaces
+
+These will generate the corresponding namespace in C++ for all helper
+code, and packages in Java. You can use `.` to specify nested namespaces /
+packages.
+
+### Includes
+
+You can include other schemas files in your current one, e.g.:
+
+ include "mydefinitions.fbs";
+
+This makes it easier to refer to types defined elsewhere. `include`
+automatically ensures each file is parsed just once, even when referred to
+more than once.
+
+When using the `flatc` compiler to generate code for schema definitions,
+only definitions in the current file will be generated, not those from the
+included files (those you still generate separately).
+
+### Root type
+
+This declares what you consider to be the root table (or struct) of the
+serialized data. This is particularly important for parsing JSON data,
+which doesn't include object type information.
+
+### File identification and extension
+
+Typically, a FlatBuffer binary buffer is not self-describing, i.e. it
+needs you to know its schema to parse it correctly. But if you
+want to use a FlatBuffer as a file format, it would be convenient
+to be able to have a "magic number" in there, like most file formats
+have, to be able to do a sanity check to see if you're reading the
+kind of file you're expecting.
+
+Now, you can always prefix a FlatBuffer with your own file header,
+but FlatBuffers has a built-in way to add an identifier to a
+FlatBuffer that takes up minimal space, and keeps the buffer
+compatible with buffers that don't have such an identifier.
+
+You can specify in a schema, similar to `root_type`, that you intend
+for this type of FlatBuffer to be used as a file format:
+
+ file_identifier "MYFI";
+
+Identifiers must always be exactly 4 characters long. These 4 characters
+will end up as bytes at offsets 4-7 (inclusive) in the buffer.
+
+For any schema that has such an identifier, `flatc` will automatically
+add the identifier to any binaries it generates (with `-b`),
+and generated calls like `FinishMonsterBuffer` also add the identifier.
+If you have specified an identifier and wish to generate a buffer
+without one, you can always still do so by calling
+`FlatBufferBuilder::Finish` explicitly.
+
+After loading a buffer, you can use a call like
+`MonsterBufferHasIdentifier` to check if the identifier is present.
+
+Note that this is best for open-ended uses such as files. If you simply wanted
+to send one of a set of possible messages over a network for example, you'd
+be better off with a union.
+
+Additionally, by default `flatc` will output binary files as `.bin`.
+This declaration in the schema will change that to whatever you want:
+
+ file_extension "ext";
+
+### RPC interface declarations
+
+You can declare RPC calls in a schema, that define a set of functions
+that take a FlatBuffer as an argument (the request) and return a FlatBuffer
+as the response (both of which must be table types):
+
+ rpc_service MonsterStorage {
+ Store(Monster):StoreResponse;
+ Retrieve(MonsterId):Monster;
+ }
+
+What code this produces and how it is used depends on language and RPC system
+used, there is preliminary support for GRPC through the `--grpc` code generator,
+see `grpc/tests` for an example.
+
+### Comments & documentation
+
+May be written as in most C-based languages. Additionally, a triple
+comment (`///`) on a line by itself signals that a comment is documentation
+for whatever is declared on the line after it
+(table/struct/field/enum/union/element), and the comment is output
+in the corresponding C++ code. Multiple such lines per item are allowed.
+
+### Attributes
+
+Attributes may be attached to a declaration, behind a field, or after
+the name of a table/struct/enum/union. These may either have a value or
+not. Some attributes like `deprecated` are understood by the compiler;
+user defined ones need to be declared with the attribute declaration
+(like `priority` in the example above), and are
+available to query if you parse the schema at runtime.
+This is useful if you write your own code generators/editors etc., and
+you wish to add additional information specific to your tool (such as a
+help text).
+
+Current understood attributes:
+
+- `id: n` (on a table field): manually set the field identifier to `n`.
+ If you use this attribute, you must use it on ALL fields of this table,
+ and the numbers must be a contiguous range from 0 onwards.
+ Additionally, since a union type effectively adds two fields, its
+ id must be that of the second field (the first field is the type
+ field and not explicitly declared in the schema).
+ For example, if the last field before the union field had id 6,
+ the union field should have id 8, and the unions type field will
+ implicitly be 7.
+ IDs allow the fields to be placed in any order in the schema.
+ When a new field is added to the schema it must use the next available ID.
+- `deprecated` (on a field): do not generate accessors for this field
+ anymore, code should stop using this data. Old data may still contain this
+ field, but it won't be accessible anymore by newer code. Note that if you
+ deprecate a field that was previous required, old code may fail to validate
+ new data (when using the optional verifier).
+- `required` (on a non-scalar table field): this field must always be set.
+ By default, all fields are optional, i.e. may be left out. This is
+ desirable, as it helps with forwards/backwards compatibility, and
+ flexibility of data structures. It is also a burden on the reading code,
+ since for non-scalar fields it requires you to check against NULL and
+ take appropriate action. By specifying this field, you force code that
+ constructs FlatBuffers to ensure this field is initialized, so the reading
+ code may access it directly, without checking for NULL. If the constructing
+ code does not initialize this field, they will get an assert, and also
+ the verifier will fail on buffers that have missing required fields. Note
+ that if you add this attribute to an existing field, this will only be
+ valid if existing data always contains this field / existing code always
+ writes this field.
+- `force_align: size` (on a struct): force the alignment of this struct
+ to be something higher than what it is naturally aligned to. Causes
+ these structs to be aligned to that amount inside a buffer, IF that
+ buffer is allocated with that alignment (which is not necessarily
+ the case for buffers accessed directly inside a `FlatBufferBuilder`).
+ Note: currently not guaranteed to have an effect when used with
+ `--object-api`, since that may allocate objects at alignments less than
+ what you specify with `force_align`.
+- `bit_flags` (on an unsigned enum): the values of this field indicate bits,
+ meaning that any unsigned value N specified in the schema will end up
+ representing 1<<N, or if you don't specify values at all, you'll get
+ the sequence 1, 2, 4, 8, ...
+- `nested_flatbuffer: "table_name"` (on a field): this indicates that the field
+ (which must be a vector of ubyte) contains flatbuffer data, for which the
+ root type is given by `table_name`. The generated code will then produce
+ a convenient accessor for the nested FlatBuffer.
+- `flexbuffer` (on a field): this indicates that the field
+ (which must be a vector of ubyte) contains flexbuffer data. The generated
+ code will then produce a convenient accessor for the FlexBuffer root.
+- `key` (on a field): this field is meant to be used as a key when sorting
+ a vector of the type of table it sits in. Can be used for in-place
+ binary search.
+- `hash` (on a field). This is an (un)signed 32/64 bit integer field, whose
+ value during JSON parsing is allowed to be a string, which will then be
+ stored as its hash. The value of attribute is the hashing algorithm to
+ use, one of `fnv1_32` `fnv1_64` `fnv1a_32` `fnv1a_64`.
+- `original_order` (on a table): since elements in a table do not need
+ to be stored in any particular order, they are often optimized for
+ space by sorting them to size. This attribute stops that from happening.
+ There should generally not be any reason to use this flag.
+- 'native_*'. Several attributes have been added to support the [C++ object
+ Based API](@ref flatbuffers_cpp_object_based_api). All such attributes
+ are prefixed with the term "native_".
+
+
+## JSON Parsing
+
+The same parser that parses the schema declarations above is also able
+to parse JSON objects that conform to this schema. So, unlike other JSON
+parsers, this parser is strongly typed, and parses directly into a FlatBuffer
+(see the compiler documentation on how to do this from the command line, or
+the C++ documentation on how to do this at runtime).
+
+Besides needing a schema, there are a few other changes to how it parses
+JSON:
+
+- It accepts field names with and without quotes, like many JSON parsers
+ already do. It outputs them without quotes as well, though can be made
+ to output them using the `strict_json` flag.
+- If a field has an enum type, the parser will recognize symbolic enum
+ values (with or without quotes) instead of numbers, e.g.
+ `field: EnumVal`. If a field is of integral type, you can still use
+ symbolic names, but values need to be prefixed with their type and
+ need to be quoted, e.g. `field: "Enum.EnumVal"`. For enums
+ representing flags, you may place multiple inside a string
+ separated by spaces to OR them, e.g.
+ `field: "EnumVal1 EnumVal2"` or `field: "Enum.EnumVal1 Enum.EnumVal2"`.
+- Similarly, for unions, these need to specified with two fields much like
+ you do when serializing from code. E.g. for a field `foo`, you must
+ add a field `foo_type: FooOne` right before the `foo` field, where
+ `FooOne` would be the table out of the union you want to use.
+- A field that has the value `null` (e.g. `field: null`) is intended to
+ have the default value for that field (thus has the same effect as if
+ that field wasn't specified at all).
+- It has some built in conversion functions, so you can write for example
+ `rad(180)` where ever you'd normally write `3.14159`.
+ Currently supports the following functions: `rad`, `deg`, `cos`, `sin`,
+ `tan`, `acos`, `asin`, `atan`.
+
+When parsing JSON, it recognizes the following escape codes in strings:
+
+- `\n` - linefeed.
+- `\t` - tab.
+- `\r` - carriage return.
+- `\b` - backspace.
+- `\f` - form feed.
+- `\"` - double quote.
+- `\\` - backslash.
+- `\/` - forward slash.
+- `\uXXXX` - 16-bit unicode code point, converted to the equivalent UTF-8
+ representation.
+- `\xXX` - 8-bit binary hexadecimal number XX. This is the only one that is
+ not in the JSON spec (see http://json.org/), but is needed to be able to
+ encode arbitrary binary in strings to text and back without losing
+ information (e.g. the byte 0xFF can't be represented in standard JSON).
+
+It also generates these escape codes back again when generating JSON from a
+binary representation.
+
+When parsing numbers, the parser is more flexible than JSON.
+A format of numeric literals is more close to the C/C++.
+According to the [grammar](@ref flatbuffers_grammar), it accepts the following
+numerical literals:
+
+- An integer literal can have any number of leading zero `0` digits.
+ Unlike C/C++, the parser ignores a leading zero, not interpreting it as the
+ beginning of the octal number.
+ The numbers `[081, -00094]` are equal to `[81, -94]` decimal integers.
+- The parser accepts unsigned and signed hexadecimal integer numbers.
+ For example: `[0x123, +0x45, -0x67]` are equal to `[291, 69, -103]` decimals.
+- The format of float-point numbers is fully compatible with C/C++ format.
+ If a modern C++ compiler is used the parser accepts hexadecimal and special
+ floating-point literals as well:
+ `[-1.0, 2., .3e0, 3.e4, 0x21.34p-5, -inf, nan]`.
+
+ The following conventions for floating-point numbers are used:
+ - The exponent suffix of hexadecimal floating-point number is mandatory.
+ - Parsed `NaN` converted to unsigned IEEE-754 `quiet-NaN` value.
+
+ Extended floating-point support was tested with:
+ - x64 Windows: `MSVC2015` and higher.
+ - x64 Linux: `LLVM 6.0`, `GCC 4.9` and higher.
+
+ For details, see [Use in C++](@ref flatbuffers_guide_use_cpp) section.
+
+- For compatibility with a JSON lint tool all numeric literals of scalar
+ fields can be wrapped to quoted string:
+ `"1", "2.0", "0x48A", "0x0C.0Ep-1", "-inf", "true"`.
+
+## Guidelines
+
+### Efficiency
+
+FlatBuffers is all about efficiency, but to realize that efficiency you
+require an efficient schema. There are usually multiple choices on
+how to represent data that have vastly different size characteristics.
+
+It is very common nowadays to represent any kind of data as dictionaries
+(as in e.g. JSON), because of its flexibility and extensibility. While
+it is possible to emulate this in FlatBuffers (as a vector
+of tables with key and value(s)), this is a bad match for a strongly
+typed system like FlatBuffers, leading to relatively large binaries.
+FlatBuffer tables are more flexible than classes/structs in most systems,
+since having a large number of fields only few of which are actually
+used is still efficient. You should thus try to organize your data
+as much as possible such that you can use tables where you might be
+tempted to use a dictionary.
+
+Similarly, strings as values should only be used when they are
+truely open-ended. If you can, always use an enum instead.
+
+FlatBuffers doesn't have inheritance, so the way to represent a set
+of related data structures is a union. Unions do have a cost however,
+so an alternative to a union is to have a single table that has
+all the fields of all the data structures you are trying to
+represent, if they are relatively similar / share many fields.
+Again, this is efficient because optional fields are cheap.
+
+FlatBuffers supports the full range of integer sizes, so try to pick
+the smallest size needed, rather than defaulting to int/long.
+
+Remember that you can share data (refer to the same string/table
+within a buffer), so factoring out repeating data into its own
+data structure may be worth it.
+
+### Style guide
+
+Identifiers in a schema are meant to translate to many different programming
+languages, so using the style of your "main" language is generally a bad idea.
+
+For this reason, below is a suggested style guide to adhere to, to keep schemas
+consistent for interoperation regardless of the target language.
+
+Where possible, the code generators for specific languages will generate
+identifiers that adhere to the language style, based on the schema identifiers.
+
+- Table, struct, enum and rpc names (types): UpperCamelCase.
+- Table and struct field names: snake_case. This is translated to lowerCamelCase
+ automatically for some languages, e.g. Java.
+- Enum values: UpperCamelCase.
+- namespaces: UpperCamelCase.
+
+Formatting (this is less important, but still worth adhering to):
+
+- Opening brace: on the same line as the start of the declaration.
+- Spacing: Indent by 2 spaces. None around `:` for types, on both sides for `=`.
+
+For an example, see the schema at the top of this file.
+
+## Gotchas
+
+### Schemas and version control
+
+FlatBuffers relies on new field declarations being added at the end, and earlier
+declarations to not be removed, but be marked deprecated when needed. We think
+this is an improvement over the manual number assignment that happens in
+Protocol Buffers (and which is still an option using the `id` attribute
+mentioned above).
+
+One place where this is possibly problematic however is source control. If user
+A adds a field, generates new binary data with this new schema, then tries to
+commit both to source control after user B already committed a new field also,
+and just auto-merges the schema, the binary files are now invalid compared to
+the new schema.
+
+The solution of course is that you should not be generating binary data before
+your schema changes have been committed, ensuring consistency with the rest of
+the world. If this is not practical for you, use explicit field ids, which
+should always generate a merge conflict if two people try to allocate the same
+id.
+
+### Schema evolution examples
+
+Some examples to clarify what happens as you change a schema:
+
+If we have the following original schema:
+
+ table { a:int; b:int; }
+
+And we extend it:
+
+ table { a:int; b:int; c:int; }
+
+This is ok. Code compiled with the old schema reading data generated with the
+new one will simply ignore the presence of the new field. Code compiled with the
+new schema reading old data will get the default value for `c` (which is 0
+in this case, since it is not specified).
+
+ table { a:int (deprecated); b:int; }
+
+This is also ok. Code compiled with the old schema reading newer data will now
+always get the default value for `a` since it is not present. Code compiled
+with the new schema now cannot read nor write `a` anymore (any existing code
+that tries to do so will result in compile errors), but can still read
+old data (they will ignore the field).
+
+ table { c:int a:int; b:int; }
+
+This is NOT ok, as this makes the schemas incompatible. Old code reading newer
+data will interpret `c` as if it was `a`, and new code reading old data
+accessing `a` will instead receive `b`.
+
+ table { c:int (id: 2); a:int (id: 0); b:int (id: 1); }
+
+This is ok. If your intent was to order/group fields in a way that makes sense
+semantically, you can do so using explicit id assignment. Now we are compatible
+with the original schema, and the fields can be ordered in any way, as long as
+we keep the sequence of ids.
+
+ table { b:int; }
+
+NOT ok. We can only remove a field by deprecation, regardless of wether we use
+explicit ids or not.
+
+ table { a:uint; b:uint; }
+
+This is MAYBE ok, and only in the case where the type change is the same size,
+like here. If old data never contained any negative numbers, this will be
+safe to do.
+
+ table { a:int = 1; b:int = 2; }
+
+Generally NOT ok. Any older data written that had 0 values were not written to
+the buffer, and rely on the default value to be recreated. These will now have
+those values appear to `1` and `2` instead. There may be cases in which this
+is ok, but care must be taken.
+
+ table { aa:int; bb:int; }
+
+Occasionally ok. You've renamed fields, which will break all code (and JSON
+files!) that use this schema, but as long as the change is obvious, this is not
+incompatible with the actual binary buffers, since those only ever address
+fields by id/offset.
+<br>
+
+### Testing whether a field is present in a table
+
+Most serialization formats (e.g. JSON or Protocol Buffers) make it very
+explicit in the format whether a field is present in an object or not,
+allowing you to use this as "extra" information.
+
+In FlatBuffers, this also holds for everything except scalar values.
+
+FlatBuffers by default will not write fields that are equal to the default
+value (for scalars), sometimes resulting in a significant space savings.
+
+However, this also means testing whether a field is "present" is somewhat
+meaningless, since it does not tell you if the field was actually written by
+calling `add_field` style calls, unless you're only interested in this
+information for non-default values.
+
+Some `FlatBufferBuilder` implementations have an option called `force_defaults`
+that circumvents this behavior, and writes fields even if they are equal to
+the default. You can then use `IsFieldPresent` to query this.
+
+Another option that works in all languages is to wrap a scalar field in a
+struct. This way it will return null if it is not present. The cool thing
+is that structs don't take up any more space than the scalar they represent.
+
+ [Interface Definition Language]: https://en.wikipedia.org/wiki/Interface_description_language
diff --git a/docs/source/Support.md b/docs/source/Support.md
new file mode 100644
index 0000000..c8ac7f7
--- /dev/null
+++ b/docs/source/Support.md
@@ -0,0 +1,46 @@
+Platform / Language / Feature support {#flatbuffers_support}
+=====================================
+
+FlatBuffers is actively being worked on, which means that certain platform /
+language / feature combinations may not be available yet.
+
+This page tries to track those issues, to make informed decisions easier.
+In general:
+
+ * Languages: language support beyond the ones created by the original
+ FlatBuffer authors typically depends on community contributions.
+ * Features: C++ was the first language supported, since our original
+ target was high performance game development. It thus has the richest
+ feature set, and is likely most robust. Other languages are catching up
+ however.
+ * Platforms: All language implementations are typically portable to most
+ platforms, unless where noted otherwise.
+
+NOTE: this table is a start, it needs to be extended.
+
+Feature | C++ | Java | C# | Go | Python | JS | TS | C | PHP | Dart | Lobster | Rust
+------------------------------ | ------ | ------ | ------ | ------ | ------ | --------- | --------- | ------ | --- | ------- | ------- | ----
+Codegen for all basic features | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | WiP | Yes | Yes | Yes
+JSON parsing | Yes | No | No | No | No | No | No | Yes | No | No | Yes | No
+Simple mutation | Yes | Yes | Yes | Yes | No | No | No | No | No | No | No | No
+Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No
+Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No
+Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes
+Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes
+Performance: | Superb | Great | Great | Great | Ok | ? | ? | Superb | ? | ? | Great | Superb
+Platform: Windows | VS2010 | Yes | Yes | ? | ? | ? | Yes | VS2010 | ? | Yes | Yes | Yes
+Platform: Linux | GCC282 | Yes | ? | Yes | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
+Platform: OS X | Xcode4 | ? | ? | ? | Yes | ? | Yes | Yes | ? | Yes | Yes | Yes
+Platform: Android | NDK10d | Yes | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
+Platform: iOS | ? | ? | ? | ? | ? | ? | ? | ? | ? | Flutter | Yes | ?
+Engine: Unity | ? | ? | Yes | ? | ? | ? | ? | ? | ? | ? | No | ?
+Primary authors (github) | aard* | aard* | ev*/js*| rw | rw | evanw/ev* | kr* | mik* | ch* | dnfield | aard* | rw
+
+ * aard = aardappel (previously: gwvo)
+ * ev = evolutional
+ * js = jonsimantov
+ * mik = mikkelfj
+ * ch = chobie
+ * kr = krojew
+
+<br>
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
new file mode 100644
index 0000000..e8d8519
--- /dev/null
+++ b/docs/source/Tutorial.md
@@ -0,0 +1,3219 @@
+Tutorial {#flatbuffers_guide_tutorial}
+========
+
+## Overview
+
+This tutorial provides a basic example of how to work with
+[FlatBuffers](@ref flatbuffers_overview). We will step through a simple example
+application, which shows you how to:
+
+ - Write a FlatBuffer `schema` file.
+ - Use the `flatc` FlatBuffer compiler.
+ - Parse [JSON](http://json.org) files that conform to a schema into
+ FlatBuffer binary files.
+ - Use the generated files in many of the supported languages (such as C++,
+ Java, and more.)
+
+During this example, imagine that you are creating a game where the main
+character, the hero of the story, needs to slay some `orc`s. We will walk
+through each step necessary to create this monster type using FlatBuffers.
+
+Please select your desired language for our quest:
+\htmlonly
+<form>
+ <input type="radio" name="language" value="cpp" checked="checked">C++</input>
+ <input type="radio" name="language" value="java">Java</input>
+ <input type="radio" name="language" value="kotlin">Kotlin</input>
+ <input type="radio" name="language" value="csharp">C#</input>
+ <input type="radio" name="language" value="go">Go</input>
+ <input type="radio" name="language" value="python">Python</input>
+ <input type="radio" name="language" value="javascript">JavaScript</input>
+ <input type="radio" name="language" value="typescript">TypeScript</input>
+ <input type="radio" name="language" value="php">PHP</input>
+ <input type="radio" name="language" value="c">C</input>
+ <input type="radio" name="language" value="dart">Dart</input>
+ <input type="radio" name="language" value="lua">Lua</input>
+ <input type="radio" name="language" value="lobster">Lobster</input>
+ <input type="radio" name="language" value="rust">Rust</input>
+</form>
+\endhtmlonly
+
+\htmlonly
+<script>
+ /**
+ * Check if an HTML `class` attribute is in the language-specific format.
+ * @param {string} languageClass An HTML `class` attribute in the format
+ * 'language-{lang}', where {lang} is a programming language (e.g. 'cpp',
+ * 'java', 'go', etc.).
+ * @return {boolean} Returns `true` if `languageClass` was in the valid
+ * format, prefixed with 'language-'. Otherwise, it returns false.
+ */
+ function isProgrammingLanguageClassName(languageClass) {
+ if (languageClass && languageClass.substring(0, 9) == 'language-' &&
+ languageClass.length > 8) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Given a language-specific HTML `class` attribute, extract the language.
+ * @param {string} languageClass The string name of an HTML `class` attribute,
+ * in the format `language-{lang}`, where {lang} is a programming language
+ * (e.g. 'cpp', 'java', 'go', etc.).
+ * @return {string} Returns a string containing only the {lang} portion of
+ * the class name. If the input was invalid, then it returns `null`.
+ */
+ function extractProgrammingLanguageFromLanguageClass(languageClass) {
+ if (isProgrammingLanguageClassName(languageClass)) {
+ return languageClass.substring(9);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Hide every code snippet, except for the language that is selected.
+ */
+ function displayChosenLanguage() {
+ var selection = $('input:checked').val();
+
+ var htmlElements = document.getElementsByTagName('*');
+ for (var i = 0; i < htmlElements.length; i++) {
+ if (isProgrammingLanguageClassName(htmlElements[i].className)) {
+ if (extractProgrammingLanguageFromLanguageClass(
+ htmlElements[i].className).toLowerCase() != selection) {
+ htmlElements[i].style.display = 'none';
+ } else {
+ htmlElements[i].style.display = 'initial';
+ }
+ }
+ }
+ }
+
+ $( document ).ready(displayChosenLanguage);
+
+ $('input[type=radio]').on("click", displayChosenLanguage);
+</script>
+\endhtmlonly
+
+## Where to Find the Example Code
+
+Samples demonstating the concepts in this example are located in the source code
+package, under the `samples` directory. You can browse the samples on GitHub
+[here](https://github.com/google/flatbuffers/tree/master/samples).
+
+<div class="language-c">
+*Note: The above does not apply to C, instead [look here](https://github.com/dvidelabs/flatcc/tree/master/samples).*
+</div>
+
+For your chosen language, please cross-reference with:
+
+<div class="language-cpp">
+[sample_binary.cpp](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.cpp)
+</div>
+<div class="language-java">
+[SampleBinary.java](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.java)
+</div>
+<div class="language-kotlin">
+[SampleBinary.kt](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.kt)
+</div>
+<div class="language-csharp">
+[SampleBinary.cs](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.cs)
+</div>
+<div class="language-go">
+[sample_binary.go](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.go)
+</div>
+<div class="language-python">
+[sample_binary.py](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.py)
+</div>
+<div class="language-javascript">
+[samplebinary.js](https://github.com/google/flatbuffers/blob/master/samples/samplebinary.js)
+</div>
+<div class="language-typescript">
+<em>none yet</em>
+</div>
+<div class="language-php">
+[SampleBinary.php](https://github.com/google/flatbuffers/blob/master/samples/SampleBinary.php)
+</div>
+<div class="language-c">
+[monster.c](https://github.com/dvidelabs/flatcc/blob/master/samples/monster/monster.c)
+</div>
+<div class="language-dart">
+[example.dart](https://github.com/google/flatbuffers/blob/master/dart/example/example.dart)
+</div>
+<div class="language-lua">
+[sample_binary.lua](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.lua)
+</div>
+<div class="language-lobster">
+[sample_binary.lobster](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.lobster)
+</div>
+<div class="language-rust">
+[sample_binary.rs](https://github.com/google/flatbuffers/blob/master/samples/sample_binary.rs)
+</div>
+
+
+## Writing the Monsters' FlatBuffer Schema
+
+To start working with FlatBuffers, you first need to create a `schema` file,
+which defines the format for each data structure you wish to serialize. Here is
+the `schema` that defines the template for our monsters:
+
+~~~
+ // Example IDL file for our monster's schema.
+
+ namespace MyGame.Sample;
+
+ enum Color:byte { Red = 0, Green, Blue = 2 }
+
+ union Equipment { Weapon } // Optionally add more tables.
+
+ struct Vec3 {
+ x:float;
+ y:float;
+ z:float;
+ }
+
+ table Monster {
+ pos:Vec3; // Struct.
+ mana:short = 150;
+ hp:short = 100;
+ name:string;
+ friendly:bool = false (deprecated);
+ inventory:[ubyte]; // Vector of scalars.
+ color:Color = Blue; // Enum.
+ weapons:[Weapon]; // Vector of tables.
+ equipped:Equipment; // Union.
+ path:[Vec3]; // Vector of structs.
+ }
+
+ table Weapon {
+ name:string;
+ damage:short;
+ }
+
+ root_type Monster;
+~~~
+
+As you can see, the syntax for the `schema`
+[Interface Definition Language (IDL)](https://en.wikipedia.org/wiki/Interface_description_language)
+is similar to those of the C family of languages, and other IDL languages. Let's
+examine each part of this `schema` to determine what it does.
+
+The `schema` starts with a `namespace` declaration. This determines the
+corresponding package/namespace for the generated code. In our example, we have
+the `Sample` namespace inside of the `MyGame` namespace.
+
+Next, we have an `enum` definition. In this example, we have an `enum` of type
+`byte`, named `Color`. We have three values in this `enum`: `Red`, `Green`, and
+`Blue`. We specify `Red = 0` and `Blue = 2`, but we do not specify an explicit
+value for `Green`. Since the behavior of an `enum` is to increment if
+unspecified, `Green` will receive the implicit value of `1`.
+
+Following the `enum` is a `union`. The `union` in this example is not very
+useful, as it only contains the one `table` (named `Weapon`). If we had created
+multiple tables that we would want the `union` to be able to reference, we
+could add more elements to the `union Equipment`.
+
+After the `union` comes a `struct Vec3`, which represents a floating point
+vector with `3` dimensions. We use a `struct` here, over a `table`, because
+`struct`s are ideal for data structures that will not change, since they use
+less memory and have faster lookup.
+
+The `Monster` table is the main object in our FlatBuffer. This will be used as
+the template to store our `orc` monster. We specify some default values for
+fields, such as `mana:short = 150`. All unspecified fields will default to `0`
+or `NULL`. Another thing to note is the line
+`friendly:bool = false (deprecated);`. Since you cannot delete fields from a
+`table` (to support backwards compatability), you can set fields as
+`deprecated`, which will prevent the generation of accessors for this field in
+the generated code. Be careful when using `deprecated`, however, as it may break
+legacy code that used this accessor.
+
+The `Weapon` table is a sub-table used within our FlatBuffer. It is
+used twice: once within the `Monster` table and once within the `Equipment`
+enum. For our `Monster`, it is used to populate a `vector of tables` via the
+`weapons` field within our `Monster`. It is also the only table referenced by
+the `Equipment` union.
+
+The last part of the `schema` is the `root_type`. The root type declares what
+will be the root table for the serialized data. In our case, the root type is
+our `Monster` table.
+
+The scalar types can also use alias type names such as `int16` instead
+of `short` and `float32` instead of `float`. Thus we could also write
+the `Weapon` table as:
+
+ table Weapon {
+ name:string;
+ damage:int16;
+ }
+
+#### More Information About Schemas
+
+You can find a complete guide to writing `schema` files in the
+[Writing a schema](@ref flatbuffers_guide_writing_schema) section of the
+Programmer's Guide. You can also view the formal
+[Grammar of the schema language](@ref flatbuffers_grammar).
+
+## Compiling the Monsters' Schema
+
+After you have written the FlatBuffers schema, the next step is to compile it.
+
+If you have not already done so, please follow
+[these instructions](@ref flatbuffers_guide_building) to build `flatc`, the
+FlatBuffer compiler.
+
+Once `flatc` is built successfully, compile the schema for your language:
+
+<div class="language-c">
+*Note: If you're working in C, you need to use the separate project [FlatCC](https://github.com/dvidelabs/flatcc) which contains a schema compiler and runtime library in C for C.*
+<br>
+See [flatcc build instructions](https://github.com/dvidelabs/flatcc#building).
+<br>
+Please be aware of the difference between `flatc` and `flatcc` tools.
+<br>
+</div>
+
+<div class="language-cpp">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --cpp monster.fbs
+~~~
+</div>
+<div class="language-java">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --java monster.fbs
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --kotlin monster.fbs
+~~~
+</div>
+<div class="language-csharp">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --csharp monster.fbs
+~~~
+</div>
+<div class="language-go">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --go monster.fbs
+~~~
+</div>
+<div class="language-python">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --python monster.fbs
+~~~
+</div>
+<div class="language-javascript">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --js monster.fbs
+~~~
+</div>
+<div class="language-typescript">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --ts monster.fbs
+~~~
+</div>
+<div class="language-php">
+~~~{.sh}
+ cd flatbuffers/sample
+ ./../flatc --php monster.fbs
+~~~
+</div>
+<div class="language-c">
+~~~{.sh}
+ cd flatcc
+ mkdir -p build/tmp/samples/monster
+ bin/flatcc -a -o build/tmp/samples/monster samples/monster/monster.fbs
+ # or just
+ flatcc/samples/monster/build.sh
+~~~
+</div>
+<div class="language-dart">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --dart monster.fbs
+~~~
+</div>
+<div class="language-lua">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --lua monster.fbs
+~~~
+</div>
+<div class="language-lobster">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --lobster monster.fbs
+~~~
+</div>
+<div class="language-rust">
+~~~{.sh}
+ cd flatbuffers/samples
+ ./../flatc --rust monster.fbs
+~~~
+</div>
+
+For a more complete guide to using the `flatc` compiler, please read the
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
+section of the Programmer's Guide.
+
+## Reading and Writing Monster FlatBuffers
+
+Now that we have compiled the schema for our programming language, we can
+start creating some monsters and serializing/deserializing them from
+FlatBuffers.
+
+#### Creating and Writing Orc FlatBuffers
+
+The first step is to import/include the library, generated files, etc.
+
+<div class="language-cpp">
+~~~{.cpp}
+ #include "monster_generated.h" // This was generated by `flatc`.
+
+ using namespace MyGame::Sample; // Specified in the schema.
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ import MyGame.Sample.*; //The `flatc` generated files. (Monster, Vec3, etc.)
+
+ import com.google.flatbuffers.FlatBufferBuilder;
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kotlin}
+ import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.)
+
+ import com.google.flatbuffers.FlatBufferBuilder
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ using FlatBuffers;
+ using MyGame.Sample; // The `flatc` generated files. (Monster, Vec3, etc.)
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ import (
+ flatbuffers "github.com/google/flatbuffers/go"
+ sample "MyGame/Sample"
+ )
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ import flatbuffers
+
+ # Generated by `flatc`.
+ import MyGame.Sample.Color
+ import MyGame.Sample.Equipment
+ import MyGame.Sample.Monster
+ import MyGame.Sample.Vec3
+ import MyGame.Sample.Weapon
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // The following code is for JavaScript module loaders (e.g. Node.js). See
+ // below for a browser-based HTML/JavaScript example of including the library.
+ var flatbuffers = require('/js/flatbuffers').flatbuffers;
+ var MyGame = require('./monster_generated').MyGame; // Generated by `flatc`.
+
+ //--------------------------------------------------------------------------//
+
+ // The following code is for browser-based HTML/JavaScript. Use the above code
+ // for JavaScript module loaders (e.g. Node.js).
+ <script src="../js/flatbuffers.js"></script>
+ <script src="monster_generated.js"></script> // Generated by `flatc`.
+~~~
+</div>
+<div class="language-typescript">
+ // note: import flatbuffers with your desired import method
+
+ import { MyGame } from './monster_generated';
+</div>
+<div class="language-php">
+~~~{.php}
+ // It is recommended that your use PSR autoload when using FlatBuffers in PHP.
+ // Here is an example from `SampleBinary.php`:
+ function __autoload($class_name) {
+ // The last segment of the class name matches the file name.
+ $class = substr($class_name, strrpos($class_name, "\\") + 1);
+ $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root.
+
+ // Contains the `*.php` files for the FlatBuffers library and the `flatc` generated files.
+ $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")),
+ join(DIRECTORY_SEPARATOR, array($root_dir, "samples", "MyGame", "Sample")));
+ foreach ($paths as $path) {
+ $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
+ if (file_exists($file)) {
+ require($file);
+ break;
+ }
+ }
+ }
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ #include "monster_builder.h" // Generated by `flatcc`.
+
+ // Convenient namespace macro to manage long namespace prefix.
+ #undef ns
+ #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
+
+ // A helper to simplify creating vectors from C-arrays.
+ #define c_vec_len(V) (sizeof(V)/sizeof((V)[0]))
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+ // Generated by `flatc`.
+ import 'monster_my_game.sample_generated.dart' as myGame;
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- require the flatbuffers module
+ local flatbuffers = require("flatbuffers")
+
+ -- require the generated files from `flatc`.
+ local color = require("MyGame.Sample.Color")
+ local equipment = require("MyGame.Sample.Equipment")
+ local monster = require("MyGame.Sample.Monster")
+ local vec3 = require("MyGame.Sample.Vec3")
+ local weapon = require("MyGame.Sample.Weapon")
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ import from "../lobster/" // Where to find flatbuffers.lobster
+ import monster_generated
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // import the flatbuffers runtime library
+ extern crate flatbuffers;
+
+ // import the generated code
+ #[allow(dead_code, unused_imports)]
+ #[path = "./monster_generated.rs"]
+ mod monster_generated;
+ pub use monster_generated::my_game::sample::{get_root_as_monster,
+ Color, Equipment,
+ Monster, MonsterArgs,
+ Vec3,
+ Weapon, WeaponArgs};
+~~~
+</div>
+
+Now we are ready to start building some buffers. In order to start, we need
+to create an instance of the `FlatBufferBuilder`, which will contain the buffer
+as it grows. You can pass an initial size of the buffer (here 1024 bytes),
+which will grow automatically if needed:
+
+<div class="language-cpp">
+~~~{.cpp}
+ // Create a `FlatBufferBuilder`, which will be used to create our
+ // monsters' FlatBuffers.
+ flatbuffers::FlatBufferBuilder builder(1024);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ // Create a `FlatBufferBuilder`, which will be used to create our
+ // monsters' FlatBuffers.
+ FlatBufferBuilder builder = new FlatBufferBuilder(1024);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ // Create a `FlatBufferBuilder`, which will be used to create our
+ // monsters' FlatBuffers.
+ val builder = FlatBufferBuilder(1024)
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ // Create a `FlatBufferBuilder`, which will be used to create our
+ // monsters' FlatBuffers.
+ var builder = new FlatBufferBuilder(1024);
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // Create a `FlatBufferBuilder`, which will be used to create our
+ // monsters' FlatBuffers.
+ builder := flatbuffers.NewBuilder(1024)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ # Create a `FlatBufferBuilder`, which will be used to create our
+ # monsters' FlatBuffers.
+ builder = flatbuffers.Builder(1024)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // Create a `flatbuffer.Builder`, which will be used to create our
+ // monsters' FlatBuffers.
+ var builder = new flatbuffers.Builder(1024);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ // Create a `flatbuffer.Builder`, which will be used to create our
+ // monsters' FlatBuffers.
+ let builder = new flatbuffers.Builder(1024);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // Create a `FlatBufferBuilder`, which will be used to create our
+ // monsters' FlatBuffers.
+ $builder = new Google\FlatBuffers\FlatbufferBuilder(1024);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ flatcc_builder_t builder, *B;
+ B = &builder;
+ // Initialize the builder object.
+ flatcc_builder_init(B);
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // Create the fb.Builder object that will be used by our generated builders
+ // Note that if you are only planning to immediately get the byte array this builder would create,
+ // you can use the convenience method `toBytes()` on the generated builders.
+ // For example, you could do something like `new myGame.MonsterBuilder(...).toBytes()`
+ var builder = new fb.Builder(initialSize: 1024);
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- get access to the builder, providing an array of size 1024
+ local builder = flatbuffers.Builder(1024)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ // get access to the builder
+ let builder = flatbuffers_builder {}
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Build up a serialized buffer algorithmically.
+ // Initialize it with a capacity of 1024 bytes.
+ let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024);
+~~~
+</div>
+
+After creating the `builder`, we can start serializing our data. Before we make
+our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto weapon_one_name = builder.CreateString("Sword");
+ short weapon_one_damage = 3;
+
+ auto weapon_two_name = builder.CreateString("Axe");
+ short weapon_two_damage = 5;
+
+ // Use the `CreateWeapon` shortcut to create Weapons with all the fields set.
+ auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage);
+ auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ int weaponOneName = builder.createString("Sword")
+ short weaponOneDamage = 3;
+
+ int weaponTwoName = builder.createString("Axe");
+ short weaponTwoDamage = 5;
+
+ // Use the `createWeapon()` helper function to create the weapons, since we set every field.
+ int sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage);
+ int axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val weaponOneName = builder.createString("Sword")
+ val weaponOneDamage: Short = 3;
+
+ val weaponTwoName = builder.createString("Axe")
+ val weaponTwoDamage: Short = 5;
+
+ // Use the `createWeapon()` helper function to create the weapons, since we set every field.
+ val sword = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage)
+ val axe = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage)
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ var weaponOneName = builder.CreateString("Sword");
+ var weaponOneDamage = 3;
+
+ var weaponTwoName = builder.CreateString("Axe");
+ var weaponTwoDamage = 5;
+
+ // Use the `CreateWeapon()` helper function to create the weapons, since we set every field.
+ var sword = Weapon.CreateWeapon(builder, weaponOneName, (short)weaponOneDamage);
+ var axe = Weapon.CreateWeapon(builder, weaponTwoName, (short)weaponTwoDamage);
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ weaponOne := builder.CreateString("Sword")
+ weaponTwo := builder.CreateString("Axe")
+
+ // Create the first `Weapon` ("Sword").
+ sample.WeaponStart(builder)
+ sample.WeaponAddName(builder, weaponOne)
+ sample.WeaponAddDamage(builder, 3)
+ sword := sample.WeaponEnd(builder)
+
+ // Create the second `Weapon` ("Axe").
+ sample.WeaponStart(builder)
+ sample.WeaponAddName(builder, weaponTwo)
+ sample.WeaponAddDamage(builder, 5)
+ axe := sample.WeaponEnd(builder)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ weapon_one = builder.CreateString('Sword')
+ weapon_two = builder.CreateString('Axe')
+
+ # Create the first `Weapon` ('Sword').
+ MyGame.Sample.Weapon.WeaponStart(builder)
+ MyGame.Sample.Weapon.WeaponAddName(builder, weapon_one)
+ MyGame.Sample.Weapon.WeaponAddDamage(builder, 3)
+ sword = MyGame.Sample.Weapon.WeaponEnd(builder)
+
+ # Create the second `Weapon` ('Axe').
+ MyGame.Sample.Weapon.WeaponStart(builder)
+ MyGame.Sample.Weapon.WeaponAddName(builder, weapon_two)
+ MyGame.Sample.Weapon.WeaponAddDamage(builder, 5)
+ axe = MyGame.Sample.Weapon.WeaponEnd(builder)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var weaponOne = builder.createString('Sword');
+ var weaponTwo = builder.createString('Axe');
+
+ // Create the first `Weapon` ('Sword').
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponOne);
+ MyGame.Sample.Weapon.addDamage(builder, 3);
+ var sword = MyGame.Sample.Weapon.endWeapon(builder);
+
+ // Create the second `Weapon` ('Axe').
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponTwo);
+ MyGame.Sample.Weapon.addDamage(builder, 5);
+ var axe = MyGame.Sample.Weapon.endWeapon(builder);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.js}
+ let weaponOne = builder.createString('Sword');
+ let weaponTwo = builder.createString('Axe');
+
+ // Create the first `Weapon` ('Sword').
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponOne);
+ MyGame.Sample.Weapon.addDamage(builder, 3);
+ let sword = MyGame.Sample.Weapon.endWeapon(builder);
+
+ // Create the second `Weapon` ('Axe').
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponTwo);
+ MyGame.Sample.Weapon.addDamage(builder, 5);
+ let axe = MyGame.Sample.Weapon.endWeapon(builder);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // Create the `Weapon`s using the `createWeapon()` helper function.
+ $weapon_one_name = $builder->createString("Sword");
+ $sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one_name, 3);
+
+ $weapon_two_name = $builder->createString("Axe");
+ $axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two_name, 5);
+
+ // Create an array from the two `Weapon`s and pass it to the
+ // `CreateWeaponsVector()` method to create a FlatBuffer vector.
+ $weaps = array($sword, $axe);
+ $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ flatbuffers_string_ref_t weapon_one_name = flatbuffers_string_create_str(B, "Sword");
+ uint16_t weapon_one_damage = 3;
+
+ flatbuffers_string_ref_t weapon_two_name = flatbuffers_string_create_str(B, "Axe");
+ uint16_t weapon_two_damage = 5;
+
+ ns(Weapon_ref_t) sword = ns(Weapon_create(B, weapon_one_name, weapon_one_damage));
+ ns(Weapon_ref_t) axe = ns(Weapon_create(B, weapon_two_name, weapon_two_damage));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // The generated Builder classes work much like in other languages,
+ final int weaponOneName = builder.writeString("Sword");
+ final int weaponOneDamage = 3;
+
+ final int weaponTwoName = builder.writeString("Axe");
+ final int weaponTwoDamage = 5;
+
+ final swordBuilder = new myGame.WeaponBuilder(builder)
+ ..begin()
+ ..addNameOffset(weaponOneName)
+ ..addDamage(weaponOneDamage);
+ final int sword = swordBuilder.finish();
+
+ final axeBuilder = new myGame.WeaponBuilder(builder)
+ ..begin()
+ ..addNameOffset(weaponTwoName)
+ ..addDamage(weaponTwoDamage);
+ final int axe = axeBuilder.finish();
+
+
+
+ // The generated ObjectBuilder classes offer an easier to use alternative
+ // at the cost of requiring some additional reference allocations. If memory
+ // usage is critical, or if you'll be working with especially large messages
+ // or tables, you should prefer using the generated Builder classes.
+ // The following code would produce an identical buffer as above.
+ final String weaponOneName = "Sword";
+ final int weaponOneDamage = 3;
+
+ final String weaponTwoName = "Axe";
+ final int weaponTwoDamage = 5;
+
+ final myGame.WeaponBuilder sword = new myGame.WeaponObjectBuilder(
+ name: weaponOneName,
+ damage: weaponOneDamage,
+ );
+
+ final myGame.WeaponBuilder axe = new myGame.WeaponObjectBuilder(
+ name: weaponTwoName,
+ damage: weaponTwoDamage,
+ );
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local weaponOne = builder:CreateString("Sword")
+ local weaponTwo = builder:CreateString("Axe")
+
+ -- Create the first 'Weapon'
+ weapon.Start(builder)
+ weapon.AddName(builder, weaponOne)
+ weapon.AddDamage(builder, 3)
+ local sword = weapon.End(builder)
+
+ -- Create the second 'Weapon'
+ weapon.Start(builder)
+ weapon.AddName(builder, weaponTwo)
+ weapon.AddDamage(builder, 5)
+ local axe = weapon.End(builder)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let weapon_names = [ "Sword", "Axe" ]
+ let weapon_damages = [ 3, 5 ]
+
+ let weapon_offsets = map(weapon_names) name, i:
+ let ns = builder.CreateString(name)
+ MyGame_Sample_WeaponBuilder { b }
+ .start()
+ .add_name(ns)
+ .add_damage(weapon_damages[i])
+ .end()
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Serialize some weapons for the Monster: A 'sword' and an 'axe'.
+ let weapon_one_name = builder.create_string("Sword");
+ let weapon_two_name = builder.create_string("Axe");
+
+ // Use the `Weapon::create` shortcut to create Weapons with named field
+ // arguments.
+ let sword = Weapon::create(&mut builder, &WeaponArgs{
+ name: Some(weapon_one_name),
+ damage: 3,
+ });
+ let axe = Weapon::create(&mut builder, &WeaponArgs{
+ name: Some(weapon_two_name),
+ damage: 5,
+ });
+~~~
+</div>
+
+Now let's create our monster, the `orc`. For this `orc`, lets make him
+`red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him
+a large pool of hit points with `300`. We can give him a vector of weapons
+to choose from (our `Sword` and `Axe` from earlier). In this case, we will
+equip him with the `Axe`, since it is the most powerful of the two. Lastly,
+let's fill his inventory with some potential treasures that can be taken once he
+is defeated.
+
+Before we serialize a monster, we need to first serialize any objects that are
+contained there-in, i.e. we serialize the data tree using depth-first, pre-order
+traversal. This is generally easy to do on any tree structures.
+
+<div class="language-cpp">
+~~~{.cpp}
+ // Serialize a name for our monster, called "Orc".
+ auto name = builder.CreateString("Orc");
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ unsigned char treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto inventory = builder.CreateVector(treasure, 10);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ // Serialize a name for our monster, called "Orc".
+ int name = builder.createString("Orc");
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ byte[] treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ int inv = Monster.createInventoryVector(builder, treasure);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ // Serialize a name for our monster, called "Orc".
+ val name = builder.createString("Orc")
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ val inv = Monster.createInventoryVector(builder, treasure)
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ // Serialize a name for our monster, called "Orc".
+ var name = builder.CreateString("Orc");
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ // Note: Since we prepend the bytes, this loop iterates in reverse order.
+ Monster.StartInventoryVector(builder, 10);
+ for (int i = 9; i >= 0; i--)
+ {
+ builder.AddByte((byte)i);
+ }
+ var inv = builder.EndVector();
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // Serialize a name for our monster, called "Orc".
+ name := builder.CreateString("Orc")
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ // Note: Since we prepend the bytes, this loop iterates in reverse.
+ sample.MonsterStartInventoryVector(builder, 10)
+ for i := 9; i >= 0; i-- {
+ builder.PrependByte(byte(i))
+ }
+ inv := builder.EndVector(10)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ # Serialize a name for our monster, called "Orc".
+ name = builder.CreateString("Orc")
+
+ # Create a `vector` representing the inventory of the Orc. Each number
+ # could correspond to an item that can be claimed after he is slain.
+ # Note: Since we prepend the bytes, this loop iterates in reverse.
+ MyGame.Sample.Monster.MonsterStartInventoryVector(builder, 10)
+ for i in reversed(range(0, 10)):
+ builder.PrependByte(i)
+ inv = builder.EndVector(10)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // Serialize a name for our monster, called 'Orc'.
+ var name = builder.createString('Orc');
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ var treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ var inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.js}
+ // Serialize a name for our monster, called 'Orc'.
+ let name = builder.createString('Orc');
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ let treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ let inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // Serialize a name for our monster, called "Orc".
+ $name = $builder->createString("Orc");
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ $treasure = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Serialize a name for our monster, called "Orc".
+ // The _str suffix indicates the source is an ascii-z string.
+ flatbuffers_string_ref_t name = flatbuffers_string_create_str(B, "Orc");
+
+ // Create a `vector` representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ uint8_t treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ flatbuffers_uint8_vec_ref_t inventory;
+ // `c_vec_len` is the convenience macro we defined earlier.
+ inventory = flatbuffers_uint8_vec_create(B, treasure, c_vec_len(treasure));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // Serialize a name for our monster, called "Orc".
+ final int name = builder.writeString('Orc');
+
+ // Create a list representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ final inventory = builder.writeListUint8(treasure);
+
+ // The following code should be used instead if you intend to use the
+ // ObjectBuilder classes:
+ // Serialize a name for our monster, called "Orc".
+ final String name = 'Orc';
+
+ // Create a list representing the inventory of the Orc. Each number
+ // could correspond to an item that can be claimed after he is slain.
+ final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+~~~
+</div>
+<div class="language-lua">
+~~~{.py}
+ -- Serialize a name for our mosnter, called 'orc'
+ local name = builder:CreateString("Orc")
+
+ -- Create a `vector` representing the inventory of the Orc. Each number
+ -- could correspond to an item that can be claimed after he is slain.
+ -- Note: Since we prepend the bytes, this loop iterates in reverse.
+ monster.StartInventoryVector(builder, 10)
+ for i=10,1,-1 do
+ builder:PrependByte(i)
+ end
+ local inv = builder:EndVector(10)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ // Name of the monster.
+ let name = builder.CreateString("Orc")
+
+ // Inventory.
+ let inv = builder.MyGame_Sample_MonsterCreateInventoryVector(map(10): _)
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Name of the Monster.
+ let name = builder.create_string("Orc");
+
+ // Inventory.
+ let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+~~~
+</div>
+
+We serialized two built-in data types (`string` and `vector`) and captured
+their return values. These values are offsets into the serialized data,
+indicating where they are stored, such that we can refer to them below when
+adding fields to our monster.
+
+*Note: To create a `vector` of nested objects (e.g. `table`s, `string`s, or
+other `vector`s), collect their offsets into a temporary data structure, and
+then create an additional `vector` containing their offsets.*
+
+If instead of creating a vector from an existing array you serialize elements
+individually one by one, take care to note that this happens in reverse order,
+as buffers are built back to front.
+
+For example, take a look at the two `Weapon`s that we created earlier (`Sword`
+and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in
+memory. Therefore we can create a FlatBuffer `vector` to contain these
+offsets.
+
+<div class="language-cpp">
+~~~{.cpp}
+ // Place the weapons into a `std::vector`, then convert that into a FlatBuffer `vector`.
+ std::vector<flatbuffers::Offset<Weapon>> weapons_vector;
+ weapons_vector.push_back(sword);
+ weapons_vector.push_back(axe);
+ auto weapons = builder.CreateVector(weapons_vector);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ // Place the two weapons into an array, and pass it to the `createWeaponsVector()` method to
+ // create a FlatBuffer vector.
+ int[] weaps = new int[2];
+ weaps[0] = sword;
+ weaps[1] = axe;
+
+ // Pass the `weaps` array into the `createWeaponsVector()` method to create a FlatBuffer vector.
+ int weapons = Monster.createWeaponsVector(builder, weaps);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ // Place the two weapons into an array, and pass it to the `createWeaponsVector()` method to
+ // create a FlatBuffer vector.
+ val weaps = intArrayOf(sword, axe)
+
+ // Pass the `weaps` array into the `createWeaponsVector()` method to create a FlatBuffer vector.
+ val weapons = Monster.createWeaponsVector(builder, weaps)
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ var weaps = new Offset<Weapon>[2];
+ weaps[0] = sword;
+ weaps[1] = axe;
+
+ // Pass the `weaps` array into the `CreateWeaponsVector()` method to create a FlatBuffer vector.
+ var weapons = Monster.CreateWeaponsVector(builder, weaps);
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // Create a FlatBuffer vector and prepend the weapons.
+ // Note: Since we prepend the data, prepend them in reverse order.
+ sample.MonsterStartWeaponsVector(builder, 2)
+ builder.PrependUOffsetT(axe)
+ builder.PrependUOffsetT(sword)
+ weapons := builder.EndVector(2)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ # Create a FlatBuffer vector and prepend the weapons.
+ # Note: Since we prepend the data, prepend them in reverse order.
+ MyGame.Sample.Monster.MonsterStartWeaponsVector(builder, 2)
+ builder.PrependUOffsetTRelative(axe)
+ builder.PrependUOffsetTRelative(sword)
+ weapons = builder.EndVector(2)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // Create an array from the two `Weapon`s and pass it to the
+ // `createWeaponsVector()` method to create a FlatBuffer vector.
+ var weaps = [sword, axe];
+ var weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ // Create an array from the two `Weapon`s and pass it to the
+ // `createWeaponsVector()` method to create a FlatBuffer vector.
+ let weaps = [sword, axe];
+ let weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // Create an array from the two `Weapon`s and pass it to the
+ // `CreateWeaponsVector()` method to create a FlatBuffer vector.
+ $weaps = array($sword, $axe);
+ $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // We use the internal builder stack to implement a dynamic vector.
+ ns(Weapon_vec_start(B));
+ ns(Weapon_vec_push(B, sword));
+ ns(Weapon_vec_push(B, axe));
+ ns(Weapon_vec_ref_t) weapons = ns(Weapon_vec_end(B));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // If using the Builder classes, serialize the `[sword,axe]`
+ final weapons = builder.writeList([sword, axe]);
+
+ // If using the ObjectBuilders, just create an array from the two `Weapon`s
+ final List<myGame.WeaponBuilder> weaps = [sword, axe];
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Create a FlatBuffer vector and prepend the weapons.
+ -- Note: Since we prepend the data, prepend them in reverse order.
+ monster.StartWeaponsVector(builder, 2)
+ builder:PrependUOffsetTRelative(axe)
+ builder:PrependUOffsetTRelative(sword)
+ local weapons = builder:EndVector(2)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let weapons = builder.MyGame_Sample_MonsterCreateWeaponsVector(weapon_offsets)
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weapons = builder.create_vector(&[sword, axe]);
+~~~
+</div>
+
+<br>
+Note there's additional convenience overloads of `CreateVector`, allowing you
+to work with data that's not in a `std::vector`, or allowing you to generate
+elements by calling a lambda. For the common case of `std::vector<std::string>`
+there's also `CreateVectorOfStrings`.
+</div>
+
+Note that vectors of structs are serialized differently from tables, since
+structs are stored in-line in the vector. For example, to create a vector
+for the `path` field above:
+
+<div class="language-cpp">
+~~~{.cpp}
+ Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) };
+ auto path = builder.CreateVectorOfStructs(points, 2);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ Monster.startPathVector(fbb, 2);
+ Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
+ Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f);
+ int path = fbb.endVector();
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ Monster.startPathVector(fbb, 2)
+ Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)
+ Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f)
+ val path = fbb.endVector()
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ Monster.StartPathVector(fbb, 2);
+ Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
+ Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f);
+ var path = fbb.EndVector();
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ sample.MonsterStartPathVector(builder, 2)
+ sample.CreateVec3(builder, 1.0, 2.0, 3.0)
+ sample.CreateVec3(builder, 4.0, 5.0, 6.0)
+ path := builder.EndVector(2)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ MyGame.Sample.Monster.MonsterStartPathVector(builder, 2)
+ MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
+ MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
+ path = builder.EndVector(2)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ MyGame.Sample.Monster.startPathVector(builder, 2);
+ MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
+ MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
+ var path = builder.endVector();
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ MyGame.Sample.Monster.startPathVector(builder, 2);
+ MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
+ MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
+ let path = builder.endVector();
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ \MyGame\Example\Monster::StartPathVector($builder, 2);
+ \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
+ \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
+ $path = $builder->endVector();
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // TBD
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // Using the Builder classes, you can write a list of structs like so:
+ // Note that the intended order should be reversed if order is important.
+ final vec3Builder = new myGame.Vec3Builder(builder);
+ vec3Builder.finish(4.0, 5.0, 6.0);
+ vec3Builder.finish(1.0, 2.0, 3.0);
+ final int path = builder.endStructVector(2); // the length of the vector
+
+ // Otherwise, using the ObjectBuilder classes:
+ // The dart implementation provides a simple interface for writing vectors
+ // of structs, in `writeListOfStructs`. This method takes
+ // `List<ObjectBuilder>` and is used by the generated builder classes.
+ final List<myGame.Vec3ObjectBuilder> path = [
+ new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
+ new myGame.Vec3ObjectBuilder(x: 4.0, y: 5.0, z: 6.0)
+ ];
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Create a FlatBuffer vector and prepend the path locations.
+ -- Note: Since we prepend the data, prepend them in reverse order.
+ monster.StartPathVector(builder, 2)
+ vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
+ vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
+ local path = builder:EndVector(2)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ builder.MyGame_Sample_MonsterStartPathVector(2)
+ builder.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0)
+ builder.MyGame_Sample_CreateVec3(4.0, 5.0, 6.0)
+ let path = builder.EndVector(2)
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Create the path vector of Vec3 objects.
+ let x = Vec3::new(1.0, 2.0, 3.0);
+ let y = Vec3::new(4.0, 5.0, 6.0);
+ let path = builder.create_vector(&[x, y]);
+
+ // Note that, for convenience, it is also valid to create a vector of
+ // references to structs, like this:
+ // let path = builder.create_vector(&[&x, &y]);
+~~~
+</div>
+
+We have now serialized the non-scalar components of the orc, so we
+can serialize the monster itself:
+
+<div class="language-cpp">
+~~~{.cpp}
+ // Create the position struct
+ auto position = Vec3(1.0f, 2.0f, 3.0f);
+
+ // Set his hit points to 300 and his mana to 150.
+ int hp = 300;
+ int mana = 150;
+
+ // Finally, create the monster using the `CreateMonster` helper function
+ // to set all fields.
+ auto orc = CreateMonster(builder, &position, mana, hp, name, inventory,
+ Color_Red, weapons, Equipment_Weapon, axe.Union(),
+ path);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ // Create our monster using `startMonster()` and `endMonster()`.
+ Monster.startMonster(builder);
+ Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f));
+ Monster.addName(builder, name);
+ Monster.addColor(builder, Color.Red);
+ Monster.addHp(builder, (short)300);
+ Monster.addInventory(builder, inv);
+ Monster.addWeapons(builder, weapons);
+ Monster.addEquippedType(builder, Equipment.Weapon);
+ Monster.addEquipped(builder, axe);
+ Monster.addPath(builder, path);
+ int orc = Monster.endMonster(builder);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ // Create our monster using `startMonster()` and `endMonster()`.
+ Monster.startMonster(builder)
+ Monster.addPos(builder, Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f))
+ Monster.addName(builder, name)
+ Monster.addColor(builder, Color.Red)
+ Monster.addHp(builder, 300.toShort())
+ Monster.addInventory(builder, inv)
+ Monster.addWeapons(builder, weapons)
+ Monster.addEquippedType(builder, Equipment.Weapon)
+ Monster.addEquipped(builder, axe)
+ Monster.addPath(builder, path)
+ val orc = Monster.endMonster(builder)
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ // Create our monster using `StartMonster()` and `EndMonster()`.
+ Monster.StartMonster(builder);
+ Monster.AddPos(builder, Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f));
+ Monster.AddHp(builder, (short)300);
+ Monster.AddName(builder, name);
+ Monster.AddInventory(builder, inv);
+ Monster.AddColor(builder, Color.Red);
+ Monster.AddWeapons(builder, weapons);
+ Monster.AddEquippedType(builder, Equipment.Weapon);
+ Monster.AddEquipped(builder, axe.Value); // Axe
+ Monster.AddPath(builder, path);
+ var orc = Monster.EndMonster(builder);
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // Create our monster using `MonsterStart()` and `MonsterEnd()`.
+ sample.MonsterStart(builder)
+ sample.MonsterAddPos(builder, sample.CreateVec3(builder, 1.0, 2.0, 3.0))
+ sample.MonsterAddHp(builder, 300)
+ sample.MonsterAddName(builder, name)
+ sample.MonsterAddInventory(builder, inv)
+ sample.MonsterAddColor(builder, sample.ColorRed)
+ sample.MonsterAddWeapons(builder, weapons)
+ sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
+ sample.MonsterAddEquipped(builder, axe)
+ sample.MonsterAddPath(builder, path)
+ orc := sample.MonsterEnd(builder)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ # Create our monster by using `MonsterStart()` and `MonsterEnd()`.
+ MyGame.Sample.Monster.MonsterStart(builder)
+ MyGame.Sample.Monster.MonsterAddPos(builder,
+ MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
+ MyGame.Sample.Monster.MonsterAddHp(builder, 300)
+ MyGame.Sample.Monster.MonsterAddName(builder, name)
+ MyGame.Sample.Monster.MonsterAddInventory(builder, inv)
+ MyGame.Sample.Monster.MonsterAddColor(builder,
+ MyGame.Sample.Color.Color().Red)
+ MyGame.Sample.Monster.MonsterAddWeapons(builder, weapons)
+ MyGame.Sample.Monster.MonsterAddEquippedType(
+ builder, MyGame.Sample.Equipment.Equipment().Weapon)
+ MyGame.Sample.Monster.MonsterAddEquipped(builder, axe)
+ MyGame.Sample.Monster.MonsterAddPath(builder, path)
+ orc = MyGame.Sample.Monster.MonsterEnd(builder)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // Create our monster by using `startMonster()` and `endMonster()`.
+ MyGame.Sample.Monster.startMonster(builder);
+ MyGame.Sample.Monster.addPos(builder,
+ MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0));
+ MyGame.Sample.Monster.addHp(builder, 300);
+ MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red)
+ MyGame.Sample.Monster.addName(builder, name);
+ MyGame.Sample.Monster.addInventory(builder, inv);
+ MyGame.Sample.Monster.addWeapons(builder, weapons);
+ MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
+ MyGame.Sample.Monster.addEquipped(builder, axe);
+ MyGame.Sample.Monster.addPath(builder, path);
+ var orc = MyGame.Sample.Monster.endMonster(builder);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ // Create our monster by using `startMonster()` and `endMonster()`.
+ MyGame.Sample.Monster.startMonster(builder);
+ MyGame.Sample.Monster.addPos(builder,
+ MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0));
+ MyGame.Sample.Monster.addHp(builder, 300);
+ MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red)
+ MyGame.Sample.Monster.addName(builder, name);
+ MyGame.Sample.Monster.addInventory(builder, inv);
+ MyGame.Sample.Monster.addWeapons(builder, weapons);
+ MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
+ MyGame.Sample.Monster.addEquipped(builder, axe);
+ MyGame.Sample.Monster.addPath(builder, path);
+ let orc = MyGame.Sample.Monster.endMonster(builder);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // Create our monster by using `StartMonster()` and `EndMonster()`.
+ \MyGame\Sample\Monster::StartMonster($builder);
+ \MyGame\Sample\Monster::AddPos($builder,
+ \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0));
+ \MyGame\Sample\Monster::AddHp($builder, 300);
+ \MyGame\Sample\Monster::AddName($builder, $name);
+ \MyGame\Sample\Monster::AddInventory($builder, $inv);
+ \MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red);
+ \MyGame\Sample\Monster::AddWeapons($builder, $weapons);
+ \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon);
+ \MyGame\Sample\Monster::AddEquipped($builder, $axe);
+ \MyGame\Sample\Monster::AddPath($builder, $path);
+ $orc = \MyGame\Sample\Monster::EndMonster($builder);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Set his hit points to 300 and his mana to 150.
+ uint16_t hp = 300;
+ uint16_t mana = 150;
+
+ // Define an equipment union. `create` calls in C has a single
+ // argument for unions where C++ has both a type and a data argument.
+ ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
+ ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
+ ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
+ weapons, equipped, path));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // Using the Builder API:
+ // Set his hit points to 300 and his mana to 150.
+ final int hp = 300;
+ final int mana = 150;
+
+ final monster = new myGame.MonsterBuilder(builder)
+ ..begin()
+ ..addNameOffset(name)
+ ..addInventoryOffset(inventory)
+ ..addWeaponsOffset(weapons)
+ ..addEquippedType(myGame.EquipmentTypeId.Weapon)
+ ..addEquippedOffset(axe)
+ ..addHp(hp)
+ ..addMana(mana)
+ ..addPos(vec3Builder.finish(1.0, 2.0, 3.0))
+ ..addPathOffset(path)
+ ..addColor(myGame.Color.Red);
+
+ final int orc = monster.finish();
+
+ // -Or- using the ObjectBuilder API:
+ // Set his hit points to 300 and his mana to 150.
+ final int hp = 300;
+ final int mana = 150;
+
+ // Note that these parameters are optional - it is not necessary to set
+ // all of them.
+ // Also note that it is not necessary to `finish` the builder helpers above
+ // - the generated code will automatically reuse offsets if the same object
+ // is used in more than one place (e.g. the axe appearing in `weapons` and
+ // `equipped`).
+ final myGame.MonsterBuilder orcBuilder = new myGame.MonsterBuilder(
+ name: name,
+ inventory: treasure,
+ weapons: weaps,
+ equippedType: myGame.EquipmentTypeId.Weapon,
+ equipped: axe,
+ path: path,
+ hp: hp,
+ mana: mana,
+ pos: new myGame.Vec3Builder(x: 1.0, y: 2.0, z: 3.0),
+ color: myGame.Color.Red,
+ path: [
+ new myGame.Vec3ObjectBuilder(x: 1.0, y: 2.0, z: 3.0),
+ new myGame.Vec3ObjectBuilder(x: 4.0, y: 5.0, z: 6.0)
+ ]);
+
+ final int orc = orcBuilder.finish(builder);
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Create our monster by using Start() andEnd()
+ monster.Start(builder)
+ monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
+ monster.AddHp(builder, 300)
+ monster.AddName(builder, name)
+ monster.AddInventory(builder, inv)
+ monster.AddColor(builder, color.Red)
+ monster.AddWeapons(builder, weapons)
+ monster.AddEquippedType(builder, equipment.Weapon)
+ monster.AddEquipped(builder, axe)
+ monster.AddPath(builder, path)
+ local orc = monster.End(builder)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let orc = MyGame_Sample_MonsterBuilder { b }
+ .start()
+ .add_pos(b.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0))
+ .add_hp(300)
+ .add_name(name)
+ .add_inventory(inv)
+ .add_color(MyGame_Sample_Color_Red)
+ .add_weapons(weapons)
+ .add_equipped_type(MyGame_Sample_Equipment_Weapon)
+ .add_equipped(weapon_offsets[1])
+ .add_path(path)
+ .end()
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Create the monster using the `Monster::create` helper function. This
+ // function accepts a `MonsterArgs` struct, which supplies all of the data
+ // needed to build a `Monster`. To supply empty/default fields, just use the
+ // Rust built-in `Default::default()` function, as demonstrated below.
+ let orc = Monster::create(&mut builder, &MonsterArgs{
+ pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)),
+ mana: 150,
+ hp: 80,
+ name: Some(name),
+ inventory: Some(inventory),
+ color: Color::Red,
+ weapons: Some(weapons),
+ equipped_type: Equipment::Weapon,
+ equipped: Some(axe.as_union_value()),
+ path: Some(path),
+ ..Default::default()
+ });
+~~~
+</div>
+
+Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
+are simple combinations of scalars that are always stored inline, just like
+scalars themselves.
+
+**Important**: Unlike structs, you should not nest tables or other objects,
+which is why we created all the strings/vectors/tables that this monster refers
+to before `start`. If you try to create any of them between `start` and `end`,
+you will get an assert/exception/panic depending on your language.
+
+*Note: Since we are passing `150` as the `mana` field, which happens to be the
+default value, the field will not actually be written to the buffer, since the
+default value will be returned on query anyway. This is a nice space savings,
+especially if default values are common in your data. It also means that you do
+not need to be worried of adding a lot of fields that are only used in a small
+number of instances, as it will not bloat the buffer if unused.*
+
+<div class="language-cpp">
+<br>
+If you do not wish to set every field in a `table`, it may be more convenient to
+manually set each field of your monster, instead of calling `CreateMonster()`.
+The following snippet is functionally equivalent to the above code, but provides
+a bit more flexibility.
+<br>
+~~~{.cpp}
+ // You can use this code instead of `CreateMonster()`, to create our orc
+ // manually.
+ MonsterBuilder monster_builder(builder);
+ monster_builder.add_pos(&position);
+ monster_builder.add_hp(hp);
+ monster_builder.add_name(name);
+ monster_builder.add_inventory(inventory);
+ monster_builder.add_color(Color_Red);
+ monster_builder.add_weapons(weapons);
+ monster_builder.add_equipped_type(Equipment_Weapon);
+ monster_builder.add_equipped(axe.Union());
+ auto orc = monster_builder.Finish();
+~~~
+</div>
+<div class="language-c">
+If you do not wish to set every field in a `table`, it may be more convenient to
+manually set each field of your monster, instead of calling `create_monster_as_root()`.
+The following snippet is functionally equivalent to the above code, but provides
+a bit more flexibility.
+<br>
+~~~{.c}
+ // It is important to pair `start_as_root` with `end_as_root`.
+ ns(Monster_start_as_root(B));
+ ns(Monster_pos_create(B, 1.0f, 2.0f, 3.0f));
+ // or alternatively
+ //ns(Monster_pos_add(&pos);
+
+ ns(Monster_hp_add(B, hp));
+ // Notice that `Monser_name_add` adds a string reference unlike the
+ // add_str and add_strn variants.
+ ns(Monster_name_add(B, name));
+ ns(Monster_inventory_add(B, inventory));
+ ns(Monster_color_add(B, ns(Color_Red)));
+ ns(Monster_weapons_add(B, weapons));
+ ns(Monster_equipped_add(B, equipped));
+ // Complete the monster object and make it the buffer root object.
+ ns(Monster_end_as_root(B));
+~~~
+</div>
+
+Before finishing the serialization, let's take a quick look at FlatBuffer
+`union Equipped`. There are two parts to each FlatBuffer `union`. The first, is
+a hidden field `_type`, that is generated to hold the type of `table` referred
+to by the `union`. This allows you to know which type to cast to at runtime.
+Second, is the `union`'s data.
+
+In our example, the last two things we added to our `Monster` were the
+`Equipped Type` and the `Equipped` union itself.
+
+Here is a repetition these lines, to help highlight them more clearly:
+
+<div class="language-cpp">
+ ~~~{.cpp}
+ monster_builder.add_equipped_type(Equipment_Weapon); // Union type
+ monster_builder.add_equipped(axe); // Union data
+ ~~~
+</div>
+<div class="language-java">
+ ~~~{.java}
+ Monster.addEquippedType(builder, Equipment.Weapon); // Union type
+ Monster.addEquipped(axe); // Union data
+ ~~~
+</div>
+<div class="language-kotlin">
+ ~~~{.kt}
+ Monster.addEquippedType(builder, Equipment.Weapon) // Union type
+ Monster.addEquipped(axe) // Union data
+ ~~~
+</div>
+<div class="language-csharp">
+ ~~~{.cs}
+ Monster.AddEquippedType(builder, Equipment.Weapon); // Union type
+ Monster.AddEquipped(builder, axe.Value); // Union data
+ ~~~
+</div>
+<div class="language-go">
+ ~~~{.go}
+ sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon) // Union type
+ sample.MonsterAddEquipped(builder, axe) // Union data
+ ~~~
+</div>
+<div class="language-python">
+ ~~~{.py}
+ MyGame.Sample.Monster.MonsterAddEquippedType( # Union type
+ builder, MyGame.Sample.Equipment.Equipment().Weapon)
+ MyGame.Sample.Monster.MonsterAddEquipped(builder, axe) # Union data
+ ~~~
+</div>
+<div class="language-javascript">
+ ~~~{.js}
+ MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon); // Union type
+ MyGame.Sample.Monster.addEquipped(builder, axe); // Union data
+ ~~~
+</div>
+<div class="language-typescript">
+ ~~~{.ts}
+ MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon); // Union type
+ MyGame.Sample.Monster.addEquipped(builder, axe); // Union data
+ ~~~
+</div>
+<div class="language-php">
+ ~~~{.php}
+ \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon); // Union type
+ \MyGame\Sample\Monster::AddEquipped($builder, $axe); // Union data
+ ~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Add union type and data simultaneously.
+ ns(Monster_equipped_Weapon_add(B, axe));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // using the builder API:
+ ..addEquippedType(myGame.EquipmentTypeId.Weapon)
+ ..addEquippedOffset(axe)
+
+ // in the ObjectBuilder API:
+ equippedTypeId: myGame.EquipmentTypeId.Weapon, // Union type
+ equipped: axe, // Union data
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ monster.AddEquippedType(builder, equipment.Weapon) -- Union type
+ monster.AddEquipped(builder, axe) -- Union data
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ .add_equipped_type(MyGame_Sample_Equipment_Weapon)
+ .add_equipped(axe)
+~~~
+</div>
+<div class="language-rust">
+ ~~~{.rs}
+ // You need to call `as_union_value` to turn an object into a type that
+ // can be used as a union value.
+ monster_builder.add_equipped_type(Equipment::Weapon); // Union type
+ monster_builder.add_equipped(axe.as_union_value()); // Union data
+ ~~~
+</div>
+
+After you have created your buffer, you will have the offset to the root of the
+data in the `orc` variable, so you can finish the buffer by calling the
+appropriate `finish` method.
+
+
+<div class="language-cpp">
+~~~{.cpp}
+ // Call `Finish()` to instruct the builder that this monster is complete.
+ // Note: Regardless of how you created the `orc`, you still need to call
+ // `Finish()` on the `FlatBufferBuilder`.
+ builder.Finish(orc); // You could also call `FinishMonsterBuffer(builder,
+ // orc);`.
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`.
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ builder.finish(orc) // You could also call `Monster.finishMonsterBuffer(builder, orc);`.
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ // Call `Finish()` to instruct the builder that this monster is complete.
+ builder.Finish(orc.Value); // You could also call `Monster.FinishMonsterBuffer(builder, orc);`.
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // Call `Finish()` to instruct the builder that this monster is complete.
+ builder.Finish(orc)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ # Call `Finish()` to instruct the builder that this monster is complete.
+ builder.Finish(orc)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ builder.finish(orc); // You could also call `MyGame.Sample.Monster.finishMonsterBuffer(builder,
+ // orc);`.
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ builder.finish(orc); // You could also call `MyGame.Sample.Monster.finishMonsterBuffer(builder,
+ // orc);`.
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ $builder->finish($orc); // You may also call `\MyGame\Sample\Monster::FinishMonsterBuffer(
+ // $builder, $orc);`.
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Because we used `Monster_create_as_root`, we do not need a `finish` call in C`.
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ // See the next code section, as in Dart `finish` will also return the byte array.
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Call 'Finish()' to instruct the builder that this monster is complete.
+ builder:Finish(orc)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ // Call `Finish()` to instruct the builder that this monster is complete.
+ builder.Finish(orc)
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Call `finish()` to instruct the builder that this monster is complete.
+ builder.finish(orc, None);
+~~~
+</div>
+
+The buffer is now ready to be stored somewhere, sent over the network, be
+compressed, or whatever you'd like to do with it. You can access the buffer
+like so:
+
+<div class="language-cpp">
+~~~{.cpp}
+ // This must be called after `Finish()`.
+ uint8_t *buf = builder.GetBufferPointer();
+ int size = builder.GetSize(); // Returns the size of the buffer that
+ // `GetBufferPointer()` points to.
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ // This must be called after `finish()`.
+ java.nio.ByteBuffer buf = builder.dataBuffer();
+ // The data in this ByteBuffer does NOT start at 0, but at buf.position().
+ // The number of bytes is buf.remaining().
+
+ // Alternatively this copies the above data out of the ByteBuffer for you:
+ byte[] buf = builder.sizedByteArray();
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ // This must be called after `finish()`.
+ val buf = builder.dataBuffer()
+ // The data in this ByteBuffer does NOT start at 0, but at buf.position().
+ // The number of bytes is buf.remaining().
+
+ // Alternatively this copies the above data out of the ByteBuffer for you:
+ val buf = builder.sizedByteArray()
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ // This must be called after `Finish()`.
+ var buf = builder.DataBuffer; // Of type `FlatBuffers.ByteBuffer`.
+ // The data in this ByteBuffer does NOT start at 0, but at buf.Position.
+ // The end of the data is marked by buf.Length, so the size is
+ // buf.Length - buf.Position.
+
+ // Alternatively this copies the above data out of the ByteBuffer for you:
+ byte[] buf = builder.SizedByteArray();
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // This must be called after `Finish()`.
+ buf := builder.FinishedBytes() // Of type `byte[]`.
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ # This must be called after `Finish()`.
+ buf = builder.Output() // Of type `bytearray`.
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // This must be called after `finish()`.
+ var buf = builder.asUint8Array(); // Of type `Uint8Array`.
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ // This must be called after `finish()`.
+ let buf = builder.asUint8Array(); // Of type `Uint8Array`.
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // This must be called after `finish()`.
+ $buf = $builder->dataBuffer(); // Of type `Google\FlatBuffers\ByteBuffer`
+ // The data in this ByteBuffer does NOT start at 0, but at buf->getPosition().
+ // The end of the data is marked by buf->capacity(), so the size is
+ // buf->capacity() - buf->getPosition().
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ uint8_t *buf;
+ size_t size;
+
+ // Allocate and extract a readable buffer from internal builder heap.
+ // The returned buffer must be deallocated using `free`.
+ // NOTE: Finalizing the buffer does NOT change the builder, it
+ // just creates a snapshot of the builder content.
+ buf = flatcc_builder_finalize_buffer(B, &size);
+ // use buf
+ free(buf);
+
+ // Optionally reset builder to reuse builder without deallocating
+ // internal stack and heap.
+ flatcc_builder_reset(B);
+ // build next buffer.
+ // ...
+
+ // Cleanup.
+ flatcc_builder_clear(B);
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ final Uint8List buf = builder.finish(orc);
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Get the flatbuffer as a string containing the binary data
+ local bufAsString = builder:Output()
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ // This must be called after `Finish()`.
+ let buf = builder.SizedCopy() // Of type `string`.
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // This must be called after `finish()`.
+ // `finished_data` returns a byte slice.
+ let buf = builder.finished_data(); // Of type `&[u8]`
+~~~
+</div>
+
+
+Now you can write the bytes to a file, send them over the network..
+**Make sure your file mode (or transfer protocol) is set to BINARY, not text.**
+If you transfer a FlatBuffer in text mode, the buffer will be corrupted,
+which will lead to hard to find problems when you read the buffer.
+
+#### Reading Orc FlatBuffers
+
+Now that we have successfully created an `Orc` FlatBuffer, the monster data can
+be saved, sent over a network, etc. Let's now adventure into the inverse, and
+access a FlatBuffer.
+
+This section requires the same import/include, namespace, etc. requirements as
+before:
+
+<div class="language-cpp">
+~~~{.cpp}
+ #include "monster_generated.h" // This was generated by `flatc`.
+
+ using namespace MyGame::Sample; // Specified in the schema.
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ import MyGame.Sample.*; //The `flatc` generated files. (Monster, Vec3, etc.)
+
+ import com.google.flatbuffers.FlatBufferBuilder;
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ import MyGame.Sample.* //The `flatc` generated files. (Monster, Vec3, etc.)
+
+ import com.google.flatbuffers.FlatBufferBuilder
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ using FlatBuffers;
+ using MyGame.Sample; // The `flatc` generated files. (Monster, Vec3, etc.)
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ import (
+ flatbuffers "github.com/google/flatbuffers/go"
+ sample "MyGame/Sample"
+ )
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ import flatbuffers
+
+ # Generated by `flatc`.
+ import MyGame.Sample.Any
+ import MyGame.Sample.Color
+ import MyGame.Sample.Monster
+ import MyGame.Sample.Vec3
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ // The following code is for JavaScript module loaders (e.g. Node.js). See
+ // below for a browser-based HTML/JavaScript example of including the library.
+ var flatbuffers = require('/js/flatbuffers').flatbuffers;
+ var MyGame = require('./monster_generated').MyGame; // Generated by `flatc`.
+
+ //--------------------------------------------------------------------------//
+
+ // The following code is for browser-based HTML/JavaScript. Use the above code
+ // for JavaScript module loaders (e.g. Node.js).
+ <script src="../js/flatbuffers.js"></script>
+ <script src="monster_generated.js"></script> // Generated by `flatc`.
+~~~
+</div>
+<div class="language-typescript">
+~~~{.js}
+ // note: import flabuffers with your desired import method
+
+ import { MyGame } from './monster_generated';
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ // It is recommended that your use PSR autoload when using FlatBuffers in PHP.
+ // Here is an example from `SampleBinary.php`:
+ function __autoload($class_name) {
+ // The last segment of the class name matches the file name.
+ $class = substr($class_name, strrpos($class_name, "\\") + 1);
+ $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root.
+
+ // Contains the `*.php` files for the FlatBuffers library and the `flatc` generated files.
+ $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")),
+ join(DIRECTORY_SEPARATOR, array($root_dir, "samples", "MyGame", "Sample")));
+ foreach ($paths as $path) {
+ $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
+ if (file_exists($file)) {
+ require($file);
+ break;
+ }
+ }
+ }
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Only needed if we don't have `#include "monster_builder.h"`.
+ #include "monster_reader.h"
+
+ #undef ns
+ #define ns(x) FLATBUFFERS_WRAP_NAMESPACE(MyGame_Sample, x) // Specified in the schema.
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+import './monster_my_game.sample_generated.dart' as myGame;
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ -- require the flatbuffers module
+ local flatbuffers = require("flatbuffers")
+
+ -- require the generated files from `flatc`.
+ local color = require("MyGame.Sample.Color")
+ local equipment = require("MyGame.Sample.Equipment")
+ local monster = require("MyGame.Sample.Monster")
+ local vec3 = require("MyGame.Sample.Vec3")
+ local weapon = require("MyGame.Sample.Weapon")
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ import from "../lobster/" // Where to find flatbuffers.lobster
+ import monster_generated
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // import the flatbuffers runtime library
+ extern crate flatbuffers;
+
+ // import the generated code
+ #[allow(dead_code, unused_imports)]
+ #[path = "./monster_generated.rs"]
+ mod monster_generated;
+ pub use monster_generated::my_game::sample::{get_root_as_monster,
+ Color, Equipment,
+ Monster, MonsterArgs,
+ Vec3,
+ Weapon, WeaponArgs};
+~~~
+</div>
+
+Then, assuming you have a buffer of bytes received from disk,
+network, etc., you can create start accessing the buffer like so:
+
+**Again, make sure you read the bytes in BINARY mode, otherwise the code below
+won't work**
+
+<div class="language-cpp">
+~~~{.cpp}
+ uint8_t *buffer_pointer = /* the data you just read */;
+
+ // Get a pointer to the root object inside the buffer.
+ auto monster = GetMonster(buffer_pointer);
+
+ // `monster` is of type `Monster *`.
+ // Note: root object pointers are NOT the same as `buffer_pointer`.
+ // `GetMonster` is a convenience function that calls `GetRoot<Monster>`,
+ // the latter is also available for non-root types.
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ byte[] bytes = /* the data you just read */
+ java.nio.ByteBuffer buf = java.nio.ByteBuffer.wrap(bytes);
+
+ // Get an accessor to the root object inside the buffer.
+ Monster monster = Monster.getRootAsMonster(buf);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val bytes = /* the data you just read */
+ val buf = java.nio.ByteBuffer.wrap(bytes)
+
+ // Get an accessor to the root object inside the buffer.
+ Monster monster = Monster.getRootAsMonster(buf)
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ byte[] bytes = /* the data you just read */
+ var buf = new ByteBuffer(bytes);
+
+ // Get an accessor to the root object inside the buffer.
+ var monster = Monster.GetRootAsMonster(buf);
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ var buf []byte = /* the data you just read */
+
+ // Get an accessor to the root object inside the buffer.
+ monster := sample.GetRootAsMonster(buf, 0)
+
+ // Note: We use `0` for the offset here, which is typical for most buffers
+ // you would read. If you wanted to read from `builder.Bytes` directly, you
+ // would need to pass in the offset of `builder.Head()`, as the builder
+ // constructs the buffer backwards, so may not start at offset 0.
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ buf = /* the data you just read, in an object of type "bytearray" */
+
+ // Get an accessor to the root object inside the buffer.
+ monster = MyGame.Sample.Monster.Monster.GetRootAsMonster(buf, 0)
+
+ # Note: We use `0` for the offset here, which is typical for most buffers
+ # you would read. If you wanted to read from the `builder.Bytes` directly,
+ # you would need to pass in the offset of `builder.Head()`, as the builder
+ # constructs the buffer backwards, so may not start at offset 0.
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var bytes = /* the data you just read, in an object of type "Uint8Array" */
+ var buf = new flatbuffers.ByteBuffer(bytes);
+
+ // Get an accessor to the root object inside the buffer.
+ var monster = MyGame.Sample.Monster.getRootAsMonster(buf);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ let bytes = /* the data you just read, in an object of type "Uint8Array" */
+ let buf = new flatbuffers.ByteBuffer(bytes);
+
+ // Get an accessor to the root object inside the buffer.
+ let monster = MyGame.Sample.Monster.getRootAsMonster(buf);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ $bytes = /* the data you just read, in a string */
+ $buf = Google\FlatBuffers\ByteBuffer::wrap($bytes);
+
+ // Get an accessor to the root object inside the buffer.
+ $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Note that we use the `table_t` suffix when reading a table object
+ // as opposed to the `ref_t` suffix used during the construction of
+ // the buffer.
+ ns(Monster_table_t) monster = ns(Monster_as_root(buffer));
+
+ // Note: root object pointers are NOT the same as the `buffer` pointer.
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+List<int> data = ... // the data, e.g. from file or network
+// A generated factory constructor that will read the data.
+myGame.Monster monster = new myGame.Monster(data);
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local bufAsString = -- The data you just read in
+
+ -- Convert the string representation into binary array Lua structure
+ local buf = flatbuffers.binaryArray.New(bufAsString)
+
+ -- Get an accessor to the root object insert the buffer
+ local mon = monster.GetRootAsMonster(buf, 0)
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ buf = /* the data you just read, in a string */
+
+ // Get an accessor to the root object inside the buffer.
+ let monster = MyGame_Sample_GetRootAsMonster(buf)
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ let buf = /* the data you just read, in a &[u8] */
+
+ // Get an accessor to the root object inside the buffer.
+ let monster = get_root_as_monster(buf);
+~~~
+</div>
+
+If you look in the generated files from the schema compiler, you will see it generated
+accessors for all non-`deprecated` fields. For example:
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto hp = monster->hp();
+ auto mana = monster->mana();
+ auto name = monster->name()->c_str();
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ short hp = monster.hp();
+ short mana = monster.mana();
+ String name = monster.name();
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val hp = monster.hp
+ val mana = monster.mana
+ val name = monster.name
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ // For C#, unlike most other languages support by FlatBuffers, most values (except for
+ // vectors and unions) are available as properties instead of accessor methods.
+ var hp = monster.Hp
+ var mana = monster.Mana
+ var name = monster.Name
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ hp := monster.Hp()
+ mana := monster.Mana()
+ name := string(monster.Name()) // Note: `monster.Name()` returns a byte[].
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ hp = monster.Hp()
+ mana = monster.Mana()
+ name = monster.Name()
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var hp = $monster.hp();
+ var mana = $monster.mana();
+ var name = $monster.name();
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ let hp = $monster.hp();
+ let mana = $monster.mana();
+ let name = $monster.name();
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ $hp = $monster->getHp();
+ $mana = $monster->getMana();
+ $name = monster->getName();
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ uint16_t hp = ns(Monster_hp(monster));
+ uint16_t mana = ns(Monster_mana(monster));
+ flatbuffers_string_t name = ns(Monster_name(monster));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ // For Dart, unlike other languages support by FlatBuffers, most values
+ // are available as properties instead of accessor methods.
+ var hp = monster.hp;
+ var mana = monster.mana;
+ var name = monster.name;
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local hp = mon:Hp()
+ local mana = mon:Mana()
+ local name = mon:Name()
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let hp = monster.hp
+ let mana = monster.mana
+ let name = monster.name
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Get and test some scalar types from the FlatBuffer.
+ let hp = monster.hp();
+ let mana = monster.mana();
+ let name = monster.name();
+~~~
+</div>
+
+These should hold `300`, `150`, and `"Orc"` respectively.
+
+*Note: The default value `150` wasn't stored in `mana`, but we are still able to retrieve it.*
+
+To access sub-objects, in the case of our `pos`, which is a `Vec3`:
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto pos = monster->pos();
+ auto x = pos->x();
+ auto y = pos->y();
+ auto z = pos->z();
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ Vec3 pos = monster.pos();
+ float x = pos.x();
+ float y = pos.y();
+ float z = pos.z();
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val pos = monster.pos!!
+ val x = pos.x
+ val y = pos.y
+ val z = pos.z
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ var pos = monster.Pos.Value;
+ var x = pos.X;
+ var y = pos.Y;
+ var z = pos.Z;
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ pos := monster.Pos(nil)
+ x := pos.X()
+ y := pos.Y()
+ z := pos.Z()
+
+ // Note: Whenever you access a new object, like in `Pos()`, a new temporary
+ // accessor object gets created. If your code is very performance sensitive,
+ // you can pass in a pointer to an existing `Vec3` instead of `nil`. This
+ // allows you to reuse it across many calls to reduce the amount of object
+ // allocation/garbage collection.
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ pos = monster.Pos()
+ x = pos.X()
+ y = pos.Y()
+ z = pos.Z()
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var pos = monster.pos();
+ var x = pos.x();
+ var y = pos.y();
+ var z = pos.z();
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ let pos = monster.pos();
+ let x = pos.x();
+ let y = pos.y();
+ let z = pos.z();
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ $pos = $monster->getPos();
+ $x = $pos->getX();
+ $y = $pos->getY();
+ $z = $pos->getZ();
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ ns(Vec3_struct_t) pos = ns(Monster_pos(monster));
+ float x = ns(Vec3_x(pos));
+ float y = ns(Vec3_y(pos));
+ float z = ns(Vec3_z(pos));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ myGame.Vec3 pos = monster.pos;
+ double x = pos.x;
+ double y = pos.y;
+ double z = pos.z;
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local pos = mon:Pos()
+ local x = pos:X()
+ local y = pos:Y()
+ local z = pos:Z()
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let pos = monster.pos
+ let x = pos.x
+ let y = pos.y
+ let z = pos.z
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ let pos = monster.pos().unwrap();
+ let x = pos.x();
+ let y = pos.y();
+ let z = pos.z();
+~~~
+</div>
+
+`x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively.
+
+*Note: Had we not set `pos` during serialization, it would be a `NULL`-value.*
+
+Similarly, we can access elements of the inventory `vector` by indexing it. You
+can also iterate over the length of the array/vector representing the
+FlatBuffers `vector`.
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto inv = monster->inventory(); // A pointer to a `flatbuffers::Vector<>`.
+ auto inv_len = inv->size();
+ auto third_item = inv->Get(2);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ int invLength = monster.inventoryLength();
+ byte thirdItem = monster.inventory(2);
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kotlin}
+ val invLength = monster.inventoryLength
+ val thirdItem = monster.inventory(2)!!
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ int invLength = monster.InventoryLength;
+ var thirdItem = monster.Inventory(2);
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ invLength := monster.InventoryLength()
+ thirdItem := monster.Inventory(2)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ inv_len = monster.InventoryLength()
+ third_item = monster.Inventory(2)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var invLength = monster.inventoryLength();
+ var thirdItem = monster.inventory(2);
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ let invLength = monster.inventoryLength();
+ let thirdItem = monster.inventory(2);
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ $inv_len = $monster->getInventoryLength();
+ $third_item = $monster->getInventory(2);
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // If `inv` hasn't been set, it will be null. It is valid get
+ // the length of null which will be 0, useful for iteration.
+ flatbuffers_uint8_vec_t inv = ns(Monster_inventory(monster));
+ size_t inv_len = flatbuffers_uint8_vec_len(inv);
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ int invLength = monster.inventory.length;
+ var thirdItem = monster.inventory[2];
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local invLength = mon:InventoryLength()
+ local thirdItem = mon:Inventory(3) -- Lua is 1-based
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let inv_len = monster.inventory_length
+ let third_item = monster.inventory(2)
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Get a test an element from the `inventory` FlatBuffer's `vector`.
+ let inv = monster.inventory().unwrap();
+
+ // Note that this vector is returned as a slice, because direct access for
+ // this type, a `u8` vector, is safe on all platforms:
+ let third_item = inv[2];
+~~~
+</div>
+
+For `vector`s of `table`s, you can access the elements like any other vector,
+except your need to handle the result as a FlatBuffer `table`:
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto weapons = monster->weapons(); // A pointer to a `flatbuffers::Vector<>`.
+ auto weapon_len = weapons->size();
+ auto second_weapon_name = weapons->Get(1)->name()->str();
+ auto second_weapon_damage = weapons->Get(1)->damage()
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ int weaponsLength = monster.weaponsLength();
+ String secondWeaponName = monster.weapons(1).name();
+ short secondWeaponDamage = monster.weapons(1).damage();
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val weaponsLength = monster.weaponsLength
+ val secondWeaponName = monster.weapons(1)!!.name
+ val secondWeaponDamage = monster.weapons(1)!!.damage
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ int weaponsLength = monster.WeaponsLength;
+ var secondWeaponName = monster.Weapons(1).Name;
+ var secondWeaponDamage = monster.Weapons(1).Damage;
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ weaponLength := monster.WeaponsLength()
+ weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
+ // to capture the output of the function.
+ if monster.Weapons(weapon, 1) {
+ secondWeaponName := weapon.Name()
+ secondWeaponDamage := weapon.Damage()
+ }
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ weapons_length = monster.WeaponsLength()
+ second_weapon_name = monster.Weapons(1).Name()
+ second_weapon_damage = monster.Weapons(1).Damage()
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var weaponsLength = monster.weaponsLength();
+ var secondWeaponName = monster.weapons(1).name();
+ var secondWeaponDamage = monster.weapons(1).damage();
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ let weaponsLength = monster.weaponsLength();
+ let secondWeaponName = monster.weapons(1).name();
+ let secondWeaponDamage = monster.weapons(1).damage();
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ $weapons_len = $monster->getWeaponsLength();
+ $second_weapon_name = $monster->getWeapons(1)->getName();
+ $second_weapon_damage = $monster->getWeapons(1)->getDamage();
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ ns(Weapon_vec_t) weapons = ns(Monster_weapons(monster));
+ size_t weapons_len = ns(Weapon_vec_len(weapons));
+ // We can use `const char *` instead of `flatbuffers_string_t`.
+ const char *second_weapon_name = ns(Weapon_name(ns(Weapon_vec_at(weapons, 1))));
+ uint16_t second_weapon_damage = ns(Weapon_damage(ns(Weapon_vec_at(weapons, 1))));
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ int weaponsLength = monster.weapons.length;
+ var secondWeaponName = monster.weapons[1].name;
+ var secondWeaponDamage = monster.Weapons[1].damage;
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local weaponsLength = mon:WeaponsLength()
+ local secondWeaponName = mon:Weapon(2):Name()
+ local secondWeaponDamage = mon:Weapon(2):Damage()
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ let weapons_length = monster.weapons_length
+ let second_weapon_name = monster.weapons(1).name
+ let second_weapon_damage = monster.weapons(1).damage
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Get and test the `weapons` FlatBuffers's `vector`.
+ let weps = monster.weapons().unwrap();
+ let weps_len = weps.len();
+
+ let wep2 = weps.get(1);
+ let second_weapon_name = wep2.name();
+ let second_weapon_damage = wep2.damage();
+~~~
+</div>
+
+Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created
+the `union`, we need to get both parts of the `union`: the type and the data.
+
+We can access the type to dynamically cast the data as needed (since the
+`union` only stores a FlatBuffer `table`).
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto union_type = monster.equipped_type();
+
+ if (union_type == Equipment_Weapon) {
+ auto weapon = static_cast<const Weapon*>(monster->equipped()); // Requires `static_cast`
+ // to type `const Weapon*`.
+
+ auto weapon_name = weapon->name()->str(); // "Axe"
+ auto weapon_damage = weapon->damage(); // 5
+ }
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ int unionType = monster.EquippedType();
+
+ if (unionType == Equipment.Weapon) {
+ Weapon weapon = (Weapon)monster.equipped(new Weapon()); // Requires explicit cast
+ // to `Weapon`.
+
+ String weaponName = weapon.name(); // "Axe"
+ short weaponDamage = weapon.damage(); // 5
+ }
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val unionType = monster.EquippedType
+
+ if (unionType == Equipment.Weapon) {
+ val weapon = monster.equipped(Weapon()) as Weapon // Requires explicit cast
+ // to `Weapon`.
+
+ val weaponName = weapon.name // "Axe"
+ val weaponDamage = weapon.damage // 5
+ }
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ var unionType = monster.EquippedType;
+
+ if (unionType == Equipment.Weapon) {
+ var weapon = monster.Equipped<Weapon>().Value;
+
+ var weaponName = weapon.Name; // "Axe"
+ var weaponDamage = weapon.Damage; // 5
+ }
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ // We need a `flatbuffers.Table` to capture the output of the
+ // `monster.Equipped()` function.
+ unionTable := new(flatbuffers.Table)
+
+ if monster.Equipped(unionTable) {
+ unionType := monster.EquippedType()
+
+ if unionType == sample.EquipmentWeapon {
+ // Create a `sample.Weapon` object that can be initialized with the contents
+ // of the `flatbuffers.Table` (`unionTable`), which was populated by
+ // `monster.Equipped()`.
+ unionWeapon = new(sample.Weapon)
+ unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
+
+ weaponName = unionWeapon.Name()
+ weaponDamage = unionWeapon.Damage()
+ }
+ }
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ union_type = monster.EquippedType()
+
+ if union_type == MyGame.Sample.Equipment.Equipment().Weapon:
+ # `monster.Equipped()` returns a `flatbuffers.Table`, which can be used to
+ # initialize a `MyGame.Sample.Weapon.Weapon()`.
+ union_weapon = MyGame.Sample.Weapon.Weapon()
+ union_weapon.Init(monster.Equipped().Bytes, monster.Equipped().Pos)
+
+ weapon_name = union_weapon.Name() // 'Axe'
+ weapon_damage = union_weapon.Damage() // 5
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ var unionType = monster.equippedType();
+
+ if (unionType == MyGame.Sample.Equipment.Weapon) {
+ var weapon_name = monster.equipped(new MyGame.Sample.Weapon()).name(); // 'Axe'
+ var weapon_damage = monster.equipped(new MyGame.Sample.Weapon()).damage(); // 5
+ }
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ let unionType = monster.equippedType();
+
+ if (unionType == MyGame.Sample.Equipment.Weapon) {
+ let weapon_name = monster.equipped(new MyGame.Sample.Weapon()).name(); // 'Axe'
+ let weapon_damage = monster.equipped(new MyGame.Sample.Weapon()).damage(); // 5
+ }
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ $union_type = $monster->getEquippedType();
+
+ if ($union_type == \MyGame\Sample\Equipment::Weapon) {
+ $weapon_name = $monster->getEquipped(new \MyGame\Sample\Weapon())->getName(); // "Axe"
+ $weapon_damage = $monster->getEquipped(new \MyGame\Sample\Weapon())->getDamage(); // 5
+ }
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ // Access union type field.
+ if (ns(Monster_equipped_type(monster)) == ns(Equipment_Weapon)) {
+ // Cast to appropriate type:
+ // C allows for silent void pointer assignment, so we need no explicit cast.
+ ns(Weapon_table_t) weapon = ns(Monster_equipped(monster));
+ const char *weapon_name = ns(Weapon_name(weapon)); // "Axe"
+ uint16_t weapon_damage = ns(Weapon_damage(weapon)); // 5
+ }
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ var unionType = monster.equippedType.value;
+
+ if (unionType == myGame.EquipmentTypeId.Weapon.value) {
+ myGame.Weapon weapon = mon.equipped as myGame.Weapon;
+
+ var weaponName = weapon.name; // "Axe"
+ var weaponDamage = weapon.damage; // 5
+ }
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ local unionType = mon:EquippedType()
+
+ if unionType == equipment.Weapon then
+ local unionWeapon = weapon.New()
+ unionWeapon:Init(mon:Equipped().bytes, mon:Equipped().pos)
+
+ local weaponName = unionWeapon:Name() -- 'Axe'
+ local weaponDamage = unionWeapon:Damage() -- 5
+ end
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ union_type = monster.equipped_type
+
+ if union_type == MyGame_Sample_Equipment_Weapon:
+ // `monster.equipped_as_Weapon` returns a FlatBuffer handle much like normal table fields,
+ // but this is only valid to call if we already know it is the correct type.
+ let union_weapon = monster.equipped_as_Weapon
+
+ let weapon_name = union_weapon.name // "Axe"
+ let weapon_damage = union_weapon.damage // 5
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ // Get and test the `Equipment` union (`equipped` field).
+ // `equipped_as_weapon` returns a FlatBuffer handle much like normal table
+ // fields, but this will return `None` is the union is not actually of that
+ // type.
+ if monster.equipped_type() == Equipment::Weapon {
+ let equipped = monster.equipped_as_weapon().unwrap();
+ let weapon_name = equipped.name();
+ let weapon_damage = equipped.damage();
+~~~
+</div>
+
+## Mutating FlatBuffers
+
+As you saw above, typically once you have created a FlatBuffer, it is read-only
+from that moment on. There are, however, cases where you have just received a
+FlatBuffer, and you'd like to modify something about it before sending it on to
+another recipient. With the above functionality, you'd have to generate an
+entirely new FlatBuffer, while tracking what you modified in your own data
+structures. This is inconvenient.
+
+For this reason FlatBuffers can also be mutated in-place. While this is great
+for making small fixes to an existing buffer, you generally want to create
+buffers from scratch whenever possible, since it is much more efficient and the
+API is much more general purpose.
+
+To get non-const accessors, invoke `flatc` with `--gen-mutable`.
+
+Similar to how we read fields using the accessors above, we can now use the
+mutators like so:
+
+<div class="language-cpp">
+~~~{.cpp}
+ auto monster = GetMutableMonster(buffer_pointer); // non-const
+ monster->mutate_hp(10); // Set the table `hp` field.
+ monster->mutable_pos()->mutate_z(4); // Set struct field.
+ monster->mutable_inventory()->Mutate(0, 1); // Set vector element.
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+ Monster monster = Monster.getRootAsMonster(buf);
+ monster.mutateHp(10); // Set table field.
+ monster.pos().mutateZ(4); // Set struct field.
+ monster.mutateInventory(0, 1); // Set vector element.
+~~~
+</div>
+<div class="language-kotlin">
+~~~{.kt}
+ val monster = Monster.getRootAsMonster(buf)
+ monster.mutateHp(10) // Set table field.
+ monster.pos!!.mutateZ(4) // Set struct field.
+ monster.mutateInventory(0, 1) // Set vector element.
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+ var monster = Monster.GetRootAsMonster(buf);
+ monster.MutateHp(10); // Set table field.
+ monster.Pos.MutateZ(4); // Set struct field.
+ monster.MutateInventory(0, 1); // Set vector element.
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+ <API for mutating FlatBuffers is not yet available in Go.>
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+ <API for mutating FlatBuffers is not yet available in Python.>
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+ <API for mutating FlatBuffers is not yet supported in JavaScript.>
+~~~
+</div>
+<div class="language-typescript">
+~~~{.ts}
+ <API for mutating FlatBuffers is not yet supported in TypeScript.>
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+ <API for mutating FlatBuffers is not yet supported in PHP.>
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+ <API for in-place mutating FlatBuffers will not be supported in C
+ (except in-place vector sorting is possible).>
+~~~
+</div>
+<div class="language-dart">
+~~~{.dart}
+ <API for mutating FlatBuffers not yet available in Dart.>
+~~~
+</div>
+<div class="language-lua">
+~~~{.lua}
+ <API for mutating FlatBuffers is not yet available in Lua.>
+~~~
+</div>
+<div class="language-lobster">
+~~~{.lobster}
+ <API for mutating FlatBuffers is not yet available in Lobster.>
+~~~
+</div>
+<div class="language-rust">
+~~~{.rs}
+ <API for mutating FlatBuffers is not yet available in Rust.>
+~~~
+</div>
+
+We use the somewhat verbose term `mutate` instead of `set` to indicate that this
+is a special use case, not to be confused with the default way of constructing
+FlatBuffer data.
+
+After the above mutations, you can send on the FlatBuffer to a new recipient
+without any further work!
+
+Note that any `mutate` functions on a table will return a boolean, which is
+`false` if the field we're trying to set is not present in the buffer. Fields
+that are not present if they weren't set, or even if they happen to be equal to
+the default value. For example, in the creation code above, the `mana`
+field is equal to `150`, which is the default value, so it was never stored in
+the buffer. Trying to call the corresponding `mutate` method for `mana` on such
+data will return `false`, and the value won't actually be modified!
+
+One way to solve this is to call `ForceDefaults` on a FlatBufferBuilder to
+force all fields you set to actually be written. This, of course, increases the
+size of the buffer somewhat, but this may be acceptable for a mutable buffer.
+
+If this is not sufficient, other ways of mutating FlatBuffers may be supported
+in your language through an object based API (`--gen-object-api`) or reflection.
+See the individual language documents for support.
+
+## Using `flatc` as a JSON Conversion Tool
+
+If you are working with C, C++, or Lobster, you can parse JSON at runtime.
+If your language does not support JSON at the moment, `flatc` may provide an
+alternative. Using `flatc` is often the preferred method, as it doesn't require you to
+add any new code to your program. It is also efficient, since you can ship with
+the binary data. The drawback is that it requires an extra step for your
+users/developers to perform (although it may be able to be automated
+as part of your compilation).
+
+#### JSON to binary representation
+
+Lets say you have a JSON file that describes your monster. In this example,
+we will use the file `flatbuffers/samples/monsterdata.json`.
+
+Here are the contents of the file:
+
+~~~{.json}
+{
+ pos: {
+ x: 1.0,
+ y: 2.0,
+ z: 3.0
+ },
+ hp: 300,
+ name: "Orc",
+ weapons: [
+ {
+ name: "axe",
+ damage: 100
+ },
+ {
+ name: "bow",
+ damage: 90
+ }
+ ],
+ equipped_type: "Weapon",
+ equipped: {
+ name: "bow",
+ damage: 90
+ }
+}
+~~~
+
+You can run this file through the `flatc` compiler with the `-b` flag and
+our `monster.fbs` schema to produce a FlatBuffer binary file.
+
+~~~{.sh}
+./../flatc -b monster.fbs monsterdata.json
+~~~
+
+The output of this will be a file `monsterdata.bin`, which will contain the
+FlatBuffer binary representation of the contents from our `.json` file.
+
+<div class="language-cpp">
+*Note: If you're working in C++, you can also parse JSON at runtime. See the
+[Use in C++](@ref flatbuffers_guide_use_cpp) section of the Programmer's
+Guide for more information.*
+</div>
+<div class="language-c">
+*Note: If you're working in C, the `flatcc --json` (not `flatc`)
+compiler will generate schema specific high performance json parsers and
+printers that you can compile and use at runtime. The `flatc` compiler (not
+`flatcc`) on the other hand, is still useful for general offline json to
+flatbuffer conversion from a given schema. There are no current plans
+for `flatcc` to support this.*
+</div>
+<div class="language-lobster">
+*Note: If you're working in Lobster, you can also parse JSON at runtime. See the
+[Use in Lobster](@ref flatbuffers_guide_use_lobster) section of the Programmer's
+Guide for more information.*
+</div>
+
+#### FlatBuffer binary to JSON
+
+Converting from a FlatBuffer binary representation to JSON is supported as well:
+~~~{.sh}
+./../flatc --json --raw-binary monster.fbs -- monsterdata.bin
+~~~
+This will convert `monsterdata.bin` back to its original JSON representation.
+You need to pass the corresponding FlatBuffers schema so that flatc knows how to
+interpret the binary buffer. Since `monster.fbs` does not specify an explicit
+`file_identifier` for binary buffers, `flatc` needs to be forced into reading
+the `.bin` file using the `--raw-binary` option.
+
+The FlatBuffer binary representation does not explicitly encode default values,
+therefore they are not present in the resulting JSON unless you specify
+`--defaults-json`.
+
+If you intend to process the JSON with other tools, you may consider switching
+on `--strict-json` so that identifiers are quoted properly.
+
+*Note: The resulting JSON file is not necessarily identical with the original JSON.
+If the binary representation contains floating point numbers, floats and doubles
+are rounded to 6 and 12 digits, respectively, in order to represent them as
+decimals in the JSON document. *
+
+## Advanced Features for Each Language
+
+Each language has a dedicated `Use in XXX` page in the Programmer's Guide
+to cover the nuances of FlatBuffers in that language.
+
+For your chosen language, see:
+
+<div class="language-cpp">
+[Use in C++](@ref flatbuffers_guide_use_cpp)
+</div>
+<div class="language-java">
+[Use in Java/C#](@ref flatbuffers_guide_use_java_c-sharp)
+</div>
+<div class="language-kotlin">
+[Use in Kotlin](@ref flatbuffers_guide_use_kotlin)
+</div>
+<div class="language-csharp">
+[Use in Java/C#](@ref flatbuffers_guide_use_java_c-sharp)
+</div>
+<div class="language-go">
+[Use in Go](@ref flatbuffers_guide_use_go)
+</div>
+<div class="language-python">
+[Use in Python](@ref flatbuffers_guide_use_python)
+</div>
+<div class="language-javascript">
+[Use in JavaScript](@ref flatbuffers_guide_use_javascript)
+</div>
+<div class="language-typescript">
+[Use in TypeScript](@ref flatbuffers_guide_use_typescript)
+</div>
+<div class="language-php">
+[Use in PHP](@ref flatbuffers_guide_use_php)
+</div>
+<div class="language-c">
+[Use in C](@ref flatbuffers_guide_use_c)
+</div>
+<div class="language-dart">
+[Use in Dart](@ref flatbuffers_guide_use_dart)
+</div>
+<div class="language-lua">
+[Use in Lua](@ref flatbuffers_guide_use_lua)
+</div>
+<div class="language-lobster">
+[Use in Lobster](@ref flatbuffers_guide_use_lobster)
+</div>
+<div class="language-rust">
+[Use in Rust](@ref flatbuffers_guide_use_rust)
+</div>
+
+<br>
diff --git a/docs/source/TypeScriptUsage.md b/docs/source/TypeScriptUsage.md
new file mode 100644
index 0000000..02aa239
--- /dev/null
+++ b/docs/source/TypeScriptUsage.md
@@ -0,0 +1,66 @@
+Use in TypeScript {#flatbuffers_guide_use_typescript}
+=================
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in TypeScript, it should be noted that
+the [Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to
+general FlatBuffers usage in all of the supported languages
+(including TypeScript). This page is specifically designed to cover the nuances
+of FlatBuffers usage in TypeScript.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers TypeScript library code location
+
+The code for the FlatBuffers TypeScript library can be found at
+`flatbuffers/js` with typings available at `@types/flatbuffers`.
+
+## Testing the FlatBuffers TypeScript library
+
+To run the tests, use the [TypeScriptTest.sh](https://github.com/google/
+flatbuffers/blob/master/tests/TypeScriptTest.sh) shell script.
+
+*Note: The TypeScript test file requires [Node.js](https://nodejs.org/en/).*
+
+## Using the FlatBuffers TypeScript libary
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in TypeScript.*
+
+FlatBuffers supports both reading and writing FlatBuffers in TypeScript.
+
+To use FlatBuffers in your own code, first generate TypeScript classes from your
+schema with the `--ts` option to `flatc`. Then you can include both FlatBuffers
+and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in TypeScript:
+First, include the library and generated code. Then read the file into an
+`Uint8Array`. Make a `flatbuffers.ByteBuffer` out of the `Uint8Array`, and pass
+the ByteBuffer to the `getRootAsMonster` function.
+
+~~~{.ts}
+ // note: import flatbuffers with your desired import method
+
+ import { MyGame } from './monster_generated';
+
+ let data = new Uint8Array(fs.readFileSync('monster.dat'));
+ let buf = new flatbuffers.ByteBuffer(data);
+
+ let monster = MyGame.Example.Monster.getRootAsMonster(buf);
+~~~
+
+Now you can access values like this:
+
+~~~{.ts}
+ let hp = monster.hp();
+ let pos = monster.pos();
+~~~
+
+## Text parsing FlatBuffers in TypeScript
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from TypeScript.
diff --git a/docs/source/WhitePaper.md b/docs/source/WhitePaper.md
new file mode 100644
index 0000000..e504ada
--- /dev/null
+++ b/docs/source/WhitePaper.md
@@ -0,0 +1,128 @@
+FlatBuffers white paper {#flatbuffers_white_paper}
+=======================
+
+This document tries to shed some light on to the "why" of FlatBuffers, a
+new serialization library.
+
+## Motivation
+
+Back in the good old days, performance was all about instructions and
+cycles. Nowadays, processing units have run so far ahead of the memory
+subsystem, that making an efficient application should start and finish
+with thinking about memory. How much you use of it. How you lay it out
+and access it. How you allocate it. When you copy it.
+
+Serialization is a pervasive activity in a lot programs, and a common
+source of memory inefficiency, with lots of temporary data structures
+needed to parse and represent data, and inefficient allocation patterns
+and locality.
+
+If it would be possible to do serialization with no temporary objects,
+no additional allocation, no copying, and good locality, this could be
+of great value. The reason serialization systems usually don't manage
+this is because it goes counter to forwards/backwards compatability, and
+platform specifics like endianness and alignment.
+
+FlatBuffers is what you get if you try anyway.
+
+In particular, FlatBuffers focus is on mobile hardware (where memory
+size and memory bandwidth is even more constrained than on desktop
+hardware), and applications that have the highest performance needs:
+games.
+
+## FlatBuffers
+
+*This is a summary of FlatBuffers functionality, with some rationale.
+A more detailed description can be found in the FlatBuffers
+documentation.*
+
+### Summary
+
+A FlatBuffer is a binary buffer containing nested objects (structs,
+tables, vectors,..) organized using offsets so that the data can be
+traversed in-place just like any pointer-based data structure. Unlike
+most in-memory data structures however, it uses strict rules of
+alignment and endianness (always little) to ensure these buffers are
+cross platform. Additionally, for objects that are tables, FlatBuffers
+provides forwards/backwards compatibility and general optionality of
+fields, to support most forms of format evolution.
+
+You define your object types in a schema, which can then be compiled to
+C++ or Java for low to zero overhead reading & writing.
+Optionally, JSON data can be dynamically parsed into buffers.
+
+### Tables
+
+Tables are the cornerstone of FlatBuffers, since format evolution is
+essential for most applications of serialization. Typically, dealing
+with format changes is something that can be done transparently during
+the parsing process of most serialization solutions out there.
+But a FlatBuffer isn't parsed before it is accessed.
+
+Tables get around this by using an extra indirection to access fields,
+through a *vtable*. Each table comes with a vtable (which may be shared
+between multiple tables with the same layout), and contains information
+where fields for this particular kind of instance of vtable are stored.
+The vtable may also indicate that the field is not present (because this
+FlatBuffer was written with an older version of the software, of simply
+because the information was not necessary for this instance, or deemed
+deprecated), in which case a default value is returned.
+
+Tables have a low overhead in memory (since vtables are small and
+shared) and in access cost (an extra indirection), but provide great
+flexibility. Tables may even cost less memory than the equivalent
+struct, since fields do not need to be stored when they are equal to
+their default.
+
+FlatBuffers additionally offers "naked" structs, which do not offer
+forwards/backwards compatibility, but can be even smaller (useful for
+very small objects that are unlikely to change, like e.g. a coordinate
+pair or a RGBA color).
+
+### Schemas
+
+While schemas reduce some generality (you can't just read any data
+without having its schema), they have a lot of upsides:
+
+- Most information about the format can be factored into the generated
+ code, reducing memory needed to store data, and time to access it.
+
+- The strong typing of the data definitions means less error
+ checking/handling at runtime (less can go wrong).
+
+- A schema enables us to access a buffer without parsing.
+
+FlatBuffer schemas are fairly similar to those of the incumbent,
+Protocol Buffers, and generally should be readable to those familiar
+with the C family of languages. We chose to improve upon the features
+offered by .proto files in the following ways:
+
+- Deprecation of fields instead of manual field id assignment.
+ Extending an object in a .proto means hunting for a free slot among
+ the numbers (preferring lower numbers since they have a more compact
+ representation). Besides being inconvenient, it also makes removing
+ fields problematic: you either have to keep them, not making it
+ obvious that this field shouldn't be read/written anymore, and still
+ generating accessors. Or you remove it, but now you risk that
+ there's still old data around that uses that field by the time
+ someone reuses that field id, with nasty consequences.
+
+- Differentiating between tables and structs (see above). Effectively
+ all table fields are `optional`, and all struct fields are
+ `required`.
+
+- Having a native vector type instead of `repeated`. This gives you a
+ length without having to collect all items, and in the case of
+ scalars provides for a more compact representation, and one that
+ guarantees adjacency.
+
+- Having a native `union` type instead of using a series of `optional`
+ fields, all of which must be checked individually.
+
+- Being able to define defaults for all scalars, instead of having to
+ deal with their optionality at each access.
+
+- A parser that can deal with both schemas and data definitions (JSON
+ compatible) uniformly.
+
+<br>
diff --git a/docs/source/doxyfile b/docs/source/doxyfile
new file mode 100644
index 0000000..6ba3c10
--- /dev/null
+++ b/docs/source/doxyfile
@@ -0,0 +1,2371 @@
+# Doxyfile 1.8.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "FlatBuffers"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ".."
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-
+# Traditional, Croatian, Czech, Danish, Dutch, English, Esperanto, Farsi,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en,
+# Korean, Korean-en, Latvian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = NO # Due to the multiple languages included in the API
+ # reference for FlatBuffers, the Auto-links were
+ # wrong more often than not.
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = NO
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = NO
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE = doxygen_layout.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = NO
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = "FlatBuffers.md" \
+ "Building.md" \
+ "Compiler.md" \
+ "Schemas.md" \
+ "CppUsage.md" \
+ "CUsage.md" \
+ "DartUsage.md" \
+ "GoUsage.md" \
+ "JavaCsharpUsage.md" \
+ "JavaScriptUsage.md" \
+ "TypeScriptUsage.md" \
+ "PHPUsage.md" \
+ "PythonUsage.md" \
+ "LuaUsage.md" \
+ "LobsterUsage.md" \
+ "RustUsage.md" \
+ "Support.md" \
+ "Benchmarks.md" \
+ "WhitePaper.md" \
+ "FlexBuffers.md" \
+ "Internals.md" \
+ "Grammar.md" \
+ "../../CONTRIBUTING.md" \
+ "Tutorial.md" \
+ "GoApi.md" \
+ "gRPC/CppUsage.md" \
+ "groups" \
+ "../../java/com/google/flatbuffers" \
+ "../../python/flatbuffers/builder.py" \
+ "../../js/flatbuffers.js" \
+ "../../php/FlatbufferBuilder.php" \
+ "../../net/FlatBuffers/FlatBufferBuilder.cs" \
+ "../../include/flatbuffers/flatbuffers.h" \
+ "../../go/builder.go"
+ "../../rust/flatbuffers/src/builder.rs"
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js \
+ *.go
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = *_test.py |
+ __init__.py
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH = "GoApi_generated.txt" "../../grpc/samples"
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *.cpp *.h *.txt *.fbs
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS = *.py=py_filter
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = FlatBuffers.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = ../header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = ../footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET = style.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES = "../images/fpl_logo_small.png" \
+ "../images/ftv2mnode.png" \
+ "../images/ftv2pnode.png"
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = NO
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = NO
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml
new file mode 100644
index 0000000..a232507
--- /dev/null
+++ b/docs/source/doxygen_layout.xml
@@ -0,0 +1,248 @@
+<!-- Copyright 2015 Google Inc. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<doxygenlayout version="1.0">
+ <navindex>
+ <tab type="mainpage" visible="no" title=""/>
+ <tab type="usergroup" url="" title="Programmer's Guide">
+ <tab type="user" url="@ref flatbuffers_guide_building"
+ title="Building"/>
+ <tab type="user" url="@ref flatbuffers_guide_tutorial" title="Tutorial"/>
+ <tab type="user" url="@ref flatbuffers_guide_using_schema_compiler"
+ title="Using the schema compiler"/>
+ <tab type="user" url="@ref flatbuffers_guide_writing_schema"
+ title="Writing a schema"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_cpp"
+ title="Use in C++"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_c"
+ title="Use in C"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_go"
+ title="Use in Go"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_java_c-sharp"
+ title="Use in Java/C#"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_javascript"
+ title="Use in JavaScript"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_typescript"
+ title="Use in TypeScript"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_php"
+ title="Use in PHP"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_python"
+ title="Use in Python"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_dart"
+ title="Use in Dart"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_lua"
+ title="Use in Lua"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_lobster"
+ title="Use in Lobster"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_rust"
+ title="Use in Rust"/>
+ <tab type="user" url="@ref flexbuffers"
+ title="Schema-less version"/>
+ <tab type="usergroup" url="" title="gRPC">
+ <tab type="user" url="@ref flatbuffers_grpc_guide_use_cpp"
+ title="Use in C++"/>
+ </tab>
+ </tab>
+ <tab type="user" url="@ref flatbuffers_support"
+ title="Platform / Language / Feature support"/>
+ <tab type="user" url="@ref flatbuffers_benchmarks"
+ title="Benchmarks"/>
+ <tab type="user" url="@ref flatbuffers_white_paper"
+ title="FlatBuffers white paper"/>
+ <tab type="user" url="@ref flatbuffers_internals"
+ title="FlatBuffers internals"/>
+ <tab type="user" url="@ref flatbuffers_grammar"
+ title="Grammar of the schema language"/>
+ <tab type="usergroup" url="" title="API Reference">
+ <tab type="modules" visible="yes" title="APIs" intro=""/>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ </tab>
+ <tab type="user" url="@ref contributing" title="Contributing"/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <detaileddescription title=""/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <detaileddescription title=""/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <detaileddescription title=""/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ </directory>
+</doxygenlayout>
diff --git a/docs/source/gRPC/CppUsage.md b/docs/source/gRPC/CppUsage.md
new file mode 100644
index 0000000..93dbb29
--- /dev/null
+++ b/docs/source/gRPC/CppUsage.md
@@ -0,0 +1,29 @@
+Use in C++ {#flatbuffers_grpc_guide_use_cpp}
+==========
+
+## Before you get started
+
+Before diving into the FlatBuffers gRPC usage in C++, you should already be
+familiar with the following:
+
+- FlatBuffers as a serialization format
+- [gRPC](http://www.grpc.io/docs/) usage
+
+## Using the FlatBuffers gRPC C++ library
+
+NOTE: The examples below are also in the `grpc/samples/greeter` directory.
+
+We will illustrate usage with the following schema:
+
+@include grpc/samples/greeter/greeter.fbs
+
+When we run `flatc`, we pass in the `--grpc` option and generage an additional
+`greeter.grpc.fb.h` and `greeter.grpc.fb.cc`.
+
+Example server code looks like this:
+
+@include grpc/samples/greeter/server.cpp
+
+Example client code looks like this:
+
+@include grpc/samples/greeter/client.cpp
diff --git a/docs/source/groups b/docs/source/groups
new file mode 100644
index 0000000..c3aea18
--- /dev/null
+++ b/docs/source/groups
@@ -0,0 +1,23 @@
+/// @defgroup flatbuffers_cpp_api C++ API
+/// @brief FlatBuffers API for C++
+
+/// @defgroup flatbuffers_csharp_api C# API
+/// @brief FlatBuffers API for C#
+
+/// @defgroup flatbuffers_go_api Go API
+/// @brief FlatBuffers API for Go
+
+/// @defgroup flatbuffers_java_api Java API
+/// @brief FlatBuffers API for Java
+
+/// @defgroup flatbuffers_javascript_api JavaScript API
+/// @brief FlatBuffers API for JavaScript
+
+/// @defgroup flatbuffers_typescript_api TypeScript API
+/// @brief FlatBuffers API for TypeScript
+
+/// @defgroup flatbuffers_php_api PHP API
+/// @brief FlatBuffers API for PHP
+
+/// @defgroup flatbuffers_python_api Python API
+/// @brief FlatBuffers API for Python
diff --git a/docs/source/style.css b/docs/source/style.css
new file mode 100644
index 0000000..6045a97
--- /dev/null
+++ b/docs/source/style.css
@@ -0,0 +1,396 @@
+body,
+#projectname,
+table,
+div,
+p,
+dl,
+.title,
+.tabs,
+.tabs2,
+.tabs3,
+#nav-tree .label {
+ font-family: roboto, sans-serif;
+}
+
+#commonprojectlogo {
+ padding: 5px 0px 5px 15px;
+}
+
+#projectname {
+ color: #00bcd4;
+ font-size: 280%;
+ padding: 15px 0px;
+ font-weight: 300;
+}
+
+#titlearea {
+ border-bottom: 2px solid #e5e5e5;
+}
+
+.title {
+ color: #212121;
+ font: 300 34px/40px Roboto,sans-serif;
+}
+
+#nav-tree {
+ background-color: #fff;
+}
+
+#navrow1, #navrow2 {
+ border-bottom: 2px solid #e7e7e7;
+}
+
+.tabs, .tabs2, .tabs3 {
+ font-size: 14px;
+}
+
+.tabs,
+.tabs2,
+.tabs3,
+.tablist li,
+.tablist li.current a {
+ background-image: none;
+}
+
+.tablist {
+ list-style: none;
+}
+
+.tablist li, .tablist li p {
+ margin: 0;
+}
+
+.tablist li a,
+.tablist li.current a {
+ color: #757575;
+ text-shadow: none;
+}
+
+.tablist li.current a {
+ background: #00bcd4;
+ color: #fff;
+}
+
+.tablist a {
+ background-image: none;
+ border-right: 2px solid #e5e5e5;
+ font-weight: normal;
+}
+
+.tablist a:hover,
+.tablist li.current a:hover {
+ background-image: none;
+ text-decoration: underline;
+ text-shadow: none;
+}
+
+.tablist a:hover {
+ color: #00bcd4;
+}
+
+.tablist li.current a:hover {
+ color: #fff;
+}
+
+div.header {
+ background-color: #f7f7f7;
+ background-image: none;
+ border-bottom: none;
+}
+
+#MSearchBox {
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ display: inline-block;
+ height: 20px;
+ right: 10px;
+}
+
+#MSearchBox .left,
+#MSearchBox .right,
+#MSearchField {
+ background: none;
+}
+
+a.SelectItem:hover {
+ background-color: #00bcd4;
+}
+
+#nav-tree {
+ background-image: none;
+}
+
+#nav-tree .selected {
+ background-image: none;
+ text-shadow: none;
+ background-color: #f7f7f7;
+}
+
+#nav-tree a {
+ color: #212121;
+}
+
+#nav-tree .selected a {
+ color: #0288d1;
+}
+
+#nav-tree .item:hover {
+ background-color: #f7f7f7;
+}
+
+#nav-tree .item:hover a {
+ color: #0288d1;
+}
+
+#nav-tree .label {
+ font-size: 13px;
+}
+
+#nav-sync {
+ display: none;
+}
+
+.ui-resizable-e {
+ background: #ebebeb;
+ border-left: 1px solid #ddd;
+ border-right: 1px solid #ddd;
+}
+
+.contents tr td .image {
+ margin-top: 24px;
+}
+
+.image {
+ text-align: left;
+ margin-bottom: 8px;
+}
+
+a:link,
+a:visited,
+.contents a:link,
+.contents a:visited,
+a.el {
+ color: #0288d1;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+div.contents {
+ margin-right: 12px;
+}
+
+.directory tr, .directory tr.even {
+ background: #7cb342;
+ border-top: 1px solid #7cb342;
+}
+
+.directory td,
+.directory td.entry,
+.directory td.desc {
+ background: rgba(255,255,255,.95);
+ border-left: none;
+ color: #212121;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ padding-left: 8px;
+ padding-right: 8px;
+}
+
+.directory tr#row_0_ {
+ border-top-color: #7cb342;
+}
+
+.directory tr#row_0_ td {
+ background: #7cb342;
+ color: #fff;
+ font-size: 18px;
+}
+
+.memSeparator {
+ border-bottom: none;
+}
+
+.memitem {
+ background: #7cb342;
+}
+
+.memproto, dl.reflist dt {
+ background: #7cb342;
+ background-image: none;
+ border: none;
+ box-shadow: none;
+ -webkit-box-shadow: none;
+ color: #fff;
+ text-shadow: none;
+}
+
+.memproto .memtemplate,
+.memproto a.el,
+.memproto .paramname {
+ color: #fff;
+}
+
+.memdoc, dl.reflist dd {
+ border: none;
+ background-color: rgba(255,255,255,.95);
+ background-image: none;
+ box-shadow: none;
+ -webkit-box-shadow: none;
+ -webkit-border-bottom-left-radius: 0;
+ -webkit-border-bottom-right-radius: 0;
+}
+
+.memitem, table.doxtable, table.memberdecls {
+ margin-bottom: 24px;
+}
+
+table.doxtable th {
+ background: #7cb342;
+}
+
+table.doxtable tr {
+ background: #7cb342;
+ border-top: 1px solid #7cb342;
+}
+
+table.doxtable td, table.doxtable th {
+ border: none;
+ padding: 10px 8px;
+}
+
+table.doxtable td {
+ background-color: rgba(255,255,255,.95);
+}
+
+.memberdecls {
+ background: #7cb342;
+ border-top: 1px solid #7cb342;
+}
+
+.memberdecls .heading h2 {
+ border-bottom: none;
+ color: #fff;
+ font-size: 110%;
+ font-weight: bold;
+ margin: 0 0 0 6px;
+}
+
+.memberdecls tr:not(.heading) td {
+ background-color: rgba(255,255,255,.95);
+}
+
+h1, h2, h2.groupheader, h3, h4, h5, h6 {
+ color: #212121;
+}
+
+h1 {
+ border-bottom: 1px solid #ebebeb;
+ font: 400 28px/32px Roboto,sans-serif;
+ letter-spacing: -.01em;
+ margin: 40px 0 20px;
+ padding-bottom: 3px;
+}
+
+h2, h2.groupheader {
+ border-bottom: 1px solid #ebebeb;
+ font: 400 23px/32px Roboto,sans-serif;
+ letter-spacing: -.01em;
+ margin: 40px 0 20px;
+ padding-bottom: 3px;
+}
+
+h3 {
+ font: 500 20px/32px Roboto,sans-serif;
+ margin: 32px 0 16px;
+}
+
+h4 {
+ font: 500 18px/32px Roboto,sans-serif;
+ margin: 32px 0 16px;
+}
+
+ol,
+ul {
+ margin: 0;
+ padding-left: 40px;
+}
+
+ol {
+ list-style: decimal outside;
+}
+
+ol ol {
+ list-style-type: lower-alpha;
+}
+
+ol ol ol {
+ list-style-type: lower-roman;
+}
+
+ul {
+ list-style: disc outside;
+}
+
+li,
+li p {
+ margin: 8px 0;
+ padding: 0;
+}
+
+div.summary
+{
+ float: none;
+ font-size: 8pt;
+ padding-left: 5px;
+ width: calc(100% - 10px);
+ text-align: left;
+ display: block;
+}
+
+div.ingroups {
+ margin-top: 8px;
+}
+
+div.fragment {
+ border: 1px solid #ddd;
+ color: #455a64;
+ font: 14px/20px Roboto Mono, monospace;
+ padding: 8px;
+}
+
+div.line {
+ line-height: 1.5;
+ font-size: inherit;
+}
+
+code, pre {
+ color: #455a64;
+ background: #f7f7f7;
+ font: 400 100% Roboto Mono,monospace;
+ padding: 1px 4px;
+}
+
+span.preprocessor, span.comment {
+ color: #0b8043;
+}
+
+span.keywordtype {
+ color: #0097a7;
+}
+
+.paramname {
+ color: #ef6c00;
+}
+
+.memTemplParams {
+ color: #ef6c00;
+}
+
+span.mlabel {
+ background: rgba(255,255,255,.25);
+ border: none;
+}
+
+blockquote {
+ border: 1px solid #ddd;
+}
diff --git a/go/BUILD.bazel b/go/BUILD.bazel
new file mode 100644
index 0000000..78bd8d8
--- /dev/null
+++ b/go/BUILD.bazel
@@ -0,0 +1,23 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+alias(
+ name = "go_default_library",
+ actual = ":go",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "go",
+ srcs = [
+ "builder.go",
+ "doc.go",
+ "encode.go",
+ "grpc.go",
+ "lib.go",
+ "sizes.go",
+ "struct.go",
+ "table.go",
+ ],
+ importpath = "github.com/google/flatbuffers/go",
+ visibility = ["//visibility:public"],
+)
diff --git a/go/builder.go b/go/builder.go
new file mode 100644
index 0000000..8d75700
--- /dev/null
+++ b/go/builder.go
@@ -0,0 +1,771 @@
+package flatbuffers
+
+// Builder is a state machine for creating FlatBuffer objects.
+// Use a Builder to construct object(s) starting from leaf nodes.
+//
+// A Builder constructs byte buffers in a last-first manner for simplicity and
+// performance.
+type Builder struct {
+ // `Bytes` gives raw access to the buffer. Most users will want to use
+ // FinishedBytes() instead.
+ Bytes []byte
+
+ minalign int
+ vtable []UOffsetT
+ objectEnd UOffsetT
+ vtables []UOffsetT
+ head UOffsetT
+ nested bool
+ finished bool
+}
+
+const fileIdentifierLength = 4
+
+// NewBuilder initializes a Builder of size `initial_size`.
+// The internal buffer is grown as needed.
+func NewBuilder(initialSize int) *Builder {
+ if initialSize <= 0 {
+ initialSize = 0
+ }
+
+ b := &Builder{}
+ b.Bytes = make([]byte, initialSize)
+ b.head = UOffsetT(initialSize)
+ b.minalign = 1
+ b.vtables = make([]UOffsetT, 0, 16) // sensible default capacity
+
+ return b
+}
+
+// Reset truncates the underlying Builder buffer, facilitating alloc-free
+// reuse of a Builder. It also resets bookkeeping data.
+func (b *Builder) Reset() {
+ if b.Bytes != nil {
+ b.Bytes = b.Bytes[:cap(b.Bytes)]
+ }
+
+ if b.vtables != nil {
+ b.vtables = b.vtables[:0]
+ }
+
+ if b.vtable != nil {
+ b.vtable = b.vtable[:0]
+ }
+
+ b.head = UOffsetT(len(b.Bytes))
+ b.minalign = 1
+ b.nested = false
+ b.finished = false
+}
+
+// FinishedBytes returns a pointer to the written data in the byte buffer.
+// Panics if the builder is not in a finished state (which is caused by calling
+// `Finish()`).
+func (b *Builder) FinishedBytes() []byte {
+ b.assertFinished()
+ return b.Bytes[b.Head():]
+}
+
+// StartObject initializes bookkeeping for writing a new object.
+func (b *Builder) StartObject(numfields int) {
+ b.assertNotNested()
+ b.nested = true
+
+ // use 32-bit offsets so that arithmetic doesn't overflow.
+ if cap(b.vtable) < numfields || b.vtable == nil {
+ b.vtable = make([]UOffsetT, numfields)
+ } else {
+ b.vtable = b.vtable[:numfields]
+ for i := 0; i < len(b.vtable); i++ {
+ b.vtable[i] = 0
+ }
+ }
+
+ b.objectEnd = b.Offset()
+}
+
+// WriteVtable serializes the vtable for the current object, if applicable.
+//
+// Before writing out the vtable, this checks pre-existing vtables for equality
+// to this one. If an equal vtable is found, point the object to the existing
+// vtable and return.
+//
+// Because vtable values are sensitive to alignment of object data, not all
+// logically-equal vtables will be deduplicated.
+//
+// A vtable has the following format:
+// <VOffsetT: size of the vtable in bytes, including this value>
+// <VOffsetT: size of the object in bytes, including the vtable offset>
+// <VOffsetT: offset for a field> * N, where N is the number of fields in
+// the schema for this type. Includes deprecated fields.
+// Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide.
+//
+// An object has the following format:
+// <SOffsetT: offset to this object's vtable (may be negative)>
+// <byte: data>+
+func (b *Builder) WriteVtable() (n UOffsetT) {
+ // Prepend a zero scalar to the object. Later in this function we'll
+ // write an offset here that points to the object's vtable:
+ b.PrependSOffsetT(0)
+
+ objectOffset := b.Offset()
+ existingVtable := UOffsetT(0)
+
+ // Trim vtable of trailing zeroes.
+ i := len(b.vtable) - 1
+ for ; i >= 0 && b.vtable[i] == 0; i-- {
+ }
+ b.vtable = b.vtable[:i+1]
+
+ // Search backwards through existing vtables, because similar vtables
+ // are likely to have been recently appended. See
+ // BenchmarkVtableDeduplication for a case in which this heuristic
+ // saves about 30% of the time used in writing objects with duplicate
+ // tables.
+ for i := len(b.vtables) - 1; i >= 0; i-- {
+ // Find the other vtable, which is associated with `i`:
+ vt2Offset := b.vtables[i]
+ vt2Start := len(b.Bytes) - int(vt2Offset)
+ vt2Len := GetVOffsetT(b.Bytes[vt2Start:])
+
+ metadata := VtableMetadataFields * SizeVOffsetT
+ vt2End := vt2Start + int(vt2Len)
+ vt2 := b.Bytes[vt2Start+metadata : vt2End]
+
+ // Compare the other vtable to the one under consideration.
+ // If they are equal, store the offset and break:
+ if vtableEqual(b.vtable, objectOffset, vt2) {
+ existingVtable = vt2Offset
+ break
+ }
+ }
+
+ if existingVtable == 0 {
+ // Did not find a vtable, so write this one to the buffer.
+
+ // Write out the current vtable in reverse , because
+ // serialization occurs in last-first order:
+ for i := len(b.vtable) - 1; i >= 0; i-- {
+ var off UOffsetT
+ if b.vtable[i] != 0 {
+ // Forward reference to field;
+ // use 32bit number to assert no overflow:
+ off = objectOffset - b.vtable[i]
+ }
+
+ b.PrependVOffsetT(VOffsetT(off))
+ }
+
+ // The two metadata fields are written last.
+
+ // First, store the object bytesize:
+ objectSize := objectOffset - b.objectEnd
+ b.PrependVOffsetT(VOffsetT(objectSize))
+
+ // Second, store the vtable bytesize:
+ vBytes := (len(b.vtable) + VtableMetadataFields) * SizeVOffsetT
+ b.PrependVOffsetT(VOffsetT(vBytes))
+
+ // Next, write the offset to the new vtable in the
+ // already-allocated SOffsetT at the beginning of this object:
+ objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
+ WriteSOffsetT(b.Bytes[objectStart:],
+ SOffsetT(b.Offset())-SOffsetT(objectOffset))
+
+ // Finally, store this vtable in memory for future
+ // deduplication:
+ b.vtables = append(b.vtables, b.Offset())
+ } else {
+ // Found a duplicate vtable.
+
+ objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
+ b.head = UOffsetT(objectStart)
+
+ // Write the offset to the found vtable in the
+ // already-allocated SOffsetT at the beginning of this object:
+ WriteSOffsetT(b.Bytes[b.head:],
+ SOffsetT(existingVtable)-SOffsetT(objectOffset))
+ }
+
+ b.vtable = b.vtable[:0]
+ return objectOffset
+}
+
+// EndObject writes data necessary to finish object construction.
+func (b *Builder) EndObject() UOffsetT {
+ b.assertNested()
+ n := b.WriteVtable()
+ b.nested = false
+ return n
+}
+
+// Doubles the size of the byteslice, and copies the old data towards the
+// end of the new byteslice (since we build the buffer backwards).
+func (b *Builder) growByteBuffer() {
+ if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 {
+ panic("cannot grow buffer beyond 2 gigabytes")
+ }
+ newLen := len(b.Bytes) * 2
+ if newLen == 0 {
+ newLen = 1
+ }
+
+ if cap(b.Bytes) >= newLen {
+ b.Bytes = b.Bytes[:newLen]
+ } else {
+ extension := make([]byte, newLen-len(b.Bytes))
+ b.Bytes = append(b.Bytes, extension...)
+ }
+
+ middle := newLen / 2
+ copy(b.Bytes[middle:], b.Bytes[:middle])
+}
+
+// Head gives the start of useful data in the underlying byte buffer.
+// Note: unlike other functions, this value is interpreted as from the left.
+func (b *Builder) Head() UOffsetT {
+ return b.head
+}
+
+// Offset relative to the end of the buffer.
+func (b *Builder) Offset() UOffsetT {
+ return UOffsetT(len(b.Bytes)) - b.head
+}
+
+// Pad places zeros at the current offset.
+func (b *Builder) Pad(n int) {
+ for i := 0; i < n; i++ {
+ b.PlaceByte(0)
+ }
+}
+
+// Prep prepares to write an element of `size` after `additional_bytes`
+// have been written, e.g. if you write a string, you need to align such
+// the int length field is aligned to SizeInt32, and the string data follows it
+// directly.
+// If all you need to do is align, `additionalBytes` will be 0.
+func (b *Builder) Prep(size, additionalBytes int) {
+ // Track the biggest thing we've ever aligned to.
+ if size > b.minalign {
+ b.minalign = size
+ }
+ // Find the amount of alignment needed such that `size` is properly
+ // aligned after `additionalBytes`:
+ alignSize := (^(len(b.Bytes) - int(b.Head()) + additionalBytes)) + 1
+ alignSize &= (size - 1)
+
+ // Reallocate the buffer if needed:
+ for int(b.head) <= alignSize+size+additionalBytes {
+ oldBufSize := len(b.Bytes)
+ b.growByteBuffer()
+ b.head += UOffsetT(len(b.Bytes) - oldBufSize)
+ }
+ b.Pad(alignSize)
+}
+
+// PrependSOffsetT prepends an SOffsetT, relative to where it will be written.
+func (b *Builder) PrependSOffsetT(off SOffsetT) {
+ b.Prep(SizeSOffsetT, 0) // Ensure alignment is already done.
+ if !(UOffsetT(off) <= b.Offset()) {
+ panic("unreachable: off <= b.Offset()")
+ }
+ off2 := SOffsetT(b.Offset()) - off + SOffsetT(SizeSOffsetT)
+ b.PlaceSOffsetT(off2)
+}
+
+// PrependUOffsetT prepends an UOffsetT, relative to where it will be written.
+func (b *Builder) PrependUOffsetT(off UOffsetT) {
+ b.Prep(SizeUOffsetT, 0) // Ensure alignment is already done.
+ if !(off <= b.Offset()) {
+ panic("unreachable: off <= b.Offset()")
+ }
+ off2 := b.Offset() - off + UOffsetT(SizeUOffsetT)
+ b.PlaceUOffsetT(off2)
+}
+
+// StartVector initializes bookkeeping for writing a new vector.
+//
+// A vector has the following format:
+// <UOffsetT: number of elements in this vector>
+// <T: data>+, where T is the type of elements of this vector.
+func (b *Builder) StartVector(elemSize, numElems, alignment int) UOffsetT {
+ b.assertNotNested()
+ b.nested = true
+ b.Prep(SizeUint32, elemSize*numElems)
+ b.Prep(alignment, elemSize*numElems) // Just in case alignment > int.
+ return b.Offset()
+}
+
+// EndVector writes data necessary to finish vector construction.
+func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
+ b.assertNested()
+
+ // we already made space for this, so write without PrependUint32
+ b.PlaceUOffsetT(UOffsetT(vectorNumElems))
+
+ b.nested = false
+ return b.Offset()
+}
+
+// CreateString writes a null-terminated string as a vector.
+func (b *Builder) CreateString(s string) UOffsetT {
+ b.assertNotNested()
+ b.nested = true
+
+ b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
+ b.PlaceByte(0)
+
+ l := UOffsetT(len(s))
+
+ b.head -= l
+ copy(b.Bytes[b.head:b.head+l], s)
+
+ return b.EndVector(len(s))
+}
+
+// CreateByteString writes a byte slice as a string (null-terminated).
+func (b *Builder) CreateByteString(s []byte) UOffsetT {
+ b.assertNotNested()
+ b.nested = true
+
+ b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
+ b.PlaceByte(0)
+
+ l := UOffsetT(len(s))
+
+ b.head -= l
+ copy(b.Bytes[b.head:b.head+l], s)
+
+ return b.EndVector(len(s))
+}
+
+// CreateByteVector writes a ubyte vector
+func (b *Builder) CreateByteVector(v []byte) UOffsetT {
+ b.assertNotNested()
+ b.nested = true
+
+ b.Prep(int(SizeUOffsetT), len(v)*SizeByte)
+
+ l := UOffsetT(len(v))
+
+ b.head -= l
+ copy(b.Bytes[b.head:b.head+l], v)
+
+ return b.EndVector(len(v))
+}
+
+func (b *Builder) assertNested() {
+ // If you get this assert, you're in an object while trying to write
+ // data that belongs outside of an object.
+ // To fix this, write non-inline data (like vectors) before creating
+ // objects.
+ if !b.nested {
+ panic("Incorrect creation order: must be inside object.")
+ }
+}
+
+func (b *Builder) assertNotNested() {
+ // If you hit this, you're trying to construct a Table/Vector/String
+ // during the construction of its parent table (between the MyTableBuilder
+ // and builder.Finish()).
+ // Move the creation of these sub-objects to above the MyTableBuilder to
+ // not get this assert.
+ // Ignoring this assert may appear to work in simple cases, but the reason
+ // it is here is that storing objects in-line may cause vtable offsets
+ // to not fit anymore. It also leads to vtable duplication.
+ if b.nested {
+ panic("Incorrect creation order: object must not be nested.")
+ }
+}
+
+func (b *Builder) assertFinished() {
+ // If you get this assert, you're attempting to get access a buffer
+ // which hasn't been finished yet. Be sure to call builder.Finish()
+ // with your root table.
+ // If you really need to access an unfinished buffer, use the Bytes
+ // buffer directly.
+ if !b.finished {
+ panic("Incorrect use of FinishedBytes(): must call 'Finish' first.")
+ }
+}
+
+// PrependBoolSlot prepends a bool onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependBoolSlot(o int, x, d bool) {
+ val := byte(0)
+ if x {
+ val = 1
+ }
+ def := byte(0)
+ if d {
+ def = 1
+ }
+ b.PrependByteSlot(o, val, def)
+}
+
+// PrependByteSlot prepends a byte onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependByteSlot(o int, x, d byte) {
+ if x != d {
+ b.PrependByte(x)
+ b.Slot(o)
+ }
+}
+
+// PrependUint8Slot prepends a uint8 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependUint8Slot(o int, x, d uint8) {
+ if x != d {
+ b.PrependUint8(x)
+ b.Slot(o)
+ }
+}
+
+// PrependUint16Slot prepends a uint16 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependUint16Slot(o int, x, d uint16) {
+ if x != d {
+ b.PrependUint16(x)
+ b.Slot(o)
+ }
+}
+
+// PrependUint32Slot prepends a uint32 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependUint32Slot(o int, x, d uint32) {
+ if x != d {
+ b.PrependUint32(x)
+ b.Slot(o)
+ }
+}
+
+// PrependUint64Slot prepends a uint64 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependUint64Slot(o int, x, d uint64) {
+ if x != d {
+ b.PrependUint64(x)
+ b.Slot(o)
+ }
+}
+
+// PrependInt8Slot prepends a int8 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependInt8Slot(o int, x, d int8) {
+ if x != d {
+ b.PrependInt8(x)
+ b.Slot(o)
+ }
+}
+
+// PrependInt16Slot prepends a int16 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependInt16Slot(o int, x, d int16) {
+ if x != d {
+ b.PrependInt16(x)
+ b.Slot(o)
+ }
+}
+
+// PrependInt32Slot prepends a int32 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependInt32Slot(o int, x, d int32) {
+ if x != d {
+ b.PrependInt32(x)
+ b.Slot(o)
+ }
+}
+
+// PrependInt64Slot prepends a int64 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependInt64Slot(o int, x, d int64) {
+ if x != d {
+ b.PrependInt64(x)
+ b.Slot(o)
+ }
+}
+
+// PrependFloat32Slot prepends a float32 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependFloat32Slot(o int, x, d float32) {
+ if x != d {
+ b.PrependFloat32(x)
+ b.Slot(o)
+ }
+}
+
+// PrependFloat64Slot prepends a float64 onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependFloat64Slot(o int, x, d float64) {
+ if x != d {
+ b.PrependFloat64(x)
+ b.Slot(o)
+ }
+}
+
+// PrependUOffsetTSlot prepends an UOffsetT onto the object at vtable slot `o`.
+// If value `x` equals default `d`, then the slot will be set to zero and no
+// other data will be written.
+func (b *Builder) PrependUOffsetTSlot(o int, x, d UOffsetT) {
+ if x != d {
+ b.PrependUOffsetT(x)
+ b.Slot(o)
+ }
+}
+
+// PrependStructSlot prepends a struct onto the object at vtable slot `o`.
+// Structs are stored inline, so nothing additional is being added.
+// In generated code, `d` is always 0.
+func (b *Builder) PrependStructSlot(voffset int, x, d UOffsetT) {
+ if x != d {
+ b.assertNested()
+ if x != b.Offset() {
+ panic("inline data write outside of object")
+ }
+ b.Slot(voffset)
+ }
+}
+
+// Slot sets the vtable key `voffset` to the current location in the buffer.
+func (b *Builder) Slot(slotnum int) {
+ b.vtable[slotnum] = UOffsetT(b.Offset())
+}
+
+// FinishWithFileIdentifier finalizes a buffer, pointing to the given `rootTable`.
+// as well as applys a file identifier
+func (b *Builder) FinishWithFileIdentifier(rootTable UOffsetT, fid []byte) {
+ if fid == nil || len(fid) != fileIdentifierLength {
+ panic("incorrect file identifier length")
+ }
+ // In order to add a file identifier to the flatbuffer message, we need
+ // to prepare an alignment and file identifier length
+ b.Prep(b.minalign, SizeInt32+fileIdentifierLength)
+ for i := fileIdentifierLength - 1; i >= 0; i-- {
+ // place the file identifier
+ b.PlaceByte(fid[i])
+ }
+ // finish
+ b.Finish(rootTable)
+}
+
+// Finish finalizes a buffer, pointing to the given `rootTable`.
+func (b *Builder) Finish(rootTable UOffsetT) {
+ b.assertNotNested()
+ b.Prep(b.minalign, SizeUOffsetT)
+ b.PrependUOffsetT(rootTable)
+ b.finished = true
+}
+
+// vtableEqual compares an unwritten vtable to a written vtable.
+func vtableEqual(a []UOffsetT, objectStart UOffsetT, b []byte) bool {
+ if len(a)*SizeVOffsetT != len(b) {
+ return false
+ }
+
+ for i := 0; i < len(a); i++ {
+ x := GetVOffsetT(b[i*SizeVOffsetT : (i+1)*SizeVOffsetT])
+
+ // Skip vtable entries that indicate a default value.
+ if x == 0 && a[i] == 0 {
+ continue
+ }
+
+ y := SOffsetT(objectStart) - SOffsetT(a[i])
+ if SOffsetT(x) != y {
+ return false
+ }
+ }
+ return true
+}
+
+// PrependBool prepends a bool to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependBool(x bool) {
+ b.Prep(SizeBool, 0)
+ b.PlaceBool(x)
+}
+
+// PrependUint8 prepends a uint8 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependUint8(x uint8) {
+ b.Prep(SizeUint8, 0)
+ b.PlaceUint8(x)
+}
+
+// PrependUint16 prepends a uint16 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependUint16(x uint16) {
+ b.Prep(SizeUint16, 0)
+ b.PlaceUint16(x)
+}
+
+// PrependUint32 prepends a uint32 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependUint32(x uint32) {
+ b.Prep(SizeUint32, 0)
+ b.PlaceUint32(x)
+}
+
+// PrependUint64 prepends a uint64 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependUint64(x uint64) {
+ b.Prep(SizeUint64, 0)
+ b.PlaceUint64(x)
+}
+
+// PrependInt8 prepends a int8 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependInt8(x int8) {
+ b.Prep(SizeInt8, 0)
+ b.PlaceInt8(x)
+}
+
+// PrependInt16 prepends a int16 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependInt16(x int16) {
+ b.Prep(SizeInt16, 0)
+ b.PlaceInt16(x)
+}
+
+// PrependInt32 prepends a int32 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependInt32(x int32) {
+ b.Prep(SizeInt32, 0)
+ b.PlaceInt32(x)
+}
+
+// PrependInt64 prepends a int64 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependInt64(x int64) {
+ b.Prep(SizeInt64, 0)
+ b.PlaceInt64(x)
+}
+
+// PrependFloat32 prepends a float32 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependFloat32(x float32) {
+ b.Prep(SizeFloat32, 0)
+ b.PlaceFloat32(x)
+}
+
+// PrependFloat64 prepends a float64 to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependFloat64(x float64) {
+ b.Prep(SizeFloat64, 0)
+ b.PlaceFloat64(x)
+}
+
+// PrependByte prepends a byte to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependByte(x byte) {
+ b.Prep(SizeByte, 0)
+ b.PlaceByte(x)
+}
+
+// PrependVOffsetT prepends a VOffsetT to the Builder buffer.
+// Aligns and checks for space.
+func (b *Builder) PrependVOffsetT(x VOffsetT) {
+ b.Prep(SizeVOffsetT, 0)
+ b.PlaceVOffsetT(x)
+}
+
+// PlaceBool prepends a bool to the Builder, without checking for space.
+func (b *Builder) PlaceBool(x bool) {
+ b.head -= UOffsetT(SizeBool)
+ WriteBool(b.Bytes[b.head:], x)
+}
+
+// PlaceUint8 prepends a uint8 to the Builder, without checking for space.
+func (b *Builder) PlaceUint8(x uint8) {
+ b.head -= UOffsetT(SizeUint8)
+ WriteUint8(b.Bytes[b.head:], x)
+}
+
+// PlaceUint16 prepends a uint16 to the Builder, without checking for space.
+func (b *Builder) PlaceUint16(x uint16) {
+ b.head -= UOffsetT(SizeUint16)
+ WriteUint16(b.Bytes[b.head:], x)
+}
+
+// PlaceUint32 prepends a uint32 to the Builder, without checking for space.
+func (b *Builder) PlaceUint32(x uint32) {
+ b.head -= UOffsetT(SizeUint32)
+ WriteUint32(b.Bytes[b.head:], x)
+}
+
+// PlaceUint64 prepends a uint64 to the Builder, without checking for space.
+func (b *Builder) PlaceUint64(x uint64) {
+ b.head -= UOffsetT(SizeUint64)
+ WriteUint64(b.Bytes[b.head:], x)
+}
+
+// PlaceInt8 prepends a int8 to the Builder, without checking for space.
+func (b *Builder) PlaceInt8(x int8) {
+ b.head -= UOffsetT(SizeInt8)
+ WriteInt8(b.Bytes[b.head:], x)
+}
+
+// PlaceInt16 prepends a int16 to the Builder, without checking for space.
+func (b *Builder) PlaceInt16(x int16) {
+ b.head -= UOffsetT(SizeInt16)
+ WriteInt16(b.Bytes[b.head:], x)
+}
+
+// PlaceInt32 prepends a int32 to the Builder, without checking for space.
+func (b *Builder) PlaceInt32(x int32) {
+ b.head -= UOffsetT(SizeInt32)
+ WriteInt32(b.Bytes[b.head:], x)
+}
+
+// PlaceInt64 prepends a int64 to the Builder, without checking for space.
+func (b *Builder) PlaceInt64(x int64) {
+ b.head -= UOffsetT(SizeInt64)
+ WriteInt64(b.Bytes[b.head:], x)
+}
+
+// PlaceFloat32 prepends a float32 to the Builder, without checking for space.
+func (b *Builder) PlaceFloat32(x float32) {
+ b.head -= UOffsetT(SizeFloat32)
+ WriteFloat32(b.Bytes[b.head:], x)
+}
+
+// PlaceFloat64 prepends a float64 to the Builder, without checking for space.
+func (b *Builder) PlaceFloat64(x float64) {
+ b.head -= UOffsetT(SizeFloat64)
+ WriteFloat64(b.Bytes[b.head:], x)
+}
+
+// PlaceByte prepends a byte to the Builder, without checking for space.
+func (b *Builder) PlaceByte(x byte) {
+ b.head -= UOffsetT(SizeByte)
+ WriteByte(b.Bytes[b.head:], x)
+}
+
+// PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for space.
+func (b *Builder) PlaceVOffsetT(x VOffsetT) {
+ b.head -= UOffsetT(SizeVOffsetT)
+ WriteVOffsetT(b.Bytes[b.head:], x)
+}
+
+// PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for space.
+func (b *Builder) PlaceSOffsetT(x SOffsetT) {
+ b.head -= UOffsetT(SizeSOffsetT)
+ WriteSOffsetT(b.Bytes[b.head:], x)
+}
+
+// PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for space.
+func (b *Builder) PlaceUOffsetT(x UOffsetT) {
+ b.head -= UOffsetT(SizeUOffsetT)
+ WriteUOffsetT(b.Bytes[b.head:], x)
+}
diff --git a/go/doc.go b/go/doc.go
new file mode 100644
index 0000000..694edc7
--- /dev/null
+++ b/go/doc.go
@@ -0,0 +1,3 @@
+// Package flatbuffers provides facilities to read and write flatbuffers
+// objects.
+package flatbuffers
diff --git a/go/encode.go b/go/encode.go
new file mode 100644
index 0000000..72d4f3a
--- /dev/null
+++ b/go/encode.go
@@ -0,0 +1,238 @@
+package flatbuffers
+
+import (
+ "math"
+)
+
+type (
+ // A SOffsetT stores a signed offset into arbitrary data.
+ SOffsetT int32
+ // A UOffsetT stores an unsigned offset into vector data.
+ UOffsetT uint32
+ // A VOffsetT stores an unsigned offset in a vtable.
+ VOffsetT uint16
+)
+
+const (
+ // VtableMetadataFields is the count of metadata fields in each vtable.
+ VtableMetadataFields = 2
+)
+
+// GetByte decodes a little-endian byte from a byte slice.
+func GetByte(buf []byte) byte {
+ return byte(GetUint8(buf))
+}
+
+// GetBool decodes a little-endian bool from a byte slice.
+func GetBool(buf []byte) bool {
+ return buf[0] == 1
+}
+
+// GetUint8 decodes a little-endian uint8 from a byte slice.
+func GetUint8(buf []byte) (n uint8) {
+ n = uint8(buf[0])
+ return
+}
+
+// GetUint16 decodes a little-endian uint16 from a byte slice.
+func GetUint16(buf []byte) (n uint16) {
+ _ = buf[1] // Force one bounds check. See: golang.org/issue/14808
+ n |= uint16(buf[0])
+ n |= uint16(buf[1]) << 8
+ return
+}
+
+// GetUint32 decodes a little-endian uint32 from a byte slice.
+func GetUint32(buf []byte) (n uint32) {
+ _ = buf[3] // Force one bounds check. See: golang.org/issue/14808
+ n |= uint32(buf[0])
+ n |= uint32(buf[1]) << 8
+ n |= uint32(buf[2]) << 16
+ n |= uint32(buf[3]) << 24
+ return
+}
+
+// GetUint64 decodes a little-endian uint64 from a byte slice.
+func GetUint64(buf []byte) (n uint64) {
+ _ = buf[7] // Force one bounds check. See: golang.org/issue/14808
+ n |= uint64(buf[0])
+ n |= uint64(buf[1]) << 8
+ n |= uint64(buf[2]) << 16
+ n |= uint64(buf[3]) << 24
+ n |= uint64(buf[4]) << 32
+ n |= uint64(buf[5]) << 40
+ n |= uint64(buf[6]) << 48
+ n |= uint64(buf[7]) << 56
+ return
+}
+
+// GetInt8 decodes a little-endian int8 from a byte slice.
+func GetInt8(buf []byte) (n int8) {
+ n = int8(buf[0])
+ return
+}
+
+// GetInt16 decodes a little-endian int16 from a byte slice.
+func GetInt16(buf []byte) (n int16) {
+ _ = buf[1] // Force one bounds check. See: golang.org/issue/14808
+ n |= int16(buf[0])
+ n |= int16(buf[1]) << 8
+ return
+}
+
+// GetInt32 decodes a little-endian int32 from a byte slice.
+func GetInt32(buf []byte) (n int32) {
+ _ = buf[3] // Force one bounds check. See: golang.org/issue/14808
+ n |= int32(buf[0])
+ n |= int32(buf[1]) << 8
+ n |= int32(buf[2]) << 16
+ n |= int32(buf[3]) << 24
+ return
+}
+
+// GetInt64 decodes a little-endian int64 from a byte slice.
+func GetInt64(buf []byte) (n int64) {
+ _ = buf[7] // Force one bounds check. See: golang.org/issue/14808
+ n |= int64(buf[0])
+ n |= int64(buf[1]) << 8
+ n |= int64(buf[2]) << 16
+ n |= int64(buf[3]) << 24
+ n |= int64(buf[4]) << 32
+ n |= int64(buf[5]) << 40
+ n |= int64(buf[6]) << 48
+ n |= int64(buf[7]) << 56
+ return
+}
+
+// GetFloat32 decodes a little-endian float32 from a byte slice.
+func GetFloat32(buf []byte) float32 {
+ x := GetUint32(buf)
+ return math.Float32frombits(x)
+}
+
+// GetFloat64 decodes a little-endian float64 from a byte slice.
+func GetFloat64(buf []byte) float64 {
+ x := GetUint64(buf)
+ return math.Float64frombits(x)
+}
+
+// GetUOffsetT decodes a little-endian UOffsetT from a byte slice.
+func GetUOffsetT(buf []byte) UOffsetT {
+ return UOffsetT(GetInt32(buf))
+}
+
+// GetSOffsetT decodes a little-endian SOffsetT from a byte slice.
+func GetSOffsetT(buf []byte) SOffsetT {
+ return SOffsetT(GetInt32(buf))
+}
+
+// GetVOffsetT decodes a little-endian VOffsetT from a byte slice.
+func GetVOffsetT(buf []byte) VOffsetT {
+ return VOffsetT(GetUint16(buf))
+}
+
+// WriteByte encodes a little-endian uint8 into a byte slice.
+func WriteByte(buf []byte, n byte) {
+ WriteUint8(buf, uint8(n))
+}
+
+// WriteBool encodes a little-endian bool into a byte slice.
+func WriteBool(buf []byte, b bool) {
+ buf[0] = 0
+ if b {
+ buf[0] = 1
+ }
+}
+
+// WriteUint8 encodes a little-endian uint8 into a byte slice.
+func WriteUint8(buf []byte, n uint8) {
+ buf[0] = byte(n)
+}
+
+// WriteUint16 encodes a little-endian uint16 into a byte slice.
+func WriteUint16(buf []byte, n uint16) {
+ _ = buf[1] // Force one bounds check. See: golang.org/issue/14808
+ buf[0] = byte(n)
+ buf[1] = byte(n >> 8)
+}
+
+// WriteUint32 encodes a little-endian uint32 into a byte slice.
+func WriteUint32(buf []byte, n uint32) {
+ _ = buf[3] // Force one bounds check. See: golang.org/issue/14808
+ buf[0] = byte(n)
+ buf[1] = byte(n >> 8)
+ buf[2] = byte(n >> 16)
+ buf[3] = byte(n >> 24)
+}
+
+// WriteUint64 encodes a little-endian uint64 into a byte slice.
+func WriteUint64(buf []byte, n uint64) {
+ _ = buf[7] // Force one bounds check. See: golang.org/issue/14808
+ buf[0] = byte(n)
+ buf[1] = byte(n >> 8)
+ buf[2] = byte(n >> 16)
+ buf[3] = byte(n >> 24)
+ buf[4] = byte(n >> 32)
+ buf[5] = byte(n >> 40)
+ buf[6] = byte(n >> 48)
+ buf[7] = byte(n >> 56)
+}
+
+// WriteInt8 encodes a little-endian int8 into a byte slice.
+func WriteInt8(buf []byte, n int8) {
+ buf[0] = byte(n)
+}
+
+// WriteInt16 encodes a little-endian int16 into a byte slice.
+func WriteInt16(buf []byte, n int16) {
+ _ = buf[1] // Force one bounds check. See: golang.org/issue/14808
+ buf[0] = byte(n)
+ buf[1] = byte(n >> 8)
+}
+
+// WriteInt32 encodes a little-endian int32 into a byte slice.
+func WriteInt32(buf []byte, n int32) {
+ _ = buf[3] // Force one bounds check. See: golang.org/issue/14808
+ buf[0] = byte(n)
+ buf[1] = byte(n >> 8)
+ buf[2] = byte(n >> 16)
+ buf[3] = byte(n >> 24)
+}
+
+// WriteInt64 encodes a little-endian int64 into a byte slice.
+func WriteInt64(buf []byte, n int64) {
+ _ = buf[7] // Force one bounds check. See: golang.org/issue/14808
+ buf[0] = byte(n)
+ buf[1] = byte(n >> 8)
+ buf[2] = byte(n >> 16)
+ buf[3] = byte(n >> 24)
+ buf[4] = byte(n >> 32)
+ buf[5] = byte(n >> 40)
+ buf[6] = byte(n >> 48)
+ buf[7] = byte(n >> 56)
+}
+
+// WriteFloat32 encodes a little-endian float32 into a byte slice.
+func WriteFloat32(buf []byte, n float32) {
+ WriteUint32(buf, math.Float32bits(n))
+}
+
+// WriteFloat64 encodes a little-endian float64 into a byte slice.
+func WriteFloat64(buf []byte, n float64) {
+ WriteUint64(buf, math.Float64bits(n))
+}
+
+// WriteVOffsetT encodes a little-endian VOffsetT into a byte slice.
+func WriteVOffsetT(buf []byte, n VOffsetT) {
+ WriteUint16(buf, uint16(n))
+}
+
+// WriteSOffsetT encodes a little-endian SOffsetT into a byte slice.
+func WriteSOffsetT(buf []byte, n SOffsetT) {
+ WriteInt32(buf, int32(n))
+}
+
+// WriteUOffsetT encodes a little-endian UOffsetT into a byte slice.
+func WriteUOffsetT(buf []byte, n UOffsetT) {
+ WriteUint32(buf, uint32(n))
+}
diff --git a/go/grpc.go b/go/grpc.go
new file mode 100644
index 0000000..e7dabd3
--- /dev/null
+++ b/go/grpc.go
@@ -0,0 +1,23 @@
+package flatbuffers
+
+// Codec implements gRPC-go Codec which is used to encode and decode messages.
+var Codec = "flatbuffers"
+
+type FlatbuffersCodec struct{}
+
+func (FlatbuffersCodec) Marshal(v interface{}) ([]byte, error) {
+ return v.(*Builder).FinishedBytes(), nil
+}
+
+func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error {
+ v.(flatbuffersInit).Init(data, GetUOffsetT(data))
+ return nil
+}
+
+func (FlatbuffersCodec) String() string {
+ return Codec
+}
+
+type flatbuffersInit interface {
+ Init(data []byte, i UOffsetT)
+}
diff --git a/go/lib.go b/go/lib.go
new file mode 100644
index 0000000..adfce52
--- /dev/null
+++ b/go/lib.go
@@ -0,0 +1,13 @@
+package flatbuffers
+
+// FlatBuffer is the interface that represents a flatbuffer.
+type FlatBuffer interface {
+ Table() Table
+ Init(buf []byte, i UOffsetT)
+}
+
+// GetRootAs is a generic helper to initialize a FlatBuffer with the provided buffer bytes and its data offset.
+func GetRootAs(buf []byte, offset UOffsetT, fb FlatBuffer) {
+ n := GetUOffsetT(buf[offset:])
+ fb.Init(buf, n+offset)
+}
diff --git a/go/sizes.go b/go/sizes.go
new file mode 100644
index 0000000..ba22169
--- /dev/null
+++ b/go/sizes.go
@@ -0,0 +1,55 @@
+package flatbuffers
+
+import (
+ "unsafe"
+)
+
+const (
+ // See http://golang.org/ref/spec#Numeric_types
+
+ // SizeUint8 is the byte size of a uint8.
+ SizeUint8 = 1
+ // SizeUint16 is the byte size of a uint16.
+ SizeUint16 = 2
+ // SizeUint32 is the byte size of a uint32.
+ SizeUint32 = 4
+ // SizeUint64 is the byte size of a uint64.
+ SizeUint64 = 8
+
+ // SizeInt8 is the byte size of a int8.
+ SizeInt8 = 1
+ // SizeInt16 is the byte size of a int16.
+ SizeInt16 = 2
+ // SizeInt32 is the byte size of a int32.
+ SizeInt32 = 4
+ // SizeInt64 is the byte size of a int64.
+ SizeInt64 = 8
+
+ // SizeFloat32 is the byte size of a float32.
+ SizeFloat32 = 4
+ // SizeFloat64 is the byte size of a float64.
+ SizeFloat64 = 8
+
+ // SizeByte is the byte size of a byte.
+ // The `byte` type is aliased (by Go definition) to uint8.
+ SizeByte = 1
+
+ // SizeBool is the byte size of a bool.
+ // The `bool` type is aliased (by flatbuffers convention) to uint8.
+ SizeBool = 1
+
+ // SizeSOffsetT is the byte size of an SOffsetT.
+ // The `SOffsetT` type is aliased (by flatbuffers convention) to int32.
+ SizeSOffsetT = 4
+ // SizeUOffsetT is the byte size of an UOffsetT.
+ // The `UOffsetT` type is aliased (by flatbuffers convention) to uint32.
+ SizeUOffsetT = 4
+ // SizeVOffsetT is the byte size of an VOffsetT.
+ // The `VOffsetT` type is aliased (by flatbuffers convention) to uint16.
+ SizeVOffsetT = 2
+)
+
+// byteSliceToString converts a []byte to string without a heap allocation.
+func byteSliceToString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
diff --git a/go/struct.go b/go/struct.go
new file mode 100644
index 0000000..11258f7
--- /dev/null
+++ b/go/struct.go
@@ -0,0 +1,8 @@
+package flatbuffers
+
+// Struct wraps a byte slice and provides read access to its data.
+//
+// Structs do not have a vtable.
+type Struct struct {
+ Table
+}
diff --git a/go/table.go b/go/table.go
new file mode 100644
index 0000000..b273146
--- /dev/null
+++ b/go/table.go
@@ -0,0 +1,505 @@
+package flatbuffers
+
+// Table wraps a byte slice and provides read access to its data.
+//
+// The variable `Pos` indicates the root of the FlatBuffers object therein.
+type Table struct {
+ Bytes []byte
+ Pos UOffsetT // Always < 1<<31.
+}
+
+// Offset provides access into the Table's vtable.
+//
+// Fields which are deprecated are ignored by checking against the vtable's length.
+func (t *Table) Offset(vtableOffset VOffsetT) VOffsetT {
+ vtable := UOffsetT(SOffsetT(t.Pos) - t.GetSOffsetT(t.Pos))
+ if vtableOffset < t.GetVOffsetT(vtable) {
+ return t.GetVOffsetT(vtable + UOffsetT(vtableOffset))
+ }
+ return 0
+}
+
+// Indirect retrieves the relative offset stored at `offset`.
+func (t *Table) Indirect(off UOffsetT) UOffsetT {
+ return off + GetUOffsetT(t.Bytes[off:])
+}
+
+// String gets a string from data stored inside the flatbuffer.
+func (t *Table) String(off UOffsetT) string {
+ b := t.ByteVector(off)
+ return byteSliceToString(b)
+}
+
+// ByteVector gets a byte slice from data stored inside the flatbuffer.
+func (t *Table) ByteVector(off UOffsetT) []byte {
+ off += GetUOffsetT(t.Bytes[off:])
+ start := off + UOffsetT(SizeUOffsetT)
+ length := GetUOffsetT(t.Bytes[off:])
+ return t.Bytes[start : start+length]
+}
+
+// VectorLen retrieves the length of the vector whose offset is stored at
+// "off" in this object.
+func (t *Table) VectorLen(off UOffsetT) int {
+ off += t.Pos
+ off += GetUOffsetT(t.Bytes[off:])
+ return int(GetUOffsetT(t.Bytes[off:]))
+}
+
+// Vector retrieves the start of data of the vector whose offset is stored
+// at "off" in this object.
+func (t *Table) Vector(off UOffsetT) UOffsetT {
+ off += t.Pos
+ x := off + GetUOffsetT(t.Bytes[off:])
+ // data starts after metadata containing the vector length
+ x += UOffsetT(SizeUOffsetT)
+ return x
+}
+
+// Union initializes any Table-derived type to point to the union at the given
+// offset.
+func (t *Table) Union(t2 *Table, off UOffsetT) {
+ off += t.Pos
+ t2.Pos = off + t.GetUOffsetT(off)
+ t2.Bytes = t.Bytes
+}
+
+// GetBool retrieves a bool at the given offset.
+func (t *Table) GetBool(off UOffsetT) bool {
+ return GetBool(t.Bytes[off:])
+}
+
+// GetByte retrieves a byte at the given offset.
+func (t *Table) GetByte(off UOffsetT) byte {
+ return GetByte(t.Bytes[off:])
+}
+
+// GetUint8 retrieves a uint8 at the given offset.
+func (t *Table) GetUint8(off UOffsetT) uint8 {
+ return GetUint8(t.Bytes[off:])
+}
+
+// GetUint16 retrieves a uint16 at the given offset.
+func (t *Table) GetUint16(off UOffsetT) uint16 {
+ return GetUint16(t.Bytes[off:])
+}
+
+// GetUint32 retrieves a uint32 at the given offset.
+func (t *Table) GetUint32(off UOffsetT) uint32 {
+ return GetUint32(t.Bytes[off:])
+}
+
+// GetUint64 retrieves a uint64 at the given offset.
+func (t *Table) GetUint64(off UOffsetT) uint64 {
+ return GetUint64(t.Bytes[off:])
+}
+
+// GetInt8 retrieves a int8 at the given offset.
+func (t *Table) GetInt8(off UOffsetT) int8 {
+ return GetInt8(t.Bytes[off:])
+}
+
+// GetInt16 retrieves a int16 at the given offset.
+func (t *Table) GetInt16(off UOffsetT) int16 {
+ return GetInt16(t.Bytes[off:])
+}
+
+// GetInt32 retrieves a int32 at the given offset.
+func (t *Table) GetInt32(off UOffsetT) int32 {
+ return GetInt32(t.Bytes[off:])
+}
+
+// GetInt64 retrieves a int64 at the given offset.
+func (t *Table) GetInt64(off UOffsetT) int64 {
+ return GetInt64(t.Bytes[off:])
+}
+
+// GetFloat32 retrieves a float32 at the given offset.
+func (t *Table) GetFloat32(off UOffsetT) float32 {
+ return GetFloat32(t.Bytes[off:])
+}
+
+// GetFloat64 retrieves a float64 at the given offset.
+func (t *Table) GetFloat64(off UOffsetT) float64 {
+ return GetFloat64(t.Bytes[off:])
+}
+
+// GetUOffsetT retrieves a UOffsetT at the given offset.
+func (t *Table) GetUOffsetT(off UOffsetT) UOffsetT {
+ return GetUOffsetT(t.Bytes[off:])
+}
+
+// GetVOffsetT retrieves a VOffsetT at the given offset.
+func (t *Table) GetVOffsetT(off UOffsetT) VOffsetT {
+ return GetVOffsetT(t.Bytes[off:])
+}
+
+// GetSOffsetT retrieves a SOffsetT at the given offset.
+func (t *Table) GetSOffsetT(off UOffsetT) SOffsetT {
+ return GetSOffsetT(t.Bytes[off:])
+}
+
+// GetBoolSlot retrieves the bool that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetBoolSlot(slot VOffsetT, d bool) bool {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetBool(t.Pos + UOffsetT(off))
+}
+
+// GetByteSlot retrieves the byte that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetByteSlot(slot VOffsetT, d byte) byte {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetByte(t.Pos + UOffsetT(off))
+}
+
+// GetInt8Slot retrieves the int8 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetInt8Slot(slot VOffsetT, d int8) int8 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetInt8(t.Pos + UOffsetT(off))
+}
+
+// GetUint8Slot retrieves the uint8 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetUint8Slot(slot VOffsetT, d uint8) uint8 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetUint8(t.Pos + UOffsetT(off))
+}
+
+// GetInt16Slot retrieves the int16 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetInt16Slot(slot VOffsetT, d int16) int16 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetInt16(t.Pos + UOffsetT(off))
+}
+
+// GetUint16Slot retrieves the uint16 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetUint16Slot(slot VOffsetT, d uint16) uint16 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetUint16(t.Pos + UOffsetT(off))
+}
+
+// GetInt32Slot retrieves the int32 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetInt32Slot(slot VOffsetT, d int32) int32 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetInt32(t.Pos + UOffsetT(off))
+}
+
+// GetUint32Slot retrieves the uint32 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetUint32Slot(slot VOffsetT, d uint32) uint32 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetUint32(t.Pos + UOffsetT(off))
+}
+
+// GetInt64Slot retrieves the int64 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetInt64Slot(slot VOffsetT, d int64) int64 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetInt64(t.Pos + UOffsetT(off))
+}
+
+// GetUint64Slot retrieves the uint64 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetUint64Slot(slot VOffsetT, d uint64) uint64 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetUint64(t.Pos + UOffsetT(off))
+}
+
+// GetFloat32Slot retrieves the float32 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetFloat32Slot(slot VOffsetT, d float32) float32 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetFloat32(t.Pos + UOffsetT(off))
+}
+
+// GetFloat64Slot retrieves the float64 that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetFloat64Slot(slot VOffsetT, d float64) float64 {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+
+ return t.GetFloat64(t.Pos + UOffsetT(off))
+}
+
+// GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
+// points to. If the vtable value is zero, the default value `d`
+// will be returned.
+func (t *Table) GetVOffsetTSlot(slot VOffsetT, d VOffsetT) VOffsetT {
+ off := t.Offset(slot)
+ if off == 0 {
+ return d
+ }
+ return VOffsetT(off)
+}
+
+// MutateBool updates a bool at the given offset.
+func (t *Table) MutateBool(off UOffsetT, n bool) bool {
+ WriteBool(t.Bytes[off:], n)
+ return true
+}
+
+// MutateByte updates a Byte at the given offset.
+func (t *Table) MutateByte(off UOffsetT, n byte) bool {
+ WriteByte(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint8 updates a Uint8 at the given offset.
+func (t *Table) MutateUint8(off UOffsetT, n uint8) bool {
+ WriteUint8(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint16 updates a Uint16 at the given offset.
+func (t *Table) MutateUint16(off UOffsetT, n uint16) bool {
+ WriteUint16(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint32 updates a Uint32 at the given offset.
+func (t *Table) MutateUint32(off UOffsetT, n uint32) bool {
+ WriteUint32(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUint64 updates a Uint64 at the given offset.
+func (t *Table) MutateUint64(off UOffsetT, n uint64) bool {
+ WriteUint64(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt8 updates a Int8 at the given offset.
+func (t *Table) MutateInt8(off UOffsetT, n int8) bool {
+ WriteInt8(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt16 updates a Int16 at the given offset.
+func (t *Table) MutateInt16(off UOffsetT, n int16) bool {
+ WriteInt16(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt32 updates a Int32 at the given offset.
+func (t *Table) MutateInt32(off UOffsetT, n int32) bool {
+ WriteInt32(t.Bytes[off:], n)
+ return true
+}
+
+// MutateInt64 updates a Int64 at the given offset.
+func (t *Table) MutateInt64(off UOffsetT, n int64) bool {
+ WriteInt64(t.Bytes[off:], n)
+ return true
+}
+
+// MutateFloat32 updates a Float32 at the given offset.
+func (t *Table) MutateFloat32(off UOffsetT, n float32) bool {
+ WriteFloat32(t.Bytes[off:], n)
+ return true
+}
+
+// MutateFloat64 updates a Float64 at the given offset.
+func (t *Table) MutateFloat64(off UOffsetT, n float64) bool {
+ WriteFloat64(t.Bytes[off:], n)
+ return true
+}
+
+// MutateUOffsetT updates a UOffsetT at the given offset.
+func (t *Table) MutateUOffsetT(off UOffsetT, n UOffsetT) bool {
+ WriteUOffsetT(t.Bytes[off:], n)
+ return true
+}
+
+// MutateVOffsetT updates a VOffsetT at the given offset.
+func (t *Table) MutateVOffsetT(off UOffsetT, n VOffsetT) bool {
+ WriteVOffsetT(t.Bytes[off:], n)
+ return true
+}
+
+// MutateSOffsetT updates a SOffsetT at the given offset.
+func (t *Table) MutateSOffsetT(off UOffsetT, n SOffsetT) bool {
+ WriteSOffsetT(t.Bytes[off:], n)
+ return true
+}
+
+// MutateBoolSlot updates the bool at given vtable location
+func (t *Table) MutateBoolSlot(slot VOffsetT, n bool) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateBool(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateByteSlot updates the byte at given vtable location
+func (t *Table) MutateByteSlot(slot VOffsetT, n byte) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateByte(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt8Slot updates the int8 at given vtable location
+func (t *Table) MutateInt8Slot(slot VOffsetT, n int8) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt8(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint8Slot updates the uint8 at given vtable location
+func (t *Table) MutateUint8Slot(slot VOffsetT, n uint8) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint8(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt16Slot updates the int16 at given vtable location
+func (t *Table) MutateInt16Slot(slot VOffsetT, n int16) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt16(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint16Slot updates the uint16 at given vtable location
+func (t *Table) MutateUint16Slot(slot VOffsetT, n uint16) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint16(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt32Slot updates the int32 at given vtable location
+func (t *Table) MutateInt32Slot(slot VOffsetT, n int32) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt32(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint32Slot updates the uint32 at given vtable location
+func (t *Table) MutateUint32Slot(slot VOffsetT, n uint32) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint32(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateInt64Slot updates the int64 at given vtable location
+func (t *Table) MutateInt64Slot(slot VOffsetT, n int64) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateInt64(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateUint64Slot updates the uint64 at given vtable location
+func (t *Table) MutateUint64Slot(slot VOffsetT, n uint64) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateUint64(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateFloat32Slot updates the float32 at given vtable location
+func (t *Table) MutateFloat32Slot(slot VOffsetT, n float32) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateFloat32(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
+
+// MutateFloat64Slot updates the float64 at given vtable location
+func (t *Table) MutateFloat64Slot(slot VOffsetT, n float64) bool {
+ if off := t.Offset(slot); off != 0 {
+ t.MutateFloat64(t.Pos+UOffsetT(off), n)
+ return true
+ }
+
+ return false
+}
diff --git a/grpc/README.md b/grpc/README.md
new file mode 100644
index 0000000..544651d
--- /dev/null
+++ b/grpc/README.md
@@ -0,0 +1,31 @@
+GRPC implementation and test
+============================
+
+NOTE: files in `src/` are shared with the GRPC project, and maintained there
+(any changes should be submitted to GRPC instead). These files are copied
+from GRPC, and work with both the Protobuf and FlatBuffers code generator.
+
+`tests/` contains a GRPC specific test, you need to have built and installed
+the GRPC libraries for this to compile. This test will build using the
+`FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project.
+
+## Building Flatbuffers with gRPC
+
+### Linux
+
+1. Download, build and install gRPC. See [instructions](https://github.com/grpc/grpc/tree/master/src/cpp).
+ * Lets say your gRPC clone is at `/your/path/to/grpc_repo`.
+ * Install gRPC in a custom directory by running `make install prefix=/your/path/to/grpc_repo/install`.
+2. `export GRPC_INSTALL_PATH=/your/path/to/grpc_repo/install`
+3. `export PROTOBUF_DOWNLOAD_PATH=/your/path/to/grpc_repo/third_party/protobuf`
+4. `mkdir build ; cd build`
+5. `cmake -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=${GRPC_INSTALL_PATH} -DPROTOBUF_DOWNLOAD_PATH=${PROTOBUF_DOWNLOAD_PATH} ..`
+6. `make`
+
+## Running FlatBuffer gRPC tests
+
+### Linux
+
+1. `ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1`
+2. `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GRPC_INSTALL_PATH}/lib`
+3. `make test ARGS=-V`
diff --git a/grpc/build_grpc.sh b/grpc/build_grpc.sh
new file mode 100755
index 0000000..8fb9e1c
--- /dev/null
+++ b/grpc/build_grpc.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+grpc_1_15_1_githash=1a60e6971f428323245a930031ad267bb3142ba4
+
+function build_grpc () {
+ git clone https://github.com/grpc/grpc.git google/grpc
+ cd google/grpc
+ git checkout ${grpc_1_15_1_githash}
+ git submodule update --init
+ make
+ make install prefix=`pwd`/install
+ if [ ! -f ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1 ]; then
+ ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1
+ fi
+ cd ../..
+}
+
+GRPC_INSTALL_PATH=`pwd`/google/grpc/install
+PROTOBUF_DOWNLOAD_PATH=`pwd`/google/grpc/third_party/protobuf
+
+build_grpc
diff --git a/grpc/flatbuffers-java-grpc/pom.xml b/grpc/flatbuffers-java-grpc/pom.xml
new file mode 100644
index 0000000..b5b88cb
--- /dev/null
+++ b/grpc/flatbuffers-java-grpc/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-parent</artifactId>
+ <version>1.11.1</version>
+ </parent>
+ <artifactId>flatbuffers-java-grpc</artifactId>
+ <name>${project.artifactId}</name>
+ <packaging>bundle</packaging>
+ <description>
+ Utilities supporting generated code for GRPC
+ </description>
+ <developers>
+ <developer>
+ <name>Wouter van Oortmerssen</name>
+ </developer>
+ <developer>
+ <name>Yuri Finkelstein</name>
+ <url>https://github.com/yfinkelstein</url>
+ </developer>
+ </developers>
+ <properties>
+ <gRPC.version>1.11.1</gRPC.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-java</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-core</artifactId>
+ <version>${gRPC.version}</version>
+ </dependency>
+ </dependencies>
+</project>
+
diff --git a/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java b/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java
new file mode 100644
index 0000000..768708b
--- /dev/null
+++ b/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.flatbuffers.grpc;
+
+import com.google.flatbuffers.Table;
+import io.grpc.Drainable;
+import io.grpc.KnownLength;
+import io.grpc.MethodDescriptor;
+
+import javax.annotation.Nullable;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+public class FlatbuffersUtils {
+ abstract public static class FBExtactor <T extends Table> {
+ T extract (InputStream stream) throws IOException {
+ if (stream instanceof KnownLength) {
+ int size = stream.available();
+ ByteBuffer buffer = ByteBuffer.allocate(size);
+ stream.read(buffer.array());
+ return extract(buffer);
+ } else
+ throw new RuntimeException("The class " + stream.getClass().getCanonicalName() + " does not extend from KnownLength ");
+ }
+
+ public abstract T extract(ByteBuffer buffer);
+
+ }
+
+ static class FBInputStream extends InputStream implements Drainable, KnownLength {
+ private final ByteBuffer buffer;
+ private final int size;
+ @Nullable private ByteArrayInputStream inputStream;
+
+ FBInputStream(ByteBuffer buffer) {
+ this.buffer = buffer;
+ this.size = buffer.remaining();
+ }
+
+ private void makeStreamIfNotAlready() {
+ if (inputStream == null)
+ inputStream = new ByteArrayInputStream(buffer.array(), buffer.position(), size);
+ }
+
+ @Override
+ public int drainTo(OutputStream target) throws IOException {
+ target.write(buffer.array(), buffer.position(), size);
+ return size;
+ }
+
+ @Override
+ public int read() throws IOException {
+ makeStreamIfNotAlready();
+ return inputStream.read();
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ makeStreamIfNotAlready();
+ if (inputStream == null) {
+ if (len >= size) {
+ System.arraycopy(buffer.array(), buffer.position(), b, off, size);
+ return size;
+ } else {
+ makeStreamIfNotAlready();
+ return inputStream.read(b, off, len);
+ }
+ } else
+ return inputStream.read(b, off, len);
+ }
+
+ @Override
+ public int available() throws IOException {
+ return inputStream == null ? size : inputStream.available();
+ }
+
+ }
+
+ public static <T extends Table> MethodDescriptor.Marshaller<T> marshaller(final Class<T> clazz, final FBExtactor<T> extractor) {
+ return new MethodDescriptor.ReflectableMarshaller<T>() {
+ @Override
+ public Class<T> getMessageClass() {
+ return clazz;
+ }
+
+ @Override
+ public InputStream stream(T value) {
+ return new FBInputStream (value.getByteBuffer());
+ }
+
+ @Override
+ public T parse(InputStream stream) {
+ try {
+ return extractor.extract(stream);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ }
+}
diff --git a/grpc/pom.xml b/grpc/pom.xml
new file mode 100644
index 0000000..a0fca79
--- /dev/null
+++ b/grpc/pom.xml
@@ -0,0 +1,213 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-parent</artifactId>
+ <packaging>pom</packaging>
+ <version>1.11.1</version>
+ <name>flatbuffers-parent</name>
+ <description>parent pom for flatbuffers java artifacts</description>
+ <properties>
+ <scm.url>https://github.com/google/flatbuffers</scm.url>
+ <scm.connection>scm:git:${scm.url}.git</scm.connection>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+
+ <issueManagement>
+ <system>GitHub</system>
+ <url>https://github.com/google/flatbuffers/issues</url>
+ </issueManagement>
+
+ <developers>
+ <developer>
+ <name>Wouter van Oortmerssen</name>
+ </developer>
+ </developers>
+
+ <url>${scm.url}</url>
+
+ <scm>
+ <connection>${scm.connection}</connection>
+ <developerConnection>${scm.connection}</developerConnection>
+ <url>${scm.url}</url>
+ <tag>HEAD</tag>
+ </scm>
+
+ <distributionManagement>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+ <build>
+ <extensions>
+ <extension>
+ <!--
+ os-maven-plugin is a Maven extension/plugin that generates various useful platform-dependent
+ project properties normalized from ${os.detected.name} and ${os.detected.arch}.
+ -->
+ <groupId>kr.motd.maven</groupId>
+ <artifactId>os-maven-plugin</artifactId>
+ <version>1.5.0.Final</version>
+ </extension>
+ </extensions>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.6.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>3.0.2</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>3.0.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.12</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.7</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.3</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.5.0</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>3.0.1</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>ossrh</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>true</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ <useReleaseProfile>false</useReleaseProfile>
+ <releaseProfiles>release</releaseProfiles>
+ <goals>deploy</goals>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <modules>
+<!-- consider the benefits of publishing all maven artifacts in this project
+
+ <module>flatbuffers-compiler</module>
+ <module>flatbuffers-java</module>
+
+-->
+ <module>flatbuffers-java-grpc</module>
+ </modules>
+
+</project>
diff --git a/grpc/samples/greeter/Makefile b/grpc/samples/greeter/Makefile
new file mode 100644
index 0000000..3746705
--- /dev/null
+++ b/grpc/samples/greeter/Makefile
@@ -0,0 +1,14 @@
+CXXFLAGS ?= -I../../../include
+LDFLAGS ?=
+
+.PHONY: all
+all: server client
+
+greeter_generated.h: greeter.fbs
+ flatc --grpc --cpp $<
+
+server: server.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
+ g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ server.cpp greeter.grpc.fb.cc -o $@
+
+client: client.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
+ g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ client.cpp greeter.grpc.fb.cc -o $@
diff --git a/grpc/samples/greeter/client.cpp b/grpc/samples/greeter/client.cpp
new file mode 100644
index 0000000..2e42f8f
--- /dev/null
+++ b/grpc/samples/greeter/client.cpp
@@ -0,0 +1,85 @@
+#include "greeter.grpc.fb.h"
+#include "greeter_generated.h"
+
+#include <grpc++/grpc++.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+class GreeterClient {
+ public:
+ GreeterClient(std::shared_ptr<grpc::Channel> channel)
+ : stub_(Greeter::NewStub(channel)) {}
+
+ std::string SayHello(const std::string &name) {
+ flatbuffers::grpc::MessageBuilder mb;
+ auto name_offset = mb.CreateString(name);
+ auto request_offset = CreateHelloRequest(mb, name_offset);
+ mb.Finish(request_offset);
+ auto request_msg = mb.ReleaseMessage<HelloRequest>();
+
+ flatbuffers::grpc::Message<HelloReply> response_msg;
+
+ grpc::ClientContext context;
+
+ auto status = stub_->SayHello(&context, request_msg, &response_msg);
+ if (status.ok()) {
+ const HelloReply *response = response_msg.GetRoot();
+ return response->message()->str();
+ } else {
+ std::cerr << status.error_code() << ": " << status.error_message()
+ << std::endl;
+ return "RPC failed";
+ }
+ }
+
+ void SayManyHellos(const std::string &name, int num_greetings,
+ std::function<void(const std::string &)> callback) {
+ flatbuffers::grpc::MessageBuilder mb;
+ auto name_offset = mb.CreateString(name);
+ auto request_offset =
+ CreateManyHellosRequest(mb, name_offset, num_greetings);
+ mb.Finish(request_offset);
+ auto request_msg = mb.ReleaseMessage<ManyHellosRequest>();
+
+ flatbuffers::grpc::Message<HelloReply> response_msg;
+
+ grpc::ClientContext context;
+
+ auto stream = stub_->SayManyHellos(&context, request_msg);
+ while (stream->Read(&response_msg)) {
+ const HelloReply *response = response_msg.GetRoot();
+ callback(response->message()->str());
+ }
+ auto status = stream->Finish();
+ if (!status.ok()) {
+ std::cerr << status.error_code() << ": " << status.error_message()
+ << std::endl;
+ callback("RPC failed");
+ }
+ }
+
+ private:
+ std::unique_ptr<Greeter::Stub> stub_;
+};
+
+int main(int argc, char **argv) {
+ std::string server_address("localhost:50051");
+
+ auto channel =
+ grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials());
+ GreeterClient greeter(channel);
+
+ std::string name("world");
+
+ std::string message = greeter.SayHello(name);
+ std::cerr << "Greeter received: " << message << std::endl;
+
+ int num_greetings = 10;
+ greeter.SayManyHellos(name, num_greetings, [](const std::string &message) {
+ std::cerr << "Greeter received: " << message << std::endl;
+ });
+
+ return 0;
+}
diff --git a/grpc/samples/greeter/greeter.fbs b/grpc/samples/greeter/greeter.fbs
new file mode 100644
index 0000000..811303c
--- /dev/null
+++ b/grpc/samples/greeter/greeter.fbs
@@ -0,0 +1,17 @@
+table HelloReply {
+ message:string;
+}
+
+table HelloRequest {
+ name:string;
+}
+
+table ManyHellosRequest {
+ name:string;
+ num_greetings:int;
+}
+
+rpc_service Greeter {
+ SayHello(HelloRequest):HelloReply;
+ SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server");
+}
diff --git a/grpc/samples/greeter/server.cpp b/grpc/samples/greeter/server.cpp
new file mode 100644
index 0000000..82c97dc
--- /dev/null
+++ b/grpc/samples/greeter/server.cpp
@@ -0,0 +1,80 @@
+#include "greeter.grpc.fb.h"
+#include "greeter_generated.h"
+
+#include <grpc++/grpc++.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+class GreeterServiceImpl final : public Greeter::Service {
+ virtual grpc::Status SayHello(
+ grpc::ServerContext *context,
+ const flatbuffers::grpc::Message<HelloRequest> *request_msg,
+ flatbuffers::grpc::Message<HelloReply> *response_msg) override {
+ // flatbuffers::grpc::MessageBuilder mb_;
+ // We call GetRoot to "parse" the message. Verification is already
+ // performed by default. See the notes below for more details.
+ const HelloRequest *request = request_msg->GetRoot();
+
+ // Fields are retrieved as usual with FlatBuffers
+ const std::string &name = request->name()->str();
+
+ // `flatbuffers::grpc::MessageBuilder` is a `FlatBufferBuilder` with a
+ // special allocator for efficient gRPC buffer transfer, but otherwise
+ // usage is the same as usual.
+ auto msg_offset = mb_.CreateString("Hello, " + name);
+ auto hello_offset = CreateHelloReply(mb_, msg_offset);
+ mb_.Finish(hello_offset);
+
+ // The `ReleaseMessage<T>()` function detaches the message from the
+ // builder, so we can transfer the resopnse to gRPC while simultaneously
+ // detaching that memory buffer from the builer.
+ *response_msg = mb_.ReleaseMessage<HelloReply>();
+ assert(response_msg->Verify());
+
+ // Return an OK status.
+ return grpc::Status::OK;
+ }
+
+ virtual grpc::Status SayManyHellos(
+ grpc::ServerContext *context,
+ const flatbuffers::grpc::Message<ManyHellosRequest> *request_msg,
+ grpc::ServerWriter<flatbuffers::grpc::Message<HelloReply>> *writer)
+ override {
+ // The streaming usage below is simply a combination of standard gRPC
+ // streaming with the FlatBuffers usage shown above.
+ const ManyHellosRequest *request = request_msg->GetRoot();
+ const std::string &name = request->name()->str();
+ int num_greetings = request->num_greetings();
+
+ for (int i = 0; i < num_greetings; i++) {
+ auto msg_offset = mb_.CreateString("Many hellos, " + name);
+ auto hello_offset = CreateHelloReply(mb_, msg_offset);
+ mb_.Finish(hello_offset);
+ writer->Write(mb_.ReleaseMessage<HelloReply>());
+ }
+
+ return grpc::Status::OK;
+ }
+
+ flatbuffers::grpc::MessageBuilder mb_;
+};
+
+void RunServer() {
+ std::string server_address("0.0.0.0:50051");
+ GreeterServiceImpl service;
+
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
+ std::cerr << "Server listening on " << server_address << std::endl;
+
+ server->Wait();
+}
+
+int main(int argc, const char *argv[]) {
+ RunServer();
+ return 0;
+}
diff --git a/grpc/src/compiler/config.h b/grpc/src/compiler/config.h
new file mode 100644
index 0000000..4adc594
--- /dev/null
+++ b/grpc/src/compiler/config.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef SRC_COMPILER_CONFIG_H
+#define SRC_COMPILER_CONFIG_H
+
+// This file is here only because schema_interface.h, which is copied from gRPC,
+// includes it. There is nothing for Flatbuffers to configure.
+
+#endif // SRC_COMPILER_CONFIG_H
diff --git a/grpc/src/compiler/cpp_generator.cc b/grpc/src/compiler/cpp_generator.cc
new file mode 100644
index 0000000..6cfd22e
--- /dev/null
+++ b/grpc/src/compiler/cpp_generator.cc
@@ -0,0 +1,1780 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <map>
+
+#include "src/compiler/cpp_generator.h"
+#include "flatbuffers/util.h"
+
+#include <sstream>
+
+namespace grpc_cpp_generator {
+namespace {
+
+grpc::string message_header_ext() { return "_generated.h"; }
+grpc::string service_header_ext() { return ".grpc.fb.h"; }
+
+template <class T>
+grpc::string as_string(T x) {
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
+ return method->ClientStreaming() && !method->ServerStreaming();
+}
+
+inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
+ return !method->ClientStreaming() && method->ServerStreaming();
+}
+
+grpc::string FilenameIdentifier(const grpc::string &filename) {
+ grpc::string result;
+ for (unsigned i = 0; i < filename.size(); i++) {
+ char c = filename[i];
+ if (isalnum(c)) {
+ result.push_back(c);
+ } else {
+ static char hex[] = "0123456789abcdef";
+ result.push_back('_');
+ result.push_back(hex[(c >> 4) & 0xf]);
+ result.push_back(hex[c & 0xf]);
+ }
+ }
+ return result;
+}
+} // namespace
+
+template <class T, size_t N>
+T *array_end(T (&array)[N]) {
+ return array + N;
+}
+
+void PrintIncludes(grpc_generator::Printer *printer,
+ const std::vector<grpc::string> &headers,
+ const Parameters ¶ms) {
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["l"] = params.use_system_headers ? '<' : '"';
+ vars["r"] = params.use_system_headers ? '>' : '"';
+
+ auto &s = params.grpc_search_path;
+ if (!s.empty()) {
+ vars["l"] += s;
+ if (s[s.size() - 1] != '/') {
+ vars["l"] += '/';
+ }
+ }
+
+ for (auto i = headers.begin(); i != headers.end(); i++) {
+ vars["h"] = *i;
+ printer->Print(vars, "#include $l$$h$$r$\n");
+ }
+}
+
+grpc::string GetHeaderPrologue(grpc_generator::File *file,
+ const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_identifier"] = FilenameIdentifier(file->filename());
+ vars["filename_base"] = file->filename_without_ext();
+ vars["message_header_ext"] = message_header_ext();
+
+ printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
+ printer->Print(vars,
+ "// If you make any local change, they will be lost.\n");
+ printer->Print(vars, "// source: $filename$\n");
+ grpc::string leading_comments = file->GetLeadingComments("//");
+ if (!leading_comments.empty()) {
+ printer->Print(vars, "// Original file comments:\n");
+ printer->Print(leading_comments.c_str());
+ }
+ printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
+ printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
+ printer->Print(vars, "\n");
+ printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+ printer->Print(vars, file->additional_headers().c_str());
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+grpc::string GetHeaderIncludes(grpc_generator::File *file,
+ const Parameters ¶ms) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ static const char *headers_strs[] = {
+ "grpc++/impl/codegen/async_stream.h",
+ "grpc++/impl/codegen/async_unary_call.h",
+ "grpc++/impl/codegen/method_handler_impl.h",
+ "grpc++/impl/codegen/proto_utils.h",
+ "grpc++/impl/codegen/rpc_method.h",
+ "grpc++/impl/codegen/service_type.h",
+ "grpc++/impl/codegen/status.h",
+ "grpc++/impl/codegen/stub_options.h",
+ "grpc++/impl/codegen/sync_stream.h"};
+ std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+ PrintIncludes(printer.get(), headers, params);
+ printer->Print(vars, "\n");
+ printer->Print(vars, "namespace grpc {\n");
+ printer->Print(vars, "class CompletionQueue;\n");
+ printer->Print(vars, "class Channel;\n");
+ printer->Print(vars, "class ServerCompletionQueue;\n");
+ printer->Print(vars, "class ServerContext;\n");
+ printer->Print(vars, "} // namespace grpc\n\n");
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "namespace $part$ {\n");
+ }
+ printer->Print(vars, "\n");
+ }
+ }
+ return output;
+}
+
+void PrintHeaderClientMethodInterfaces(
+ grpc_generator::Printer *printer, const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars, bool is_public) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ struct {
+ grpc::string prefix;
+ grpc::string method_params; // extra arguments to method
+ grpc::string raw_args; // extra arguments to raw version of method
+ } async_prefixes[] = {{"Async", ", void* tag", ", tag"},
+ {"PrepareAsync", "", ""}};
+
+ if (is_public) {
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response) = 0;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ printer->Print(
+ *vars,
+ "std::unique_ptr< "
+ "::grpc::ClientAsyncResponseReaderInterface< $Response$>> "
+ "$AsyncPrefix$$Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncResponseReaderInterface< $Response$>>("
+ "$AsyncPrefix$$Method$Raw(context, request, cq));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
+ " $Method$("
+ "::grpc::ClientContext* context, $Response$* response) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
+ "($Method$Raw(context, response));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>"
+ " $AsyncPrefix$$Method$(::grpc::ClientContext* context, "
+ "$Response$* "
+ "response, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncWriterInterface< $Request$>>("
+ "$AsyncPrefix$$Method$Raw(context, response, "
+ "cq$AsyncRawArgs$));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
+ " $Method$(::grpc::ClientContext* context, const $Request$& request)"
+ " {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
+ "($Method$Raw(context, request));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< $Response$>> "
+ "$AsyncPrefix$$Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncReaderInterface< $Response$>>("
+ "$AsyncPrefix$$Method$Raw(context, request, cq$AsyncRawArgs$));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientReaderWriterInterface< "
+ "$Request$, $Response$>> "
+ "$Method$(::grpc::ClientContext* context) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>("
+ "$Method$Raw(context));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "std::unique_ptr< "
+ "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>> "
+ "$AsyncPrefix$$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>>("
+ "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ } else {
+ if (method->NoStreaming()) {
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* "
+ "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) = 0;\n");
+ }
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientWriterInterface< $Request$>*"
+ " $Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response) = 0;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*"
+ " $AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n");
+ }
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientReaderInterface< $Response$>* "
+ "$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request) = 0;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientAsyncReaderInterface< $Response$>* "
+ "$AsyncPrefix$$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n");
+ }
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "virtual ::grpc::ClientReaderWriterInterface< $Request$, "
+ "$Response$>* "
+ "$Method$Raw(::grpc::ClientContext* context) = 0;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ printer->Print(
+ *vars,
+ "virtual ::grpc::ClientAsyncReaderWriterInterface< "
+ "$Request$, $Response$>* "
+ "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n");
+ }
+ }
+ }
+}
+
+void PrintHeaderClientMethod(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars,
+ bool is_public) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ struct {
+ grpc::string prefix;
+ grpc::string method_params; // extra arguments to method
+ grpc::string raw_args; // extra arguments to raw version of method
+ } async_prefixes[] = {{"Async", ", void* tag", ", tag"},
+ {"PrepareAsync", "", ""}};
+
+ if (is_public) {
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "::grpc::Status $Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response) override;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
+ "$AsyncPrefix$$Method$(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncResponseReader< $Response$>>("
+ "$AsyncPrefix$$Method$Raw(context, request, cq));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
+ " $Method$("
+ "::grpc::ClientContext* context, $Response$* response) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
+ "($Method$Raw(context, response));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>"
+ " $AsyncPrefix$$Method$(::grpc::ClientContext* context, "
+ "$Response$* response, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>("
+ "$AsyncPrefix$$Method$Raw(context, response, "
+ "cq$AsyncRawArgs$));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientReader< $Response$>>"
+ " $Method$(::grpc::ClientContext* context, const $Request$& request)"
+ " {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientReader< $Response$>>"
+ "($Method$Raw(context, request));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> "
+ "$AsyncPrefix$$Method$("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>>("
+ "$AsyncPrefix$$Method$Raw(context, request, cq$AsyncRawArgs$));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>"
+ " $Method$(::grpc::ClientContext* context) {\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientReaderWriter< $Request$, $Response$>>("
+ "$Method$Raw(context));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(*vars,
+ "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< "
+ "$Request$, $Response$>> "
+ "$AsyncPrefix$$Method$(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "return std::unique_ptr< "
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>("
+ "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ } else {
+ if (method->NoStreaming()) {
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncResponseReader< $Response$>* "
+ "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) override;\n");
+ }
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "::grpc::ClientWriter< $Request$>* $Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response) "
+ "override;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncWriter< $Request$>* $AsyncPrefix$$Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n");
+ }
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "::grpc::ClientReader< $Response$>* $Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request)"
+ " override;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReader< $Response$>* $AsyncPrefix$$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n");
+ }
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "::grpc::ClientReaderWriter< $Request$, $Response$>* "
+ "$Method$Raw(::grpc::ClientContext* context) override;\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncRawArgs"] = async_prefix.raw_args;
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+ "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n");
+ }
+ }
+ }
+}
+
+void PrintHeaderClientMethodData(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ printer->Print(*vars,
+ "const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n");
+}
+
+void PrintHeaderServerMethodSync(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ printer->Print(method->GetLeadingComments("//").c_str());
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response);\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response);\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer);\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "virtual ::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
+ "\n");
+ }
+ printer->Print(method->GetTrailingComments("//").c_str());
+}
+
+void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class WithAsyncMethod_$Method$ : public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "WithAsyncMethod_$Method$() {\n"
+ " ::grpc::Service::MarkMethodAsync($Idx$);\n"
+ "}\n");
+ printer->Print(*vars,
+ "~WithAsyncMethod_$Method$() override {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response) final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, $Request$* request, "
+ "::grpc::ServerAsyncResponseWriter< $Response$>* response, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::Service::RequestAsyncUnary($Idx$, context, "
+ "request, response, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::Service::RequestAsyncClientStreaming($Idx$, "
+ "context, reader, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) final override "
+ "{\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, $Request$* request, "
+ "::grpc::ServerAsyncWriter< $Response$>* writer, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(
+ *vars,
+ " ::grpc::Service::RequestAsyncServerStreaming($Idx$, "
+ "context, request, writer, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+ "final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "void Request$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, "
+ "::grpc::CompletionQueue* new_call_cq, "
+ "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n");
+ printer->Print(*vars,
+ " ::grpc::Service::RequestAsyncBidiStreaming($Idx$, "
+ "context, stream, new_call_cq, notification_cq, tag);\n");
+ printer->Print("}\n");
+ }
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+}
+
+void PrintHeaderServerMethodStreamedUnary(
+ grpc_generator::Printer *printer, const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class WithStreamedUnaryMethod_$Method$ : "
+ "public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) "
+ "{}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "WithStreamedUnaryMethod_$Method$() {\n"
+ " ::grpc::Service::MarkMethodStreamed($Idx$,\n"
+ " new ::grpc::internal::StreamedUnaryHandler< $Request$, "
+ "$Response$>(std::bind"
+ "(&WithStreamedUnaryMethod_$Method$<BaseClass>::"
+ "Streamed$Method$, this, std::placeholders::_1, "
+ "std::placeholders::_2)));\n"
+ "}\n");
+ printer->Print(*vars,
+ "~WithStreamedUnaryMethod_$Method$() override {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "// disable regular version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response) final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(*vars,
+ "// replace default version of method with streamed unary\n"
+ "virtual ::grpc::Status Streamed$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerUnaryStreamer< "
+ "$Request$,$Response$>* server_unary_streamer)"
+ " = 0;\n");
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+ }
+}
+
+void PrintHeaderServerMethodSplitStreaming(
+ grpc_generator::Printer *printer, const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class WithSplitStreamingMethod_$Method$ : "
+ "public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) "
+ "{}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(
+ *vars,
+ "WithSplitStreamingMethod_$Method$() {\n"
+ " ::grpc::Service::MarkMethodStreamed($Idx$,\n"
+ " new ::grpc::internal::SplitServerStreamingHandler< $Request$, "
+ "$Response$>(std::bind"
+ "(&WithSplitStreamingMethod_$Method$<BaseClass>::"
+ "Streamed$Method$, this, std::placeholders::_1, "
+ "std::placeholders::_2)));\n"
+ "}\n");
+ printer->Print(*vars,
+ "~WithSplitStreamingMethod_$Method$() override {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ printer->Print(
+ *vars,
+ "// disable regular version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) final override "
+ "{\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ printer->Print(*vars,
+ "// replace default version of method with split streamed\n"
+ "virtual ::grpc::Status Streamed$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerSplitStreamer< "
+ "$Request$,$Response$>* server_split_streamer)"
+ " = 0;\n");
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+ }
+}
+
+void PrintHeaderServerMethodGeneric(
+ grpc_generator::Printer *printer, const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ printer->Print(*vars, "template <class BaseClass>\n");
+ printer->Print(*vars,
+ "class WithGenericMethod_$Method$ : public BaseClass {\n");
+ printer->Print(
+ " private:\n"
+ " void BaseClassMustBeDerivedFromService(const Service *service) {}\n");
+ printer->Print(" public:\n");
+ printer->Indent();
+ printer->Print(*vars,
+ "WithGenericMethod_$Method$() {\n"
+ " ::grpc::Service::MarkMethodGeneric($Idx$);\n"
+ "}\n");
+ printer->Print(*vars,
+ "~WithGenericMethod_$Method$() override {\n"
+ " BaseClassMustBeDerivedFromService(this);\n"
+ "}\n");
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "$Response$* response) final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) final override "
+ "{\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "// disable synchronous version of this method\n"
+ "::grpc::Status $Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
+ "final override {\n"
+ " abort();\n"
+ " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+ "}\n");
+ }
+ printer->Outdent();
+ printer->Print(*vars, "};\n");
+}
+
+void PrintHeaderService(grpc_generator::Printer *printer,
+ const grpc_generator::Service *service,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Service"] = service->name();
+
+ printer->Print(service->GetLeadingComments("//").c_str());
+ printer->Print(*vars,
+ "class $Service$ final {\n"
+ " public:\n");
+ printer->Indent();
+
+ // Service metadata
+ printer->Print(*vars,
+ "static constexpr char const* service_full_name() {\n"
+ " return \"$Package$$Service$\";\n"
+ "}\n");
+
+ // Client side
+ printer->Print(
+ "class StubInterface {\n"
+ " public:\n");
+ printer->Indent();
+ printer->Print("virtual ~StubInterface() {}\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(service->method(i)->GetLeadingComments("//").c_str());
+ PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
+ true);
+ printer->Print(service->method(i)->GetTrailingComments("//").c_str());
+ }
+ printer->Outdent();
+ printer->Print("private:\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
+ false);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Print(
+ "class Stub final : public StubInterface"
+ " {\n public:\n");
+ printer->Indent();
+ printer->Print(
+ "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& "
+ "channel);\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
+ }
+ printer->Outdent();
+ printer->Print("\n private:\n");
+ printer->Indent();
+ printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethod(printer, service->method(i).get(), vars, false);
+ }
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderClientMethodData(printer, service->method(i).get(), vars);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Print(
+ "static std::unique_ptr<Stub> NewStub(const std::shared_ptr< "
+ "::grpc::ChannelInterface>& channel, "
+ "const ::grpc::StubOptions& options = ::grpc::StubOptions());\n");
+
+ printer->Print("\n");
+
+ // Server side - base
+ printer->Print(
+ "class Service : public ::grpc::Service {\n"
+ " public:\n");
+ printer->Indent();
+ printer->Print("Service();\n");
+ printer->Print("virtual ~Service();\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintHeaderServerMethodSync(printer, service->method(i).get(), vars);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+
+ // Server side - Asynchronous
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodAsync(printer, service->method(i).get(), vars);
+ }
+
+ printer->Print("typedef ");
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["method_name"] = service->method(i).get()->name();
+ printer->Print(*vars, "WithAsyncMethod_$method_name$<");
+ }
+ printer->Print("Service");
+ for (int i = 0; i < service->method_count(); ++i) {
+ printer->Print(" >");
+ }
+ printer->Print(" AsyncService;\n");
+
+ // Server side - Generic
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodGeneric(printer, service->method(i).get(), vars);
+ }
+
+ // Server side - Streamed Unary
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodStreamedUnary(printer, service->method(i).get(),
+ vars);
+ }
+
+ printer->Print("typedef ");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["method_name"] = service->method(i).get()->name();
+ if (service->method(i)->NoStreaming()) {
+ printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<");
+ }
+ }
+ printer->Print("Service");
+ for (int i = 0; i < service->method_count(); ++i) {
+ if (service->method(i)->NoStreaming()) {
+ printer->Print(" >");
+ }
+ }
+ printer->Print(" StreamedUnaryService;\n");
+
+ // Server side - controlled server-side streaming
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintHeaderServerMethodSplitStreaming(printer, service->method(i).get(),
+ vars);
+ }
+
+ printer->Print("typedef ");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["method_name"] = service->method(i).get()->name();
+ auto method = service->method(i);
+ if (ServerOnlyStreaming(method.get())) {
+ printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
+ }
+ }
+ printer->Print("Service");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ if (ServerOnlyStreaming(method.get())) {
+ printer->Print(" >");
+ }
+ }
+ printer->Print(" SplitStreamedService;\n");
+
+ // Server side - typedef for controlled both unary and server-side streaming
+ printer->Print("typedef ");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["method_name"] = service->method(i).get()->name();
+ auto method = service->method(i);
+ if (ServerOnlyStreaming(method.get())) {
+ printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
+ }
+ if (service->method(i)->NoStreaming()) {
+ printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<");
+ }
+ }
+ printer->Print("Service");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ if (service->method(i)->NoStreaming() ||
+ ServerOnlyStreaming(method.get())) {
+ printer->Print(" >");
+ }
+ }
+ printer->Print(" StreamedService;\n");
+
+ printer->Outdent();
+ printer->Print("};\n");
+ printer->Print(service->GetTrailingComments("//").c_str());
+}
+
+grpc::string GetHeaderServices(grpc_generator::File *file,
+ const Parameters ¶ms) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+ // Package string is empty or ends with a dot. It is used to fully qualify
+ // method names.
+ vars["Package"] = file->package();
+ if (!file->package().empty()) {
+ vars["Package"].append(".");
+ }
+
+ if (!params.services_namespace.empty()) {
+ vars["services_namespace"] = params.services_namespace;
+ printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
+ }
+
+ for (int i = 0; i < file->service_count(); ++i) {
+ PrintHeaderService(printer.get(), file->service(i).get(), &vars);
+ printer->Print("\n");
+ }
+
+ if (!params.services_namespace.empty()) {
+ printer->Print(vars, "} // namespace $services_namespace$\n\n");
+ }
+ }
+ return output;
+}
+
+grpc::string GetHeaderEpilogue(grpc_generator::File *file,
+ const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_identifier"] = FilenameIdentifier(file->filename());
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.rbegin(); part != parts.rend(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "} // namespace $part$\n");
+ }
+ printer->Print(vars, "\n");
+ }
+
+ printer->Print(vars, "\n");
+ printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n");
+
+ printer->Print(file->GetTrailingComments("//").c_str());
+ }
+ return output;
+}
+
+grpc::string GetSourcePrologue(grpc_generator::File *file,
+ const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_base"] = file->filename_without_ext();
+ vars["message_header_ext"] = message_header_ext();
+ vars["service_header_ext"] = service_header_ext();
+
+ printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
+ printer->Print(vars,
+ "// If you make any local change, they will be lost.\n");
+ printer->Print(vars, "// source: $filename$\n\n");
+
+ printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+ printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+grpc::string GetSourceIncludes(grpc_generator::File *file,
+ const Parameters ¶ms) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ static const char *headers_strs[] = {
+ "grpc++/impl/codegen/async_stream.h",
+ "grpc++/impl/codegen/async_unary_call.h",
+ "grpc++/impl/codegen/channel_interface.h",
+ "grpc++/impl/codegen/client_unary_call.h",
+ "grpc++/impl/codegen/method_handler_impl.h",
+ "grpc++/impl/codegen/rpc_service_method.h",
+ "grpc++/impl/codegen/service_type.h",
+ "grpc++/impl/codegen/sync_stream.h"};
+ std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+ PrintIncludes(printer.get(), headers, params);
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "namespace $part$ {\n");
+ }
+ }
+
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+void PrintSourceClientMethod(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ struct {
+ grpc::string prefix;
+ grpc::string start; // bool literal expressed as string
+ grpc::string method_params; // extra arguments to method
+ grpc::string create_args; // extra arguments to creator
+ } async_prefixes[] = {{"Async", "true", ", void* tag", ", tag"},
+ {"PrepareAsync", "false", "", ", nullptr"}};
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Stub::$Method$("
+ "::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response) {\n");
+ printer->Print(*vars,
+ " return ::grpc::internal::BlockingUnaryCall"
+ "(channel_.get(), rpcmethod_$Method$_, "
+ "context, request, response);\n}\n\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncStart"] = async_prefix.start;
+ printer->Print(*vars,
+ "::grpc::ClientAsyncResponseReader< $Response$>* "
+ "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::"
+ "ClientContext* context, "
+ "const $Request$& request, "
+ "::grpc::CompletionQueue* cq) {\n");
+ printer->Print(
+ *vars,
+ " return "
+ "::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>"
+ "::Create(channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, request, $AsyncStart$);\n"
+ "}\n\n");
+ }
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "::grpc::ClientWriter< $Request$>* "
+ "$ns$$Service$::Stub::$Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response) {\n");
+ printer->Print(
+ *vars,
+ " return ::grpc::internal::ClientWriterFactory< $Request$>::Create("
+ "channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context, response);\n"
+ "}\n\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncStart"] = async_prefix.start;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncCreateArgs"] = async_prefix.create_args;
+ printer->Print(*vars,
+ "::grpc::ClientAsyncWriter< $Request$>* "
+ "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw("
+ "::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Print(
+ *vars,
+ " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>"
+ "::Create(channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, response, $AsyncStart$$AsyncCreateArgs$);\n"
+ "}\n\n");
+ }
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "::grpc::ClientReader< $Response$>* "
+ "$ns$$Service$::Stub::$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request) {\n");
+ printer->Print(
+ *vars,
+ " return ::grpc::internal::ClientReaderFactory< $Response$>::Create("
+ "channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context, request);\n"
+ "}\n\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncStart"] = async_prefix.start;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncCreateArgs"] = async_prefix.create_args;
+ printer->Print(
+ *vars,
+ "::grpc::ClientAsyncReader< $Response$>* "
+ "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw("
+ "::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Print(
+ *vars,
+ " return ::grpc::internal::ClientAsyncReaderFactory< $Response$>"
+ "::Create(channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, request, $AsyncStart$$AsyncCreateArgs$);\n"
+ "}\n\n");
+ }
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "::grpc::ClientReaderWriter< $Request$, $Response$>* "
+ "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n");
+ printer->Print(*vars,
+ " return ::grpc::internal::ClientReaderWriterFactory< "
+ "$Request$, $Response$>::Create("
+ "channel_.get(), "
+ "rpcmethod_$Method$_, "
+ "context);\n"
+ "}\n\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncStart"] = async_prefix.start;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["AsyncCreateArgs"] = async_prefix.create_args;
+ printer->Print(*vars,
+ "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+ "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::"
+ "ClientContext* context, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n");
+ printer->Print(*vars,
+ " return "
+ "::grpc::internal::ClientAsyncReaderWriterFactory< "
+ "$Request$, $Response$>::Create("
+ "channel_.get(), cq, "
+ "rpcmethod_$Method$_, "
+ "context, $AsyncStart$$AsyncCreateArgs$);\n"
+ "}\n\n");
+ }
+ }
+}
+
+void PrintSourceServerMethod(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "const $Request$* request, $Response$* response) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) request;\n");
+ printer->Print(" (void) response;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReader< $Request$>* reader, "
+ "$Response$* response) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) reader;\n");
+ printer->Print(" (void) response;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "const $Request$* request, "
+ "::grpc::ServerWriter< $Response$>* writer) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) request;\n");
+ printer->Print(" (void) writer;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(*vars,
+ "::grpc::Status $ns$$Service$::Service::$Method$("
+ "::grpc::ServerContext* context, "
+ "::grpc::ServerReaderWriter< $Response$, $Request$>* "
+ "stream) {\n");
+ printer->Print(" (void) context;\n");
+ printer->Print(" (void) stream;\n");
+ printer->Print(
+ " return ::grpc::Status("
+ "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
+ printer->Print("}\n\n");
+ }
+}
+
+void PrintSourceService(grpc_generator::Printer *printer,
+ const grpc_generator::Service *service,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Service"] = service->name();
+
+ if (service->method_count() > 0) {
+ printer->Print(*vars,
+ "static const char* $prefix$$Service$_method_names[] = {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Method"] = service->method(i).get()->name();
+ printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n");
+ }
+ printer->Print(*vars, "};\n\n");
+ }
+
+ printer->Print(*vars,
+ "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
+ "const std::shared_ptr< ::grpc::ChannelInterface>& channel, "
+ "const ::grpc::StubOptions& options) {\n"
+ " std::unique_ptr< $ns$$Service$::Stub> stub(new "
+ "$ns$$Service$::Stub(channel));\n"
+ " return stub;\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "$ns$$Service$::Stub::Stub(const std::shared_ptr< "
+ "::grpc::ChannelInterface>& channel)\n");
+ printer->Indent();
+ printer->Print(": channel_(channel)");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ (*vars)["Method"] = method->name();
+ (*vars)["Idx"] = as_string(i);
+ if (method->NoStreaming()) {
+ (*vars)["StreamingType"] = "NORMAL_RPC";
+ // NOTE: There is no reason to consider streamed-unary as a separate
+ // category here since this part is setting up the client-side stub
+ // and this appears as a NORMAL_RPC from the client-side.
+ } else if (ClientOnlyStreaming(method.get())) {
+ (*vars)["StreamingType"] = "CLIENT_STREAMING";
+ } else if (ServerOnlyStreaming(method.get())) {
+ (*vars)["StreamingType"] = "SERVER_STREAMING";
+ } else {
+ (*vars)["StreamingType"] = "BIDI_STREAMING";
+ }
+ printer->Print(*vars,
+ ", rpcmethod_$Method$_("
+ "$prefix$$Service$_method_names[$Idx$], "
+ "::grpc::internal::RpcMethod::$StreamingType$, "
+ "channel"
+ ")\n");
+ }
+ printer->Print("{}\n\n");
+ printer->Outdent();
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintSourceClientMethod(printer, service->method(i).get(), vars);
+ }
+
+ printer->Print(*vars, "$ns$$Service$::Service::Service() {\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ (*vars)["Idx"] = as_string(i);
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::internal::RpcMethod::NORMAL_RPC,\n"
+ " new ::grpc::internal::RpcMethodHandler< $ns$$Service$::Service, "
+ "$Request$, "
+ "$Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ } else if (ClientOnlyStreaming(method.get())) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n"
+ " new ::grpc::internal::ClientStreamingHandler< "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ } else if (ServerOnlyStreaming(method.get())) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::internal::RpcMethod::SERVER_STREAMING,\n"
+ " new ::grpc::internal::ServerStreamingHandler< "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
+ " $prefix$$Service$_method_names[$Idx$],\n"
+ " ::grpc::internal::RpcMethod::BIDI_STREAMING,\n"
+ " new ::grpc::internal::BidiStreamingHandler< "
+ "$ns$$Service$::Service, $Request$, $Response$>(\n"
+ " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
+ }
+ }
+ printer->Outdent();
+ printer->Print(*vars, "}\n\n");
+ printer->Print(*vars,
+ "$ns$$Service$::Service::~Service() {\n"
+ "}\n\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ (*vars)["Idx"] = as_string(i);
+ PrintSourceServerMethod(printer, service->method(i).get(), vars);
+ }
+}
+
+grpc::string GetSourceServices(grpc_generator::File *file,
+ const Parameters ¶ms) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+ // Package string is empty or ends with a dot. It is used to fully qualify
+ // method names.
+ vars["Package"] = file->package();
+ if (!file->package().empty()) {
+ vars["Package"].append(".");
+ }
+ if (!params.services_namespace.empty()) {
+ vars["ns"] = params.services_namespace + "::";
+ vars["prefix"] = params.services_namespace;
+ } else {
+ vars["ns"] = "";
+ vars["prefix"] = "";
+ }
+
+ for (int i = 0; i < file->service_count(); ++i) {
+ PrintSourceService(printer.get(), file->service(i).get(), &vars);
+ printer->Print("\n");
+ }
+ }
+ return output;
+}
+
+grpc::string GetSourceEpilogue(grpc_generator::File *file,
+ const Parameters & /*params*/) {
+ grpc::string temp;
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ temp.append("} // namespace ");
+ temp.append(*part);
+ temp.append("\n");
+ }
+ temp.append("\n");
+ }
+
+ return temp;
+}
+
+// TODO(mmukhi): Make sure we need parameters or not.
+grpc::string GetMockPrologue(grpc_generator::File *file,
+ const Parameters & /*params*/) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ vars["filename"] = file->filename();
+ vars["filename_base"] = file->filename_without_ext();
+ vars["message_header_ext"] = message_header_ext();
+ vars["service_header_ext"] = service_header_ext();
+
+ printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
+ printer->Print(vars,
+ "// If you make any local change, they will be lost.\n");
+ printer->Print(vars, "// source: $filename$\n\n");
+
+ printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+ printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
+ printer->Print(vars, file->additional_headers().c_str());
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+// TODO(mmukhi): Add client-stream and completion-queue headers.
+grpc::string GetMockIncludes(grpc_generator::File *file,
+ const Parameters ¶ms) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+
+ static const char *headers_strs[] = {
+ "grpc++/impl/codegen/async_stream.h",
+ "grpc++/impl/codegen/sync_stream.h",
+ "gmock/gmock.h",
+ };
+ std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+ PrintIncludes(printer.get(), headers, params);
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ vars["part"] = *part;
+ printer->Print(vars, "namespace $part$ {\n");
+ }
+ }
+
+ printer->Print(vars, "\n");
+ }
+ return output;
+}
+
+void PrintMockClientMethods(grpc_generator::Printer *printer,
+ const grpc_generator::Method *method,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type_name();
+ (*vars)["Response"] = method->output_type_name();
+
+ struct {
+ grpc::string prefix;
+ grpc::string method_params; // extra arguments to method
+ int extra_method_param_count;
+ } async_prefixes[] = {{"Async", ", void* tag", 1}, {"PrepareAsync", "", 0}};
+
+ if (method->NoStreaming()) {
+ printer->Print(
+ *vars,
+ "MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, "
+ "const $Request$& request, $Response$* response));\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ printer->Print(
+ *vars,
+ "MOCK_METHOD3($AsyncPrefix$$Method$Raw, "
+ "::grpc::ClientAsyncResponseReaderInterface< $Response$>*"
+ "(::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq));\n");
+ }
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "MOCK_METHOD2($Method$Raw, "
+ "::grpc::ClientWriterInterface< $Request$>*"
+ "(::grpc::ClientContext* context, $Response$* response));\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["MockArgs"] =
+ flatbuffers::NumToString(3 + async_prefix.extra_method_param_count);
+ printer->Print(*vars,
+ "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, "
+ "::grpc::ClientAsyncWriterInterface< $Request$>*"
+ "(::grpc::ClientContext* context, $Response$* response, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n");
+ }
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "MOCK_METHOD2($Method$Raw, "
+ "::grpc::ClientReaderInterface< $Response$>*"
+ "(::grpc::ClientContext* context, const $Request$& request));\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["MockArgs"] =
+ flatbuffers::NumToString(3 + async_prefix.extra_method_param_count);
+ printer->Print(
+ *vars,
+ "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, "
+ "::grpc::ClientAsyncReaderInterface< $Response$>*"
+ "(::grpc::ClientContext* context, const $Request$& request, "
+ "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n");
+ }
+ } else if (method->BidiStreaming()) {
+ printer->Print(
+ *vars,
+ "MOCK_METHOD1($Method$Raw, "
+ "::grpc::ClientReaderWriterInterface< $Request$, $Response$>*"
+ "(::grpc::ClientContext* context));\n");
+ for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) {
+ auto& async_prefix = async_prefixes[i];
+ (*vars)["AsyncPrefix"] = async_prefix.prefix;
+ (*vars)["AsyncMethodParams"] = async_prefix.method_params;
+ (*vars)["MockArgs"] =
+ flatbuffers::NumToString(2 + async_prefix.extra_method_param_count);
+ printer->Print(
+ *vars,
+ "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, "
+ "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*"
+ "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq"
+ "$AsyncMethodParams$));\n");
+ }
+ }
+}
+
+void PrintMockService(grpc_generator::Printer *printer,
+ const grpc_generator::Service *service,
+ std::map<grpc::string, grpc::string> *vars) {
+ (*vars)["Service"] = service->name();
+
+ printer->Print(*vars,
+ "class Mock$Service$Stub : public $Service$::StubInterface {\n"
+ " public:\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintMockClientMethods(printer, service->method(i).get(), vars);
+ }
+ printer->Outdent();
+ printer->Print("};\n");
+}
+
+grpc::string GetMockServices(grpc_generator::File *file,
+ const Parameters ¶ms) {
+ grpc::string output;
+ {
+ // Scope the output stream so it closes and finalizes output to the string.
+ auto printer = file->CreatePrinter(&output);
+ std::map<grpc::string, grpc::string> vars;
+ // Package string is empty or ends with a dot. It is used to fully qualify
+ // method names.
+ vars["Package"] = file->package();
+ if (!file->package().empty()) {
+ vars["Package"].append(".");
+ }
+
+ if (!params.services_namespace.empty()) {
+ vars["services_namespace"] = params.services_namespace;
+ printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
+ }
+
+ for (int i = 0; i < file->service_count(); i++) {
+ PrintMockService(printer.get(), file->service(i).get(), &vars);
+ printer->Print("\n");
+ }
+
+ if (!params.services_namespace.empty()) {
+ printer->Print(vars, "} // namespace $services_namespace$\n\n");
+ }
+ }
+ return output;
+}
+
+grpc::string GetMockEpilogue(grpc_generator::File *file,
+ const Parameters & /*params*/) {
+ grpc::string temp;
+
+ if (!file->package().empty()) {
+ std::vector<grpc::string> parts = file->package_parts();
+
+ for (auto part = parts.begin(); part != parts.end(); part++) {
+ temp.append("} // namespace ");
+ temp.append(*part);
+ temp.append("\n");
+ }
+ temp.append("\n");
+ }
+
+ return temp;
+}
+
+} // namespace grpc_cpp_generator
diff --git a/grpc/src/compiler/cpp_generator.h b/grpc/src/compiler/cpp_generator.h
new file mode 100644
index 0000000..6119ebe
--- /dev/null
+++ b/grpc/src/compiler/cpp_generator.h
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
+
+// cpp_generator.h/.cc do not directly depend on GRPC/ProtoBuf, such that they
+// can be used to generate code for other serialization systems, such as
+// FlatBuffers.
+
+#include <memory>
+#include <vector>
+
+#include "src/compiler/config.h"
+#include "src/compiler/schema_interface.h"
+
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+} // namespace grpc
+
+namespace grpc_cpp_generator {
+
+// Contains all the parameters that are parsed from the command line.
+struct Parameters {
+ // Puts the service into a namespace
+ grpc::string services_namespace;
+ // Use system includes (<>) or local includes ("")
+ bool use_system_headers;
+ // Prefix to any grpc include
+ grpc::string grpc_search_path;
+ // Generate GMOCK code to facilitate unit testing.
+ bool generate_mock_code;
+};
+
+// Return the prologue of the generated header file.
+grpc::string GetHeaderPrologue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the includes needed for generated header file.
+grpc::string GetHeaderIncludes(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the includes needed for generated source file.
+grpc::string GetSourceIncludes(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the epilogue of the generated header file.
+grpc::string GetHeaderEpilogue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the prologue of the generated source file.
+grpc::string GetSourcePrologue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the services for generated header file.
+grpc::string GetHeaderServices(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the services for generated source file.
+grpc::string GetSourceServices(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the epilogue of the generated source file.
+grpc::string GetSourceEpilogue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the prologue of the generated mock file.
+grpc::string GetMockPrologue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the includes needed for generated mock file.
+grpc::string GetMockIncludes(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the services for generated mock file.
+grpc::string GetMockServices(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the epilogue of generated mock file.
+grpc::string GetMockEpilogue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the prologue of the generated mock file.
+grpc::string GetMockPrologue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the includes needed for generated mock file.
+grpc::string GetMockIncludes(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the services for generated mock file.
+grpc::string GetMockServices(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+// Return the epilogue of generated mock file.
+grpc::string GetMockEpilogue(grpc_generator::File *file,
+ const Parameters ¶ms);
+
+} // namespace grpc_cpp_generator
+
+#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
diff --git a/grpc/src/compiler/go_generator.cc b/grpc/src/compiler/go_generator.cc
new file mode 100644
index 0000000..604828d
--- /dev/null
+++ b/grpc/src/compiler/go_generator.cc
@@ -0,0 +1,446 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation AN/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <map>
+#include <cctype>
+#include <sstream>
+
+#include "src/compiler/go_generator.h"
+
+template <class T>
+grpc::string as_string(T x) {
+ std::ostringstream out;
+ out << x;
+ return out.str();
+}
+
+inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
+ return method->ClientStreaming() && !method->ServerStreaming();
+}
+
+inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
+ return !method->ClientStreaming() && method->ServerStreaming();
+}
+
+namespace grpc_go_generator {
+
+// Returns string with first letter to lowerCase
+grpc::string unexportName(grpc::string s) {
+ if (s.empty())
+ return s;
+ s[0] = static_cast<char>(std::tolower(s[0]));
+ return s;
+}
+
+// Returns string with first letter to uppercase
+grpc::string exportName(grpc::string s) {
+ if (s.empty())
+ return s;
+ s[0] = static_cast<char>(std::toupper(s[0]));
+ return s;
+}
+
+// Generates imports for the service
+void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["filename"] = file->filename();
+ printer->Print("//Generated by gRPC Go plugin\n");
+ printer->Print("//If you make any local changes, they will be lost\n");
+ printer->Print(vars, "//source: $filename$\n\n");
+ printer->Print(vars, "package $Package$\n\n");
+ if (file->additional_headers() != "") {
+ printer->Print(file->additional_headers().c_str());
+ printer->Print("\n\n");
+ }
+ printer->Print("import (\n");
+ printer->Indent();
+ printer->Print(vars, "$context$ \"context\"\n");
+ printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n");
+ printer->Outdent();
+ printer->Print(")\n\n");
+}
+
+// Generates Server method signature source
+void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = method->get_input_type_name();
+ vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
+ if (method->NoStreaming()) {
+ printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
+ } else {
+ printer->Print(vars, "$Method$($Service$_$Method$Server) error");
+ }
+}
+
+void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = method->get_input_type_name();
+ vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
+ vars["FullMethodName"] = "/" + vars["ServicePrefix"] + "." + vars["Service"] + "/" + vars["Method"];
+ vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
+ if (method->NoStreaming()) {
+ printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "in := new($Request$)\n");
+ printer->Print("if err := dec(in); err != nil { return nil, err }\n");
+ printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n");
+ printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n");
+ printer->Indent();
+ printer->Print("Server: srv,\n");
+ printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Print("return interceptor(ctx, in, info, handler)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ return;
+ }
+ vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
+ printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
+ printer->Indent();
+ if (ServerOnlyStreaming(method)) {
+ printer->Print(vars, "m := new($Request$)\n");
+ printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n");
+ printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n");
+ } else {
+ printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method);
+ bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method);
+ bool genSendAndClose = ClientOnlyStreaming(method);
+
+ printer->Print(vars, "type $Service$_$Method$Server interface { \n");
+ printer->Indent();
+ if (genSend) {
+ printer->Print(vars, "Send(* $Response$) error\n");
+ }
+ if (genRecv) {
+ printer->Print(vars, "Recv() (* $Request$, error)\n");
+ }
+ if (genSendAndClose) {
+ printer->Print(vars, "SendAndClose(* $Response$) error\n");
+ }
+ printer->Print(vars, "$grpc$.ServerStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ printer->Print(vars, "type $StreamType$ struct {\n");
+ printer->Indent();
+ printer->Print(vars, "$grpc$.ServerStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ if (genSend) {
+ printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n");
+ printer->Indent();
+ printer->Print("return x.ServerStream.SendMsg(m)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+ if (genRecv) {
+ printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "m := new($Request$)\n");
+ printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n");
+ printer->Print("return m, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+ if (genSendAndClose) {
+ printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n");
+ printer->Indent();
+ printer->Print("return x.ServerStream.SendMsg(m)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+}
+
+// Generates Client method signature source
+void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
+ if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
+ vars["Request"] = "";
+ }
+ vars["Response"] = "* " + method->get_output_type_name();
+ if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) {
+ vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
+ }
+ printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
+}
+
+// Generates Client method source
+void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
+ std::map<grpc::string, grpc::string> vars) {
+ printer->Print(vars, "func (c *$ServiceUnexported$Client) ");
+ GenerateClientMethodSignature(method, printer, vars);
+ printer->Print(" {\n");
+ printer->Indent();
+ vars["Method"] = exportName(method->name());
+ vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
+ vars["Response"] = method->get_output_type_name();
+ vars["FullMethodName"] = "/" + vars["ServicePrefix"] + "." + vars["Service"] + "/" + vars["Method"];
+ if (method->NoStreaming()) {
+ printer->Print(vars, "out := new($Response$)\n");
+ printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
+ printer->Print("if err != nil { return nil, err }\n");
+ printer->Print("return out, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ return;
+ }
+ vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client";
+ printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n");
+ printer->Print("if err != nil { return nil, err }\n");
+
+ printer->Print(vars, "x := &$StreamType${stream}\n");
+ if (ServerOnlyStreaming(method)) {
+ printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
+ printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
+ }
+ printer->Print("return x,nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method);
+ bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method);
+ bool genCloseAndRecv = ClientOnlyStreaming(method);
+
+ //Stream interface
+ printer->Print(vars, "type $Service$_$Method$Client interface {\n");
+ printer->Indent();
+ if (genSend) {
+ printer->Print(vars, "Send(*$Request$) error\n");
+ }
+ if (genRecv) {
+ printer->Print(vars, "Recv() (*$Response$, error)\n");
+ }
+ if (genCloseAndRecv) {
+ printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n");
+ }
+ printer->Print(vars, "$grpc$.ClientStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ //Stream Client
+ printer->Print(vars, "type $StreamType$ struct{\n");
+ printer->Indent();
+ printer->Print(vars, "$grpc$.ClientStream\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ if (genSend) {
+ printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n");
+ printer->Indent();
+ printer->Print("return x.ClientStream.SendMsg(m)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+ if (genRecv) {
+ printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n");
+ printer->Indent();
+ printer->Print(vars, "m := new($Response$)\n");
+ printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
+ printer->Print("return m, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+
+ if (genCloseAndRecv) {
+ printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n");
+ printer->Indent();
+ printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
+ printer->Print(vars, "m := new ($Response$)\n");
+ printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
+ printer->Print("return m, nil\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+ }
+}
+
+// Generates client API for the service
+void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer,
+ std::map<grpc::string, grpc::string> vars) {
+ vars["Service"] = exportName(service->name());
+ // Client Interface
+ printer->Print(vars, "// Client API for $Service$ service\n");
+ printer->Print(vars, "type $Service$Client interface{\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ GenerateClientMethodSignature(service->method(i).get(), printer, vars);
+ printer->Print("\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // Client structure
+ vars["ServiceUnexported"] = unexportName(vars["Service"]);
+ printer->Print(vars, "type $ServiceUnexported$Client struct {\n");
+ printer->Indent();
+ printer->Print(vars, "cc *$grpc$.ClientConn\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // NewClient
+ printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n");
+ printer->Indent();
+ printer->Print(vars, "return &$ServiceUnexported$Client{cc}");
+ printer->Outdent();
+ printer->Print("\n}\n\n");
+
+ int unary_methods = 0, streaming_methods = 0;
+ vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc";
+ for (int i = 0; i < service->method_count(); i++) {
+ auto method = service->method(i);
+ if (method->NoStreaming()) {
+ vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]";
+ unary_methods++;
+ } else {
+ vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]";
+ streaming_methods++;
+ }
+ GenerateClientMethod(method.get(), printer, vars);
+ }
+
+ //Server Interface
+ printer->Print(vars, "// Server API for $Service$ service\n");
+ printer->Print(vars, "type $Service$Server interface {\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ GenerateServerMethodSignature(service->method(i).get(), printer, vars);
+ printer->Print("\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ // Server registration.
+ printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n");
+ printer->Indent();
+ printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+ for (int i = 0; i < service->method_count(); i++) {
+ GenerateServerMethod(service->method(i).get(), printer, vars);
+ printer->Print("\n");
+ }
+
+
+ //Service Descriptor
+ printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
+ printer->Indent();
+ printer->Print(vars, "ServiceName: \"$ServicePrefix$.$Service$\",\n");
+ printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
+ printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ auto method = service->method(i);
+ vars["Method"] = method->name();
+ vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
+ if (method->NoStreaming()) {
+ printer->Print("{\n");
+ printer->Indent();
+ printer->Print(vars, "MethodName: \"$Method$\",\n");
+ printer->Print(vars, "Handler: $Handler$, \n");
+ printer->Outdent();
+ printer->Print("},\n");
+ }
+ }
+ printer->Outdent();
+ printer->Print("},\n");
+ printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n");
+ printer->Indent();
+ for (int i = 0; i < service->method_count(); i++) {
+ auto method = service->method(i);
+ vars["Method"] = method->name();
+ vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
+ if (!method->NoStreaming()) {
+ printer->Print("{\n");
+ printer->Indent();
+ printer->Print(vars, "StreamName: \"$Method$\",\n");
+ printer->Print(vars, "Handler: $Handler$, \n");
+ if (ClientOnlyStreaming(method.get())) {
+ printer->Print("ClientStreams: true,\n");
+ } else if (ServerOnlyStreaming(method.get())) {
+ printer->Print("ServerStreams: true,\n");
+ } else {
+ printer->Print("ServerStreams: true,\n");
+ printer->Print("ClientStreams: true,\n");
+ }
+ printer->Outdent();
+ printer->Print("},\n");
+ }
+ }
+ printer->Outdent();
+ printer->Print("},\n");
+ printer->Outdent();
+ printer->Print("}\n\n");
+
+}
+
+
+// Returns source for the service
+grpc::string GenerateServiceSource(grpc_generator::File *file,
+ const grpc_generator::Service *service,
+ grpc_go_generator::Parameters *parameters) {
+ grpc::string out;
+ auto p = file->CreatePrinter(&out);
+ auto printer = p.get();
+ std::map<grpc::string, grpc::string> vars;
+ vars["Package"] = parameters->package_name;
+ vars["ServicePrefix"] = parameters->service_prefix;
+ vars["grpc"] = "grpc";
+ vars["context"] = "context";
+ GenerateImports(file, printer, vars);
+ if (parameters->custom_method_io_type != "") {
+ vars["CustomMethodIO"] = parameters->custom_method_io_type;
+ }
+ GenerateService(service, printer, vars);
+ return out;
+}
+}// Namespace grpc_go_generator
diff --git a/grpc/src/compiler/go_generator.h b/grpc/src/compiler/go_generator.h
new file mode 100644
index 0000000..baa94e0
--- /dev/null
+++ b/grpc/src/compiler/go_generator.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
+#define GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
+
+//go generator is used to generate GRPC code for serialization system, such as flatbuffers
+#include <memory>
+#include <vector>
+
+#include "src/compiler/schema_interface.h"
+
+namespace grpc_go_generator {
+
+struct Parameters {
+ //Defines the custom parameter types for methods
+ //eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server
+ grpc::string custom_method_io_type;
+
+ //Package name for the service
+ grpc::string package_name;
+
+ //Prefix for RPC Calls
+ grpc::string service_prefix;
+};
+
+// Return the source of the generated service file.
+grpc::string GenerateServiceSource(grpc_generator::File *file,
+ const grpc_generator::Service *service,
+ grpc_go_generator::Parameters *parameters);
+
+}
+
+#endif // GRPC_INTERNAL_COMPILER_GO_GENERATOR_H
diff --git a/grpc/src/compiler/java_generator.cc b/grpc/src/compiler/java_generator.cc
new file mode 100644
index 0000000..661c9ee
--- /dev/null
+++ b/grpc/src/compiler/java_generator.cc
@@ -0,0 +1,1135 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "java_generator.h"
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <utility>
+#include <vector>
+
+// just to get flatbuffer_version_string()
+#include <flatbuffers/flatbuffers.h>
+#include <flatbuffers/util.h>
+#define to_string flatbuffers::NumToString
+
+// Stringify helpers used solely to cast GRPC_VERSION
+#ifndef STR
+#define STR(s) #s
+#endif
+
+#ifndef XSTR
+#define XSTR(s) STR(s)
+#endif
+
+
+typedef grpc_generator::Printer Printer;
+typedef std::map<grpc::string, grpc::string> VARS;
+typedef grpc_generator::Service ServiceDescriptor;
+typedef grpc_generator::CommentHolder
+ DescriptorType; // base class of all 'descriptors'
+typedef grpc_generator::Method MethodDescriptor;
+
+namespace grpc_java_generator {
+typedef std::string string;
+// Generates imports for the service
+void GenerateImports(grpc_generator::File* file,
+ grpc_generator::Printer* printer, VARS& vars) {
+ vars["filename"] = file->filename();
+ printer->Print(
+ vars,
+ "//Generated by flatc compiler (version $flatc_version$)\n");
+ printer->Print("//If you make any local changes, they will be lost\n");
+ printer->Print(vars, "//source: $filename$.fbs\n\n");
+ printer->Print(vars, "package $Package$;\n\n");
+ vars["Package"] = vars["Package"] + ".";
+ if (!file->additional_headers().empty()) {
+ printer->Print(file->additional_headers().c_str());
+ printer->Print("\n\n");
+ }
+}
+
+// Adjust a method name prefix identifier to follow the JavaBean spec:
+// - decapitalize the first letter
+// - remove embedded underscores & capitalize the following letter
+static string MixedLower(const string& word) {
+ string w;
+ w += static_cast<string::value_type>(tolower(word[0]));
+ bool after_underscore = false;
+ for (size_t i = 1; i < word.length(); ++i) {
+ if (word[i] == '_') {
+ after_underscore = true;
+ } else {
+ w += after_underscore ? static_cast<string::value_type>(toupper(word[i]))
+ : word[i];
+ after_underscore = false;
+ }
+ }
+ return w;
+}
+
+// Converts to the identifier to the ALL_UPPER_CASE format.
+// - An underscore is inserted where a lower case letter is followed by an
+// upper case letter.
+// - All letters are converted to upper case
+static string ToAllUpperCase(const string& word) {
+ string w;
+ for (size_t i = 0; i < word.length(); ++i) {
+ w += static_cast<string::value_type>(toupper(word[i]));
+ if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) {
+ w += '_';
+ }
+ }
+ return w;
+}
+
+static inline string LowerMethodName(const MethodDescriptor* method) {
+ return MixedLower(method->name());
+}
+
+static inline string MethodPropertiesFieldName(const MethodDescriptor* method) {
+ return "METHOD_" + ToAllUpperCase(method->name());
+}
+
+static inline string MethodPropertiesGetterName(
+ const MethodDescriptor* method) {
+ return MixedLower("get_" + method->name() + "_method");
+}
+
+static inline string MethodIdFieldName(const MethodDescriptor* method) {
+ return "METHODID_" + ToAllUpperCase(method->name());
+}
+
+static inline string JavaClassName(VARS& vars, const string& name) {
+ // string name = google::protobuf::compiler::java::ClassName(desc);
+ return vars["Package"] + name;
+}
+
+static inline string ServiceClassName(const string& service_name) {
+ return service_name + "Grpc";
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in
+// distribution.
+template <typename ITR>
+static void GrpcSplitStringToIteratorUsing(const string& full,
+ const char* delim, ITR& result) {
+ // Optimize the common case where delim is a single character.
+ if (delim[0] != '\0' && delim[1] == '\0') {
+ char c = delim[0];
+ const char* p = full.data();
+ const char* end = p + full.size();
+ while (p != end) {
+ if (*p == c) {
+ ++p;
+ } else {
+ const char* start = p;
+ while (++p != end && *p != c)
+ ;
+ *result++ = string(start, p - start);
+ }
+ }
+ return;
+ }
+
+ string::size_type begin_index, end_index;
+ begin_index = full.find_first_not_of(delim);
+ while (begin_index != string::npos) {
+ end_index = full.find_first_of(delim, begin_index);
+ if (end_index == string::npos) {
+ *result++ = full.substr(begin_index);
+ return;
+ }
+ *result++ = full.substr(begin_index, (end_index - begin_index));
+ begin_index = full.find_first_not_of(delim, end_index);
+ }
+}
+
+static void GrpcSplitStringUsing(const string& full, const char* delim,
+ std::vector<string>* result) {
+ std::back_insert_iterator<std::vector<string>> it(*result);
+ GrpcSplitStringToIteratorUsing(full, delim, it);
+}
+
+static std::vector<string> GrpcSplit(const string& full, const char* delim) {
+ std::vector<string> result;
+ GrpcSplitStringUsing(full, delim, &result);
+ return result;
+}
+
+// TODO(nmittler): Remove once protobuf includes javadoc methods in
+// distribution.
+static string GrpcEscapeJavadoc(const string& input) {
+ string result;
+ result.reserve(input.size() * 2);
+
+ char prev = '*';
+
+ for (string::size_type i = 0; i < input.size(); i++) {
+ char c = input[i];
+ switch (c) {
+ case '*':
+ // Avoid "/*".
+ if (prev == '/') {
+ result.append("*");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '/':
+ // Avoid "*/".
+ if (prev == '*') {
+ result.append("/");
+ } else {
+ result.push_back(c);
+ }
+ break;
+ case '@':
+ // '@' starts javadoc tags including the @deprecated tag, which will
+ // cause a compile-time error if inserted before a declaration that
+ // does not have a corresponding @Deprecated annotation.
+ result.append("@");
+ break;
+ case '<':
+ // Avoid interpretation as HTML.
+ result.append("<");
+ break;
+ case '>':
+ // Avoid interpretation as HTML.
+ result.append(">");
+ break;
+ case '&':
+ // Avoid interpretation as HTML.
+ result.append("&");
+ break;
+ case '\\':
+ // Java interprets Unicode escape sequences anywhere!
+ result.append("\");
+ break;
+ default:
+ result.push_back(c);
+ break;
+ }
+
+ prev = c;
+ }
+
+ return result;
+}
+
+static std::vector<string> GrpcGetDocLines(const string& comments) {
+ if (!comments.empty()) {
+ // TODO(kenton): Ideally we should parse the comment text as Markdown and
+ // write it back as HTML, but this requires a Markdown parser. For now
+ // we just use <pre> to get fixed-width text formatting.
+
+ // If the comment itself contains block comment start or end markers,
+ // HTML-escape them so that they don't accidentally close the doc comment.
+ string escapedComments = GrpcEscapeJavadoc(comments);
+
+ std::vector<string> lines = GrpcSplit(escapedComments, "\n");
+ while (!lines.empty() && lines.back().empty()) {
+ lines.pop_back();
+ }
+ return lines;
+ }
+ return std::vector<string>();
+}
+
+static std::vector<string> GrpcGetDocLinesForDescriptor(
+ const DescriptorType* descriptor) {
+ return descriptor->GetAllComments();
+ // return GrpcGetDocLines(descriptor->GetLeadingComments("///"));
+}
+
+static void GrpcWriteDocCommentBody(Printer* printer, VARS& vars,
+ const std::vector<string>& lines,
+ bool surroundWithPreTag) {
+ if (!lines.empty()) {
+ if (surroundWithPreTag) {
+ printer->Print(" * <pre>\n");
+ }
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ // Most lines should start with a space. Watch out for lines that start
+ // with a /, since putting that right after the leading asterisk will
+ // close the comment.
+ vars["line"] = lines[i];
+ if (!lines[i].empty() && lines[i][0] == '/') {
+ printer->Print(vars, " * $line$\n");
+ } else {
+ printer->Print(vars, " *$line$\n");
+ }
+ }
+
+ if (surroundWithPreTag) {
+ printer->Print(" * </pre>\n");
+ }
+ }
+}
+
+static void GrpcWriteDocComment(Printer* printer, VARS& vars,
+ const string& comments) {
+ printer->Print("/**\n");
+ std::vector<string> lines = GrpcGetDocLines(comments);
+ GrpcWriteDocCommentBody(printer, vars, lines, false);
+ printer->Print(" */\n");
+}
+
+static void GrpcWriteServiceDocComment(Printer* printer, VARS& vars,
+ const ServiceDescriptor* service) {
+ printer->Print("/**\n");
+ std::vector<string> lines = GrpcGetDocLinesForDescriptor(service);
+ GrpcWriteDocCommentBody(printer, vars, lines, true);
+ printer->Print(" */\n");
+}
+
+void GrpcWriteMethodDocComment(Printer* printer, VARS& vars,
+ const MethodDescriptor* method) {
+ printer->Print("/**\n");
+ std::vector<string> lines = GrpcGetDocLinesForDescriptor(method);
+ GrpcWriteDocCommentBody(printer, vars, lines, true);
+ printer->Print(" */\n");
+}
+
+//outputs static singleton extractor for type stored in "extr_type" and "extr_type_name" vars
+static void PrintTypeExtractor(Printer* p, VARS& vars) {
+ p->Print(
+ vars,
+ "private static volatile FlatbuffersUtils.FBExtactor<$extr_type$> "
+ "extractorOf$extr_type_name$;\n"
+ "private static FlatbuffersUtils.FBExtactor<$extr_type$> "
+ "getExtractorOf$extr_type_name$() {\n"
+ " if (extractorOf$extr_type_name$ != null) return "
+ "extractorOf$extr_type_name$;\n"
+ " synchronized ($service_class_name$.class) {\n"
+ " if (extractorOf$extr_type_name$ != null) return "
+ "extractorOf$extr_type_name$;\n"
+ " extractorOf$extr_type_name$ = new "
+ "FlatbuffersUtils.FBExtactor<$extr_type$>() {\n"
+ " public $extr_type$ extract (ByteBuffer buffer) {\n"
+ " return "
+ "$extr_type$.getRootAs$extr_type_name$(buffer);\n"
+ " }\n"
+ " };\n"
+ " return extractorOf$extr_type_name$;\n"
+ " }\n"
+ "}\n\n");
+}
+static void PrintMethodFields(Printer* p, VARS& vars,
+ const ServiceDescriptor* service) {
+ p->Print("// Static method descriptors that strictly reflect the proto.\n");
+ vars["service_name"] = service->name();
+
+ //set of names of rpc input- and output- types that were already encountered.
+ //this is needed to avoid duplicating type extractor since it's possible that
+ //the same type is used as an input or output type of more than a single RPC method
+ std::set<std::string> encounteredTypes;
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ vars["arg_in_id"] = to_string(2L * i); //trying to make msvc 10 happy
+ vars["arg_out_id"] = to_string(2L * i + 1);
+ vars["method_name"] = method->name();
+ vars["input_type_name"] = method->get_input_type_name();
+ vars["output_type_name"] = method->get_output_type_name();
+ vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
+ vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
+ vars["method_field_name"] = MethodPropertiesFieldName(method.get());
+ vars["method_new_field_name"] = MethodPropertiesGetterName(method.get());
+ vars["method_method_name"] = MethodPropertiesGetterName(method.get());
+ bool client_streaming = method->ClientStreaming() || method->BidiStreaming();
+ bool server_streaming = method->ServerStreaming() || method->BidiStreaming();
+ if (client_streaming) {
+ if (server_streaming) {
+ vars["method_type"] = "BIDI_STREAMING";
+ } else {
+ vars["method_type"] = "CLIENT_STREAMING";
+ }
+ } else {
+ if (server_streaming) {
+ vars["method_type"] = "SERVER_STREAMING";
+ } else {
+ vars["method_type"] = "UNARY";
+ }
+ }
+
+ p->Print(
+ vars,
+ "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/"
+ "1901\")\n"
+ "@$Deprecated$ // Use {@link #$method_method_name$()} instead. \n"
+ "public static final $MethodDescriptor$<$input_type$,\n"
+ " $output_type$> $method_field_name$ = $method_method_name$();\n"
+ "\n"
+ "private static volatile $MethodDescriptor$<$input_type$,\n"
+ " $output_type$> $method_new_field_name$;\n"
+ "\n");
+
+ if (encounteredTypes.insert(vars["input_type_name"]).second) {
+ vars["extr_type"] = vars["input_type"];
+ vars["extr_type_name"] = vars["input_type_name"];
+ PrintTypeExtractor(p, vars);
+ }
+
+ if (encounteredTypes.insert(vars["output_type_name"]).second) {
+ vars["extr_type"] = vars["output_type"];
+ vars["extr_type_name"] = vars["output_type_name"];
+ PrintTypeExtractor(p, vars);
+ }
+
+ p->Print(
+ vars,
+ "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/"
+ "1901\")\n"
+ "public static $MethodDescriptor$<$input_type$,\n"
+ " $output_type$> $method_method_name$() {\n"
+ " $MethodDescriptor$<$input_type$, $output_type$> "
+ "$method_new_field_name$;\n"
+ " if (($method_new_field_name$ = "
+ "$service_class_name$.$method_new_field_name$) == null) {\n"
+ " synchronized ($service_class_name$.class) {\n"
+ " if (($method_new_field_name$ = "
+ "$service_class_name$.$method_new_field_name$) == null) {\n"
+ " $service_class_name$.$method_new_field_name$ = "
+ "$method_new_field_name$ = \n"
+ " $MethodDescriptor$.<$input_type$, "
+ "$output_type$>newBuilder()\n"
+ " .setType($MethodType$.$method_type$)\n"
+ " .setFullMethodName(generateFullMethodName(\n"
+ " \"$Package$$service_name$\", \"$method_name$\"))\n"
+ " .setSampledToLocalTracing(true)\n"
+ " .setRequestMarshaller(FlatbuffersUtils.marshaller(\n"
+ " $input_type$.class, "
+ "getExtractorOf$input_type_name$()))\n"
+ " .setResponseMarshaller(FlatbuffersUtils.marshaller(\n"
+ " $output_type$.class, "
+ "getExtractorOf$output_type_name$()))\n");
+
+ // vars["proto_method_descriptor_supplier"] = service->name() +
+ // "MethodDescriptorSupplier";
+ p->Print(vars, " .setSchemaDescriptor(null)\n");
+ //" .setSchemaDescriptor(new
+ //$proto_method_descriptor_supplier$(\"$method_name$\"))\n");
+
+ p->Print(vars, " .build();\n");
+ p->Print(vars,
+ " }\n"
+ " }\n"
+ " }\n"
+ " return $method_new_field_name$;\n"
+ "}\n");
+
+ p->Print("\n");
+ }
+}
+enum StubType {
+ ASYNC_INTERFACE = 0,
+ BLOCKING_CLIENT_INTERFACE = 1,
+ FUTURE_CLIENT_INTERFACE = 2,
+ BLOCKING_SERVER_INTERFACE = 3,
+ ASYNC_CLIENT_IMPL = 4,
+ BLOCKING_CLIENT_IMPL = 5,
+ FUTURE_CLIENT_IMPL = 6,
+ ABSTRACT_CLASS = 7,
+};
+
+enum CallType { ASYNC_CALL = 0, BLOCKING_CALL = 1, FUTURE_CALL = 2 };
+
+static void PrintBindServiceMethodBody(Printer* p, VARS& vars,
+ const ServiceDescriptor* service);
+
+// Prints a client interface or implementation class, or a server interface.
+static void PrintStub(Printer* p, VARS& vars, const ServiceDescriptor* service,
+ StubType type) {
+ const string service_name = service->name();
+ vars["service_name"] = service_name;
+ vars["abstract_name"] = service_name + "ImplBase";
+ string stub_name = service_name;
+ string client_name = service_name;
+ CallType call_type = ASYNC_CALL;
+ bool impl_base = false;
+ bool interface = false;
+ switch (type) {
+ case ABSTRACT_CLASS:
+ call_type = ASYNC_CALL;
+ impl_base = true;
+ break;
+ case ASYNC_CLIENT_IMPL:
+ call_type = ASYNC_CALL;
+ stub_name += "Stub";
+ break;
+ case BLOCKING_CLIENT_INTERFACE:
+ interface = true;
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BLOCKING_CLIENT_IMPL:
+ call_type = BLOCKING_CALL;
+ stub_name += "BlockingStub";
+ client_name += "BlockingClient";
+ break;
+ case FUTURE_CLIENT_INTERFACE:
+ interface = true;
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case FUTURE_CLIENT_IMPL:
+ call_type = FUTURE_CALL;
+ stub_name += "FutureStub";
+ client_name += "FutureClient";
+ break;
+ case ASYNC_INTERFACE:
+ call_type = ASYNC_CALL;
+ interface = true;
+ break;
+ default:
+ GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type;
+ }
+ vars["stub_name"] = stub_name;
+ vars["client_name"] = client_name;
+
+ // Class head
+ if (!interface) {
+ GrpcWriteServiceDocComment(p, vars, service);
+ }
+ if (impl_base) {
+ p->Print(vars,
+ "public static abstract class $abstract_name$ implements "
+ "$BindableService$ {\n");
+ } else {
+ p->Print(vars,
+ "public static final class $stub_name$ extends "
+ "$AbstractStub$<$stub_name$> {\n");
+ }
+ p->Indent();
+
+ // Constructor and build() method
+ if (!impl_base && !interface) {
+ p->Print(vars, "private $stub_name$($Channel$ channel) {\n");
+ p->Indent();
+ p->Print("super(channel);\n");
+ p->Outdent();
+ p->Print("}\n\n");
+ p->Print(vars,
+ "private $stub_name$($Channel$ channel,\n"
+ " $CallOptions$ callOptions) {\n");
+ p->Indent();
+ p->Print("super(channel, callOptions);\n");
+ p->Outdent();
+ p->Print("}\n\n");
+ p->Print(vars,
+ "@$Override$\n"
+ "protected $stub_name$ build($Channel$ channel,\n"
+ " $CallOptions$ callOptions) {\n");
+ p->Indent();
+ p->Print(vars, "return new $stub_name$(channel, callOptions);\n");
+ p->Outdent();
+ p->Print("}\n");
+ }
+
+ // RPC methods
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
+ vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
+ vars["lower_method_name"] = LowerMethodName(&*method);
+ vars["method_method_name"] = MethodPropertiesGetterName(&*method);
+ bool client_streaming = method->ClientStreaming() || method->BidiStreaming();
+ bool server_streaming = method->ServerStreaming() || method->BidiStreaming();
+
+ if (call_type == BLOCKING_CALL && client_streaming) {
+ // Blocking client interface with client streaming is not available
+ continue;
+ }
+
+ if (call_type == FUTURE_CALL && (client_streaming || server_streaming)) {
+ // Future interface doesn't support streaming.
+ continue;
+ }
+
+ // Method signature
+ p->Print("\n");
+ // TODO(nmittler): Replace with WriteMethodDocComment once included by the
+ // protobuf distro.
+ if (!interface) {
+ GrpcWriteMethodDocComment(p, vars, &*method);
+ }
+ p->Print("public ");
+ switch (call_type) {
+ case BLOCKING_CALL:
+ GRPC_CODEGEN_CHECK(!client_streaming)
+ << "Blocking client interface with client streaming is unavailable";
+ if (server_streaming) {
+ // Server streaming
+ p->Print(vars,
+ "$Iterator$<$output_type$> $lower_method_name$(\n"
+ " $input_type$ request)");
+ } else {
+ // Simple RPC
+ p->Print(vars,
+ "$output_type$ $lower_method_name$($input_type$ request)");
+ }
+ break;
+ case ASYNC_CALL:
+ if (client_streaming) {
+ // Bidirectional streaming or client streaming
+ p->Print(vars,
+ "$StreamObserver$<$input_type$> $lower_method_name$(\n"
+ " $StreamObserver$<$output_type$> responseObserver)");
+ } else {
+ // Server streaming or simple RPC
+ p->Print(vars,
+ "void $lower_method_name$($input_type$ request,\n"
+ " $StreamObserver$<$output_type$> responseObserver)");
+ }
+ break;
+ case FUTURE_CALL:
+ GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
+ << "Future interface doesn't support streaming. "
+ << "client_streaming=" << client_streaming << ", "
+ << "server_streaming=" << server_streaming;
+ p->Print(vars,
+ "$ListenableFuture$<$output_type$> $lower_method_name$(\n"
+ " $input_type$ request)");
+ break;
+ }
+
+ if (interface) {
+ p->Print(";\n");
+ continue;
+ }
+ // Method body.
+ p->Print(" {\n");
+ p->Indent();
+ if (impl_base) {
+ switch (call_type) {
+ // NB: Skipping validation of service methods. If something is wrong,
+ // we wouldn't get to this point as compiler would return errors when
+ // generating service interface.
+ case ASYNC_CALL:
+ if (client_streaming) {
+ p->Print(vars,
+ "return "
+ "asyncUnimplementedStreamingCall($method_method_name$(), "
+ "responseObserver);\n");
+ } else {
+ p->Print(vars,
+ "asyncUnimplementedUnaryCall($method_method_name$(), "
+ "responseObserver);\n");
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (!interface) {
+ switch (call_type) {
+ case BLOCKING_CALL:
+ GRPC_CODEGEN_CHECK(!client_streaming)
+ << "Blocking client streaming interface is not available";
+ if (server_streaming) {
+ vars["calls_method"] = "blockingServerStreamingCall";
+ vars["params"] = "request";
+ } else {
+ vars["calls_method"] = "blockingUnaryCall";
+ vars["params"] = "request";
+ }
+ p->Print(vars,
+ "return $calls_method$(\n"
+ " getChannel(), $method_method_name$(), "
+ "getCallOptions(), $params$);\n");
+ break;
+ case ASYNC_CALL:
+ if (server_streaming) {
+ if (client_streaming) {
+ vars["calls_method"] = "asyncBidiStreamingCall";
+ vars["params"] = "responseObserver";
+ } else {
+ vars["calls_method"] = "asyncServerStreamingCall";
+ vars["params"] = "request, responseObserver";
+ }
+ } else {
+ if (client_streaming) {
+ vars["calls_method"] = "asyncClientStreamingCall";
+ vars["params"] = "responseObserver";
+ } else {
+ vars["calls_method"] = "asyncUnaryCall";
+ vars["params"] = "request, responseObserver";
+ }
+ }
+ vars["last_line_prefix"] = client_streaming ? "return " : "";
+ p->Print(vars,
+ "$last_line_prefix$$calls_method$(\n"
+ " getChannel().newCall($method_method_name$(), "
+ "getCallOptions()), $params$);\n");
+ break;
+ case FUTURE_CALL:
+ GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming)
+ << "Future interface doesn't support streaming. "
+ << "client_streaming=" << client_streaming << ", "
+ << "server_streaming=" << server_streaming;
+ vars["calls_method"] = "futureUnaryCall";
+ p->Print(vars,
+ "return $calls_method$(\n"
+ " getChannel().newCall($method_method_name$(), "
+ "getCallOptions()), request);\n");
+ break;
+ }
+ }
+ p->Outdent();
+ p->Print("}\n");
+ }
+
+ if (impl_base) {
+ p->Print("\n");
+ p->Print(
+ vars,
+ "@$Override$ public final $ServerServiceDefinition$ bindService() {\n");
+ vars["instance"] = "this";
+ PrintBindServiceMethodBody(p, vars, service);
+ p->Print("}\n");
+ }
+
+ p->Outdent();
+ p->Print("}\n\n");
+}
+
+static bool CompareMethodClientStreaming(
+ const std::unique_ptr<const grpc_generator::Method>& method1,
+ const std::unique_ptr<const grpc_generator::Method>& method2) {
+ return method1->ClientStreaming() < method2->ClientStreaming();
+}
+
+// Place all method invocations into a single class to reduce memory footprint
+// on Android.
+static void PrintMethodHandlerClass(Printer* p, VARS& vars,
+ const ServiceDescriptor* service) {
+ // Sort method ids based on ClientStreaming() so switch tables are compact.
+ std::vector<std::unique_ptr<const grpc_generator::Method>> sorted_methods(
+ service->method_count());
+ for (int i = 0; i < service->method_count(); ++i) {
+ sorted_methods[i] = service->method(i);
+ }
+ stable_sort(sorted_methods.begin(), sorted_methods.end(),
+ CompareMethodClientStreaming);
+ for (size_t i = 0; i < sorted_methods.size(); i++) {
+ auto& method = sorted_methods[i];
+ vars["method_id"] = to_string(i);
+ vars["method_id_name"] = MethodIdFieldName(&*method);
+ p->Print(vars,
+ "private static final int $method_id_name$ = $method_id$;\n");
+ }
+ p->Print("\n");
+ vars["service_name"] = service->name() + "ImplBase";
+ p->Print(vars,
+ "private static final class MethodHandlers<Req, Resp> implements\n"
+ " io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,\n"
+ " io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,\n"
+ " io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,\n"
+ " io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {\n"
+ " private final $service_name$ serviceImpl;\n"
+ " private final int methodId;\n"
+ "\n"
+ " MethodHandlers($service_name$ serviceImpl, int methodId) {\n"
+ " this.serviceImpl = serviceImpl;\n"
+ " this.methodId = methodId;\n"
+ " }\n\n");
+ p->Indent();
+ p->Print(vars,
+ "@$Override$\n"
+ "@java.lang.SuppressWarnings(\"unchecked\")\n"
+ "public void invoke(Req request, $StreamObserver$<Resp> "
+ "responseObserver) {\n"
+ " switch (methodId) {\n");
+ p->Indent();
+ p->Indent();
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ if (method->ClientStreaming() || method->BidiStreaming()) {
+ continue;
+ }
+ vars["method_id_name"] = MethodIdFieldName(&*method);
+ vars["lower_method_name"] = LowerMethodName(&*method);
+ vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
+ vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
+ p->Print(vars,
+ "case $method_id_name$:\n"
+ " serviceImpl.$lower_method_name$(($input_type$) request,\n"
+ " ($StreamObserver$<$output_type$>) responseObserver);\n"
+ " break;\n");
+ }
+ p->Print(
+ "default:\n"
+ " throw new AssertionError();\n");
+
+ p->Outdent();
+ p->Outdent();
+ p->Print(
+ " }\n"
+ "}\n\n");
+
+ p->Print(vars,
+ "@$Override$\n"
+ "@java.lang.SuppressWarnings(\"unchecked\")\n"
+ "public $StreamObserver$<Req> invoke(\n"
+ " $StreamObserver$<Resp> responseObserver) {\n"
+ " switch (methodId) {\n");
+ p->Indent();
+ p->Indent();
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ if (!(method->ClientStreaming() || method->BidiStreaming())) {
+ continue;
+ }
+ vars["method_id_name"] = MethodIdFieldName(&*method);
+ vars["lower_method_name"] = LowerMethodName(&*method);
+ vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
+ vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
+ p->Print(
+ vars,
+ "case $method_id_name$:\n"
+ " return ($StreamObserver$<Req>) serviceImpl.$lower_method_name$(\n"
+ " ($StreamObserver$<$output_type$>) responseObserver);\n");
+ }
+ p->Print(
+ "default:\n"
+ " throw new AssertionError();\n");
+
+ p->Outdent();
+ p->Outdent();
+ p->Print(
+ " }\n"
+ "}\n");
+
+ p->Outdent();
+ p->Print("}\n\n");
+}
+
+static void PrintGetServiceDescriptorMethod(Printer* p, VARS& vars,
+ const ServiceDescriptor* service) {
+ vars["service_name"] = service->name();
+ // vars["proto_base_descriptor_supplier"] = service->name() +
+ // "BaseDescriptorSupplier"; vars["proto_file_descriptor_supplier"] =
+ // service->name() + "FileDescriptorSupplier";
+ // vars["proto_method_descriptor_supplier"] = service->name() +
+ // "MethodDescriptorSupplier"; vars["proto_class_name"] =
+ // google::protobuf::compiler::java::ClassName(service->file());
+ // p->Print(
+ // vars,
+ // "private static abstract class
+ // $proto_base_descriptor_supplier$\n" " implements
+ // $ProtoFileDescriptorSupplier$,
+ // $ProtoServiceDescriptorSupplier$ {\n" "
+ // $proto_base_descriptor_supplier$() {}\n"
+ // "\n"
+ // " @$Override$\n"
+ // " public com.google.protobuf.Descriptors.FileDescriptor
+ // getFileDescriptor() {\n" " return
+ // $proto_class_name$.getDescriptor();\n" " }\n"
+ // "\n"
+ // " @$Override$\n"
+ // " public com.google.protobuf.Descriptors.ServiceDescriptor
+ // getServiceDescriptor() {\n" " return
+ // getFileDescriptor().findServiceByName(\"$service_name$\");\n"
+ // " }\n"
+ // "}\n"
+ // "\n"
+ // "private static final class
+ // $proto_file_descriptor_supplier$\n" " extends
+ // $proto_base_descriptor_supplier$ {\n" "
+ // $proto_file_descriptor_supplier$() {}\n"
+ // "}\n"
+ // "\n"
+ // "private static final class
+ // $proto_method_descriptor_supplier$\n" " extends
+ // $proto_base_descriptor_supplier$\n" " implements
+ // $ProtoMethodDescriptorSupplier$ {\n" " private final
+ // String methodName;\n"
+ // "\n"
+ // " $proto_method_descriptor_supplier$(String methodName)
+ // {\n" " this.methodName = methodName;\n" " }\n"
+ // "\n"
+ // " @$Override$\n"
+ // " public com.google.protobuf.Descriptors.MethodDescriptor
+ // getMethodDescriptor() {\n" " return
+ // getServiceDescriptor().findMethodByName(methodName);\n" "
+ // }\n"
+ // "}\n\n");
+
+ p->Print(
+ vars,
+ "private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n");
+
+ p->Print(vars,
+ "public static $ServiceDescriptor$ getServiceDescriptor() {\n");
+ p->Indent();
+ p->Print(vars, "$ServiceDescriptor$ result = serviceDescriptor;\n");
+ p->Print("if (result == null) {\n");
+ p->Indent();
+ p->Print(vars, "synchronized ($service_class_name$.class) {\n");
+ p->Indent();
+ p->Print("result = serviceDescriptor;\n");
+ p->Print("if (result == null) {\n");
+ p->Indent();
+
+ p->Print(vars,
+ "serviceDescriptor = result = "
+ "$ServiceDescriptor$.newBuilder(SERVICE_NAME)");
+ p->Indent();
+ p->Indent();
+ p->Print(vars, "\n.setSchemaDescriptor(null)");
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ vars["method_method_name"] = MethodPropertiesGetterName(&*method);
+ p->Print(vars, "\n.addMethod($method_method_name$())");
+ }
+ p->Print("\n.build();\n");
+ p->Outdent();
+ p->Outdent();
+
+ p->Outdent();
+ p->Print("}\n");
+ p->Outdent();
+ p->Print("}\n");
+ p->Outdent();
+ p->Print("}\n");
+ p->Print("return result;\n");
+ p->Outdent();
+ p->Print("}\n");
+}
+
+static void PrintBindServiceMethodBody(Printer* p, VARS& vars,
+ const ServiceDescriptor* service) {
+ vars["service_name"] = service->name();
+ p->Indent();
+ p->Print(vars,
+ "return "
+ "$ServerServiceDefinition$.builder(getServiceDescriptor())\n");
+ p->Indent();
+ p->Indent();
+ for (int i = 0; i < service->method_count(); ++i) {
+ auto method = service->method(i);
+ vars["lower_method_name"] = LowerMethodName(&*method);
+ vars["method_method_name"] = MethodPropertiesGetterName(&*method);
+ vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
+ vars["output_type"] = JavaClassName(vars, method->get_output_type_name());
+ vars["method_id_name"] = MethodIdFieldName(&*method);
+ bool client_streaming = method->ClientStreaming() || method->BidiStreaming();
+ bool server_streaming = method->ServerStreaming() || method->BidiStreaming();
+ if (client_streaming) {
+ if (server_streaming) {
+ vars["calls_method"] = "asyncBidiStreamingCall";
+ } else {
+ vars["calls_method"] = "asyncClientStreamingCall";
+ }
+ } else {
+ if (server_streaming) {
+ vars["calls_method"] = "asyncServerStreamingCall";
+ } else {
+ vars["calls_method"] = "asyncUnaryCall";
+ }
+ }
+ p->Print(vars, ".addMethod(\n");
+ p->Indent();
+ p->Print(vars,
+ "$method_method_name$(),\n"
+ "$calls_method$(\n");
+ p->Indent();
+ p->Print(vars,
+ "new MethodHandlers<\n"
+ " $input_type$,\n"
+ " $output_type$>(\n"
+ " $instance$, $method_id_name$)))\n");
+ p->Outdent();
+ p->Outdent();
+ }
+ p->Print(".build();\n");
+ p->Outdent();
+ p->Outdent();
+ p->Outdent();
+}
+
+static void PrintService(Printer* p, VARS& vars,
+ const ServiceDescriptor* service,
+ bool disable_version) {
+ vars["service_name"] = service->name();
+ vars["service_class_name"] = ServiceClassName(service->name());
+ vars["grpc_version"] = "";
+#ifdef GRPC_VERSION
+ if (!disable_version) {
+ vars["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")";
+ }
+#else
+ (void)disable_version;
+#endif
+ // TODO(nmittler): Replace with WriteServiceDocComment once included by
+ // protobuf distro.
+ GrpcWriteServiceDocComment(p, vars, service);
+ p->Print(vars,
+ "@$Generated$(\n"
+ " value = \"by gRPC proto compiler$grpc_version$\",\n"
+ " comments = \"Source: $file_name$.fbs\")\n"
+ "public final class $service_class_name$ {\n\n");
+ p->Indent();
+ p->Print(vars, "private $service_class_name$() {}\n\n");
+
+ p->Print(vars,
+ "public static final String SERVICE_NAME = "
+ "\"$Package$$service_name$\";\n\n");
+
+ PrintMethodFields(p, vars, service);
+
+ // TODO(nmittler): Replace with WriteDocComment once included by protobuf
+ // distro.
+ GrpcWriteDocComment(
+ p, vars,
+ " Creates a new async stub that supports all call types for the service");
+ p->Print(vars,
+ "public static $service_name$Stub newStub($Channel$ channel) {\n");
+ p->Indent();
+ p->Print(vars, "return new $service_name$Stub(channel);\n");
+ p->Outdent();
+ p->Print("}\n\n");
+
+ // TODO(nmittler): Replace with WriteDocComment once included by protobuf
+ // distro.
+ GrpcWriteDocComment(
+ p, vars,
+ " Creates a new blocking-style stub that supports unary and streaming "
+ "output calls on the service");
+ p->Print(vars,
+ "public static $service_name$BlockingStub newBlockingStub(\n"
+ " $Channel$ channel) {\n");
+ p->Indent();
+ p->Print(vars, "return new $service_name$BlockingStub(channel);\n");
+ p->Outdent();
+ p->Print("}\n\n");
+
+ // TODO(nmittler): Replace with WriteDocComment once included by protobuf
+ // distro.
+ GrpcWriteDocComment(
+ p, vars,
+ " Creates a new ListenableFuture-style stub that supports unary calls "
+ "on the service");
+ p->Print(vars,
+ "public static $service_name$FutureStub newFutureStub(\n"
+ " $Channel$ channel) {\n");
+ p->Indent();
+ p->Print(vars, "return new $service_name$FutureStub(channel);\n");
+ p->Outdent();
+ p->Print("}\n\n");
+
+ PrintStub(p, vars, service, ABSTRACT_CLASS);
+ PrintStub(p, vars, service, ASYNC_CLIENT_IMPL);
+ PrintStub(p, vars, service, BLOCKING_CLIENT_IMPL);
+ PrintStub(p, vars, service, FUTURE_CLIENT_IMPL);
+
+ PrintMethodHandlerClass(p, vars, service);
+ PrintGetServiceDescriptorMethod(p, vars, service);
+ p->Outdent();
+ p->Print("}\n");
+}
+
+void PrintStaticImports(Printer* p) {
+ p->Print(
+ "import java.nio.ByteBuffer;\n"
+ "import static "
+ "io.grpc.MethodDescriptor.generateFullMethodName;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.asyncUnaryCall;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.blockingUnaryCall;\n"
+ "import static "
+ "io.grpc.stub.ClientCalls.futureUnaryCall;\n"
+ "import static "
+ "io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ServerCalls.asyncUnaryCall;\n"
+ "import static "
+ "io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n"
+ "import static "
+ "io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n\n");
+}
+
+void GenerateService(const grpc_generator::Service* service,
+ grpc_generator::Printer* printer, VARS& vars,
+ bool disable_version) {
+ // All non-generated classes must be referred by fully qualified names to
+ // avoid collision with generated classes.
+ vars["String"] = "java.lang.String";
+ vars["Deprecated"] = "java.lang.Deprecated";
+ vars["Override"] = "java.lang.Override";
+ vars["Channel"] = "io.grpc.Channel";
+ vars["CallOptions"] = "io.grpc.CallOptions";
+ vars["MethodType"] = "io.grpc.MethodDescriptor.MethodType";
+ vars["ServerMethodDefinition"] = "io.grpc.ServerMethodDefinition";
+ vars["BindableService"] = "io.grpc.BindableService";
+ vars["ServerServiceDefinition"] = "io.grpc.ServerServiceDefinition";
+ vars["ServiceDescriptor"] = "io.grpc.ServiceDescriptor";
+ vars["ProtoFileDescriptorSupplier"] =
+ "io.grpc.protobuf.ProtoFileDescriptorSupplier";
+ vars["ProtoServiceDescriptorSupplier"] =
+ "io.grpc.protobuf.ProtoServiceDescriptorSupplier";
+ vars["ProtoMethodDescriptorSupplier"] =
+ "io.grpc.protobuf.ProtoMethodDescriptorSupplier";
+ vars["AbstractStub"] = "io.grpc.stub.AbstractStub";
+ vars["MethodDescriptor"] = "io.grpc.MethodDescriptor";
+ vars["NanoUtils"] = "io.grpc.protobuf.nano.NanoUtils";
+ vars["StreamObserver"] = "io.grpc.stub.StreamObserver";
+ vars["Iterator"] = "java.util.Iterator";
+ vars["Generated"] = "javax.annotation.Generated";
+ vars["ListenableFuture"] =
+ "com.google.common.util.concurrent.ListenableFuture";
+ vars["ExperimentalApi"] = "io.grpc.ExperimentalApi";
+
+ PrintStaticImports(printer);
+
+ PrintService(printer, vars, service, disable_version);
+}
+
+grpc::string GenerateServiceSource(
+ grpc_generator::File* file, const grpc_generator::Service* service,
+ grpc_java_generator::Parameters* parameters) {
+ grpc::string out;
+ auto printer = file->CreatePrinter(&out);
+ VARS vars;
+ vars["flatc_version"] = grpc::string(
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." FLATBUFFERS_STRING(
+ FLATBUFFERS_VERSION_MINOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION));
+
+ vars["file_name"] = file->filename();
+
+ if (!parameters->package_name.empty()) {
+ vars["Package"] = parameters->package_name; // ServiceJavaPackage(service);
+ }
+ GenerateImports(file, &*printer, vars);
+ GenerateService(service, &*printer, vars, false);
+ return out;
+}
+
+} // namespace grpc_java_generator
diff --git a/grpc/src/compiler/java_generator.h b/grpc/src/compiler/java_generator.h
new file mode 100644
index 0000000..b101fbf
--- /dev/null
+++ b/grpc/src/compiler/java_generator.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NET_GRPC_COMPILER_JAVA_GENERATOR_H_
+#define NET_GRPC_COMPILER_JAVA_GENERATOR_H_
+
+#include <stdlib.h> // for abort()
+#include <iostream>
+#include <map>
+#include <string>
+
+#include "src/compiler/schema_interface.h"
+
+class LogMessageVoidify {
+ public:
+ LogMessageVoidify() {}
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) {}
+};
+
+class LogHelper {
+ std::ostream* os_;
+
+ public:
+ LogHelper(std::ostream* os) : os_(os) {}
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning( \
+ disable : 4722) // the flow of control terminates in a destructor
+ // (needed to compile ~LogHelper where destructor emits abort intentionally -
+ // inherited from grpc/java code generator).
+#endif
+ ~LogHelper() {
+ *os_ << std::endl;
+ ::abort();
+ }
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+ std::ostream& get_os() const { return *os_; }
+};
+
+// Abort the program after logging the mesage if the given condition is not
+// true. Otherwise, do nothing.
+#define GRPC_CODEGEN_CHECK(x) \
+ (x) ? (void)0 \
+ : LogMessageVoidify() & LogHelper(&std::cerr).get_os() \
+ << "CHECK FAILED: " << __FILE__ << ":" \
+ << __LINE__ << ": "
+
+// Abort the program after logging the mesage.
+#define GRPC_CODEGEN_FAIL GRPC_CODEGEN_CHECK(false)
+
+namespace grpc_java_generator {
+struct Parameters {
+ // //Defines the custom parameter types for methods
+ // //eg: flatbuffers uses flatbuffers.Builder as input for the client
+ // and output for the server grpc::string custom_method_io_type;
+
+ // Package name for the service
+ grpc::string package_name;
+};
+
+// Return the source of the generated service file.
+grpc::string GenerateServiceSource(grpc_generator::File* file,
+ const grpc_generator::Service* service,
+ grpc_java_generator::Parameters* parameters);
+
+} // namespace grpc_java_generator
+
+#endif // NET_GRPC_COMPILER_JAVA_GENERATOR_H_
diff --git a/grpc/src/compiler/schema_interface.h b/grpc/src/compiler/schema_interface.h
new file mode 100644
index 0000000..2be2ed7
--- /dev/null
+++ b/grpc/src/compiler/schema_interface.h
@@ -0,0 +1,126 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
+#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
+
+#include "src/compiler/config.h"
+
+#include <memory>
+#include <vector>
+
+#ifndef GRPC_CUSTOM_STRING
+# include <string>
+# define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+} // namespace grpc
+
+namespace grpc_generator {
+
+// A common interface for objects having comments in the source.
+// Return formatted comments to be inserted in generated code.
+struct CommentHolder {
+ virtual ~CommentHolder() {}
+ virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0;
+ virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0;
+ virtual std::vector<grpc::string> GetAllComments() const = 0;
+};
+
+// An abstract interface representing a method.
+struct Method : public CommentHolder {
+ virtual ~Method() {}
+
+ virtual grpc::string name() const = 0;
+
+ virtual grpc::string input_type_name() const = 0;
+ virtual grpc::string output_type_name() const = 0;
+
+ virtual bool get_module_and_message_path_input(
+ grpc::string *str, grpc::string generator_file_name,
+ bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
+ virtual bool get_module_and_message_path_output(
+ grpc::string *str, grpc::string generator_file_name,
+ bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
+
+ virtual grpc::string get_input_type_name() const = 0;
+ virtual grpc::string get_output_type_name() const = 0;
+ virtual bool NoStreaming() const = 0;
+ virtual bool ClientStreaming() const = 0;
+ virtual bool ServerStreaming() const = 0;
+ virtual bool BidiStreaming() const = 0;
+};
+
+// An abstract interface representing a service.
+struct Service : public CommentHolder {
+ virtual ~Service() {}
+
+ virtual grpc::string name() const = 0;
+
+ virtual int method_count() const = 0;
+ virtual std::unique_ptr<const Method> method(int i) const = 0;
+};
+
+struct Printer {
+ virtual ~Printer() {}
+
+ virtual void Print(const std::map<grpc::string, grpc::string> &vars,
+ const char *template_string) = 0;
+ virtual void Print(const char *string) = 0;
+ virtual void Indent() = 0;
+ virtual void Outdent() = 0;
+};
+
+// An interface that allows the source generated to be output using various
+// libraries/idls/serializers.
+struct File : public CommentHolder {
+ virtual ~File() {}
+
+ virtual grpc::string filename() const = 0;
+ virtual grpc::string filename_without_ext() const = 0;
+ virtual grpc::string package() const = 0;
+ virtual std::vector<grpc::string> package_parts() const = 0;
+ virtual grpc::string additional_headers() const = 0;
+
+ virtual int service_count() const = 0;
+ virtual std::unique_ptr<const Service> service(int i) const = 0;
+
+ virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
+};
+} // namespace grpc_generator
+
+#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
diff --git a/grpc/tests/GameFactory.java b/grpc/tests/GameFactory.java
new file mode 100644
index 0000000..520ae39
--- /dev/null
+++ b/grpc/tests/GameFactory.java
@@ -0,0 +1,42 @@
+import java.nio.ByteBuffer;
+import MyGame.Example.Monster;
+import MyGame.Example.Stat;
+import com.google.flatbuffers.FlatBufferBuilder;
+
+class GameFactory {
+ public static Monster createMonster(String monsterName, short nestedMonsterHp, short nestedMonsterMana) {
+ FlatBufferBuilder builder = new FlatBufferBuilder();
+
+ int name_offset = builder.createString(monsterName);
+ Monster.startMonster(builder);
+ Monster.addName(builder, name_offset);
+ Monster.addHp(builder, nestedMonsterHp);
+ Monster.addMana(builder, nestedMonsterMana);
+ int monster_offset = Monster.endMonster(builder);
+ Monster.finishMonsterBuffer(builder, monster_offset);
+
+ ByteBuffer buffer = builder.dataBuffer();
+ Monster monster = Monster.getRootAsMonster(buffer);
+ return monster;
+ }
+
+ public static Monster createMonsterFromStat(Stat stat, int seqNo) {
+ FlatBufferBuilder builder = new FlatBufferBuilder();
+ int name_offset = builder.createString(stat.id() + " No." + seqNo);
+ Monster.startMonster(builder);
+ Monster.addName(builder, name_offset);
+ int monster_offset = Monster.endMonster(builder);
+ Monster.finishMonsterBuffer(builder, monster_offset);
+ Monster monster = Monster.getRootAsMonster(builder.dataBuffer());
+ return monster;
+ }
+
+ public static Stat createStat(String greeting, long val, int count) {
+ FlatBufferBuilder builder = new FlatBufferBuilder();
+ int statOffset = Stat.createStat(builder, builder.createString(greeting), val, count);
+ builder.finish(statOffset);
+ Stat stat = Stat.getRootAsStat(builder.dataBuffer());
+ return stat;
+ }
+
+}
diff --git a/grpc/tests/JavaGrpcTest.java b/grpc/tests/JavaGrpcTest.java
new file mode 100644
index 0000000..98a67b5
--- /dev/null
+++ b/grpc/tests/JavaGrpcTest.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import MyGame.Example.Monster;
+import MyGame.Example.MonsterStorageGrpc;
+import MyGame.Example.Stat;
+import com.google.flatbuffers.FlatBufferBuilder;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.Server;
+import io.grpc.ServerBuilder;
+import io.grpc.stub.StreamObserver;
+import org.junit.Assert;
+
+import java.io.IOException;
+import java.lang.InterruptedException;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.CountDownLatch;
+
+
+/**
+ * Demonstrates basic client-server interaction using grpc-java over netty.
+ */
+public class JavaGrpcTest {
+ static final String BIG_MONSTER_NAME = "Cyberdemon";
+ static final short nestedMonsterHp = 600;
+ static final short nestedMonsterMana = 1024;
+ static final int numStreamedMsgs = 10;
+ static final int timeoutMs = 3000;
+ static Server server;
+ static ManagedChannel channel;
+ static MonsterStorageGrpc.MonsterStorageBlockingStub blockingStub;
+ static MonsterStorageGrpc.MonsterStorageStub asyncStub;
+
+ static class MyService extends MonsterStorageGrpc.MonsterStorageImplBase {
+ @Override
+ public void store(Monster request, io.grpc.stub.StreamObserver<Stat> responseObserver) {
+ Assert.assertEquals(request.name(), BIG_MONSTER_NAME);
+ Assert.assertEquals(request.hp(), nestedMonsterHp);
+ Assert.assertEquals(request.mana(), nestedMonsterMana);
+ System.out.println("Received store request from " + request.name());
+ // Create a response from the incoming request name.
+ Stat stat = GameFactory.createStat("Hello " + request.name(), 100, 10);
+ responseObserver.onNext(stat);
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public void retrieve(Stat request, io.grpc.stub.StreamObserver<Monster> responseObserver) {
+ // Create 10 monsters for streaming response.
+ for (int i=0; i<numStreamedMsgs; i++) {
+ Monster monster = GameFactory.createMonsterFromStat(request, i);
+ responseObserver.onNext(monster);
+ }
+ responseObserver.onCompleted();
+ }
+
+ @Override
+ public StreamObserver<Monster> getMaxHitPoint(final StreamObserver<Stat> responseObserver) {
+ return computeMinMax(responseObserver, false);
+ }
+
+ @Override
+ public StreamObserver<Monster> getMinMaxHitPoints(final StreamObserver<Stat> responseObserver) {
+ return computeMinMax(responseObserver, true);
+ }
+
+ private StreamObserver<Monster> computeMinMax(final StreamObserver<Stat> responseObserver, final boolean includeMin) {
+ final AtomicInteger maxHp = new AtomicInteger(Integer.MIN_VALUE);
+ final AtomicReference<String> maxHpMonsterName = new AtomicReference<String>();
+ final AtomicInteger maxHpCount = new AtomicInteger();
+
+ final AtomicInteger minHp = new AtomicInteger(Integer.MAX_VALUE);
+ final AtomicReference<String> minHpMonsterName = new AtomicReference<String>();
+ final AtomicInteger minHpCount = new AtomicInteger();
+
+ return new StreamObserver<Monster>() {
+ public void onNext(Monster monster) {
+ if (monster.hp() > maxHp.get()) {
+ // Found a monster of higher hit points.
+ maxHp.set(monster.hp());
+ maxHpMonsterName.set(monster.name());
+ maxHpCount.set(1);
+ }
+ else if (monster.hp() == maxHp.get()) {
+ // Count how many times we saw a monster of current max hit points.
+ maxHpCount.getAndIncrement();
+ }
+
+ if (monster.hp() < minHp.get()) {
+ // Found a monster of a lower hit points.
+ minHp.set(monster.hp());
+ minHpMonsterName.set(monster.name());
+ minHpCount.set(1);
+ }
+ else if (monster.hp() == minHp.get()) {
+ // Count how many times we saw a monster of current min hit points.
+ minHpCount.getAndIncrement();
+ }
+ }
+ public void onCompleted() {
+ Stat maxHpStat = GameFactory.createStat(maxHpMonsterName.get(), maxHp.get(), maxHpCount.get());
+ // Send max hit points first.
+ responseObserver.onNext(maxHpStat);
+ if (includeMin) {
+ // Send min hit points.
+ Stat minHpStat = GameFactory.createStat(minHpMonsterName.get(), minHp.get(), minHpCount.get());
+ responseObserver.onNext(minHpStat);
+ }
+ responseObserver.onCompleted();
+ }
+ public void onError(Throwable t) {
+ // Not expected
+ Assert.fail();
+ };
+ };
+ }
+ }
+
+ @org.junit.BeforeClass
+ public static void startServer() throws IOException {
+ server = ServerBuilder.forPort(0).addService(new MyService()).build().start();
+ int port = server.getPort();
+ channel = ManagedChannelBuilder.forAddress("localhost", port)
+ // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
+ // needing certificates.
+ .usePlaintext(true)
+ .directExecutor()
+ .build();
+ blockingStub = MonsterStorageGrpc.newBlockingStub(channel);
+ asyncStub = MonsterStorageGrpc.newStub(channel);
+ }
+
+ @org.junit.Test
+ public void testUnary() throws IOException {
+ Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
+ Stat stat = blockingStub.store(monsterRequest);
+ Assert.assertEquals(stat.id(), "Hello " + BIG_MONSTER_NAME);
+ System.out.println("Received stat response from service: " + stat.id());
+ }
+
+ @org.junit.Test
+ public void testServerStreaming() throws IOException {
+ Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
+ Stat stat = blockingStub.store(monsterRequest);
+ Iterator<Monster> iterator = blockingStub.retrieve(stat);
+ int counter = 0;
+ while(iterator.hasNext()) {
+ Monster m = iterator.next();
+ System.out.println("Received monster " + m.name());
+ counter ++;
+ }
+ Assert.assertEquals(counter, numStreamedMsgs);
+ System.out.println("FlatBuffers GRPC client/server test: completed successfully");
+ }
+
+ @org.junit.Test
+ public void testClientStreaming() throws IOException, InterruptedException {
+ final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
+ final CountDownLatch streamAlive = new CountDownLatch(1);
+
+ StreamObserver<Stat> statObserver = new StreamObserver<Stat>() {
+ public void onCompleted() {
+ streamAlive.countDown();
+ }
+ public void onError(Throwable ex) { }
+ public void onNext(Stat stat) {
+ maxHitStat.set(stat);
+ }
+ };
+ StreamObserver<Monster> monsterStream = asyncStub.getMaxHitPoint(statObserver);
+ short count = 10;
+ for (short i = 0;i < count; ++i) {
+ Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
+ monsterStream.onNext(monster);
+ }
+ monsterStream.onCompleted();
+ // Wait a little bit for the server to send the stats of the monster with the max hit-points.
+ streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
+ Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));
+ Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1));
+ Assert.assertEquals(maxHitStat.get().count(), 1);
+ }
+
+ @org.junit.Test
+ public void testBiDiStreaming() throws IOException, InterruptedException {
+ final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
+ final AtomicReference<Stat> minHitStat = new AtomicReference<Stat>();
+ final CountDownLatch streamAlive = new CountDownLatch(1);
+
+ StreamObserver<Stat> statObserver = new StreamObserver<Stat>() {
+ public void onCompleted() {
+ streamAlive.countDown();
+ }
+ public void onError(Throwable ex) { }
+ public void onNext(Stat stat) {
+ // We expect the server to send the max stat first and then the min stat.
+ if (maxHitStat.get() == null) {
+ maxHitStat.set(stat);
+ }
+ else {
+ minHitStat.set(stat);
+ }
+ }
+ };
+ StreamObserver<Monster> monsterStream = asyncStub.getMinMaxHitPoints(statObserver);
+ short count = 10;
+ for (short i = 0;i < count; ++i) {
+ Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
+ monsterStream.onNext(monster);
+ }
+ monsterStream.onCompleted();
+
+ // Wait a little bit for the server to send the stats of the monster with the max and min hit-points.
+ streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
+
+ Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));
+ Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1));
+ Assert.assertEquals(maxHitStat.get().count(), 1);
+
+ Assert.assertEquals(minHitStat.get().id(), BIG_MONSTER_NAME + 0);
+ Assert.assertEquals(minHitStat.get().val(), nestedMonsterHp * 0);
+ Assert.assertEquals(minHitStat.get().count(), 1);
+ }
+}
diff --git a/grpc/tests/go_test.go b/grpc/tests/go_test.go
new file mode 100644
index 0000000..288036b
--- /dev/null
+++ b/grpc/tests/go_test.go
@@ -0,0 +1,93 @@
+package testing
+
+import (
+ "../../tests/MyGame/Example"
+
+ "context"
+ "net"
+ "testing"
+
+ "google.golang.org/grpc"
+)
+
+type server struct{}
+
+// test used to send and receive in grpc methods
+var test = "Flatbuffers"
+var addr = "0.0.0.0:50051"
+
+// gRPC server store method
+func (s *server) Store(context context.Context, in *Example.Monster) (*flatbuffers.Builder, error) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.StatStart(b)
+ Example.StatAddId(b, i)
+ b.Finish(Example.StatEnd(b))
+ return b, nil
+
+}
+
+// gRPC server retrieve method
+func (s *server) Retrieve(context context.Context, in *Example.Stat) (*flatbuffers.Builder, error) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.MonsterStart(b)
+ Example.MonsterAddName(b, i)
+ b.Finish(Example.MonsterEnd(b))
+ return b, nil
+}
+
+func StoreClient(c Example.MonsterStorageClient, t *testing.T) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.MonsterStart(b)
+ Example.MonsterAddName(b, i)
+ b.Finish(Example.MonsterEnd(b))
+ out, err := c.Store(context.Background(), b)
+ if err != nil {
+ t.Fatalf("Store client failed: %v", err)
+ }
+ if string(out.Id()) != test {
+ t.Errorf("StoreClient failed: expected=%s, got=%s\n", test, out.Id())
+ t.Fail()
+ }
+}
+
+func RetrieveClient(c Example.MonsterStorageClient, t *testing.T) {
+ b := flatbuffers.NewBuilder(0)
+ i := b.CreateString(test)
+ Example.StatStart(b)
+ Example.StatAddId(b, i)
+ b.Finish(Example.StatEnd(b))
+ out, err := c.Retrieve(context.Background(), b)
+ if err != nil {
+ t.Fatalf("Retrieve client failed: %v", err)
+ }
+ if string(out.Name()) != test {
+ t.Errorf("RetrieveClient failed: expected=%s, got=%s\n", test, out.Name())
+ t.Fail()
+ }
+}
+
+func TestGRPC(t *testing.T) {
+ lis, err := net.Listen("tcp", addr)
+ if err != nil {
+ t.Fatalf("Failed to listen: %v", err)
+ }
+ ser := grpc.NewServer(grpc.CustomCodec(flatbuffers.FlatbuffersCodec{}))
+ Example.RegisterMonsterStorageServer(ser, &server{})
+ go func() {
+ if err := ser.Serve(lis); err != nil {
+ t.Fatalf("Failed to serve: %v", err)
+ t.FailNow()
+ }
+ }()
+ conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithCodec(flatbuffers.FlatbuffersCodec{}))
+ if err != nil {
+ t.Fatalf("Failed to connect: %v", err)
+ }
+ defer conn.Close()
+ client := Example.NewMonsterStorageClient(conn)
+ StoreClient(client, t)
+ RetrieveClient(client, t)
+}
diff --git a/grpc/tests/grpctest.cpp b/grpc/tests/grpctest.cpp
new file mode 100644
index 0000000..7e5c6e6
--- /dev/null
+++ b/grpc/tests/grpctest.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <grpc++/grpc++.h>
+
+#include "monster_test.grpc.fb.h"
+#include "monster_test_generated.h"
+#include "test_assert.h"
+
+using namespace MyGame::Example;
+using flatbuffers::grpc::MessageBuilder;
+using flatbuffers::FlatBufferBuilder;
+
+void message_builder_tests();
+
+// The callback implementation of our server, that derives from the generated
+// code. It implements all rpcs specified in the FlatBuffers schema.
+class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
+ virtual ::grpc::Status Store(
+ ::grpc::ServerContext *context,
+ const flatbuffers::grpc::Message<Monster> *request,
+ flatbuffers::grpc::Message<Stat> *response) override {
+ // Create a response from the incoming request name.
+ fbb_.Clear();
+ auto stat_offset = CreateStat(
+ fbb_, fbb_.CreateString("Hello, " + request->GetRoot()->name()->str()));
+ fbb_.Finish(stat_offset);
+ // Transfer ownership of the message to gRPC
+ *response = fbb_.ReleaseMessage<Stat>();
+ return grpc::Status::OK;
+ }
+ virtual ::grpc::Status Retrieve(
+ ::grpc::ServerContext *context,
+ const flatbuffers::grpc::Message<Stat> *request,
+ ::grpc::ServerWriter<flatbuffers::grpc::Message<Monster>> *writer)
+ override {
+ for (int i = 0; i < 5; i++) {
+ fbb_.Clear();
+ // Create 5 monsters for resposne.
+ auto monster_offset =
+ CreateMonster(fbb_, 0, 0, 0,
+ fbb_.CreateString(request->GetRoot()->id()->str() +
+ " No." + std::to_string(i)));
+ fbb_.Finish(monster_offset);
+
+ flatbuffers::grpc::Message<Monster> monster =
+ fbb_.ReleaseMessage<Monster>();
+
+ // Send monster to client using streaming.
+ writer->Write(monster);
+ }
+ return grpc::Status::OK;
+ }
+
+ private:
+ flatbuffers::grpc::MessageBuilder fbb_;
+};
+
+// Track the server instance, so we can terminate it later.
+grpc::Server *server_instance = nullptr;
+// Mutex to protec this variable.
+std::mutex wait_for_server;
+std::condition_variable server_instance_cv;
+
+// This function implements the server thread.
+void RunServer() {
+ auto server_address = "0.0.0.0:50051";
+ // Callback interface we implemented above.
+ ServiceImpl service;
+ grpc::ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+
+ // Start the server. Lock to change the variable we're changing.
+ wait_for_server.lock();
+ server_instance = builder.BuildAndStart().release();
+ wait_for_server.unlock();
+ server_instance_cv.notify_one();
+
+ std::cout << "Server listening on " << server_address << std::endl;
+ // This will block the thread and serve requests.
+ server_instance->Wait();
+}
+
+template <class Builder>
+void StoreRPC(MonsterStorage::Stub *stub) {
+ Builder fbb;
+ grpc::ClientContext context;
+ // Build a request with the name set.
+ auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
+ MessageBuilder mb(std::move(fbb));
+ mb.Finish(monster_offset);
+ auto request = mb.ReleaseMessage<Monster>();
+ flatbuffers::grpc::Message<Stat> response;
+
+ // The actual RPC.
+ auto status = stub->Store(&context, request, &response);
+
+ if (status.ok()) {
+ auto resp = response.GetRoot()->id();
+ std::cout << "RPC response: " << resp->str() << std::endl;
+ } else {
+ std::cout << "RPC failed" << std::endl;
+ }
+}
+
+template <class Builder>
+void RetrieveRPC(MonsterStorage::Stub *stub) {
+ Builder fbb;
+ grpc::ClientContext context;
+ fbb.Clear();
+ auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
+ fbb.Finish(stat_offset);
+ auto request = MessageBuilder(std::move(fbb)).ReleaseMessage<Stat>();
+
+ flatbuffers::grpc::Message<Monster> response;
+ auto stream = stub->Retrieve(&context, request);
+ while (stream->Read(&response)) {
+ auto resp = response.GetRoot()->name();
+ std::cout << "RPC Streaming response: " << resp->str() << std::endl;
+ }
+}
+
+int grpc_server_test() {
+ // Launch server.
+ std::thread server_thread(RunServer);
+
+ // wait for server to spin up.
+ std::unique_lock<std::mutex> lock(wait_for_server);
+ while (!server_instance) server_instance_cv.wait(lock);
+
+ // Now connect the client.
+ auto channel = grpc::CreateChannel("localhost:50051",
+ grpc::InsecureChannelCredentials());
+ auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
+
+ StoreRPC<MessageBuilder>(stub.get());
+ StoreRPC<FlatBufferBuilder>(stub.get());
+
+ RetrieveRPC<MessageBuilder>(stub.get());
+ RetrieveRPC<FlatBufferBuilder>(stub.get());
+
+
+#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
+ {
+ // Test that an invalid request errors out correctly
+ grpc::ClientContext context;
+ flatbuffers::grpc::Message<Monster> request; // simulate invalid message
+ flatbuffers::grpc::Message<Stat> response;
+ auto status = stub->Store(&context, request, &response);
+ // The rpc status should be INTERNAL to indicate a verification error. This
+ // matches the protobuf gRPC status code for an unparseable message.
+ assert(!status.ok());
+ assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
+ assert(strcmp(status.error_message().c_str(),
+ "Message verification failed") == 0);
+ }
+#endif
+
+ server_instance->Shutdown();
+
+ server_thread.join();
+
+ delete server_instance;
+
+ return 0;
+}
+
+int main(int /*argc*/, const char * /*argv*/ []) {
+ message_builder_tests();
+ grpc_server_test();
+
+ if (!testing_fails) {
+ TEST_OUTPUT_LINE("ALL TESTS PASSED");
+ return 0;
+ } else {
+ TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
+ return 1;
+ }
+}
+
diff --git a/grpc/tests/java-grpc-test.sh b/grpc/tests/java-grpc-test.sh
new file mode 100755
index 0000000..ec42960
--- /dev/null
+++ b/grpc/tests/java-grpc-test.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+# NOTE: make sure `mvn install` in /gprc is executed before running this test
+mvn test
diff --git a/grpc/tests/message_builder_test.cpp b/grpc/tests/message_builder_test.cpp
new file mode 100644
index 0000000..36f5bc2
--- /dev/null
+++ b/grpc/tests/message_builder_test.cpp
@@ -0,0 +1,340 @@
+#include "flatbuffers/grpc.h"
+#include "monster_test_generated.h"
+#include "test_assert.h"
+#include "test_builder.h"
+
+using MyGame::Example::Vec3;
+using MyGame::Example::CreateStat;
+using MyGame::Example::Any_NONE;
+
+bool verify(flatbuffers::grpc::Message<Monster> &msg, const std::string &expected_name, Color color) {
+ const Monster *monster = msg.GetRoot();
+ return (monster->name()->str() == expected_name) && (monster->color() == color);
+}
+
+bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string &expected_name, Color color) {
+ flatbuffers::grpc::Message<Monster> msg = mbb.ReleaseMessage<Monster>();
+ const Monster *monster = msg.GetRoot();
+ return (monster->name()->str() == expected_name) && (monster->color() == color);
+}
+
+void builder_move_assign_after_releaseraw_test(flatbuffers::grpc::MessageBuilder dst) {
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ size_t size, offset;
+ grpc_slice slice;
+ dst.ReleaseRaw(size, offset, slice);
+ flatbuffers::FlatBufferBuilder src;
+ auto root_offset2 = populate2(src);
+ src.Finish(root_offset2);
+ auto src_size = src.GetSize();
+ // Move into a released builder.
+ dst = std::move(src);
+ TEST_EQ(dst.GetSize(), src_size);
+ TEST_ASSERT(release_n_verify(dst, m2_name, m2_color));
+ TEST_EQ(src.GetSize(), 0);
+ grpc_slice_unref(slice);
+}
+
+template <class SrcBuilder>
+struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
+ static void builder_reusable_after_release_message_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) {
+ return;
+ }
+
+ flatbuffers::grpc::MessageBuilder mb;
+ std::vector<flatbuffers::grpc::Message<Monster>> buffers;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(mb);
+ mb.Finish(root_offset1);
+ buffers.push_back(mb.ReleaseMessage<Monster>());
+ TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+ }
+ }
+
+ static void builder_reusable_after_release_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE)) {
+ return;
+ }
+
+ // FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in SliceAllocator::allocate
+ // in the second iteration.
+
+ flatbuffers::grpc::MessageBuilder mb;
+ std::vector<flatbuffers::DetachedBuffer> buffers;
+ for (int i = 0; i < 2; ++i) {
+ auto root_offset1 = populate1(mb);
+ mb.Finish(root_offset1);
+ buffers.push_back(mb.Release());
+ TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+ }
+ }
+
+ static void builder_reusable_after_releaseraw_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) {
+ return;
+ }
+
+ flatbuffers::grpc::MessageBuilder mb;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(mb);
+ mb.Finish(root_offset1);
+ size_t size, offset;
+ grpc_slice slice;
+ const uint8_t *buf = mb.ReleaseRaw(size, offset, slice);
+ TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
+ grpc_slice_unref(slice);
+ }
+ }
+
+ static void builder_reusable_after_release_and_move_assign_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) {
+ return;
+ }
+
+ // FIXME: Release-move_assign loop fails assert(p == GRPC_SLICE_START_PTR(slice_))
+ // in DetachedBuffer destructor after all the iterations
+
+ flatbuffers::grpc::MessageBuilder dst;
+ std::vector<flatbuffers::DetachedBuffer> buffers;
+
+ for (int i = 0; i < 2; ++i) {
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ buffers.push_back(dst.Release());
+ TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+
+ // bring dst back to life.
+ SrcBuilder src;
+ dst = std::move(src);
+ TEST_EQ_FUNC(dst.GetSize(), 0);
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+ }
+
+ static void builder_reusable_after_release_message_and_move_assign_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN)) {
+ return;
+ }
+
+ flatbuffers::grpc::MessageBuilder dst;
+ std::vector<flatbuffers::grpc::Message<Monster>> buffers;
+
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ buffers.push_back(dst.ReleaseMessage<Monster>());
+ TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+
+ // bring dst back to life.
+ SrcBuilder src;
+ dst = std::move(src);
+ TEST_EQ_FUNC(dst.GetSize(), 0);
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+ }
+
+ static void builder_reusable_after_releaseraw_and_move_assign_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) {
+ return;
+ }
+
+ flatbuffers::grpc::MessageBuilder dst;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ size_t size, offset;
+ grpc_slice slice = grpc_empty_slice();
+ const uint8_t *buf = dst.ReleaseRaw(size, offset, slice);
+ TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
+ grpc_slice_unref(slice);
+
+ SrcBuilder src;
+ dst = std::move(src);
+ TEST_EQ_FUNC(dst.GetSize(), 0);
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+ }
+
+ static void run_tests(TestSelector selector) {
+ builder_reusable_after_release_test(selector);
+ builder_reusable_after_release_message_test(selector);
+ builder_reusable_after_releaseraw_test(selector);
+ builder_reusable_after_release_and_move_assign_test(selector);
+ builder_reusable_after_releaseraw_and_move_assign_test(selector);
+ builder_reusable_after_release_message_and_move_assign_test(selector);
+ }
+};
+
+void slice_allocator_tests() {
+ // move-construct no-delete test
+ {
+ size_t size = 2048;
+ flatbuffers::grpc::SliceAllocator sa1;
+ uint8_t *buf = sa1.allocate(size);
+ TEST_ASSERT_FUNC(buf != 0);
+ buf[0] = 100;
+ buf[size-1] = 200;
+ flatbuffers::grpc::SliceAllocator sa2(std::move(sa1));
+ // buf should not be deleted after move-construct
+ TEST_EQ_FUNC(buf[0], 100);
+ TEST_EQ_FUNC(buf[size-1], 200);
+ // buf is freed here
+ }
+
+ // move-assign test
+ {
+ flatbuffers::grpc::SliceAllocator sa1, sa2;
+ uint8_t *buf = sa1.allocate(2048);
+ sa1 = std::move(sa2);
+ // sa1 deletes previously allocated memory in move-assign.
+ // So buf is no longer usable here.
+ TEST_ASSERT_FUNC(buf != 0);
+ }
+}
+
+/// This function does not populate exactly the first half of the table. But it could.
+void populate_first_half(MyGame::Example::MonsterBuilder &wrapper, flatbuffers::Offset<flatbuffers::String> name_offset) {
+ wrapper.add_name(name_offset);
+ wrapper.add_color(m1_color);
+}
+
+/// This function does not populate exactly the second half of the table. But it could.
+void populate_second_half(MyGame::Example::MonsterBuilder &wrapper) {
+ wrapper.add_hp(77);
+ wrapper.add_mana(88);
+ Vec3 vec3;
+ wrapper.add_pos(&vec3);
+}
+
+/// This function is a hack to update the FlatBufferBuilder reference (fbb_) in the MonsterBuilder object.
+/// This function will break if fbb_ is not the first member in MonsterBuilder. In that case, some offset must be added.
+/// This function is used exclusively for testing correctness of move operations between FlatBufferBuilders.
+/// If MonsterBuilder had a fbb_ pointer, this hack would be unnecessary. That involves a code-generator change though.
+void test_only_hack_update_fbb_reference(MyGame::Example::MonsterBuilder &monsterBuilder,
+ flatbuffers::grpc::MessageBuilder &mb) {
+ *reinterpret_cast<flatbuffers::FlatBufferBuilder **>(&monsterBuilder) = &mb;
+}
+
+/// This test validates correctness of move conversion of FlatBufferBuilder to a MessageBuilder DURING
+/// a table construction. Half of the table is constructed using FlatBufferBuilder and the other half
+/// of the table is constructed using a MessageBuilder.
+void builder_move_ctor_conversion_before_finish_half_n_half_table_test() {
+ for (size_t initial_size = 4 ; initial_size <= 2048; initial_size *= 2) {
+ flatbuffers::FlatBufferBuilder fbb(initial_size);
+ auto name_offset = fbb.CreateString(m1_name);
+ MyGame::Example::MonsterBuilder monsterBuilder(fbb); // starts a table in FlatBufferBuilder
+ populate_first_half(monsterBuilder, name_offset);
+ flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
+ test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack
+ populate_second_half(monsterBuilder);
+ mb.Finish(monsterBuilder.Finish()); // ends the table in MessageBuilder
+ TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+ TEST_EQ_FUNC(fbb.GetSize(), 0);
+ }
+}
+
+/// This test populates a COMPLETE inner table before move conversion and later populates more members in the outer table.
+void builder_move_ctor_conversion_before_finish_test() {
+ for (size_t initial_size = 4 ; initial_size <= 2048; initial_size *= 2) {
+ flatbuffers::FlatBufferBuilder fbb(initial_size);
+ auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
+ flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
+ auto monster_offset = CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name), 0, m1_color, Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
+ mb.Finish(monster_offset);
+ TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+ TEST_EQ_FUNC(fbb.GetSize(), 0);
+ }
+}
+
+/// This test validates correctness of move conversion of FlatBufferBuilder to a MessageBuilder DURING
+/// a table construction. Half of the table is constructed using FlatBufferBuilder and the other half
+/// of the table is constructed using a MessageBuilder.
+void builder_move_assign_conversion_before_finish_half_n_half_table_test() {
+ flatbuffers::FlatBufferBuilder fbb;
+ flatbuffers::grpc::MessageBuilder mb;
+
+ for (int i = 0;i < 5; ++i) {
+ flatbuffers::FlatBufferBuilder fbb;
+ auto name_offset = fbb.CreateString(m1_name);
+ MyGame::Example::MonsterBuilder monsterBuilder(fbb); // starts a table in FlatBufferBuilder
+ populate_first_half(monsterBuilder, name_offset);
+ mb = std::move(fbb);
+ test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack
+ populate_second_half(monsterBuilder);
+ mb.Finish(monsterBuilder.Finish()); // ends the table in MessageBuilder
+ TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+ TEST_EQ_FUNC(fbb.GetSize(), 0);
+ }
+}
+
+/// This test populates a COMPLETE inner table before move conversion and later populates more members in the outer table.
+void builder_move_assign_conversion_before_finish_test() {
+ flatbuffers::FlatBufferBuilder fbb;
+ flatbuffers::grpc::MessageBuilder mb;
+
+ for (int i = 0;i < 5; ++i) {
+ auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0);
+ mb = std::move(fbb);
+ auto monster_offset = CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name), 0, m1_color, Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset);
+ mb.Finish(monster_offset);
+ TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+ TEST_EQ_FUNC(fbb.GetSize(), 0);
+ }
+}
+
+/// This test populates data, finishes the buffer, and does move conversion after.
+void builder_move_ctor_conversion_after_finish_test() {
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.Finish(populate1(fbb));
+ flatbuffers::grpc::MessageBuilder mb(std::move(fbb));
+ TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+ TEST_EQ_FUNC(fbb.GetSize(), 0);
+}
+
+/// This test populates data, finishes the buffer, and does move conversion after.
+void builder_move_assign_conversion_after_finish_test() {
+ flatbuffers::FlatBufferBuilder fbb;
+ flatbuffers::grpc::MessageBuilder mb;
+
+ for (int i = 0;i < 5; ++i) {
+ fbb.Finish(populate1(fbb));
+ mb = std::move(fbb);
+ TEST_ASSERT_FUNC(release_n_verify(mb, m1_name, m1_color));
+ TEST_EQ_FUNC(fbb.GetSize(), 0);
+ }
+}
+
+void message_builder_tests() {
+ using flatbuffers::grpc::MessageBuilder;
+ using flatbuffers::FlatBufferBuilder;
+
+ slice_allocator_tests();
+
+#ifndef __APPLE__
+ builder_move_ctor_conversion_before_finish_half_n_half_table_test();
+ builder_move_assign_conversion_before_finish_half_n_half_table_test();
+#endif // __APPLE__
+ builder_move_ctor_conversion_before_finish_test();
+ builder_move_assign_conversion_before_finish_test();
+
+ builder_move_ctor_conversion_after_finish_test();
+ builder_move_assign_conversion_after_finish_test();
+
+ BuilderTests<MessageBuilder, MessageBuilder>::all_tests();
+ BuilderTests<MessageBuilder, FlatBufferBuilder>::all_tests();
+
+ BuilderReuseTestSelector tests[6] = {
+ //REUSABLE_AFTER_RELEASE, // Assertion failed: (GRPC_SLICE_IS_EMPTY(slice_))
+ //REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN, // Assertion failed: (p == GRPC_SLICE_START_PTR(slice_)
+
+ REUSABLE_AFTER_RELEASE_RAW,
+ REUSABLE_AFTER_RELEASE_MESSAGE,
+ REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN,
+ REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
+ };
+
+ BuilderReuseTests<MessageBuilder, MessageBuilder>::run_tests(TestSelector(tests, tests+6));
+ BuilderReuseTests<MessageBuilder, FlatBufferBuilder>::run_tests(TestSelector(tests, tests+6));
+}
diff --git a/grpc/tests/pom.xml b/grpc/tests/pom.xml
new file mode 100644
index 0000000..addc9fa
--- /dev/null
+++ b/grpc/tests/pom.xml
@@ -0,0 +1,73 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-parent</artifactId>
+ <version>1.11.1</version>
+ </parent>
+ <artifactId>grpc-test</artifactId>
+ <description>Example/Test project demonstrating usage of flatbuffers with GRPC-Java instead of protobufs
+ </description>
+ <properties>
+ <gRPC.version>1.11.1</gRPC.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-java</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-java-grpc</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-stub</artifactId>
+ <version>${gRPC.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.grpc</groupId>
+ <artifactId>grpc-netty</artifactId>
+ <version>${gRPC.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-source</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${project.basedir}</source>
+ <source>${project.basedir}/../../tests</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ <!--<testSourceDirectory>${project.basedir}</testSourceDirectory>-->
+ </build>
+</project>
+
diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h
new file mode 100644
index 0000000..d98da13
--- /dev/null
+++ b/include/flatbuffers/base.h
@@ -0,0 +1,392 @@
+#ifndef FLATBUFFERS_BASE_H_
+#define FLATBUFFERS_BASE_H_
+
+// clang-format off
+
+// If activate should be declared and included first.
+#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
+ defined(_MSC_VER) && defined(_DEBUG)
+ // The _CRTDBG_MAP_ALLOC inside <crtdbg.h> will replace
+ // calloc/free (etc) to its debug version using #define directives.
+ #define _CRTDBG_MAP_ALLOC
+ #include <stdlib.h>
+ #include <crtdbg.h>
+ // Replace operator new by trace-enabled version.
+ #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
+ #define new DEBUG_NEW
+#endif
+
+#if !defined(FLATBUFFERS_ASSERT)
+#include <assert.h>
+#define FLATBUFFERS_ASSERT assert
+#elif defined(FLATBUFFERS_ASSERT_INCLUDE)
+// Include file with forward declaration
+#include FLATBUFFERS_ASSERT_INCLUDE
+#endif
+
+#ifndef ARDUINO
+#include <cstdint>
+#endif
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+
+#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
+ #include <utility.h>
+#else
+ #include <utility>
+#endif
+
+#include <string>
+#include <type_traits>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <iterator>
+#include <memory>
+
+#ifdef _STLPORT_VERSION
+ #define FLATBUFFERS_CPP98_STL
+#endif
+#ifndef FLATBUFFERS_CPP98_STL
+ #include <functional>
+#endif
+
+#include "flatbuffers/stl_emulation.h"
+
+#if defined(__ICCARM__)
+#include <intrinsics.h>
+#endif
+
+// Note the __clang__ check is needed, because clang presents itself
+// as an older GNUC compiler (4.2).
+// Clang 3.3 and later implement all of the ISO C++ 2011 standard.
+// Clang 3.4 and later implement all of the ISO C++ 2014 standard.
+// http://clang.llvm.org/cxx_status.html
+
+// Note the MSVC value '__cplusplus' may be incorrect:
+// The '__cplusplus' predefined macro in the MSVC stuck at the value 199711L,
+// indicating (erroneously!) that the compiler conformed to the C++98 Standard.
+// This value should be correct starting from MSVC2017-15.7-Preview-3.
+// The '__cplusplus' will be valid only if MSVC2017-15.7-P3 and the `/Zc:__cplusplus` switch is set.
+// Workaround (for details see MSDN):
+// Use the _MSC_VER and _MSVC_LANG definition instead of the __cplusplus for compatibility.
+// The _MSVC_LANG macro reports the Standard version regardless of the '/Zc:__cplusplus' switch.
+
+#if defined(__GNUC__) && !defined(__clang__)
+ #define FLATBUFFERS_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#else
+ #define FLATBUFFERS_GCC 0
+#endif
+
+#if defined(__clang__)
+ #define FLATBUFFERS_CLANG (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#else
+ #define FLATBUFFERS_CLANG 0
+#endif
+
+/// @cond FLATBUFFERS_INTERNAL
+#if __cplusplus <= 199711L && \
+ (!defined(_MSC_VER) || _MSC_VER < 1600) && \
+ (!defined(__GNUC__) || \
+ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
+ #error A C++11 compatible compiler with support for the auto typing is \
+ required for FlatBuffers.
+ #error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
+#endif
+
+#if !defined(__clang__) && \
+ defined(__GNUC__) && \
+ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
+ // Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
+ // and constexpr keywords. Note the __clang__ check is needed, because clang
+ // presents itself as an older GNUC compiler.
+ #ifndef nullptr_t
+ const class nullptr_t {
+ public:
+ template<class T> inline operator T*() const { return 0; }
+ private:
+ void operator&() const;
+ } nullptr = {};
+ #endif
+ #ifndef constexpr
+ #define constexpr const
+ #endif
+#endif
+
+// The wire format uses a little endian encoding (since that's efficient for
+// the common platforms).
+#if defined(__s390x__)
+ #define FLATBUFFERS_LITTLEENDIAN 0
+#endif // __s390x__
+#if !defined(FLATBUFFERS_LITTLEENDIAN)
+ #if defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
+ #if (defined(__BIG_ENDIAN__) || \
+ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ #define FLATBUFFERS_LITTLEENDIAN 0
+ #else
+ #define FLATBUFFERS_LITTLEENDIAN 1
+ #endif // __BIG_ENDIAN__
+ #elif defined(_MSC_VER)
+ #if defined(_M_PPC)
+ #define FLATBUFFERS_LITTLEENDIAN 0
+ #else
+ #define FLATBUFFERS_LITTLEENDIAN 1
+ #endif
+ #else
+ #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
+ #endif
+#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
+
+#define FLATBUFFERS_VERSION_MAJOR 1
+#define FLATBUFFERS_VERSION_MINOR 11
+#define FLATBUFFERS_VERSION_REVISION 0
+#define FLATBUFFERS_STRING_EXPAND(X) #X
+#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
+namespace flatbuffers {
+ // Returns version as string "MAJOR.MINOR.REVISION".
+ const char* FLATBUFFERS_VERSION();
+}
+
+#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
+ (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407)) || \
+ defined(__clang__)
+ #define FLATBUFFERS_FINAL_CLASS final
+ #define FLATBUFFERS_OVERRIDE override
+ #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE : flatbuffers::voffset_t
+#else
+ #define FLATBUFFERS_FINAL_CLASS
+ #define FLATBUFFERS_OVERRIDE
+ #define FLATBUFFERS_VTABLE_UNDERLYING_TYPE
+#endif
+
+#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
+ (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
+ (defined(__cpp_constexpr) && __cpp_constexpr >= 200704)
+ #define FLATBUFFERS_CONSTEXPR constexpr
+#else
+ #define FLATBUFFERS_CONSTEXPR const
+#endif
+
+#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
+ (defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
+ #define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR
+#else
+ #define FLATBUFFERS_CONSTEXPR_CPP14
+#endif
+
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406)) || \
+ (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023026)) || \
+ defined(__clang__)
+ #define FLATBUFFERS_NOEXCEPT noexcept
+#else
+ #define FLATBUFFERS_NOEXCEPT
+#endif
+
+// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
+// private, so be sure to put it at the end or reset access mode explicitly.
+#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
+ (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)) || \
+ defined(__clang__)
+ #define FLATBUFFERS_DELETE_FUNC(func) func = delete;
+#else
+ #define FLATBUFFERS_DELETE_FUNC(func) private: func;
+#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
+ #if defined(__has_include)
+ // Check for std::string_view (in c++17)
+ #if __has_include(<string_view>) && (__cplusplus >= 201606 || _HAS_CXX17)
+ #include <string_view>
+ namespace flatbuffers {
+ typedef std::string_view string_view;
+ }
+ #define FLATBUFFERS_HAS_STRING_VIEW 1
+ // Check for std::experimental::string_view (in c++14, compiler-dependent)
+ #elif __has_include(<experimental/string_view>) && (__cplusplus >= 201411)
+ #include <experimental/string_view>
+ namespace flatbuffers {
+ typedef std::experimental::string_view string_view;
+ }
+ #define FLATBUFFERS_HAS_STRING_VIEW 1
+ #endif
+ #endif // __has_include
+#endif // !FLATBUFFERS_HAS_STRING_VIEW
+
+#ifndef FLATBUFFERS_HAS_NEW_STRTOD
+ // Modern (C++11) strtod and strtof functions are available for use.
+ // 1) nan/inf strings as argument of strtod;
+ // 2) hex-float as argument of strtod/strtof.
+ #if (defined(_MSC_VER) && _MSC_VER >= 1900) || \
+ (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)) || \
+ (defined(__clang__))
+ #define FLATBUFFERS_HAS_NEW_STRTOD 1
+ #endif
+#endif // !FLATBUFFERS_HAS_NEW_STRTOD
+
+#ifndef FLATBUFFERS_LOCALE_INDEPENDENT
+ // Enable locale independent functions {strtof_l, strtod_l,strtoll_l, strtoull_l}.
+ // They are part of the POSIX-2008 but not part of the C/C++ standard.
+ // GCC/Clang have definition (_XOPEN_SOURCE>=700) if POSIX-2008.
+ #if ((defined(_MSC_VER) && _MSC_VER >= 1800) || \
+ (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE>=700)))
+ #define FLATBUFFERS_LOCALE_INDEPENDENT 1
+ #else
+ #define FLATBUFFERS_LOCALE_INDEPENDENT 0
+ #endif
+#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
+
+// Suppress Undefined Behavior Sanitizer (recoverable only). Usage:
+// - __supress_ubsan__("undefined")
+// - __supress_ubsan__("signed-integer-overflow")
+#if defined(__clang__)
+ #define __supress_ubsan__(type) __attribute__((no_sanitize(type)))
+#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 409)
+ #define __supress_ubsan__(type) __attribute__((no_sanitize_undefined))
+#else
+ #define __supress_ubsan__(type)
+#endif
+
+// This is constexpr function used for checking compile-time constants.
+// Avoid `#pragma warning(disable: 4127) // C4127: expression is constant`.
+template<typename T> FLATBUFFERS_CONSTEXPR inline bool IsConstTrue(T t) {
+ return !!t;
+}
+
+// Enable C++ attribute [[]] if std:c++17 or higher.
+#if ((__cplusplus >= 201703L) \
+ || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))
+ // All attributes unknown to an implementation are ignored without causing an error.
+ #define FLATBUFFERS_ATTRIBUTE(attr) [[attr]]
+
+ #define FLATBUFFERS_FALLTHROUGH() [[fallthrough]]
+#else
+ #define FLATBUFFERS_ATTRIBUTE(attr)
+
+ #if FLATBUFFERS_CLANG >= 30800
+ #define FLATBUFFERS_FALLTHROUGH() [[clang::fallthrough]]
+ #elif FLATBUFFERS_GCC >= 70300
+ #define FLATBUFFERS_FALLTHROUGH() [[gnu::fallthrough]]
+ #else
+ #define FLATBUFFERS_FALLTHROUGH()
+ #endif
+#endif
+
+/// @endcond
+
+/// @file
+namespace flatbuffers {
+
+/// @cond FLATBUFFERS_INTERNAL
+// Our default offset / size type, 32bit on purpose on 64bit systems.
+// Also, using a consistent offset type maintains compatibility of serialized
+// offset values between 32bit and 64bit systems.
+typedef uint32_t uoffset_t;
+
+// Signed offsets for references that can go in both directions.
+typedef int32_t soffset_t;
+
+// Offset/index used in v-tables, can be changed to uint8_t in
+// format forks to save a bit of space if desired.
+typedef uint16_t voffset_t;
+
+typedef uintmax_t largest_scalar_t;
+
+// In 32bits, this evaluates to 2GB - 1
+#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
+
+// We support aligning the contents of buffers up to this size.
+#define FLATBUFFERS_MAX_ALIGNMENT 16
+
+#if defined(_MSC_VER)
+ #pragma warning(push)
+ #pragma warning(disable: 4127) // C4127: conditional expression is constant
+#endif
+
+template<typename T> T EndianSwap(T t) {
+ #if defined(_MSC_VER)
+ #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
+ #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
+ #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
+ #elif defined(__ICCARM__)
+ #define FLATBUFFERS_BYTESWAP16 __REV16
+ #define FLATBUFFERS_BYTESWAP32 __REV
+ #define FLATBUFFERS_BYTESWAP64(x) \
+ ((__REV(static_cast<uint32_t>(x >> 32U))) | (static_cast<uint64_t>(__REV(static_cast<uint32_t>(x)))) << 32U)
+ #else
+ #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
+ // __builtin_bswap16 was missing prior to GCC 4.8.
+ #define FLATBUFFERS_BYTESWAP16(x) \
+ static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
+ #else
+ #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
+ #endif
+ #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
+ #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
+ #endif
+ if (sizeof(T) == 1) { // Compile-time if-then's.
+ return t;
+ } else if (sizeof(T) == 2) {
+ union { T t; uint16_t i; } u;
+ u.t = t;
+ u.i = FLATBUFFERS_BYTESWAP16(u.i);
+ return u.t;
+ } else if (sizeof(T) == 4) {
+ union { T t; uint32_t i; } u;
+ u.t = t;
+ u.i = FLATBUFFERS_BYTESWAP32(u.i);
+ return u.t;
+ } else if (sizeof(T) == 8) {
+ union { T t; uint64_t i; } u;
+ u.t = t;
+ u.i = FLATBUFFERS_BYTESWAP64(u.i);
+ return u.t;
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+}
+
+#if defined(_MSC_VER)
+ #pragma warning(pop)
+#endif
+
+
+template<typename T> T EndianScalar(T t) {
+ #if FLATBUFFERS_LITTLEENDIAN
+ return t;
+ #else
+ return EndianSwap(t);
+ #endif
+}
+
+template<typename T>
+// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
+__supress_ubsan__("alignment")
+T ReadScalar(const void *p) {
+ return EndianScalar(*reinterpret_cast<const T *>(p));
+}
+
+template<typename T>
+// UBSAN: C++ aliasing type rules, see std::bit_cast<> for details.
+__supress_ubsan__("alignment")
+void WriteScalar(void *p, T t) {
+ *reinterpret_cast<T *>(p) = EndianScalar(t);
+}
+
+template<typename T> struct Offset;
+template<typename T> __supress_ubsan__("alignment") void WriteScalar(void *p, Offset<T> t) {
+ *reinterpret_cast<uoffset_t *>(p) = EndianScalar(t.o);
+}
+
+// Computes how many bytes you'd have to pad to be able to write an
+// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
+// memory).
+inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
+ return ((~buf_size) + 1) & (scalar_size - 1);
+}
+
+} // namespace flatbuffers
+#endif // FLATBUFFERS_BASE_H_
diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h
new file mode 100644
index 0000000..0bcec91
--- /dev/null
+++ b/include/flatbuffers/code_generators.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_CODE_GENERATORS_H_
+#define FLATBUFFERS_CODE_GENERATORS_H_
+
+#include <map>
+#include <sstream>
+#include "flatbuffers/idl.h"
+
+namespace flatbuffers {
+
+// Utility class to assist in generating code through use of text templates.
+//
+// Example code:
+// CodeWriter code("\t");
+// code.SetValue("NAME", "Foo");
+// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
+// code.SetValue("NAME", "Bar");
+// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
+// std::cout << code.ToString() << std::endl;
+//
+// Output:
+// void Foo() { printf("%s", "Foo"); }
+// void Bar() { printf("%s", "Bar"); }
+class CodeWriter {
+ public:
+ CodeWriter(std::string pad = std::string())
+ : pad_(pad), cur_ident_lvl_(0), ignore_ident_(false) {}
+
+ // Clears the current "written" code.
+ void Clear() {
+ stream_.str("");
+ stream_.clear();
+ }
+
+ // Associates a key with a value. All subsequent calls to operator+=, where
+ // the specified key is contained in {{ and }} delimiters will be replaced by
+ // the given value.
+ void SetValue(const std::string &key, const std::string &value) {
+ value_map_[key] = value;
+ }
+
+ std::string GetValue(const std::string &key) const {
+ const auto it = value_map_.find(key);
+ return it == value_map_.end() ? "" : it->second;
+ }
+
+ // Appends the given text to the generated code as well as a newline
+ // character. Any text within {{ and }} delimeters is replaced by values
+ // previously stored in the CodeWriter by calling SetValue above. The newline
+ // will be suppressed if the text ends with the \\ character.
+ void operator+=(std::string text);
+
+ // Returns the current contents of the CodeWriter as a std::string.
+ std::string ToString() const { return stream_.str(); }
+
+ // Increase ident level for writing code
+ void IncrementIdentLevel() { cur_ident_lvl_++; }
+ // Decrease ident level for writing code
+ void DecrementIdentLevel() {
+ if (cur_ident_lvl_) cur_ident_lvl_--;
+ }
+
+ private:
+ std::map<std::string, std::string> value_map_;
+ std::stringstream stream_;
+ std::string pad_;
+ int cur_ident_lvl_;
+ bool ignore_ident_;
+
+ // Add ident padding (tab or space) based on ident level
+ void AppendIdent(std::stringstream &stream);
+};
+
+class BaseGenerator {
+ public:
+ virtual bool generate() = 0;
+
+ static std::string NamespaceDir(const Parser &parser, const std::string &path,
+ const Namespace &ns);
+
+ protected:
+ BaseGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name,
+ std::string qualifying_start,
+ std::string qualifying_separator)
+ : parser_(parser),
+ path_(path),
+ file_name_(file_name),
+ qualifying_start_(qualifying_start),
+ qualifying_separator_(qualifying_separator) {}
+ virtual ~BaseGenerator() {}
+
+ // No copy/assign.
+ BaseGenerator &operator=(const BaseGenerator &);
+ BaseGenerator(const BaseGenerator &);
+
+ std::string NamespaceDir(const Namespace &ns) const;
+
+ static const char *FlatBuffersGeneratedWarning();
+
+ static std::string FullNamespace(const char *separator, const Namespace &ns);
+
+ static std::string LastNamespacePart(const Namespace &ns);
+
+ // tracks the current namespace for early exit in WrapInNameSpace
+ // c++, java and csharp returns a different namespace from
+ // the following default (no early exit, always fully qualify),
+ // which works for js and php
+ virtual const Namespace *CurrentNameSpace() const { return nullptr; }
+
+ // Ensure that a type is prefixed with its namespace even within
+ // its own namespace to avoid conflict between generated method
+ // names and similarly named classes or structs
+ std::string WrapInNameSpace(const Namespace *ns,
+ const std::string &name) const;
+
+ std::string WrapInNameSpace(const Definition &def) const;
+
+ std::string GetNameSpace(const Definition &def) const;
+
+ const Parser &parser_;
+ const std::string &path_;
+ const std::string &file_name_;
+ const std::string qualifying_start_;
+ const std::string qualifying_separator_;
+};
+
+struct CommentConfig {
+ const char *first_line;
+ const char *content_line_prefix;
+ const char *last_line;
+};
+
+extern void GenComment(const std::vector<std::string> &dc,
+ std::string *code_ptr, const CommentConfig *config,
+ const char *prefix = "");
+
+class FloatConstantGenerator {
+ public:
+ virtual ~FloatConstantGenerator() {}
+ std::string GenFloatConstant(const FieldDef &field) const;
+
+ private:
+ virtual std::string Value(double v, const std::string &src) const = 0;
+ virtual std::string Inf(double v) const = 0;
+ virtual std::string NaN(double v) const = 0;
+
+ virtual std::string Value(float v, const std::string &src) const = 0;
+ virtual std::string Inf(float v) const = 0;
+ virtual std::string NaN(float v) const = 0;
+
+ template<typename T>
+ std::string GenFloatConstantImpl(const FieldDef &field) const;
+};
+
+class SimpleFloatConstantGenerator : public FloatConstantGenerator {
+ public:
+ SimpleFloatConstantGenerator(const char *nan_number,
+ const char *pos_inf_number,
+ const char *neg_inf_number);
+
+ private:
+ std::string Value(double v,
+ const std::string &src) const FLATBUFFERS_OVERRIDE;
+ std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
+ std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
+
+ std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
+ std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
+ std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
+
+ const std::string nan_number_;
+ const std::string pos_inf_number_;
+ const std::string neg_inf_number_;
+};
+
+// C++, C#, Java like generator.
+class TypedFloatConstantGenerator : public FloatConstantGenerator {
+ public:
+ TypedFloatConstantGenerator(const char *double_prefix,
+ const char *single_prefix, const char *nan_number,
+ const char *pos_inf_number,
+ const char *neg_inf_number = "");
+
+ private:
+ std::string Value(double v,
+ const std::string &src) const FLATBUFFERS_OVERRIDE;
+ std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
+
+ std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
+
+ std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
+ std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
+ std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
+
+ std::string MakeNaN(const std::string &prefix) const;
+ std::string MakeInf(bool neg, const std::string &prefix) const;
+
+ const std::string double_prefix_;
+ const std::string single_prefix_;
+ const std::string nan_number_;
+ const std::string pos_inf_number_;
+ const std::string neg_inf_number_;
+};
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_CODE_GENERATORS_H_
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
new file mode 100644
index 0000000..1a250cd
--- /dev/null
+++ b/include/flatbuffers/flatbuffers.h
@@ -0,0 +1,2703 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_H_
+#define FLATBUFFERS_H_
+
+#include "flatbuffers/base.h"
+
+#if defined(FLATBUFFERS_NAN_DEFAULTS)
+#include <cmath>
+#endif
+
+namespace flatbuffers {
+// Generic 'operator==' with conditional specialisations.
+// T e - new value of a scalar field.
+// T def - default of scalar (is known at compile-time).
+template<typename T> inline bool IsTheSameAs(T e, T def) { return e == def; }
+
+#if defined(FLATBUFFERS_NAN_DEFAULTS) && \
+ defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+// Like `operator==(e, def)` with weak NaN if T=(float|double).
+template<typename T> inline bool IsFloatTheSameAs(T e, T def) {
+ return (e == def) || ((def != def) && (e != e));
+}
+template<> inline bool IsTheSameAs<float>(float e, float def) {
+ return IsFloatTheSameAs(e, def);
+}
+template<> inline bool IsTheSameAs<double>(double e, double def) {
+ return IsFloatTheSameAs(e, def);
+}
+#endif
+
+// Wrapper for uoffset_t to allow safe template specialization.
+// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
+template<typename T> struct Offset {
+ uoffset_t o;
+ Offset() : o(0) {}
+ Offset(uoffset_t _o) : o(_o) {}
+ Offset<void> Union() const { return Offset<void>(o); }
+ bool IsNull() const { return !o; }
+};
+
+inline void EndianCheck() {
+ int endiantest = 1;
+ // If this fails, see FLATBUFFERS_LITTLEENDIAN above.
+ FLATBUFFERS_ASSERT(*reinterpret_cast<char *>(&endiantest) ==
+ FLATBUFFERS_LITTLEENDIAN);
+ (void)endiantest;
+}
+
+template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() {
+ // clang-format off
+ #ifdef _MSC_VER
+ return __alignof(T);
+ #else
+ #ifndef alignof
+ return __alignof__(T);
+ #else
+ return alignof(T);
+ #endif
+ #endif
+ // clang-format on
+}
+
+// When we read serialized data from memory, in the case of most scalars,
+// we want to just read T, but in the case of Offset, we want to actually
+// perform the indirection and return a pointer.
+// The template specialization below does just that.
+// It is wrapped in a struct since function templates can't overload on the
+// return type like this.
+// The typedef is for the convenience of callers of this function
+// (avoiding the need for a trailing return decltype)
+template<typename T> struct IndirectHelper {
+ typedef T return_type;
+ typedef T mutable_return_type;
+ static const size_t element_stride = sizeof(T);
+ static return_type Read(const uint8_t *p, uoffset_t i) {
+ return EndianScalar((reinterpret_cast<const T *>(p))[i]);
+ }
+};
+template<typename T> struct IndirectHelper<Offset<T>> {
+ typedef const T *return_type;
+ typedef T *mutable_return_type;
+ static const size_t element_stride = sizeof(uoffset_t);
+ static return_type Read(const uint8_t *p, uoffset_t i) {
+ p += i * sizeof(uoffset_t);
+ return reinterpret_cast<return_type>(p + ReadScalar<uoffset_t>(p));
+ }
+};
+template<typename T> struct IndirectHelper<const T *> {
+ typedef const T *return_type;
+ typedef T *mutable_return_type;
+ static const size_t element_stride = sizeof(T);
+ static return_type Read(const uint8_t *p, uoffset_t i) {
+ return reinterpret_cast<const T *>(p + i * sizeof(T));
+ }
+};
+
+// An STL compatible iterator implementation for Vector below, effectively
+// calling Get() for every element.
+template<typename T, typename IT> struct VectorIterator {
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef IT value_type;
+ typedef ptrdiff_t difference_type;
+ typedef IT *pointer;
+ typedef IT &reference;
+
+ VectorIterator(const uint8_t *data, uoffset_t i)
+ : data_(data + IndirectHelper<T>::element_stride * i) {}
+ VectorIterator(const VectorIterator &other) : data_(other.data_) {}
+ VectorIterator() : data_(nullptr) {}
+
+ VectorIterator &operator=(const VectorIterator &other) {
+ data_ = other.data_;
+ return *this;
+ }
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ VectorIterator &operator=(VectorIterator &&other) {
+ data_ = other.data_;
+ return *this;
+ }
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ bool operator==(const VectorIterator &other) const {
+ return data_ == other.data_;
+ }
+
+ bool operator<(const VectorIterator &other) const {
+ return data_ < other.data_;
+ }
+
+ bool operator!=(const VectorIterator &other) const {
+ return data_ != other.data_;
+ }
+
+ difference_type operator-(const VectorIterator &other) const {
+ return (data_ - other.data_) / IndirectHelper<T>::element_stride;
+ }
+
+ IT operator*() const { return IndirectHelper<T>::Read(data_, 0); }
+
+ IT operator->() const { return IndirectHelper<T>::Read(data_, 0); }
+
+ VectorIterator &operator++() {
+ data_ += IndirectHelper<T>::element_stride;
+ return *this;
+ }
+
+ VectorIterator operator++(int) {
+ VectorIterator temp(data_, 0);
+ data_ += IndirectHelper<T>::element_stride;
+ return temp;
+ }
+
+ VectorIterator operator+(const uoffset_t &offset) const {
+ return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride,
+ 0);
+ }
+
+ VectorIterator &operator+=(const uoffset_t &offset) {
+ data_ += offset * IndirectHelper<T>::element_stride;
+ return *this;
+ }
+
+ VectorIterator &operator--() {
+ data_ -= IndirectHelper<T>::element_stride;
+ return *this;
+ }
+
+ VectorIterator operator--(int) {
+ VectorIterator temp(data_, 0);
+ data_ -= IndirectHelper<T>::element_stride;
+ return temp;
+ }
+
+ VectorIterator operator-(const uoffset_t &offset) const {
+ return VectorIterator(data_ - offset * IndirectHelper<T>::element_stride,
+ 0);
+ }
+
+ VectorIterator &operator-=(const uoffset_t &offset) {
+ data_ -= offset * IndirectHelper<T>::element_stride;
+ return *this;
+ }
+
+ private:
+ const uint8_t *data_;
+};
+
+template<typename Iterator> struct VectorReverseIterator :
+ public std::reverse_iterator<Iterator> {
+
+ explicit VectorReverseIterator(Iterator iter) :
+ std::reverse_iterator<Iterator>(iter) {}
+
+ typename Iterator::value_type operator*() const {
+ return *(std::reverse_iterator<Iterator>::current);
+ }
+
+ typename Iterator::value_type operator->() const {
+ return *(std::reverse_iterator<Iterator>::current);
+ }
+};
+
+struct String;
+
+// This is used as a helper type for accessing vectors.
+// Vector::data() assumes the vector elements start after the length field.
+template<typename T> class Vector {
+ public:
+ typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type>
+ iterator;
+ typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
+ const_iterator;
+ typedef VectorReverseIterator<iterator> reverse_iterator;
+ typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
+
+ uoffset_t size() const { return EndianScalar(length_); }
+
+ // Deprecated: use size(). Here for backwards compatibility.
+ FLATBUFFERS_ATTRIBUTE(deprecated("use size() instead"))
+ uoffset_t Length() const { return size(); }
+
+ typedef typename IndirectHelper<T>::return_type return_type;
+ typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type;
+
+ return_type Get(uoffset_t i) const {
+ FLATBUFFERS_ASSERT(i < size());
+ return IndirectHelper<T>::Read(Data(), i);
+ }
+
+ return_type operator[](uoffset_t i) const { return Get(i); }
+
+ // If this is a Vector of enums, T will be its storage type, not the enum
+ // type. This function makes it convenient to retrieve value with enum
+ // type E.
+ template<typename E> E GetEnum(uoffset_t i) const {
+ return static_cast<E>(Get(i));
+ }
+
+ // If this a vector of unions, this does the cast for you. There's no check
+ // to make sure this is the right type!
+ template<typename U> const U *GetAs(uoffset_t i) const {
+ return reinterpret_cast<const U *>(Get(i));
+ }
+
+ // If this a vector of unions, this does the cast for you. There's no check
+ // to make sure this is actually a string!
+ const String *GetAsString(uoffset_t i) const {
+ return reinterpret_cast<const String *>(Get(i));
+ }
+
+ const void *GetStructFromOffset(size_t o) const {
+ return reinterpret_cast<const void *>(Data() + o);
+ }
+
+ iterator begin() { return iterator(Data(), 0); }
+ const_iterator begin() const { return const_iterator(Data(), 0); }
+
+ iterator end() { return iterator(Data(), size()); }
+ const_iterator end() const { return const_iterator(Data(), size()); }
+
+ reverse_iterator rbegin() { return reverse_iterator(end() - 1); }
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(end() - 1); }
+
+ reverse_iterator rend() { return reverse_iterator(begin() - 1); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin() - 1); }
+
+ const_iterator cbegin() const { return begin(); }
+
+ const_iterator cend() const { return end(); }
+
+ const_reverse_iterator crbegin() const { return rbegin(); }
+
+ const_reverse_iterator crend() const { return rend(); }
+
+ // Change elements if you have a non-const pointer to this object.
+ // Scalars only. See reflection.h, and the documentation.
+ void Mutate(uoffset_t i, const T &val) {
+ FLATBUFFERS_ASSERT(i < size());
+ WriteScalar(data() + i, val);
+ }
+
+ // Change an element of a vector of tables (or strings).
+ // "val" points to the new table/string, as you can obtain from
+ // e.g. reflection::AddFlatBuffer().
+ void MutateOffset(uoffset_t i, const uint8_t *val) {
+ FLATBUFFERS_ASSERT(i < size());
+ static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types");
+ WriteScalar(data() + i,
+ static_cast<uoffset_t>(val - (Data() + i * sizeof(uoffset_t))));
+ }
+
+ // Get a mutable pointer to tables/strings inside this vector.
+ mutable_return_type GetMutableObject(uoffset_t i) const {
+ FLATBUFFERS_ASSERT(i < size());
+ return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
+ }
+
+ // The raw data in little endian format. Use with care.
+ const uint8_t *Data() const {
+ return reinterpret_cast<const uint8_t *>(&length_ + 1);
+ }
+
+ uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); }
+
+ // Similarly, but typed, much like std::vector::data
+ const T *data() const { return reinterpret_cast<const T *>(Data()); }
+ T *data() { return reinterpret_cast<T *>(Data()); }
+
+ template<typename K> return_type LookupByKey(K key) const {
+ void *search_result = std::bsearch(
+ &key, Data(), size(), IndirectHelper<T>::element_stride, KeyCompare<K>);
+
+ if (!search_result) {
+ return nullptr; // Key not found.
+ }
+
+ const uint8_t *element = reinterpret_cast<const uint8_t *>(search_result);
+
+ return IndirectHelper<T>::Read(element, 0);
+ }
+
+ protected:
+ // This class is only used to access pre-existing data. Don't ever
+ // try to construct these manually.
+ Vector();
+
+ uoffset_t length_;
+
+ private:
+ // This class is a pointer. Copying will therefore create an invalid object.
+ // Private and unimplemented copy constructor.
+ Vector(const Vector &);
+
+ template<typename K> static int KeyCompare(const void *ap, const void *bp) {
+ const K *key = reinterpret_cast<const K *>(ap);
+ const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
+ auto table = IndirectHelper<T>::Read(data, 0);
+
+ // std::bsearch compares with the operands transposed, so we negate the
+ // result here.
+ return -table->KeyCompareWithValue(*key);
+ }
+};
+
+// Represent a vector much like the template above, but in this case we
+// don't know what the element types are (used with reflection.h).
+class VectorOfAny {
+ public:
+ uoffset_t size() const { return EndianScalar(length_); }
+
+ const uint8_t *Data() const {
+ return reinterpret_cast<const uint8_t *>(&length_ + 1);
+ }
+ uint8_t *Data() { return reinterpret_cast<uint8_t *>(&length_ + 1); }
+
+ protected:
+ VectorOfAny();
+
+ uoffset_t length_;
+
+ private:
+ VectorOfAny(const VectorOfAny &);
+};
+
+#ifndef FLATBUFFERS_CPP98_STL
+template<typename T, typename U>
+Vector<Offset<T>> *VectorCast(Vector<Offset<U>> *ptr) {
+ static_assert(std::is_base_of<T, U>::value, "Unrelated types");
+ return reinterpret_cast<Vector<Offset<T>> *>(ptr);
+}
+
+template<typename T, typename U>
+const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
+ static_assert(std::is_base_of<T, U>::value, "Unrelated types");
+ return reinterpret_cast<const Vector<Offset<T>> *>(ptr);
+}
+#endif
+
+// Convenient helper function to get the length of any vector, regardless
+// of whether it is null or not (the field is not set).
+template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
+ return v ? v->size() : 0;
+}
+
+// This is used as a helper type for accessing arrays.
+template<typename T, uint16_t length> class Array {
+ public:
+ typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
+ const_iterator;
+ typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
+
+ typedef typename IndirectHelper<T>::return_type return_type;
+
+ FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
+
+ return_type Get(uoffset_t i) const {
+ FLATBUFFERS_ASSERT(i < size());
+ return IndirectHelper<T>::Read(Data(), i);
+ }
+
+ return_type operator[](uoffset_t i) const { return Get(i); }
+
+ const_iterator begin() const { return const_iterator(Data(), 0); }
+ const_iterator end() const { return const_iterator(Data(), size()); }
+
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
+
+ const_iterator cbegin() const { return begin(); }
+ const_iterator cend() const { return end(); }
+
+ const_reverse_iterator crbegin() const { return rbegin(); }
+ const_reverse_iterator crend() const { return rend(); }
+
+ // Change elements if you have a non-const pointer to this object.
+ void Mutate(uoffset_t i, const T &val) {
+ FLATBUFFERS_ASSERT(i < size());
+ WriteScalar(data() + i, val);
+ }
+
+ // Get a mutable pointer to elements inside this array.
+ // @note This method should be only used to mutate arrays of structs followed
+ // by a @p Mutate operation. For primitive types use @p Mutate directly.
+ // @warning Assignments and reads to/from the dereferenced pointer are not
+ // automatically converted to the correct endianness.
+ T *GetMutablePointer(uoffset_t i) const {
+ FLATBUFFERS_ASSERT(i < size());
+ return const_cast<T *>(&data()[i]);
+ }
+
+ // The raw data in little endian format. Use with care.
+ const uint8_t *Data() const { return data_; }
+
+ uint8_t *Data() { return data_; }
+
+ // Similarly, but typed, much like std::vector::data
+ const T *data() const { return reinterpret_cast<const T *>(Data()); }
+ T *data() { return reinterpret_cast<T *>(Data()); }
+
+ protected:
+ // This class is only used to access pre-existing data. Don't ever
+ // try to construct these manually.
+ // 'constexpr' allows us to use 'size()' at compile time.
+ // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
+ // a constructor.
+#if defined(__cpp_constexpr)
+ constexpr Array();
+#else
+ Array();
+#endif
+
+ uint8_t data_[length * sizeof(T)];
+
+ private:
+ // This class is a pointer. Copying will therefore create an invalid object.
+ // Private and unimplemented copy constructor.
+ Array(const Array &);
+};
+
+// Lexicographically compare two strings (possibly containing nulls), and
+// return true if the first is less than the second.
+static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
+ const char *b_data, uoffset_t b_size) {
+ const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size));
+ return cmp == 0 ? a_size < b_size : cmp < 0;
+}
+
+struct String : public Vector<char> {
+ const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
+ std::string str() const { return std::string(c_str(), size()); }
+
+ // clang-format off
+ #ifdef FLATBUFFERS_HAS_STRING_VIEW
+ flatbuffers::string_view string_view() const {
+ return flatbuffers::string_view(c_str(), size());
+ }
+ #endif // FLATBUFFERS_HAS_STRING_VIEW
+ // clang-format on
+
+ bool operator<(const String &o) const {
+ return StringLessThan(this->data(), this->size(), o.data(), o.size());
+ }
+};
+
+// Convenience function to get std::string from a String returning an empty
+// string on null pointer.
+static inline std::string GetString(const String * str) {
+ return str ? str->str() : "";
+}
+
+// Convenience function to get char* from a String returning an empty string on
+// null pointer.
+static inline const char * GetCstring(const String * str) {
+ return str ? str->c_str() : "";
+}
+
+// Allocator interface. This is flatbuffers-specific and meant only for
+// `vector_downward` usage.
+class Allocator {
+ public:
+ virtual ~Allocator() {}
+
+ // Allocate `size` bytes of memory.
+ virtual uint8_t *allocate(size_t size) = 0;
+
+ // Deallocate `size` bytes of memory at `p` allocated by this allocator.
+ virtual void deallocate(uint8_t *p, size_t size) = 0;
+
+ // Reallocate `new_size` bytes of memory, replacing the old region of size
+ // `old_size` at `p`. In contrast to a normal realloc, this grows downwards,
+ // and is intended specifcally for `vector_downward` use.
+ // `in_use_back` and `in_use_front` indicate how much of `old_size` is
+ // actually in use at each end, and needs to be copied.
+ virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
+ size_t new_size, size_t in_use_back,
+ size_t in_use_front) {
+ FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows
+ uint8_t *new_p = allocate(new_size);
+ memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
+ in_use_front);
+ deallocate(old_p, old_size);
+ return new_p;
+ }
+
+ protected:
+ // Called by `reallocate_downward` to copy memory from `old_p` of `old_size`
+ // to `new_p` of `new_size`. Only memory of size `in_use_front` and
+ // `in_use_back` will be copied from the front and back of the old memory
+ // allocation.
+ void memcpy_downward(uint8_t *old_p, size_t old_size,
+ uint8_t *new_p, size_t new_size,
+ size_t in_use_back, size_t in_use_front) {
+ memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back,
+ in_use_back);
+ memcpy(new_p, old_p, in_use_front);
+ }
+};
+
+// DefaultAllocator uses new/delete to allocate memory regions
+class DefaultAllocator : public Allocator {
+ public:
+ uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
+ return new uint8_t[size];
+ }
+
+ void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
+ delete[] p;
+ }
+
+ static void dealloc(void *p, size_t) {
+ delete[] static_cast<uint8_t *>(p);
+ }
+};
+
+// These functions allow for a null allocator to mean use the default allocator,
+// as used by DetachedBuffer and vector_downward below.
+// This is to avoid having a statically or dynamically allocated default
+// allocator, or having to move it between the classes that may own it.
+inline uint8_t *Allocate(Allocator *allocator, size_t size) {
+ return allocator ? allocator->allocate(size)
+ : DefaultAllocator().allocate(size);
+}
+
+inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) {
+ if (allocator) allocator->deallocate(p, size);
+ else DefaultAllocator().deallocate(p, size);
+}
+
+inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p,
+ size_t old_size, size_t new_size,
+ size_t in_use_back, size_t in_use_front) {
+ return allocator
+ ? allocator->reallocate_downward(old_p, old_size, new_size,
+ in_use_back, in_use_front)
+ : DefaultAllocator().reallocate_downward(old_p, old_size, new_size,
+ in_use_back, in_use_front);
+}
+
+// DetachedBuffer is a finished flatbuffer memory region, detached from its
+// builder. The original memory region and allocator are also stored so that
+// the DetachedBuffer can manage the memory lifetime.
+class DetachedBuffer {
+ public:
+ DetachedBuffer()
+ : allocator_(nullptr),
+ own_allocator_(false),
+ buf_(nullptr),
+ reserved_(0),
+ cur_(nullptr),
+ size_(0) {}
+
+ DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf,
+ size_t reserved, uint8_t *cur, size_t sz)
+ : allocator_(allocator),
+ own_allocator_(own_allocator),
+ buf_(buf),
+ reserved_(reserved),
+ cur_(cur),
+ size_(sz) {}
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ DetachedBuffer(DetachedBuffer &&other)
+ : allocator_(other.allocator_),
+ own_allocator_(other.own_allocator_),
+ buf_(other.buf_),
+ reserved_(other.reserved_),
+ cur_(other.cur_),
+ size_(other.size_) {
+ other.reset();
+ }
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ DetachedBuffer &operator=(DetachedBuffer &&other) {
+ destroy();
+
+ allocator_ = other.allocator_;
+ own_allocator_ = other.own_allocator_;
+ buf_ = other.buf_;
+ reserved_ = other.reserved_;
+ cur_ = other.cur_;
+ size_ = other.size_;
+
+ other.reset();
+
+ return *this;
+ }
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ ~DetachedBuffer() { destroy(); }
+
+ const uint8_t *data() const { return cur_; }
+
+ uint8_t *data() { return cur_; }
+
+ size_t size() const { return size_; }
+
+ // clang-format off
+ #if 0 // disabled for now due to the ordering of classes in this header
+ template <class T>
+ bool Verify() const {
+ Verifier verifier(data(), size());
+ return verifier.Verify<T>(nullptr);
+ }
+
+ template <class T>
+ const T* GetRoot() const {
+ return flatbuffers::GetRoot<T>(data());
+ }
+
+ template <class T>
+ T* GetRoot() {
+ return flatbuffers::GetRoot<T>(data());
+ }
+ #endif
+ // clang-format on
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ // These may change access mode, leave these at end of public section
+ FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other))
+ FLATBUFFERS_DELETE_FUNC(
+ DetachedBuffer &operator=(const DetachedBuffer &other))
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+protected:
+ Allocator *allocator_;
+ bool own_allocator_;
+ uint8_t *buf_;
+ size_t reserved_;
+ uint8_t *cur_;
+ size_t size_;
+
+ inline void destroy() {
+ if (buf_) Deallocate(allocator_, buf_, reserved_);
+ if (own_allocator_ && allocator_) { delete allocator_; }
+ reset();
+ }
+
+ inline void reset() {
+ allocator_ = nullptr;
+ own_allocator_ = false;
+ buf_ = nullptr;
+ reserved_ = 0;
+ cur_ = nullptr;
+ size_ = 0;
+ }
+};
+
+// This is a minimal replication of std::vector<uint8_t> functionality,
+// except growing from higher to lower addresses. i.e push_back() inserts data
+// in the lowest address in the vector.
+// Since this vector leaves the lower part unused, we support a "scratch-pad"
+// that can be stored there for temporary data, to share the allocated space.
+// Essentially, this supports 2 std::vectors in a single buffer.
+class vector_downward {
+ public:
+ explicit vector_downward(size_t initial_size,
+ Allocator *allocator,
+ bool own_allocator,
+ size_t buffer_minalign)
+ : allocator_(allocator),
+ own_allocator_(own_allocator),
+ initial_size_(initial_size),
+ buffer_minalign_(buffer_minalign),
+ reserved_(0),
+ buf_(nullptr),
+ cur_(nullptr),
+ scratch_(nullptr) {}
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ vector_downward(vector_downward &&other)
+ #else
+ vector_downward(vector_downward &other)
+ #endif // defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ : allocator_(other.allocator_),
+ own_allocator_(other.own_allocator_),
+ initial_size_(other.initial_size_),
+ buffer_minalign_(other.buffer_minalign_),
+ reserved_(other.reserved_),
+ buf_(other.buf_),
+ cur_(other.cur_),
+ scratch_(other.scratch_) {
+ // No change in other.allocator_
+ // No change in other.initial_size_
+ // No change in other.buffer_minalign_
+ other.own_allocator_ = false;
+ other.reserved_ = 0;
+ other.buf_ = nullptr;
+ other.cur_ = nullptr;
+ other.scratch_ = nullptr;
+ }
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ vector_downward &operator=(vector_downward &&other) {
+ // Move construct a temporary and swap idiom
+ vector_downward temp(std::move(other));
+ swap(temp);
+ return *this;
+ }
+ // clang-format off
+ #endif // defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ ~vector_downward() {
+ clear_buffer();
+ clear_allocator();
+ }
+
+ void reset() {
+ clear_buffer();
+ clear();
+ }
+
+ void clear() {
+ if (buf_) {
+ cur_ = buf_ + reserved_;
+ } else {
+ reserved_ = 0;
+ cur_ = nullptr;
+ }
+ clear_scratch();
+ }
+
+ void clear_scratch() {
+ scratch_ = buf_;
+ }
+
+ void clear_allocator() {
+ if (own_allocator_ && allocator_) { delete allocator_; }
+ allocator_ = nullptr;
+ own_allocator_ = false;
+ }
+
+ void clear_buffer() {
+ if (buf_) Deallocate(allocator_, buf_, reserved_);
+ buf_ = nullptr;
+ }
+
+ // Relinquish the pointer to the caller.
+ uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
+ auto *buf = buf_;
+ allocated_bytes = reserved_;
+ offset = static_cast<size_t>(cur_ - buf_);
+
+ // release_raw only relinquishes the buffer ownership.
+ // Does not deallocate or reset the allocator. Destructor will do that.
+ buf_ = nullptr;
+ clear();
+ return buf;
+ }
+
+ // Relinquish the pointer to the caller.
+ DetachedBuffer release() {
+ // allocator ownership (if any) is transferred to DetachedBuffer.
+ DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
+ size());
+ if (own_allocator_) {
+ allocator_ = nullptr;
+ own_allocator_ = false;
+ }
+ buf_ = nullptr;
+ clear();
+ return fb;
+ }
+
+ size_t ensure_space(size_t len) {
+ FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
+ if (len > static_cast<size_t>(cur_ - scratch_)) { reallocate(len); }
+ // Beyond this, signed offsets may not have enough range:
+ // (FlatBuffers > 2GB not supported).
+ FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
+ return len;
+ }
+
+ inline uint8_t *make_space(size_t len) {
+ size_t space = ensure_space(len);
+ cur_ -= space;
+ return cur_;
+ }
+
+ // Returns nullptr if using the DefaultAllocator.
+ Allocator *get_custom_allocator() { return allocator_; }
+
+ uoffset_t size() const {
+ return static_cast<uoffset_t>(reserved_ - (cur_ - buf_));
+ }
+
+ uoffset_t scratch_size() const {
+ return static_cast<uoffset_t>(scratch_ - buf_);
+ }
+
+ size_t capacity() const { return reserved_; }
+
+ uint8_t *data() const {
+ FLATBUFFERS_ASSERT(cur_);
+ return cur_;
+ }
+
+ uint8_t *scratch_data() const {
+ FLATBUFFERS_ASSERT(buf_);
+ return buf_;
+ }
+
+ uint8_t *scratch_end() const {
+ FLATBUFFERS_ASSERT(scratch_);
+ return scratch_;
+ }
+
+ uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
+
+ void push(const uint8_t *bytes, size_t num) {
+ if (num > 0) { memcpy(make_space(num), bytes, num); }
+ }
+
+ // Specialized version of push() that avoids memcpy call for small data.
+ template<typename T> void push_small(const T &little_endian_t) {
+ make_space(sizeof(T));
+ *reinterpret_cast<T *>(cur_) = little_endian_t;
+ }
+
+ template<typename T> void scratch_push_small(const T &t) {
+ ensure_space(sizeof(T));
+ *reinterpret_cast<T *>(scratch_) = t;
+ scratch_ += sizeof(T);
+ }
+
+ // fill() is most frequently called with small byte counts (<= 4),
+ // which is why we're using loops rather than calling memset.
+ void fill(size_t zero_pad_bytes) {
+ make_space(zero_pad_bytes);
+ for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
+ }
+
+ // Version for when we know the size is larger.
+ // Precondition: zero_pad_bytes > 0
+ void fill_big(size_t zero_pad_bytes) {
+ memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
+ }
+
+ void pop(size_t bytes_to_remove) { cur_ += bytes_to_remove; }
+ void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
+
+ void swap(vector_downward &other) {
+ using std::swap;
+ swap(allocator_, other.allocator_);
+ swap(own_allocator_, other.own_allocator_);
+ swap(initial_size_, other.initial_size_);
+ swap(buffer_minalign_, other.buffer_minalign_);
+ swap(reserved_, other.reserved_);
+ swap(buf_, other.buf_);
+ swap(cur_, other.cur_);
+ swap(scratch_, other.scratch_);
+ }
+
+ void swap_allocator(vector_downward &other) {
+ using std::swap;
+ swap(allocator_, other.allocator_);
+ swap(own_allocator_, other.own_allocator_);
+ }
+
+ private:
+ // You shouldn't really be copying instances of this class.
+ FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &))
+ FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &))
+
+ Allocator *allocator_;
+ bool own_allocator_;
+ size_t initial_size_;
+ size_t buffer_minalign_;
+ size_t reserved_;
+ uint8_t *buf_;
+ uint8_t *cur_; // Points at location between empty (below) and used (above).
+ uint8_t *scratch_; // Points to the end of the scratchpad in use.
+
+ void reallocate(size_t len) {
+ auto old_reserved = reserved_;
+ auto old_size = size();
+ auto old_scratch_size = scratch_size();
+ reserved_ += (std::max)(len,
+ old_reserved ? old_reserved / 2 : initial_size_);
+ reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
+ if (buf_) {
+ buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
+ old_size, old_scratch_size);
+ } else {
+ buf_ = Allocate(allocator_, reserved_);
+ }
+ cur_ = buf_ + reserved_ - old_size;
+ scratch_ = buf_ + old_scratch_size;
+ }
+};
+
+// Converts a Field ID to a virtual table offset.
+inline voffset_t FieldIndexToOffset(voffset_t field_id) {
+ // Should correspond to what EndTable() below builds up.
+ const int fixed_fields = 2; // Vtable size and Object Size.
+ return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
+}
+
+template<typename T, typename Alloc>
+const T *data(const std::vector<T, Alloc> &v) {
+ // Eventually the returned pointer gets passed down to memcpy, so
+ // we need it to be non-null to avoid undefined behavior.
+ static uint8_t t;
+ return v.empty() ? reinterpret_cast<const T*>(&t) : &v.front();
+}
+template<typename T, typename Alloc> T *data(std::vector<T, Alloc> &v) {
+ // Eventually the returned pointer gets passed down to memcpy, so
+ // we need it to be non-null to avoid undefined behavior.
+ static uint8_t t;
+ return v.empty() ? reinterpret_cast<T*>(&t) : &v.front();
+}
+
+/// @endcond
+
+/// @addtogroup flatbuffers_cpp_api
+/// @{
+/// @class FlatBufferBuilder
+/// @brief Helper class to hold data needed in creation of a FlatBuffer.
+/// To serialize data, you typically call one of the `Create*()` functions in
+/// the generated code, which in turn call a sequence of `StartTable`/
+/// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/
+/// `CreateVector` functions. Do this is depth-first order to build up a tree to
+/// the root. `Finish()` wraps up the buffer ready for transport.
+class FlatBufferBuilder {
+ public:
+ /// @brief Default constructor for FlatBufferBuilder.
+ /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
+ /// to `1024`.
+ /// @param[in] allocator An `Allocator` to use. If null will use
+ /// `DefaultAllocator`.
+ /// @param[in] own_allocator Whether the builder/vector should own the
+ /// allocator. Defaults to / `false`.
+ /// @param[in] buffer_minalign Force the buffer to be aligned to the given
+ /// minimum alignment upon reallocation. Only needed if you intend to store
+ /// types with custom alignment AND you wish to read the buffer in-place
+ /// directly after creation.
+ explicit FlatBufferBuilder(size_t initial_size = 1024,
+ Allocator *allocator = nullptr,
+ bool own_allocator = false,
+ size_t buffer_minalign =
+ AlignOf<largest_scalar_t>())
+ : buf_(initial_size, allocator, own_allocator, buffer_minalign),
+ num_field_loc(0),
+ max_voffset_(0),
+ nested(false),
+ finished(false),
+ minalign_(1),
+ force_defaults_(false),
+ dedup_vtables_(true),
+ string_pool(nullptr) {
+ EndianCheck();
+ }
+
+ // clang-format off
+ /// @brief Move constructor for FlatBufferBuilder.
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ FlatBufferBuilder(FlatBufferBuilder &&other)
+ #else
+ FlatBufferBuilder(FlatBufferBuilder &other)
+ #endif // #if !defined(FLATBUFFERS_CPP98_STL)
+ : buf_(1024, nullptr, false, AlignOf<largest_scalar_t>()),
+ num_field_loc(0),
+ max_voffset_(0),
+ nested(false),
+ finished(false),
+ minalign_(1),
+ force_defaults_(false),
+ dedup_vtables_(true),
+ string_pool(nullptr) {
+ EndianCheck();
+ // Default construct and swap idiom.
+ // Lack of delegating constructors in vs2010 makes it more verbose than needed.
+ Swap(other);
+ }
+ // clang-format on
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ /// @brief Move assignment operator for FlatBufferBuilder.
+ FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
+ // Move construct a temporary and swap idiom
+ FlatBufferBuilder temp(std::move(other));
+ Swap(temp);
+ return *this;
+ }
+ // clang-format off
+ #endif // defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ void Swap(FlatBufferBuilder &other) {
+ using std::swap;
+ buf_.swap(other.buf_);
+ swap(num_field_loc, other.num_field_loc);
+ swap(max_voffset_, other.max_voffset_);
+ swap(nested, other.nested);
+ swap(finished, other.finished);
+ swap(minalign_, other.minalign_);
+ swap(force_defaults_, other.force_defaults_);
+ swap(dedup_vtables_, other.dedup_vtables_);
+ swap(string_pool, other.string_pool);
+ }
+
+ ~FlatBufferBuilder() {
+ if (string_pool) delete string_pool;
+ }
+
+ void Reset() {
+ Clear(); // clear builder state
+ buf_.reset(); // deallocate buffer
+ }
+
+ /// @brief Reset all the state in this FlatBufferBuilder so it can be reused
+ /// to construct another buffer.
+ void Clear() {
+ ClearOffsets();
+ buf_.clear();
+ nested = false;
+ finished = false;
+ minalign_ = 1;
+ if (string_pool) string_pool->clear();
+ }
+
+ /// @brief The current size of the serialized buffer, counting from the end.
+ /// @return Returns an `uoffset_t` with the current size of the buffer.
+ uoffset_t GetSize() const { return buf_.size(); }
+
+ /// @brief Get the serialized buffer (after you call `Finish()`).
+ /// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the
+ /// buffer.
+ uint8_t *GetBufferPointer() const {
+ Finished();
+ return buf_.data();
+ }
+
+ /// @brief Get a pointer to an unfinished buffer.
+ /// @return Returns a `uint8_t` pointer to the unfinished buffer.
+ uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
+
+ /// @brief Get the released pointer to the serialized buffer.
+ /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
+ /// @return A `FlatBuffer` that owns the buffer and its allocator and
+ /// behaves similar to a `unique_ptr` with a deleter.
+ FLATBUFFERS_ATTRIBUTE(deprecated("use Release() instead")) DetachedBuffer
+ ReleaseBufferPointer() {
+ Finished();
+ return buf_.release();
+ }
+
+ /// @brief Get the released DetachedBuffer.
+ /// @return A `DetachedBuffer` that owns the buffer and its allocator.
+ DetachedBuffer Release() {
+ Finished();
+ return buf_.release();
+ }
+
+ /// @brief Get the released pointer to the serialized buffer.
+ /// @param The size of the memory block containing
+ /// the serialized `FlatBuffer`.
+ /// @param The offset from the released pointer where the finished
+ /// `FlatBuffer` starts.
+ /// @return A raw pointer to the start of the memory block containing
+ /// the serialized `FlatBuffer`.
+ /// @remark If the allocator is owned, it gets deleted when the destructor is called..
+ uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
+ Finished();
+ return buf_.release_raw(size, offset);
+ }
+
+ /// @brief get the minimum alignment this buffer needs to be accessed
+ /// properly. This is only known once all elements have been written (after
+ /// you call Finish()). You can use this information if you need to embed
+ /// a FlatBuffer in some other buffer, such that you can later read it
+ /// without first having to copy it into its own buffer.
+ size_t GetBufferMinAlignment() {
+ Finished();
+ return minalign_;
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ void Finished() const {
+ // If you get this assert, you're attempting to get access a buffer
+ // which hasn't been finished yet. Be sure to call
+ // FlatBufferBuilder::Finish with your root table.
+ // If you really need to access an unfinished buffer, call
+ // GetCurrentBufferPointer instead.
+ FLATBUFFERS_ASSERT(finished);
+ }
+ /// @endcond
+
+ /// @brief In order to save space, fields that are set to their default value
+ /// don't get serialized into the buffer.
+ /// @param[in] bool fd When set to `true`, always serializes default values that are set.
+ /// Optional fields which are not set explicitly, will still not be serialized.
+ void ForceDefaults(bool fd) { force_defaults_ = fd; }
+
+ /// @brief By default vtables are deduped in order to save space.
+ /// @param[in] bool dedup When set to `true`, dedup vtables.
+ void DedupVtables(bool dedup) { dedup_vtables_ = dedup; }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ void Pad(size_t num_bytes) { buf_.fill(num_bytes); }
+
+ void TrackMinAlign(size_t elem_size) {
+ if (elem_size > minalign_) minalign_ = elem_size;
+ }
+
+ void Align(size_t elem_size) {
+ TrackMinAlign(elem_size);
+ buf_.fill(PaddingBytes(buf_.size(), elem_size));
+ }
+
+ void PushFlatBuffer(const uint8_t *bytes, size_t size) {
+ PushBytes(bytes, size);
+ finished = true;
+ }
+
+ void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); }
+
+ void PopBytes(size_t amount) { buf_.pop(amount); }
+
+ template<typename T> void AssertScalarT() {
+ // The code assumes power of 2 sizes and endian-swap-ability.
+ static_assert(flatbuffers::is_scalar<T>::value, "T must be a scalar type");
+ }
+
+ // Write a single aligned scalar to the buffer
+ template<typename T> uoffset_t PushElement(T element) {
+ AssertScalarT<T>();
+ T litle_endian_element = EndianScalar(element);
+ Align(sizeof(T));
+ buf_.push_small(litle_endian_element);
+ return GetSize();
+ }
+
+ template<typename T> uoffset_t PushElement(Offset<T> off) {
+ // Special case for offsets: see ReferTo below.
+ return PushElement(ReferTo(off.o));
+ }
+
+ // When writing fields, we track where they are, so we can create correct
+ // vtables later.
+ void TrackField(voffset_t field, uoffset_t off) {
+ FieldLoc fl = { off, field };
+ buf_.scratch_push_small(fl);
+ num_field_loc++;
+ max_voffset_ = (std::max)(max_voffset_, field);
+ }
+
+ // Like PushElement, but additionally tracks the field this represents.
+ template<typename T> void AddElement(voffset_t field, T e, T def) {
+ // We don't serialize values equal to the default.
+ if (IsTheSameAs(e, def) && !force_defaults_) return;
+ 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));
+ }
+
+ template<typename T> void AddStruct(voffset_t field, const T *structptr) {
+ if (!structptr) return; // Default, don't store.
+ Align(AlignOf<T>());
+ buf_.push_small(*structptr);
+ TrackField(field, GetSize());
+ }
+
+ void AddStructOffset(voffset_t field, uoffset_t off) {
+ TrackField(field, off);
+ }
+
+ // Offsets initially are relative to the end of the buffer (downwards).
+ // This function converts them to be relative to the current location
+ // in the buffer (when stored here), pointing upwards.
+ uoffset_t ReferTo(uoffset_t off) {
+ // Align to ensure GetSize() below is correct.
+ Align(sizeof(uoffset_t));
+ // Offset must refer to something already in buffer.
+ FLATBUFFERS_ASSERT(off && off <= GetSize());
+ return GetSize() - off + static_cast<uoffset_t>(sizeof(uoffset_t));
+ }
+
+ void NotNested() {
+ // If you hit this, you're trying to construct a Table/Vector/String
+ // during the construction of its parent table (between the MyTableBuilder
+ // and table.Finish().
+ // Move the creation of these sub-objects to above the MyTableBuilder to
+ // not get this assert.
+ // Ignoring this assert may appear to work in simple cases, but the reason
+ // it is here is that storing objects in-line may cause vtable offsets
+ // to not fit anymore. It also leads to vtable duplication.
+ FLATBUFFERS_ASSERT(!nested);
+ // If you hit this, fields were added outside the scope of a table.
+ FLATBUFFERS_ASSERT(!num_field_loc);
+ }
+
+ // From generated code (or from the parser), we call StartTable/EndTable
+ // with a sequence of AddElement calls in between.
+ uoffset_t StartTable() {
+ NotNested();
+ nested = true;
+ return GetSize();
+ }
+
+ // This finishes one serialized object by generating the vtable if it's a
+ // table, comparing it against existing vtables, and writing the
+ // resulting vtable offset.
+ uoffset_t EndTable(uoffset_t start) {
+ // If you get this assert, a corresponding StartTable wasn't called.
+ FLATBUFFERS_ASSERT(nested);
+ // Write the vtable offset, which is the start of any Table.
+ // We fill it's value later.
+ auto vtableoffsetloc = PushElement<soffset_t>(0);
+ // Write a vtable, which consists entirely of voffset_t elements.
+ // It starts with the number of offsets, followed by a type id, followed
+ // by the offsets themselves. In reverse:
+ // Include space for the last offset and ensure empty tables have a
+ // minimum size.
+ max_voffset_ =
+ (std::max)(static_cast<voffset_t>(max_voffset_ + sizeof(voffset_t)),
+ FieldIndexToOffset(0));
+ buf_.fill_big(max_voffset_);
+ auto table_object_size = vtableoffsetloc - start;
+ // Vtable use 16bit offsets.
+ FLATBUFFERS_ASSERT(table_object_size < 0x10000);
+ WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
+ static_cast<voffset_t>(table_object_size));
+ WriteScalar<voffset_t>(buf_.data(), max_voffset_);
+ // Write the offsets into the table
+ for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc);
+ it < buf_.scratch_end(); it += sizeof(FieldLoc)) {
+ auto field_location = reinterpret_cast<FieldLoc *>(it);
+ auto pos = static_cast<voffset_t>(vtableoffsetloc - field_location->off);
+ // If this asserts, it means you've set a field twice.
+ FLATBUFFERS_ASSERT(
+ !ReadScalar<voffset_t>(buf_.data() + field_location->id));
+ WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
+ }
+ ClearOffsets();
+ auto vt1 = reinterpret_cast<voffset_t *>(buf_.data());
+ auto vt1_size = ReadScalar<voffset_t>(vt1);
+ auto vt_use = GetSize();
+ // See if we already have generated a vtable with this exact same
+ // layout before. If so, make it point to the old one, remove this one.
+ if (dedup_vtables_) {
+ for (auto it = buf_.scratch_data(); it < buf_.scratch_end();
+ it += sizeof(uoffset_t)) {
+ auto vt_offset_ptr = reinterpret_cast<uoffset_t *>(it);
+ auto vt2 = reinterpret_cast<voffset_t *>(buf_.data_at(*vt_offset_ptr));
+ auto vt2_size = *vt2;
+ if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
+ vt_use = *vt_offset_ptr;
+ buf_.pop(GetSize() - vtableoffsetloc);
+ break;
+ }
+ }
+ // If this is a new vtable, remember it.
+ if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); }
+ // Fill the vtable offset we created above.
+ // The offset points from the beginning of the object to where the
+ // vtable is stored.
+ // Offsets default direction is downward in memory for future format
+ // flexibility (storing all vtables at the start of the file).
+ WriteScalar(buf_.data_at(vtableoffsetloc),
+ static_cast<soffset_t>(vt_use) -
+ static_cast<soffset_t>(vtableoffsetloc));
+
+ nested = false;
+ return vtableoffsetloc;
+ }
+
+ FLATBUFFERS_ATTRIBUTE(deprecated("call the version above instead"))
+ uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
+ return EndTable(start);
+ }
+
+ // This checks a required field has been set in a given table that has
+ // just been constructed.
+ template<typename T> void Required(Offset<T> table, voffset_t field);
+
+ uoffset_t StartStruct(size_t alignment) {
+ Align(alignment);
+ return GetSize();
+ }
+
+ uoffset_t EndStruct() { return GetSize(); }
+
+ void ClearOffsets() {
+ buf_.scratch_pop(num_field_loc * sizeof(FieldLoc));
+ num_field_loc = 0;
+ max_voffset_ = 0;
+ }
+
+ // Aligns such that when "len" bytes are written, an object can be written
+ // after it with "alignment" without padding.
+ void PreAlign(size_t len, size_t alignment) {
+ TrackMinAlign(alignment);
+ buf_.fill(PaddingBytes(GetSize() + len, alignment));
+ }
+ template<typename T> void PreAlign(size_t len) {
+ AssertScalarT<T>();
+ PreAlign(len, sizeof(T));
+ }
+ /// @endcond
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// @param[in] str A const char pointer to the data to be stored as a string.
+ /// @param[in] len The number of bytes that should be stored from `str`.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateString(const char *str, size_t len) {
+ NotNested();
+ PreAlign<uoffset_t>(len + 1); // Always 0-terminated.
+ buf_.fill(1);
+ PushBytes(reinterpret_cast<const uint8_t *>(str), len);
+ PushElement(static_cast<uoffset_t>(len));
+ return Offset<String>(GetSize());
+ }
+
+ /// @brief Store a string in the buffer, which is null-terminated.
+ /// @param[in] str A const char pointer to a C-string to add to the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateString(const char *str) {
+ return CreateString(str, strlen(str));
+ }
+
+ /// @brief Store a string in the buffer, which is null-terminated.
+ /// @param[in] str A char pointer to a C-string to add to the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateString(char *str) {
+ return CreateString(str, strlen(str));
+ }
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// @param[in] str A const reference to a std::string to store in the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateString(const std::string &str) {
+ return CreateString(str.c_str(), str.length());
+ }
+
+ // clang-format off
+ #ifdef FLATBUFFERS_HAS_STRING_VIEW
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// @param[in] str A const string_view to copy in to the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateString(flatbuffers::string_view str) {
+ return CreateString(str.data(), str.size());
+ }
+ #endif // FLATBUFFERS_HAS_STRING_VIEW
+ // clang-format on
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// @param[in] str A const pointer to a `String` struct to add to the buffer.
+ /// @return Returns the offset in the buffer where the string starts
+ Offset<String> CreateString(const String *str) {
+ return str ? CreateString(str->c_str(), str->size()) : 0;
+ }
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// @param[in] str A const reference to a std::string like type with support
+ /// of T::c_str() and T::length() to store in the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ template<typename T> Offset<String> CreateString(const T &str) {
+ return CreateString(str.c_str(), str.length());
+ }
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// If a string with this exact contents has already been serialized before,
+ /// instead simply returns the offset of the existing string.
+ /// @param[in] str A const char pointer to the data to be stored as a string.
+ /// @param[in] len The number of bytes that should be stored from `str`.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateSharedString(const char *str, size_t len) {
+ if (!string_pool)
+ string_pool = new StringOffsetMap(StringOffsetCompare(buf_));
+ auto size_before_string = buf_.size();
+ // Must first serialize the string, since the set is all offsets into
+ // buffer.
+ auto off = CreateString(str, len);
+ auto it = string_pool->find(off);
+ // If it exists we reuse existing serialized data!
+ if (it != string_pool->end()) {
+ // We can remove the string we serialized.
+ buf_.pop(buf_.size() - size_before_string);
+ return *it;
+ }
+ // Record this string for future use.
+ string_pool->insert(off);
+ return off;
+ }
+
+ /// @brief Store a string in the buffer, which null-terminated.
+ /// If a string with this exact contents has already been serialized before,
+ /// instead simply returns the offset of the existing string.
+ /// @param[in] str A const char pointer to a C-string to add to the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateSharedString(const char *str) {
+ return CreateSharedString(str, strlen(str));
+ }
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// If a string with this exact contents has already been serialized before,
+ /// instead simply returns the offset of the existing string.
+ /// @param[in] str A const reference to a std::string to store in the buffer.
+ /// @return Returns the offset in the buffer where the string starts.
+ Offset<String> CreateSharedString(const std::string &str) {
+ return CreateSharedString(str.c_str(), str.length());
+ }
+
+ /// @brief Store a string in the buffer, which can contain any binary data.
+ /// If a string with this exact contents has already been serialized before,
+ /// instead simply returns the offset of the existing string.
+ /// @param[in] str A const pointer to a `String` struct to add to the buffer.
+ /// @return Returns the offset in the buffer where the string starts
+ Offset<String> CreateSharedString(const String *str) {
+ return CreateSharedString(str->c_str(), str->size());
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ uoffset_t EndVector(size_t len) {
+ FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
+ nested = false;
+ return PushElement(static_cast<uoffset_t>(len));
+ }
+
+ void StartVector(size_t len, size_t elemsize) {
+ NotNested();
+ nested = true;
+ PreAlign<uoffset_t>(len * elemsize);
+ PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
+ }
+
+ // Call this right before StartVector/CreateVector if you want to force the
+ // alignment to be something different than what the element size would
+ // normally dictate.
+ // This is useful when storing a nested_flatbuffer in a vector of bytes,
+ // or when storing SIMD floats, etc.
+ void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) {
+ PreAlign(len * elemsize, alignment);
+ }
+
+ // Similar to ForceVectorAlignment but for String fields.
+ void ForceStringAlignment(size_t len, size_t alignment) {
+ PreAlign((len + 1) * sizeof(char), alignment);
+ }
+
+ /// @endcond
+
+ /// @brief Serialize an array into a FlatBuffer `vector`.
+ /// @tparam T The data type of the array elements.
+ /// @param[in] v A pointer to the array of type `T` to serialize into the
+ /// buffer as a `vector`.
+ /// @param[in] len The number of elements to serialize.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
+ // If this assert hits, you're specifying a template argument that is
+ // causing the wrong overload to be selected, remove it.
+ AssertScalarT<T>();
+ StartVector(len, sizeof(T));
+ // clang-format off
+ #if FLATBUFFERS_LITTLEENDIAN
+ PushBytes(reinterpret_cast<const uint8_t *>(v), len * sizeof(T));
+ #else
+ if (sizeof(T) == 1) {
+ PushBytes(reinterpret_cast<const uint8_t *>(v), len);
+ } else {
+ for (auto i = len; i > 0; ) {
+ PushElement(v[--i]);
+ }
+ }
+ #endif
+ // clang-format on
+ return Offset<Vector<T>>(EndVector(len));
+ }
+
+ template<typename T>
+ Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
+ StartVector(len, sizeof(Offset<T>));
+ for (auto i = len; i > 0;) { PushElement(v[--i]); }
+ return Offset<Vector<Offset<T>>>(EndVector(len));
+ }
+
+ /// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
+ /// @tparam T The data type of the `std::vector` elements.
+ /// @param v A const reference to the `std::vector` to serialize into the
+ /// buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T> Offset<Vector<T>> CreateVector(const std::vector<T> &v) {
+ return CreateVector(data(v), v.size());
+ }
+
+ // vector<bool> may be implemented using a bit-set, so we can't access it as
+ // an array. Instead, read elements manually.
+ // Background: https://isocpp.org/blog/2012/11/on-vectorbool
+ Offset<Vector<uint8_t>> CreateVector(const std::vector<bool> &v) {
+ StartVector(v.size(), sizeof(uint8_t));
+ for (auto i = v.size(); i > 0;) {
+ PushElement(static_cast<uint8_t>(v[--i]));
+ }
+ return Offset<Vector<uint8_t>>(EndVector(v.size()));
+ }
+
+ // clang-format off
+ #ifndef FLATBUFFERS_CPP98_STL
+ /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
+ /// This is a convenience function that takes care of iteration for you.
+ /// @tparam T The data type of the `std::vector` elements.
+ /// @param f A function that takes the current iteration 0..vector_size-1 and
+ /// returns any type that you can construct a FlatBuffers vector out of.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T> Offset<Vector<T>> CreateVector(size_t vector_size,
+ const std::function<T (size_t i)> &f) {
+ std::vector<T> elems(vector_size);
+ for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
+ return CreateVector(elems);
+ }
+ #endif
+ // clang-format on
+
+ /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
+ /// This is a convenience function that takes care of iteration for you.
+ /// @tparam T The data type of the `std::vector` elements.
+ /// @param f A function that takes the current iteration 0..vector_size-1,
+ /// and the state parameter returning any type that you can construct a
+ /// FlatBuffers vector out of.
+ /// @param state State passed to f.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T, typename F, typename S>
+ Offset<Vector<T>> CreateVector(size_t vector_size, F f, S *state) {
+ std::vector<T> elems(vector_size);
+ for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state);
+ return CreateVector(elems);
+ }
+
+ /// @brief Serialize a `std::vector<std::string>` into a FlatBuffer `vector`.
+ /// This is a convenience function for a common case.
+ /// @param v A const reference to the `std::vector` to serialize into the
+ /// buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ Offset<Vector<Offset<String>>> CreateVectorOfStrings(
+ const std::vector<std::string> &v) {
+ std::vector<Offset<String>> offsets(v.size());
+ for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]);
+ return CreateVector(offsets);
+ }
+
+ /// @brief Serialize an array of structs into a FlatBuffer `vector`.
+ /// @tparam T The data type of the struct array elements.
+ /// @param[in] v A pointer to the array of type `T` to serialize into the
+ /// buffer as a `vector`.
+ /// @param[in] len The number of elements to serialize.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T>
+ Offset<Vector<const T *>> CreateVectorOfStructs(const T *v, size_t len) {
+ StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
+ PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
+ return Offset<Vector<const T *>>(EndVector(len));
+ }
+
+ /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
+ /// @tparam T The data type of the struct array elements.
+ /// @tparam S The data type of the native struct array elements.
+ /// @param[in] v A pointer to the array of type `S` to serialize into the
+ /// buffer as a `vector`.
+ /// @param[in] len The number of elements to serialize.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T, typename S>
+ Offset<Vector<const T *>> CreateVectorOfNativeStructs(const S *v,
+ size_t len) {
+ extern T Pack(const S &);
+ std::vector<T> vv(len);
+ std::transform(v, v + len, vv.begin(), Pack);
+ return CreateVectorOfStructs<T>(vv.data(), vv.size());
+ }
+
+ // clang-format off
+ #ifndef FLATBUFFERS_CPP98_STL
+ /// @brief Serialize an array of structs into a FlatBuffer `vector`.
+ /// @tparam T The data type of the struct array elements.
+ /// @param[in] f A function that takes the current iteration 0..vector_size-1
+ /// and a pointer to the struct that must be filled.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ /// This is mostly useful when flatbuffers are generated with mutation
+ /// accessors.
+ template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
+ size_t vector_size, const std::function<void(size_t i, T *)> &filler) {
+ T* structs = StartVectorOfStructs<T>(vector_size);
+ for (size_t i = 0; i < vector_size; i++) {
+ filler(i, structs);
+ structs++;
+ }
+ return EndVectorOfStructs<T>(vector_size);
+ }
+ #endif
+ // clang-format on
+
+ /// @brief Serialize an array of structs into a FlatBuffer `vector`.
+ /// @tparam T The data type of the struct array elements.
+ /// @param[in] f A function that takes the current iteration 0..vector_size-1,
+ /// a pointer to the struct that must be filled and the state argument.
+ /// @param[in] state Arbitrary state to pass to f.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ /// This is mostly useful when flatbuffers are generated with mutation
+ /// accessors.
+ template<typename T, typename F, typename S>
+ Offset<Vector<const T *>> CreateVectorOfStructs(size_t vector_size, F f,
+ S *state) {
+ T *structs = StartVectorOfStructs<T>(vector_size);
+ for (size_t i = 0; i < vector_size; i++) {
+ f(i, structs, state);
+ structs++;
+ }
+ return EndVectorOfStructs<T>(vector_size);
+ }
+
+ /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`.
+ /// @tparam T The data type of the `std::vector` struct elements.
+ /// @param[in]] v A const reference to the `std::vector` of structs to
+ /// serialize into the buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T, typename Alloc>
+ Offset<Vector<const T *>> CreateVectorOfStructs(
+ const std::vector<T, Alloc> &v) {
+ return CreateVectorOfStructs(data(v), v.size());
+ }
+
+ /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
+ /// `vector`.
+ /// @tparam T The data type of the `std::vector` struct elements.
+ /// @tparam S The data type of the `std::vector` native struct elements.
+ /// @param[in]] v A const reference to the `std::vector` of structs to
+ /// serialize into the buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T, typename S>
+ Offset<Vector<const T *>> CreateVectorOfNativeStructs(
+ const std::vector<S> &v) {
+ return CreateVectorOfNativeStructs<T, S>(data(v), v.size());
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ template<typename T> struct StructKeyComparator {
+ bool operator()(const T &a, const T &b) const {
+ return a.KeyCompareLessThan(&b);
+ }
+
+ private:
+ StructKeyComparator &operator=(const StructKeyComparator &);
+ };
+ /// @endcond
+
+ /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`
+ /// in sorted order.
+ /// @tparam T The data type of the `std::vector` struct elements.
+ /// @param[in]] v A const reference to the `std::vector` of structs to
+ /// serialize into the buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T>
+ Offset<Vector<const T *>> CreateVectorOfSortedStructs(std::vector<T> *v) {
+ return CreateVectorOfSortedStructs(data(*v), v->size());
+ }
+
+ /// @brief Serialize a `std::vector` of native structs into a FlatBuffer
+ /// `vector` in sorted order.
+ /// @tparam T The data type of the `std::vector` struct elements.
+ /// @tparam S The data type of the `std::vector` native struct elements.
+ /// @param[in]] v A const reference to the `std::vector` of structs to
+ /// serialize into the buffer as a `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T, typename S>
+ Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
+ std::vector<S> *v) {
+ return CreateVectorOfSortedNativeStructs<T, S>(data(*v), v->size());
+ }
+
+ /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted
+ /// order.
+ /// @tparam T The data type of the struct array elements.
+ /// @param[in] v A pointer to the array of type `T` to serialize into the
+ /// buffer as a `vector`.
+ /// @param[in] len The number of elements to serialize.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T>
+ Offset<Vector<const T *>> CreateVectorOfSortedStructs(T *v, size_t len) {
+ std::sort(v, v + len, StructKeyComparator<T>());
+ return CreateVectorOfStructs(v, len);
+ }
+
+ /// @brief Serialize an array of native structs into a FlatBuffer `vector` in
+ /// sorted order.
+ /// @tparam T The data type of the struct array elements.
+ /// @tparam S The data type of the native struct array elements.
+ /// @param[in] v A pointer to the array of type `S` to serialize into the
+ /// buffer as a `vector`.
+ /// @param[in] len The number of elements to serialize.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T, typename S>
+ Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(S *v,
+ size_t len) {
+ extern T Pack(const S &);
+ typedef T (*Pack_t)(const S &);
+ std::vector<T> vv(len);
+ std::transform(v, v + len, vv.begin(), static_cast<Pack_t&>(Pack));
+ return CreateVectorOfSortedStructs<T>(vv, len);
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ template<typename T> struct TableKeyComparator {
+ TableKeyComparator(vector_downward &buf) : buf_(buf) {}
+ bool operator()(const Offset<T> &a, const Offset<T> &b) const {
+ auto table_a = reinterpret_cast<T *>(buf_.data_at(a.o));
+ auto table_b = reinterpret_cast<T *>(buf_.data_at(b.o));
+ return table_a->KeyCompareLessThan(table_b);
+ }
+ vector_downward &buf_;
+
+ private:
+ TableKeyComparator &operator=(const TableKeyComparator &);
+ };
+ /// @endcond
+
+ /// @brief Serialize an array of `table` offsets as a `vector` in the buffer
+ /// in sorted order.
+ /// @tparam T The data type that the offset refers to.
+ /// @param[in] v An array of type `Offset<T>` that contains the `table`
+ /// offsets to store in the buffer in sorted order.
+ /// @param[in] len The number of elements to store in the `vector`.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T>
+ Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(Offset<T> *v,
+ size_t len) {
+ std::sort(v, v + len, TableKeyComparator<T>(buf_));
+ return CreateVector(v, len);
+ }
+
+ /// @brief Serialize an array of `table` offsets as a `vector` in the buffer
+ /// in sorted order.
+ /// @tparam T The data type that the offset refers to.
+ /// @param[in] v An array of type `Offset<T>` that contains the `table`
+ /// offsets to store in the buffer in sorted order.
+ /// @return Returns a typed `Offset` into the serialized data indicating
+ /// where the vector is stored.
+ template<typename T>
+ Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
+ std::vector<Offset<T>> *v) {
+ return CreateVectorOfSortedTables(data(*v), v->size());
+ }
+
+ /// @brief Specialized version of `CreateVector` for non-copying use cases.
+ /// Write the data any time later to the returned buffer pointer `buf`.
+ /// @param[in] len The number of elements to store in the `vector`.
+ /// @param[in] elemsize The size of each element in the `vector`.
+ /// @param[out] buf A pointer to a `uint8_t` pointer that can be
+ /// written to at a later time to serialize the data into a `vector`
+ /// in the buffer.
+ uoffset_t CreateUninitializedVector(size_t len, size_t elemsize,
+ uint8_t **buf) {
+ NotNested();
+ StartVector(len, elemsize);
+ buf_.make_space(len * elemsize);
+ auto vec_start = GetSize();
+ auto vec_end = EndVector(len);
+ *buf = buf_.data_at(vec_start);
+ return vec_end;
+ }
+
+ /// @brief Specialized version of `CreateVector` for non-copying use cases.
+ /// Write the data any time later to the returned buffer pointer `buf`.
+ /// @tparam T The data type of the data that will be stored in the buffer
+ /// as a `vector`.
+ /// @param[in] len The number of elements to store in the `vector`.
+ /// @param[out] buf A pointer to a pointer of type `T` that can be
+ /// written to at a later time to serialize the data into a `vector`
+ /// in the buffer.
+ template<typename T>
+ Offset<Vector<T>> CreateUninitializedVector(size_t len, T **buf) {
+ AssertScalarT<T>();
+ return CreateUninitializedVector(len, sizeof(T),
+ reinterpret_cast<uint8_t **>(buf));
+ }
+
+ template<typename T>
+ Offset<Vector<const T*>> CreateUninitializedVectorOfStructs(size_t len, T **buf) {
+ return CreateUninitializedVector(len, sizeof(T),
+ reinterpret_cast<uint8_t **>(buf));
+ }
+
+
+ // @brief Create a vector of scalar type T given as input a vector of scalar
+ // type U, useful with e.g. pre "enum class" enums, or any existing scalar
+ // data of the wrong type.
+ template<typename T, typename U>
+ Offset<Vector<T>> CreateVectorScalarCast(const U *v, size_t len) {
+ AssertScalarT<T>();
+ AssertScalarT<U>();
+ StartVector(len, sizeof(T));
+ for (auto i = len; i > 0;) { PushElement(static_cast<T>(v[--i])); }
+ return Offset<Vector<T>>(EndVector(len));
+ }
+
+ /// @brief Write a struct by itself, typically to be part of a union.
+ template<typename T> Offset<const T *> CreateStruct(const T &structobj) {
+ NotNested();
+ Align(AlignOf<T>());
+ buf_.push_small(structobj);
+ return Offset<const T *>(GetSize());
+ }
+
+ /// @brief The length of a FlatBuffer file header.
+ static const size_t kFileIdentifierLength = 4;
+
+ /// @brief Finish serializing a buffer by writing the root offset.
+ /// @param[in] file_identifier If a `file_identifier` is given, the buffer
+ /// will be prefixed with a standard FlatBuffers file header.
+ template<typename T>
+ void Finish(Offset<T> root, const char *file_identifier = nullptr) {
+ Finish(root.o, file_identifier, false);
+ }
+
+ /// @brief Finish a buffer with a 32 bit size field pre-fixed (size of the
+ /// buffer following the size field). These buffers are NOT compatible
+ /// with standard buffers created by Finish, i.e. you can't call GetRoot
+ /// on them, you have to use GetSizePrefixedRoot instead.
+ /// All >32 bit quantities in this buffer will be aligned when the whole
+ /// size pre-fixed buffer is aligned.
+ /// These kinds of buffers are useful for creating a stream of FlatBuffers.
+ template<typename T>
+ void FinishSizePrefixed(Offset<T> root,
+ const char *file_identifier = nullptr) {
+ Finish(root.o, file_identifier, true);
+ }
+
+ void SwapBufAllocator(FlatBufferBuilder &other) {
+ buf_.swap_allocator(other.buf_);
+ }
+
+protected:
+
+ // You shouldn't really be copying instances of this class.
+ FlatBufferBuilder(const FlatBufferBuilder &);
+ FlatBufferBuilder &operator=(const FlatBufferBuilder &);
+
+ void Finish(uoffset_t root, const char *file_identifier, bool size_prefix) {
+ NotNested();
+ buf_.clear_scratch();
+ // This will cause the whole buffer to be aligned.
+ PreAlign((size_prefix ? sizeof(uoffset_t) : 0) + sizeof(uoffset_t) +
+ (file_identifier ? kFileIdentifierLength : 0),
+ minalign_);
+ if (file_identifier) {
+ FLATBUFFERS_ASSERT(strlen(file_identifier) == kFileIdentifierLength);
+ PushBytes(reinterpret_cast<const uint8_t *>(file_identifier),
+ kFileIdentifierLength);
+ }
+ PushElement(ReferTo(root)); // Location of root.
+ if (size_prefix) { PushElement(GetSize()); }
+ finished = true;
+ }
+
+ struct FieldLoc {
+ uoffset_t off;
+ voffset_t id;
+ };
+
+ vector_downward buf_;
+
+ // Accumulating offsets of table members while it is being built.
+ // We store these in the scratch pad of buf_, after the vtable offsets.
+ uoffset_t num_field_loc;
+ // Track how much of the vtable is in use, so we can output the most compact
+ // possible vtable.
+ voffset_t max_voffset_;
+
+ // Ensure objects are not nested.
+ bool nested;
+
+ // Ensure the buffer is finished before it is being accessed.
+ bool finished;
+
+ size_t minalign_;
+
+ bool force_defaults_; // Serialize values equal to their defaults anyway.
+
+ bool dedup_vtables_;
+
+ struct StringOffsetCompare {
+ StringOffsetCompare(const vector_downward &buf) : buf_(&buf) {}
+ bool operator()(const Offset<String> &a, const Offset<String> &b) const {
+ auto stra = reinterpret_cast<const String *>(buf_->data_at(a.o));
+ auto strb = reinterpret_cast<const String *>(buf_->data_at(b.o));
+ return StringLessThan(stra->data(), stra->size(),
+ strb->data(), strb->size());
+ }
+ const vector_downward *buf_;
+ };
+
+ // For use with CreateSharedString. Instantiated on first use only.
+ typedef std::set<Offset<String>, StringOffsetCompare> StringOffsetMap;
+ StringOffsetMap *string_pool;
+
+ private:
+ // Allocates space for a vector of structures.
+ // Must be completed with EndVectorOfStructs().
+ template<typename T> T *StartVectorOfStructs(size_t vector_size) {
+ StartVector(vector_size * sizeof(T) / AlignOf<T>(), AlignOf<T>());
+ return reinterpret_cast<T *>(buf_.make_space(vector_size * sizeof(T)));
+ }
+
+ // End the vector of structues in the flatbuffers.
+ // Vector should have previously be started with StartVectorOfStructs().
+ template<typename T>
+ Offset<Vector<const T *>> EndVectorOfStructs(size_t vector_size) {
+ return Offset<Vector<const T *>>(EndVector(vector_size));
+ }
+};
+/// @}
+
+/// @cond FLATBUFFERS_INTERNAL
+// Helpers to get a typed pointer to the root object contained in the buffer.
+template<typename T> T *GetMutableRoot(void *buf) {
+ EndianCheck();
+ return reinterpret_cast<T *>(
+ reinterpret_cast<uint8_t *>(buf) +
+ EndianScalar(*reinterpret_cast<uoffset_t *>(buf)));
+}
+
+template<typename T> const T *GetRoot(const void *buf) {
+ return GetMutableRoot<T>(const_cast<void *>(buf));
+}
+
+template<typename T> const T *GetSizePrefixedRoot(const void *buf) {
+ return GetRoot<T>(reinterpret_cast<const uint8_t *>(buf) + sizeof(uoffset_t));
+}
+
+/// Helpers to get a typed pointer to objects that are currently being built.
+/// @warning Creating new objects will lead to reallocations and invalidates
+/// the pointer!
+template<typename T>
+T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
+ return reinterpret_cast<T *>(fbb.GetCurrentBufferPointer() + fbb.GetSize() -
+ offset.o);
+}
+
+template<typename T>
+const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
+ return GetMutableTemporaryPointer<T>(fbb, offset);
+}
+
+/// @brief Get a pointer to the the file_identifier section of the buffer.
+/// @return Returns a const char pointer to the start of the file_identifier
+/// characters in the buffer. The returned char * has length
+/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'.
+/// This function is UNDEFINED for FlatBuffers whose schema does not include
+/// a file_identifier (likely points at padding or the start of a the root
+/// vtable).
+inline const char *GetBufferIdentifier(const void *buf, bool size_prefixed = false) {
+ return reinterpret_cast<const char *>(buf) +
+ ((size_prefixed) ? 2 * sizeof(uoffset_t) : sizeof(uoffset_t));
+}
+
+// Helper to see if the identifier in a buffer has the expected value.
+inline bool BufferHasIdentifier(const void *buf, const char *identifier, bool size_prefixed = false) {
+ return strncmp(GetBufferIdentifier(buf, size_prefixed), identifier,
+ FlatBufferBuilder::kFileIdentifierLength) == 0;
+}
+
+// Helper class to verify the integrity of a FlatBuffer
+class Verifier FLATBUFFERS_FINAL_CLASS {
+ public:
+ Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
+ uoffset_t _max_tables = 1000000, bool _check_alignment = true)
+ : buf_(buf),
+ size_(buf_len),
+ depth_(0),
+ max_depth_(_max_depth),
+ num_tables_(0),
+ max_tables_(_max_tables),
+ upper_bound_(0),
+ check_alignment_(_check_alignment)
+ {
+ FLATBUFFERS_ASSERT(size_ < FLATBUFFERS_MAX_BUFFER_SIZE);
+ }
+
+ // Central location where any verification failures register.
+ bool Check(bool ok) const {
+ // clang-format off
+ #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE
+ FLATBUFFERS_ASSERT(ok);
+ #endif
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ if (!ok)
+ upper_bound_ = 0;
+ #endif
+ // clang-format on
+ return ok;
+ }
+
+ // Verify any range within the buffer.
+ bool Verify(size_t elem, size_t elem_len) const {
+ // clang-format off
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ auto upper_bound = elem + elem_len;
+ if (upper_bound_ < upper_bound)
+ upper_bound_ = upper_bound;
+ #endif
+ // clang-format on
+ return Check(elem_len < size_ && elem <= size_ - elem_len);
+ }
+
+ template<typename T> bool VerifyAlignment(size_t elem) const {
+ return (elem & (sizeof(T) - 1)) == 0 || !check_alignment_;
+ }
+
+ // Verify a range indicated by sizeof(T).
+ template<typename T> bool Verify(size_t elem) const {
+ return VerifyAlignment<T>(elem) && Verify(elem, sizeof(T));
+ }
+
+ // Verify relative to a known-good base pointer.
+ bool Verify(const uint8_t *base, voffset_t elem_off, size_t elem_len) const {
+ return Verify(static_cast<size_t>(base - buf_) + elem_off, elem_len);
+ }
+
+ template<typename T> bool Verify(const uint8_t *base, voffset_t elem_off)
+ const {
+ return Verify(static_cast<size_t>(base - buf_) + elem_off, sizeof(T));
+ }
+
+ // Verify a pointer (may be NULL) of a table type.
+ template<typename T> bool VerifyTable(const T *table) {
+ return !table || table->Verify(*this);
+ }
+
+ // Verify a pointer (may be NULL) of any vector type.
+ template<typename T> bool VerifyVector(const Vector<T> *vec) const {
+ return !vec || VerifyVectorOrString(reinterpret_cast<const uint8_t *>(vec),
+ sizeof(T));
+ }
+
+ // Verify a pointer (may be NULL) of a vector to struct.
+ template<typename T> bool VerifyVector(const Vector<const T *> *vec) const {
+ return VerifyVector(reinterpret_cast<const Vector<T> *>(vec));
+ }
+
+ // Verify a pointer (may be NULL) to string.
+ bool VerifyString(const String *str) const {
+ size_t end;
+ return !str ||
+ (VerifyVectorOrString(reinterpret_cast<const uint8_t *>(str),
+ 1, &end) &&
+ Verify(end, 1) && // Must have terminator
+ Check(buf_[end] == '\0')); // Terminating byte must be 0.
+ }
+
+ // Common code between vectors and strings.
+ bool VerifyVectorOrString(const uint8_t *vec, size_t elem_size,
+ size_t *end = nullptr) const {
+ auto veco = static_cast<size_t>(vec - buf_);
+ // Check we can read the size field.
+ if (!Verify<uoffset_t>(veco)) return false;
+ // Check the whole array. If this is a string, the byte past the array
+ // must be 0.
+ auto size = ReadScalar<uoffset_t>(vec);
+ auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size;
+ if (!Check(size < max_elems))
+ return false; // Protect against byte_size overflowing.
+ auto byte_size = sizeof(size) + elem_size * size;
+ if (end) *end = veco + byte_size;
+ return Verify(veco, byte_size);
+ }
+
+ // Special case for string contents, after the above has been called.
+ bool VerifyVectorOfStrings(const Vector<Offset<String>> *vec) const {
+ if (vec) {
+ for (uoffset_t i = 0; i < vec->size(); i++) {
+ if (!VerifyString(vec->Get(i))) return false;
+ }
+ }
+ return true;
+ }
+
+ // Special case for table contents, after the above has been called.
+ template<typename T> bool VerifyVectorOfTables(const Vector<Offset<T>> *vec) {
+ if (vec) {
+ for (uoffset_t i = 0; i < vec->size(); i++) {
+ if (!vec->Get(i)->Verify(*this)) return false;
+ }
+ }
+ return true;
+ }
+
+ bool VerifyTableStart(const uint8_t *table) {
+ // Check the vtable offset.
+ auto tableo = static_cast<size_t>(table - buf_);
+ if (!Verify<soffset_t>(tableo)) return false;
+ // This offset may be signed, but doing the substraction unsigned always
+ // gives the result we want.
+ auto vtableo = tableo - static_cast<size_t>(ReadScalar<soffset_t>(table));
+ // Check the vtable size field, then check vtable fits in its entirety.
+ return VerifyComplexity() && Verify<voffset_t>(vtableo) &&
+ VerifyAlignment<voffset_t>(ReadScalar<voffset_t>(buf_ + vtableo)) &&
+ Verify(vtableo, ReadScalar<voffset_t>(buf_ + vtableo));
+ }
+
+ template<typename T>
+ bool VerifyBufferFromStart(const char *identifier, size_t start) {
+ if (identifier &&
+ (size_ < 2 * sizeof(flatbuffers::uoffset_t) ||
+ !BufferHasIdentifier(buf_ + start, identifier))) {
+ return false;
+ }
+
+ // Call T::Verify, which must be in the generated code for this type.
+ auto o = VerifyOffset(start);
+ return o && reinterpret_cast<const T *>(buf_ + start + o)->Verify(*this)
+ // clang-format off
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ && GetComputedSize()
+ #endif
+ ;
+ // clang-format on
+ }
+
+ // Verify this whole buffer, starting with root type T.
+ template<typename T> bool VerifyBuffer() { return VerifyBuffer<T>(nullptr); }
+
+ template<typename T> bool VerifyBuffer(const char *identifier) {
+ return VerifyBufferFromStart<T>(identifier, 0);
+ }
+
+ template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) {
+ return Verify<uoffset_t>(0U) &&
+ ReadScalar<uoffset_t>(buf_) == size_ - sizeof(uoffset_t) &&
+ VerifyBufferFromStart<T>(identifier, sizeof(uoffset_t));
+ }
+
+ uoffset_t VerifyOffset(size_t start) const {
+ if (!Verify<uoffset_t>(start)) return 0;
+ auto o = ReadScalar<uoffset_t>(buf_ + start);
+ // May not point to itself.
+ if (!Check(o != 0)) return 0;
+ // Can't wrap around / buffers are max 2GB.
+ if (!Check(static_cast<soffset_t>(o) >= 0)) return 0;
+ // Must be inside the buffer to create a pointer from it (pointer outside
+ // buffer is UB).
+ if (!Verify(start + o, 1)) return 0;
+ return o;
+ }
+
+ uoffset_t VerifyOffset(const uint8_t *base, voffset_t start) const {
+ return VerifyOffset(static_cast<size_t>(base - buf_) + start);
+ }
+
+ // Called at the start of a table to increase counters measuring data
+ // structure depth and amount, and possibly bails out with false if
+ // limits set by the constructor have been hit. Needs to be balanced
+ // with EndTable().
+ bool VerifyComplexity() {
+ depth_++;
+ num_tables_++;
+ return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_);
+ }
+
+ // Called at the end of a table to pop the depth count.
+ bool EndTable() {
+ depth_--;
+ return true;
+ }
+
+ // Returns the message size in bytes
+ size_t GetComputedSize() const {
+ // clang-format off
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ uintptr_t size = upper_bound_;
+ // Align the size to uoffset_t
+ size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1);
+ return (size > size_) ? 0 : size;
+ #else
+ // Must turn on FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE for this to work.
+ (void)upper_bound_;
+ FLATBUFFERS_ASSERT(false);
+ return 0;
+ #endif
+ // clang-format on
+ }
+
+ private:
+ const uint8_t *buf_;
+ size_t size_;
+ uoffset_t depth_;
+ uoffset_t max_depth_;
+ uoffset_t num_tables_;
+ uoffset_t max_tables_;
+ mutable size_t upper_bound_;
+ bool check_alignment_;
+};
+
+// Convenient way to bundle a buffer and its length, to pass it around
+// typed by its root.
+// A BufferRef does not own its buffer.
+struct BufferRefBase {}; // for std::is_base_of
+template<typename T> struct BufferRef : BufferRefBase {
+ BufferRef() : buf(nullptr), len(0), must_free(false) {}
+ BufferRef(uint8_t *_buf, uoffset_t _len)
+ : buf(_buf), len(_len), must_free(false) {}
+
+ ~BufferRef() {
+ if (must_free) free(buf);
+ }
+
+ const T *GetRoot() const { return flatbuffers::GetRoot<T>(buf); }
+
+ bool Verify() {
+ Verifier verifier(buf, len);
+ return verifier.VerifyBuffer<T>(nullptr);
+ }
+
+ uint8_t *buf;
+ uoffset_t len;
+ bool must_free;
+};
+
+// "structs" are flat structures that do not have an offset table, thus
+// always have all members present and do not support forwards/backwards
+// compatible extensions.
+
+class Struct FLATBUFFERS_FINAL_CLASS {
+ public:
+ template<typename T> T GetField(uoffset_t o) const {
+ return ReadScalar<T>(&data_[o]);
+ }
+
+ template<typename T> T GetStruct(uoffset_t o) const {
+ return reinterpret_cast<T>(&data_[o]);
+ }
+
+ const uint8_t *GetAddressOf(uoffset_t o) const { return &data_[o]; }
+ uint8_t *GetAddressOf(uoffset_t o) { return &data_[o]; }
+
+ private:
+ uint8_t data_[1];
+};
+
+// "tables" use an offset table (possibly shared) that allows fields to be
+// omitted and added at will, but uses an extra indirection to read.
+class Table {
+ public:
+ const uint8_t *GetVTable() const {
+ return data_ - ReadScalar<soffset_t>(data_);
+ }
+
+ // This gets the field offset for any of the functions below it, or 0
+ // if the field was not present.
+ voffset_t GetOptionalFieldOffset(voffset_t field) const {
+ // The vtable offset is always at the start.
+ auto vtable = GetVTable();
+ // The first element is the size of the vtable (fields + type id + itself).
+ auto vtsize = ReadScalar<voffset_t>(vtable);
+ // If the field we're accessing is outside the vtable, we're reading older
+ // data, so it's the same as if the offset was 0 (not present).
+ return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0;
+ }
+
+ template<typename T> T GetField(voffset_t field, T defaultval) const {
+ auto field_offset = GetOptionalFieldOffset(field);
+ return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval;
+ }
+
+ template<typename P> P GetPointer(voffset_t field) {
+ auto field_offset = GetOptionalFieldOffset(field);
+ auto p = data_ + field_offset;
+ return field_offset ? reinterpret_cast<P>(p + ReadScalar<uoffset_t>(p))
+ : nullptr;
+ }
+ template<typename P> P GetPointer(voffset_t field) const {
+ return const_cast<Table *>(this)->GetPointer<P>(field);
+ }
+
+ template<typename P> P GetStruct(voffset_t field) const {
+ auto field_offset = GetOptionalFieldOffset(field);
+ auto p = const_cast<uint8_t *>(data_ + field_offset);
+ return field_offset ? reinterpret_cast<P>(p) : nullptr;
+ }
+
+ 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;
+ }
+
+ bool SetPointer(voffset_t field, const uint8_t *val) {
+ auto field_offset = GetOptionalFieldOffset(field);
+ if (!field_offset) return false;
+ WriteScalar(data_ + field_offset,
+ static_cast<uoffset_t>(val - (data_ + field_offset)));
+ return true;
+ }
+
+ uint8_t *GetAddressOf(voffset_t field) {
+ auto field_offset = GetOptionalFieldOffset(field);
+ return field_offset ? data_ + field_offset : nullptr;
+ }
+ const uint8_t *GetAddressOf(voffset_t field) const {
+ return const_cast<Table *>(this)->GetAddressOf(field);
+ }
+
+ bool CheckField(voffset_t field) const {
+ return GetOptionalFieldOffset(field) != 0;
+ }
+
+ // Verify the vtable of this table.
+ // Call this once per table, followed by VerifyField once per field.
+ bool VerifyTableStart(Verifier &verifier) const {
+ return verifier.VerifyTableStart(data_);
+ }
+
+ // Verify a particular field.
+ template<typename T>
+ bool VerifyField(const Verifier &verifier, voffset_t field) const {
+ // Calling GetOptionalFieldOffset should be safe now thanks to
+ // VerifyTable().
+ auto field_offset = GetOptionalFieldOffset(field);
+ // Check the actual field.
+ return !field_offset || verifier.Verify<T>(data_, field_offset);
+ }
+
+ // VerifyField for required fields.
+ template<typename T>
+ bool VerifyFieldRequired(const Verifier &verifier, voffset_t field) const {
+ auto field_offset = GetOptionalFieldOffset(field);
+ return verifier.Check(field_offset != 0) &&
+ verifier.Verify<T>(data_, field_offset);
+ }
+
+ // Versions for offsets.
+ bool VerifyOffset(const Verifier &verifier, voffset_t field) const {
+ auto field_offset = GetOptionalFieldOffset(field);
+ return !field_offset || verifier.VerifyOffset(data_, field_offset);
+ }
+
+ bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const {
+ auto field_offset = GetOptionalFieldOffset(field);
+ return verifier.Check(field_offset != 0) &&
+ verifier.VerifyOffset(data_, field_offset);
+ }
+
+ private:
+ // private constructor & copy constructor: you obtain instances of this
+ // class by pointing to existing data only
+ Table();
+ Table(const Table &other);
+
+ uint8_t data_[1];
+};
+
+template<typename T> void FlatBufferBuilder::Required(Offset<T> table,
+ voffset_t field) {
+ auto table_ptr = reinterpret_cast<const Table *>(buf_.data_at(table.o));
+ bool ok = table_ptr->GetOptionalFieldOffset(field) != 0;
+ // If this fails, the caller will show what field needs to be set.
+ FLATBUFFERS_ASSERT(ok);
+ (void)ok;
+}
+
+/// @brief This can compute the start of a FlatBuffer from a root pointer, i.e.
+/// it is the opposite transformation of GetRoot().
+/// This may be useful if you want to pass on a root and have the recipient
+/// delete the buffer afterwards.
+inline const uint8_t *GetBufferStartFromRootPointer(const void *root) {
+ auto table = reinterpret_cast<const Table *>(root);
+ auto vtable = table->GetVTable();
+ // Either the vtable is before the root or after the root.
+ auto start = (std::min)(vtable, reinterpret_cast<const uint8_t *>(root));
+ // Align to at least sizeof(uoffset_t).
+ start = reinterpret_cast<const uint8_t *>(reinterpret_cast<uintptr_t>(start) &
+ ~(sizeof(uoffset_t) - 1));
+ // Additionally, there may be a file_identifier in the buffer, and the root
+ // offset. The buffer may have been aligned to any size between
+ // sizeof(uoffset_t) and FLATBUFFERS_MAX_ALIGNMENT (see "force_align").
+ // Sadly, the exact alignment is only known when constructing the buffer,
+ // since it depends on the presence of values with said alignment properties.
+ // So instead, we simply look at the next uoffset_t values (root,
+ // file_identifier, and alignment padding) to see which points to the root.
+ // None of the other values can "impersonate" the root since they will either
+ // be 0 or four ASCII characters.
+ static_assert(FlatBufferBuilder::kFileIdentifierLength == sizeof(uoffset_t),
+ "file_identifier is assumed to be the same size as uoffset_t");
+ for (auto possible_roots = FLATBUFFERS_MAX_ALIGNMENT / sizeof(uoffset_t) + 1;
+ possible_roots; possible_roots--) {
+ start -= sizeof(uoffset_t);
+ if (ReadScalar<uoffset_t>(start) + start ==
+ reinterpret_cast<const uint8_t *>(root))
+ return start;
+ }
+ // We didn't find the root, either the "root" passed isn't really a root,
+ // or the buffer is corrupt.
+ // Assert, because calling this function with bad data may cause reads
+ // outside of buffer boundaries.
+ FLATBUFFERS_ASSERT(false);
+ return nullptr;
+}
+
+/// @brief This return the prefixed size of a FlatBuffer.
+inline uoffset_t GetPrefixedSize(const uint8_t* buf){ return ReadScalar<uoffset_t>(buf); }
+
+// Base class for native objects (FlatBuffer data de-serialized into native
+// C++ data structures).
+// Contains no functionality, purely documentative.
+struct NativeTable {};
+
+/// @brief Function types to be used with resolving hashes into objects and
+/// back again. The resolver gets a pointer to a field inside an object API
+/// object that is of the type specified in the schema using the attribute
+/// `cpp_type` (it is thus important whatever you write to this address
+/// matches that type). The value of this field is initially null, so you
+/// may choose to implement a delayed binding lookup using this function
+/// if you wish. The resolver does the opposite lookup, for when the object
+/// is being serialized again.
+typedef uint64_t hash_value_t;
+// clang-format off
+#ifdef FLATBUFFERS_CPP98_STL
+ typedef void (*resolver_function_t)(void **pointer_adr, hash_value_t hash);
+ typedef hash_value_t (*rehasher_function_t)(void *pointer);
+#else
+ typedef std::function<void (void **pointer_adr, hash_value_t hash)>
+ resolver_function_t;
+ typedef std::function<hash_value_t (void *pointer)> rehasher_function_t;
+#endif
+// clang-format on
+
+// Helper function to test if a field is present, using any of the field
+// enums in the generated code.
+// `table` must be a generated table type. Since this is a template parameter,
+// this is not typechecked to be a subclass of Table, so beware!
+// Note: this function will return false for fields equal to the default
+// value, since they're not stored in the buffer (unless force_defaults was
+// used).
+template<typename T>
+bool IsFieldPresent(const T *table, typename T::FlatBuffersVTableOffset field) {
+ // Cast, since Table is a private baseclass of any table types.
+ return reinterpret_cast<const Table *>(table)->CheckField(
+ static_cast<voffset_t>(field));
+}
+
+// Utility function for reverse lookups on the EnumNames*() functions
+// (in the generated C++ code)
+// names must be NULL terminated.
+inline int LookupEnum(const char **names, const char *name) {
+ for (const char **p = names; *p; p++)
+ if (!strcmp(*p, name)) return static_cast<int>(p - names);
+ return -1;
+}
+
+// These macros allow us to layout a struct with a guarantee that they'll end
+// up looking the same on different compilers and platforms.
+// It does this by disallowing the compiler to do any padding, and then
+// does padding itself by inserting extra padding fields that make every
+// element aligned to its own size.
+// Additionally, it manually sets the alignment of the struct as a whole,
+// which is typically its largest element, or a custom size set in the schema
+// by the force_align attribute.
+// These are used in the generated code only.
+
+// clang-format off
+#if defined(_MSC_VER)
+ #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
+ __pragma(pack(1)) \
+ struct __declspec(align(alignment))
+ #define FLATBUFFERS_STRUCT_END(name, size) \
+ __pragma(pack()) \
+ static_assert(sizeof(name) == size, "compiler breaks packing rules")
+#elif defined(__GNUC__) || defined(__clang__) || defined(__ICCARM__)
+ #define FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(alignment) \
+ _Pragma("pack(1)") \
+ struct __attribute__((aligned(alignment)))
+ #define FLATBUFFERS_STRUCT_END(name, size) \
+ _Pragma("pack()") \
+ static_assert(sizeof(name) == size, "compiler breaks packing rules")
+#else
+ #error Unknown compiler, please define structure alignment macros
+#endif
+// clang-format on
+
+// Minimal reflection via code generation.
+// Besides full-fat reflection (see reflection.h) and parsing/printing by
+// loading schemas (see idl.h), we can also have code generation for mimimal
+// reflection data which allows pretty-printing and other uses without needing
+// a schema or a parser.
+// Generate code with --reflect-types (types only) or --reflect-names (names
+// also) to enable.
+// See minireflect.h for utilities using this functionality.
+
+// These types are organized slightly differently as the ones in idl.h.
+enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM };
+
+// Scalars have the same order as in idl.h
+// clang-format off
+#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \
+ ET(ET_UTYPE) \
+ ET(ET_BOOL) \
+ ET(ET_CHAR) \
+ ET(ET_UCHAR) \
+ ET(ET_SHORT) \
+ ET(ET_USHORT) \
+ ET(ET_INT) \
+ ET(ET_UINT) \
+ ET(ET_LONG) \
+ ET(ET_ULONG) \
+ ET(ET_FLOAT) \
+ ET(ET_DOUBLE) \
+ ET(ET_STRING) \
+ ET(ET_SEQUENCE) // See SequenceType.
+
+enum ElementaryType {
+ #define FLATBUFFERS_ET(E) E,
+ FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
+ #undef FLATBUFFERS_ET
+};
+
+inline const char * const *ElementaryTypeNames() {
+ static const char * const names[] = {
+ #define FLATBUFFERS_ET(E) #E,
+ FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
+ #undef FLATBUFFERS_ET
+ };
+ return names;
+}
+// clang-format on
+
+// Basic type info cost just 16bits per field!
+struct TypeCode {
+ uint16_t base_type : 4; // ElementaryType
+ uint16_t is_vector : 1;
+ int16_t sequence_ref : 11; // Index into type_refs below, or -1 for none.
+};
+
+static_assert(sizeof(TypeCode) == 2, "TypeCode");
+
+struct TypeTable;
+
+// Signature of the static method present in each type.
+typedef const TypeTable *(*TypeFunction)();
+
+struct TypeTable {
+ SequenceType st;
+ size_t num_elems; // of type_codes, values, names (but not type_refs).
+ const TypeCode *type_codes; // num_elems count
+ const TypeFunction *type_refs; // less than num_elems entries (see TypeCode).
+ const int64_t *values; // Only set for non-consecutive enum/union or structs.
+ const char * const *names; // Only set if compiled with --reflect-names.
+};
+
+// String which identifies the current version of FlatBuffers.
+// flatbuffer_version_string is used by Google developers to identify which
+// applications uploaded to Google Play are using this library. This allows
+// the development team at Google to determine the popularity of the library.
+// How it works: Applications that are uploaded to the Google Play Store are
+// scanned for this version string. We track which applications are using it
+// to measure popularity. You are free to remove it (of course) but we would
+// appreciate if you left it in.
+
+// Weak linkage is culled by VS & doesn't work on cygwin.
+// clang-format off
+#if !defined(_WIN32) && !defined(__CYGWIN__)
+
+extern volatile __attribute__((weak)) const char *flatbuffer_version_string;
+volatile __attribute__((weak)) const char *flatbuffer_version_string =
+ "FlatBuffers "
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
+
+#endif // !defined(_WIN32) && !defined(__CYGWIN__)
+
+#define FLATBUFFERS_DEFINE_BITMASK_OPERATORS(E, T)\
+ inline E operator | (E lhs, E rhs){\
+ return E(T(lhs) | T(rhs));\
+ }\
+ inline E operator & (E lhs, E rhs){\
+ return E(T(lhs) & T(rhs));\
+ }\
+ inline E operator ^ (E lhs, E rhs){\
+ return E(T(lhs) ^ T(rhs));\
+ }\
+ inline E operator ~ (E lhs){\
+ return E(~T(lhs));\
+ }\
+ inline E operator |= (E &lhs, E rhs){\
+ lhs = lhs | rhs;\
+ return lhs;\
+ }\
+ inline E operator &= (E &lhs, E rhs){\
+ lhs = lhs & rhs;\
+ return lhs;\
+ }\
+ inline E operator ^= (E &lhs, E rhs){\
+ lhs = lhs ^ rhs;\
+ return lhs;\
+ }\
+ inline bool operator !(E rhs) \
+ {\
+ return !bool(T(rhs)); \
+ }
+/// @endcond
+} // namespace flatbuffers
+
+// clang-format on
+
+#endif // FLATBUFFERS_H_
diff --git a/include/flatbuffers/flatc.h b/include/flatbuffers/flatc.h
new file mode 100644
index 0000000..f2765d2
--- /dev/null
+++ b/include/flatbuffers/flatc.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <functional>
+#include <limits>
+#include <string>
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#ifndef FLATC_H_
+# define FLATC_H_
+
+namespace flatbuffers {
+
+class FlatCompiler {
+ public:
+ // Output generator for the various programming languages and formats we
+ // support.
+ struct Generator {
+ typedef bool (*GenerateFn)(const flatbuffers::Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+ typedef std::string (*MakeRuleFn)(const flatbuffers::Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+ GenerateFn generate;
+ const char *generator_opt_short;
+ const char *generator_opt_long;
+ const char *lang_name;
+ bool schema_only;
+ GenerateFn generateGRPC;
+ flatbuffers::IDLOptions::Language lang;
+ const char *generator_help;
+ MakeRuleFn make_rule;
+ };
+
+ typedef void (*WarnFn)(const FlatCompiler *flatc, const std::string &warn,
+ bool show_exe_name);
+
+ typedef void (*ErrorFn)(const FlatCompiler *flatc, const std::string &err,
+ bool usage, bool show_exe_name);
+
+ // Parameters required to initialize the FlatCompiler.
+ struct InitParams {
+ InitParams()
+ : generators(nullptr),
+ num_generators(0),
+ warn_fn(nullptr),
+ error_fn(nullptr) {}
+
+ const Generator *generators;
+ size_t num_generators;
+ WarnFn warn_fn;
+ ErrorFn error_fn;
+ };
+
+ explicit FlatCompiler(const InitParams ¶ms) : params_(params) {}
+
+ int Compile(int argc, const char **argv);
+
+ std::string GetUsageString(const char *program_name) const;
+
+ private:
+ void ParseFile(flatbuffers::Parser &parser, const std::string &filename,
+ const std::string &contents,
+ std::vector<const char *> &include_directories) const;
+
+ void LoadBinarySchema(Parser &parser, const std::string &filename,
+ const std::string &contents);
+
+ void Warn(const std::string &warn, bool show_exe_name = true) const;
+
+ void Error(const std::string &err, bool usage = true,
+ bool show_exe_name = true) const;
+
+ InitParams params_;
+};
+
+} // namespace flatbuffers
+
+#endif // FLATC_H_
diff --git a/include/flatbuffers/flexbuffers.h b/include/flatbuffers/flexbuffers.h
new file mode 100644
index 0000000..7cba5b7
--- /dev/null
+++ b/include/flatbuffers/flexbuffers.h
@@ -0,0 +1,1538 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_FLEXBUFFERS_H_
+#define FLATBUFFERS_FLEXBUFFERS_H_
+
+#include <map>
+// Used to select STL variant.
+#include "flatbuffers/base.h"
+// We use the basic binary writing functions from the regular FlatBuffers.
+#include "flatbuffers/util.h"
+
+#ifdef _MSC_VER
+# include <intrin.h>
+#endif
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4127) // C4127: conditional expression is constant
+#endif
+
+namespace flexbuffers {
+
+class Reference;
+class Map;
+
+// These are used in the lower 2 bits of a type field to determine the size of
+// the elements (and or size field) of the item pointed to (e.g. vector).
+enum BitWidth {
+ BIT_WIDTH_8 = 0,
+ BIT_WIDTH_16 = 1,
+ BIT_WIDTH_32 = 2,
+ BIT_WIDTH_64 = 3,
+};
+
+// These are used as the upper 6 bits of a type field to indicate the actual
+// type.
+enum Type {
+ FBT_NULL = 0,
+ FBT_INT = 1,
+ FBT_UINT = 2,
+ FBT_FLOAT = 3,
+ // Types above stored inline, types below store an offset.
+ FBT_KEY = 4,
+ FBT_STRING = 5,
+ FBT_INDIRECT_INT = 6,
+ FBT_INDIRECT_UINT = 7,
+ FBT_INDIRECT_FLOAT = 8,
+ FBT_MAP = 9,
+ FBT_VECTOR = 10, // Untyped.
+ FBT_VECTOR_INT = 11, // Typed any size (stores no type table).
+ FBT_VECTOR_UINT = 12,
+ FBT_VECTOR_FLOAT = 13,
+ FBT_VECTOR_KEY = 14,
+ FBT_VECTOR_STRING = 15,
+ FBT_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field).
+ FBT_VECTOR_UINT2 = 17,
+ FBT_VECTOR_FLOAT2 = 18,
+ FBT_VECTOR_INT3 = 19, // Typed triple (no type table, no size field).
+ FBT_VECTOR_UINT3 = 20,
+ FBT_VECTOR_FLOAT3 = 21,
+ FBT_VECTOR_INT4 = 22, // Typed quad (no type table, no size field).
+ FBT_VECTOR_UINT4 = 23,
+ FBT_VECTOR_FLOAT4 = 24,
+ FBT_BLOB = 25,
+ FBT_BOOL = 26,
+ FBT_VECTOR_BOOL =
+ 36, // To Allow the same type of conversion of type to vector type
+};
+
+inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; }
+
+inline bool IsTypedVectorElementType(Type t) {
+ return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL;
+}
+
+inline bool IsTypedVector(Type t) {
+ return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING) ||
+ t == FBT_VECTOR_BOOL;
+}
+
+inline bool IsFixedTypedVector(Type t) {
+ return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4;
+}
+
+inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
+ FLATBUFFERS_ASSERT(IsTypedVectorElementType(t));
+ switch (fixed_len) {
+ case 0: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT);
+ case 2: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT2);
+ case 3: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT3);
+ case 4: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT4);
+ default: FLATBUFFERS_ASSERT(0); return FBT_NULL;
+ }
+}
+
+inline Type ToTypedVectorElementType(Type t) {
+ FLATBUFFERS_ASSERT(IsTypedVector(t));
+ return static_cast<Type>(t - FBT_VECTOR_INT + FBT_INT);
+}
+
+inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
+ FLATBUFFERS_ASSERT(IsFixedTypedVector(t));
+ auto fixed_type = t - FBT_VECTOR_INT2;
+ *len = static_cast<uint8_t>(fixed_type / 3 +
+ 2); // 3 types each, starting from length 2.
+ return static_cast<Type>(fixed_type % 3 + FBT_INT);
+}
+
+// TODO: implement proper support for 8/16bit floats, or decide not to
+// support them.
+typedef int16_t half;
+typedef int8_t quarter;
+
+// TODO: can we do this without conditionals using intrinsics or inline asm
+// on some platforms? Given branch prediction the method below should be
+// decently quick, but it is the most frequently executed function.
+// We could do an (unaligned) 64-bit read if we ifdef out the platforms for
+// which that doesn't work (or where we'd read into un-owned memory).
+template<typename R, typename T1, typename T2, typename T4, typename T8>
+R ReadSizedScalar(const uint8_t *data, uint8_t byte_width) {
+ return byte_width < 4
+ ? (byte_width < 2
+ ? static_cast<R>(flatbuffers::ReadScalar<T1>(data))
+ : static_cast<R>(flatbuffers::ReadScalar<T2>(data)))
+ : (byte_width < 8
+ ? static_cast<R>(flatbuffers::ReadScalar<T4>(data))
+ : static_cast<R>(flatbuffers::ReadScalar<T8>(data)));
+}
+
+inline int64_t ReadInt64(const uint8_t *data, uint8_t byte_width) {
+ return ReadSizedScalar<int64_t, int8_t, int16_t, int32_t, int64_t>(
+ data, byte_width);
+}
+
+inline uint64_t ReadUInt64(const uint8_t *data, uint8_t byte_width) {
+ // This is the "hottest" function (all offset lookups use this), so worth
+ // optimizing if possible.
+ // TODO: GCC apparently replaces memcpy by a rep movsb, but only if count is a
+ // constant, which here it isn't. Test if memcpy is still faster than
+ // the conditionals in ReadSizedScalar. Can also use inline asm.
+ // clang-format off
+ #if defined(_MSC_VER) && (defined(_M_X64) || defined _M_IX86)
+ uint64_t u = 0;
+ __movsb(reinterpret_cast<uint8_t *>(&u),
+ reinterpret_cast<const uint8_t *>(data), byte_width);
+ return flatbuffers::EndianScalar(u);
+ #else
+ return ReadSizedScalar<uint64_t, uint8_t, uint16_t, uint32_t, uint64_t>(
+ data, byte_width);
+ #endif
+ // clang-format on
+}
+
+inline double ReadDouble(const uint8_t *data, uint8_t byte_width) {
+ return ReadSizedScalar<double, quarter, half, float, double>(data,
+ byte_width);
+}
+
+inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
+ return offset - ReadUInt64(offset, byte_width);
+}
+
+template<typename T> const uint8_t *Indirect(const uint8_t *offset) {
+ return offset - flatbuffers::ReadScalar<T>(offset);
+}
+
+inline BitWidth WidthU(uint64_t u) {
+#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) \
+ { \
+ if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \
+ }
+ FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 8);
+ FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 16);
+ FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 32);
+#undef FLATBUFFERS_GET_FIELD_BIT_WIDTH
+ return BIT_WIDTH_64;
+}
+
+inline BitWidth WidthI(int64_t i) {
+ auto u = static_cast<uint64_t>(i) << 1;
+ return WidthU(i >= 0 ? u : ~u);
+}
+
+inline BitWidth WidthF(double f) {
+ return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32
+ : BIT_WIDTH_64;
+}
+
+// Base class of all types below.
+// Points into the data buffer and allows access to one type.
+class Object {
+ public:
+ Object(const uint8_t *data, uint8_t byte_width)
+ : data_(data), byte_width_(byte_width) {}
+
+ protected:
+ const uint8_t *data_;
+ uint8_t byte_width_;
+};
+
+// Stores size in `byte_width_` bytes before data_ pointer.
+class Sized : public Object {
+ public:
+ Sized(const uint8_t *data, uint8_t byte_width) : Object(data, byte_width) {}
+ size_t size() const {
+ return static_cast<size_t>(ReadUInt64(data_ - byte_width_, byte_width_));
+ }
+};
+
+class String : public Sized {
+ public:
+ String(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {}
+
+ size_t length() const { return size(); }
+ const char *c_str() const { return reinterpret_cast<const char *>(data_); }
+ std::string str() const { return std::string(c_str(), length()); }
+
+ static String EmptyString() {
+ static const uint8_t empty_string[] = { 0 /*len*/, 0 /*terminator*/ };
+ return String(empty_string + 1, 1);
+ }
+ bool IsTheEmptyString() const { return data_ == EmptyString().data_; }
+};
+
+class Blob : public Sized {
+ public:
+ Blob(const uint8_t *data_buf, uint8_t byte_width)
+ : Sized(data_buf, byte_width) {}
+
+ static Blob EmptyBlob() {
+ static const uint8_t empty_blob[] = { 0 /*len*/ };
+ return Blob(empty_blob + 1, 1);
+ }
+ bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; }
+ const uint8_t *data() const { return data_; }
+};
+
+class Vector : public Sized {
+ public:
+ Vector(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {}
+
+ Reference operator[](size_t i) const;
+
+ static Vector EmptyVector() {
+ static const uint8_t empty_vector[] = { 0 /*len*/ };
+ return Vector(empty_vector + 1, 1);
+ }
+ bool IsTheEmptyVector() const { return data_ == EmptyVector().data_; }
+};
+
+class TypedVector : public Sized {
+ public:
+ TypedVector(const uint8_t *data, uint8_t byte_width, Type element_type)
+ : Sized(data, byte_width), type_(element_type) {}
+
+ Reference operator[](size_t i) const;
+
+ static TypedVector EmptyTypedVector() {
+ static const uint8_t empty_typed_vector[] = { 0 /*len*/ };
+ return TypedVector(empty_typed_vector + 1, 1, FBT_INT);
+ }
+ bool IsTheEmptyVector() const {
+ return data_ == TypedVector::EmptyTypedVector().data_;
+ }
+
+ Type ElementType() { return type_; }
+
+ private:
+ Type type_;
+
+ friend Map;
+};
+
+class FixedTypedVector : public Object {
+ public:
+ FixedTypedVector(const uint8_t *data, uint8_t byte_width, Type element_type,
+ uint8_t len)
+ : Object(data, byte_width), type_(element_type), len_(len) {}
+
+ Reference operator[](size_t i) const;
+
+ static FixedTypedVector EmptyFixedTypedVector() {
+ static const uint8_t fixed_empty_vector[] = { 0 /* unused */ };
+ return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0);
+ }
+ bool IsTheEmptyFixedTypedVector() const {
+ return data_ == FixedTypedVector::EmptyFixedTypedVector().data_;
+ }
+
+ Type ElementType() { return type_; }
+ uint8_t size() { return len_; }
+
+ private:
+ Type type_;
+ uint8_t len_;
+};
+
+class Map : public Vector {
+ public:
+ Map(const uint8_t *data, uint8_t byte_width) : Vector(data, byte_width) {}
+
+ Reference operator[](const char *key) const;
+ Reference operator[](const std::string &key) const;
+
+ Vector Values() const { return Vector(data_, byte_width_); }
+
+ TypedVector Keys() const {
+ const size_t num_prefixed_fields = 3;
+ auto keys_offset = data_ - byte_width_ * num_prefixed_fields;
+ return TypedVector(Indirect(keys_offset, byte_width_),
+ static_cast<uint8_t>(
+ ReadUInt64(keys_offset + byte_width_, byte_width_)),
+ FBT_KEY);
+ }
+
+ static Map EmptyMap() {
+ static const uint8_t empty_map[] = {
+ 0 /*keys_len*/, 0 /*keys_offset*/, 1 /*keys_width*/, 0 /*len*/
+ };
+ return Map(empty_map + 4, 1);
+ }
+
+ bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; }
+};
+
+template<typename T>
+void AppendToString(std::string &s, T &&v, bool keys_quoted) {
+ s += "[ ";
+ for (size_t i = 0; i < v.size(); i++) {
+ if (i) s += ", ";
+ v[i].ToString(true, keys_quoted, s);
+ }
+ s += " ]";
+}
+
+class Reference {
+ public:
+ Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width,
+ Type type)
+ : data_(data),
+ parent_width_(parent_width),
+ byte_width_(byte_width),
+ type_(type) {}
+
+ Reference(const uint8_t *data, uint8_t parent_width, uint8_t packed_type)
+ : data_(data), parent_width_(parent_width) {
+ byte_width_ = 1U << static_cast<BitWidth>(packed_type & 3);
+ type_ = static_cast<Type>(packed_type >> 2);
+ }
+
+ Type GetType() const { return type_; }
+
+ bool IsNull() const { return type_ == FBT_NULL; }
+ bool IsBool() const { return type_ == FBT_BOOL; }
+ bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; }
+ bool IsUInt() const {
+ return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT;
+ }
+ bool IsIntOrUint() const { return IsInt() || IsUInt(); }
+ bool IsFloat() const {
+ return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT;
+ }
+ bool IsNumeric() const { return IsIntOrUint() || IsFloat(); }
+ bool IsString() const { return type_ == FBT_STRING; }
+ bool IsKey() const { return type_ == FBT_KEY; }
+ bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; }
+ bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); }
+ bool IsFixedTypedVector() const { return flexbuffers::IsFixedTypedVector(type_); }
+ bool IsAnyVector() const { return (IsTypedVector() || IsFixedTypedVector() || IsVector());}
+ bool IsMap() const { return type_ == FBT_MAP; }
+ bool IsBlob() const { return type_ == FBT_BLOB; }
+
+ bool AsBool() const {
+ return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_)
+ : AsUInt64()) != 0;
+ }
+
+ // Reads any type as a int64_t. Never fails, does most sensible conversion.
+ // Truncates floats, strings are attempted to be parsed for a number,
+ // vectors/maps return their size. Returns 0 if all else fails.
+ int64_t AsInt64() const {
+ if (type_ == FBT_INT) {
+ // A fast path for the common case.
+ return ReadInt64(data_, parent_width_);
+ } else
+ switch (type_) {
+ case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
+ case FBT_UINT: return ReadUInt64(data_, parent_width_);
+ case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
+ case FBT_FLOAT:
+ return static_cast<int64_t>(ReadDouble(data_, parent_width_));
+ case FBT_INDIRECT_FLOAT:
+ return static_cast<int64_t>(ReadDouble(Indirect(), byte_width_));
+ case FBT_NULL: return 0;
+ case FBT_STRING: return flatbuffers::StringToInt(AsString().c_str());
+ case FBT_VECTOR: return static_cast<int64_t>(AsVector().size());
+ case FBT_BOOL: return ReadInt64(data_, parent_width_);
+ default:
+ // Convert other things to int.
+ return 0;
+ }
+ }
+
+ // TODO: could specialize these to not use AsInt64() if that saves
+ // extension ops in generated code, and use a faster op than ReadInt64.
+ int32_t AsInt32() const { return static_cast<int32_t>(AsInt64()); }
+ int16_t AsInt16() const { return static_cast<int16_t>(AsInt64()); }
+ int8_t AsInt8() const { return static_cast<int8_t>(AsInt64()); }
+
+ uint64_t AsUInt64() const {
+ if (type_ == FBT_UINT) {
+ // A fast path for the common case.
+ return ReadUInt64(data_, parent_width_);
+ } else
+ switch (type_) {
+ case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_);
+ case FBT_INT: return ReadInt64(data_, parent_width_);
+ case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_);
+ case FBT_FLOAT:
+ return static_cast<uint64_t>(ReadDouble(data_, parent_width_));
+ case FBT_INDIRECT_FLOAT:
+ return static_cast<uint64_t>(ReadDouble(Indirect(), byte_width_));
+ case FBT_NULL: return 0;
+ case FBT_STRING: return flatbuffers::StringToUInt(AsString().c_str());
+ case FBT_VECTOR: return static_cast<uint64_t>(AsVector().size());
+ case FBT_BOOL: return ReadUInt64(data_, parent_width_);
+ default:
+ // Convert other things to uint.
+ return 0;
+ }
+ }
+
+ uint32_t AsUInt32() const { return static_cast<uint32_t>(AsUInt64()); }
+ uint16_t AsUInt16() const { return static_cast<uint16_t>(AsUInt64()); }
+ uint8_t AsUInt8() const { return static_cast<uint8_t>(AsUInt64()); }
+
+ double AsDouble() const {
+ if (type_ == FBT_FLOAT) {
+ // A fast path for the common case.
+ return ReadDouble(data_, parent_width_);
+ } else
+ switch (type_) {
+ case FBT_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_);
+ case FBT_INT:
+ return static_cast<double>(ReadInt64(data_, parent_width_));
+ case FBT_UINT:
+ return static_cast<double>(ReadUInt64(data_, parent_width_));
+ case FBT_INDIRECT_INT:
+ return static_cast<double>(ReadInt64(Indirect(), byte_width_));
+ case FBT_INDIRECT_UINT:
+ return static_cast<double>(ReadUInt64(Indirect(), byte_width_));
+ case FBT_NULL: return 0.0;
+ case FBT_STRING: return strtod(AsString().c_str(), nullptr);
+ case FBT_VECTOR: return static_cast<double>(AsVector().size());
+ case FBT_BOOL:
+ return static_cast<double>(ReadUInt64(data_, parent_width_));
+ default:
+ // Convert strings and other things to float.
+ return 0;
+ }
+ }
+
+ float AsFloat() const { return static_cast<float>(AsDouble()); }
+
+ const char *AsKey() const {
+ if (type_ == FBT_KEY) {
+ return reinterpret_cast<const char *>(Indirect());
+ } else {
+ return "";
+ }
+ }
+
+ // This function returns the empty string if you try to read a not-string.
+ String AsString() const {
+ if (type_ == FBT_STRING) {
+ return String(Indirect(), byte_width_);
+ } else {
+ return String::EmptyString();
+ }
+ }
+
+ // Unlike AsString(), this will convert any type to a std::string.
+ std::string ToString() const {
+ std::string s;
+ ToString(false, false, s);
+ return s;
+ }
+
+ // Convert any type to a JSON-like string. strings_quoted determines if
+ // string values at the top level receive "" quotes (inside other values
+ // they always do). keys_quoted determines if keys are quoted, at any level.
+ // TODO(wvo): add further options to have indentation/newlines.
+ void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const {
+ if (type_ == FBT_STRING) {
+ String str(Indirect(), byte_width_);
+ if (strings_quoted) {
+ flatbuffers::EscapeString(str.c_str(), str.length(), &s, true, false);
+ } else {
+ s.append(str.c_str(), str.length());
+ }
+ } else if (IsKey()) {
+ auto str = AsKey();
+ if (keys_quoted) {
+ flatbuffers::EscapeString(str, strlen(str), &s, true, false);
+ } else {
+ s += str;
+ }
+ } else if (IsInt()) {
+ s += flatbuffers::NumToString(AsInt64());
+ } else if (IsUInt()) {
+ s += flatbuffers::NumToString(AsUInt64());
+ } else if (IsFloat()) {
+ s += flatbuffers::NumToString(AsDouble());
+ } else if (IsNull()) {
+ s += "null";
+ } else if (IsBool()) {
+ s += AsBool() ? "true" : "false";
+ } else if (IsMap()) {
+ s += "{ ";
+ auto m = AsMap();
+ auto keys = m.Keys();
+ auto vals = m.Values();
+ for (size_t i = 0; i < keys.size(); i++) {
+ keys[i].ToString(true, keys_quoted, s);
+ s += ": ";
+ vals[i].ToString(true, keys_quoted, s);
+ if (i < keys.size() - 1) s += ", ";
+ }
+ s += " }";
+ } else if (IsVector()) {
+ AppendToString<Vector>(s, AsVector(), keys_quoted);
+ } else if (IsTypedVector()) {
+ AppendToString<TypedVector>(s, AsTypedVector(), keys_quoted);
+ } else if (IsFixedTypedVector()) {
+ AppendToString<FixedTypedVector>(s, AsFixedTypedVector(), keys_quoted);
+ } else if (IsBlob()) {
+ auto blob = AsBlob();
+ flatbuffers::EscapeString(reinterpret_cast<const char*>(blob.data()), blob.size(), &s, true, false);
+ } else {
+ s += "(?)";
+ }
+ }
+
+ // This function returns the empty blob if you try to read a not-blob.
+ // Strings can be viewed as blobs too.
+ Blob AsBlob() const {
+ if (type_ == FBT_BLOB || type_ == FBT_STRING) {
+ return Blob(Indirect(), byte_width_);
+ } else {
+ return Blob::EmptyBlob();
+ }
+ }
+
+ // This function returns the empty vector if you try to read a not-vector.
+ // Maps can be viewed as vectors too.
+ Vector AsVector() const {
+ if (type_ == FBT_VECTOR || type_ == FBT_MAP) {
+ return Vector(Indirect(), byte_width_);
+ } else {
+ return Vector::EmptyVector();
+ }
+ }
+
+ TypedVector AsTypedVector() const {
+ if (IsTypedVector()) {
+ return TypedVector(Indirect(), byte_width_,
+ ToTypedVectorElementType(type_));
+ } else {
+ return TypedVector::EmptyTypedVector();
+ }
+ }
+
+ FixedTypedVector AsFixedTypedVector() const {
+ if (IsFixedTypedVector()) {
+ uint8_t len = 0;
+ auto vtype = ToFixedTypedVectorElementType(type_, &len);
+ return FixedTypedVector(Indirect(), byte_width_, vtype, len);
+ } else {
+ return FixedTypedVector::EmptyFixedTypedVector();
+ }
+ }
+
+ Map AsMap() const {
+ if (type_ == FBT_MAP) {
+ return Map(Indirect(), byte_width_);
+ } else {
+ return Map::EmptyMap();
+ }
+ }
+
+ template<typename T> T As() const;
+
+ // Experimental: Mutation functions.
+ // These allow scalars in an already created buffer to be updated in-place.
+ // Since by default scalars are stored in the smallest possible space,
+ // the new value may not fit, in which case these functions return false.
+ // To avoid this, you can construct the values you intend to mutate using
+ // Builder::ForceMinimumBitWidth.
+ bool MutateInt(int64_t i) {
+ if (type_ == FBT_INT) {
+ return Mutate(data_, i, parent_width_, WidthI(i));
+ } else if (type_ == FBT_INDIRECT_INT) {
+ return Mutate(Indirect(), i, byte_width_, WidthI(i));
+ } else if (type_ == FBT_UINT) {
+ auto u = static_cast<uint64_t>(i);
+ return Mutate(data_, u, parent_width_, WidthU(u));
+ } else if (type_ == FBT_INDIRECT_UINT) {
+ auto u = static_cast<uint64_t>(i);
+ return Mutate(Indirect(), u, byte_width_, WidthU(u));
+ } else {
+ return false;
+ }
+ }
+
+ bool MutateBool(bool b) {
+ return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
+ }
+
+ bool MutateUInt(uint64_t u) {
+ if (type_ == FBT_UINT) {
+ return Mutate(data_, u, parent_width_, WidthU(u));
+ } else if (type_ == FBT_INDIRECT_UINT) {
+ return Mutate(Indirect(), u, byte_width_, WidthU(u));
+ } else if (type_ == FBT_INT) {
+ auto i = static_cast<int64_t>(u);
+ return Mutate(data_, i, parent_width_, WidthI(i));
+ } else if (type_ == FBT_INDIRECT_INT) {
+ auto i = static_cast<int64_t>(u);
+ return Mutate(Indirect(), i, byte_width_, WidthI(i));
+ } else {
+ return false;
+ }
+ }
+
+ bool MutateFloat(float f) {
+ if (type_ == FBT_FLOAT) {
+ return MutateF(data_, f, parent_width_, BIT_WIDTH_32);
+ } else if (type_ == FBT_INDIRECT_FLOAT) {
+ return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32);
+ } else {
+ return false;
+ }
+ }
+
+ bool MutateFloat(double d) {
+ if (type_ == FBT_FLOAT) {
+ return MutateF(data_, d, parent_width_, WidthF(d));
+ } else if (type_ == FBT_INDIRECT_FLOAT) {
+ return MutateF(Indirect(), d, byte_width_, WidthF(d));
+ } else {
+ return false;
+ }
+ }
+
+ bool MutateString(const char *str, size_t len) {
+ auto s = AsString();
+ if (s.IsTheEmptyString()) return false;
+ // This is very strict, could allow shorter strings, but that creates
+ // garbage.
+ if (s.length() != len) return false;
+ memcpy(const_cast<char *>(s.c_str()), str, len);
+ return true;
+ }
+ bool MutateString(const char *str) { return MutateString(str, strlen(str)); }
+ bool MutateString(const std::string &str) {
+ return MutateString(str.data(), str.length());
+ }
+
+ private:
+ const uint8_t *Indirect() const {
+ return flexbuffers::Indirect(data_, parent_width_);
+ }
+
+ template<typename T>
+ bool Mutate(const uint8_t *dest, T t, size_t byte_width,
+ BitWidth value_width) {
+ auto fits = static_cast<size_t>(static_cast<size_t>(1U) << value_width) <=
+ byte_width;
+ if (fits) {
+ t = flatbuffers::EndianScalar(t);
+ memcpy(const_cast<uint8_t *>(dest), &t, byte_width);
+ }
+ return fits;
+ }
+
+ template<typename T>
+ bool MutateF(const uint8_t *dest, T t, size_t byte_width,
+ BitWidth value_width) {
+ if (byte_width == sizeof(double))
+ return Mutate(dest, static_cast<double>(t), byte_width, value_width);
+ if (byte_width == sizeof(float))
+ return Mutate(dest, static_cast<float>(t), byte_width, value_width);
+ FLATBUFFERS_ASSERT(false);
+ return false;
+ }
+
+ const uint8_t *data_;
+ uint8_t parent_width_;
+ uint8_t byte_width_;
+ Type type_;
+};
+
+// Template specialization for As().
+template<> inline bool Reference::As<bool>() const { return AsBool(); }
+
+template<> inline int8_t Reference::As<int8_t>() const { return AsInt8(); }
+template<> inline int16_t Reference::As<int16_t>() const { return AsInt16(); }
+template<> inline int32_t Reference::As<int32_t>() const { return AsInt32(); }
+template<> inline int64_t Reference::As<int64_t>() const { return AsInt64(); }
+
+template<> inline uint8_t Reference::As<uint8_t>() const { return AsUInt8(); }
+template<> inline uint16_t Reference::As<uint16_t>() const { return AsUInt16(); }
+template<> inline uint32_t Reference::As<uint32_t>() const { return AsUInt32(); }
+template<> inline uint64_t Reference::As<uint64_t>() const { return AsUInt64(); }
+
+template<> inline double Reference::As<double>() const { return AsDouble(); }
+template<> inline float Reference::As<float>() const { return AsFloat(); }
+
+template<> inline String Reference::As<String>() const { return AsString(); }
+template<> inline std::string Reference::As<std::string>() const {
+ return AsString().str();
+}
+
+template<> inline Blob Reference::As<Blob>() const { return AsBlob(); }
+template<> inline Vector Reference::As<Vector>() const { return AsVector(); }
+template<> inline TypedVector Reference::As<TypedVector>() const {
+ return AsTypedVector();
+}
+template<> inline FixedTypedVector Reference::As<FixedTypedVector>() const {
+ return AsFixedTypedVector();
+}
+template<> inline Map Reference::As<Map>() const { return AsMap(); }
+
+inline uint8_t PackedType(BitWidth bit_width, Type type) {
+ return static_cast<uint8_t>(bit_width | (type << 2));
+}
+
+inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); }
+
+// Vector accessors.
+// Note: if you try to access outside of bounds, you get a Null value back
+// instead. Normally this would be an assert, but since this is "dynamically
+// typed" data, you may not want that (someone sends you a 2d vector and you
+// wanted 3d).
+// The Null converts seamlessly into a default value for any other type.
+// TODO(wvo): Could introduce an #ifdef that makes this into an assert?
+inline Reference Vector::operator[](size_t i) const {
+ auto len = size();
+ if (i >= len) return Reference(nullptr, 1, NullPackedType());
+ auto packed_type = (data_ + len * byte_width_)[i];
+ auto elem = data_ + i * byte_width_;
+ return Reference(elem, byte_width_, packed_type);
+}
+
+inline Reference TypedVector::operator[](size_t i) const {
+ auto len = size();
+ if (i >= len) return Reference(nullptr, 1, NullPackedType());
+ auto elem = data_ + i * byte_width_;
+ return Reference(elem, byte_width_, 1, type_);
+}
+
+inline Reference FixedTypedVector::operator[](size_t i) const {
+ if (i >= len_) return Reference(nullptr, 1, NullPackedType());
+ auto elem = data_ + i * byte_width_;
+ return Reference(elem, byte_width_, 1, type_);
+}
+
+template<typename T> int KeyCompare(const void *key, const void *elem) {
+ auto str_elem = reinterpret_cast<const char *>(
+ Indirect<T>(reinterpret_cast<const uint8_t *>(elem)));
+ auto skey = reinterpret_cast<const char *>(key);
+ return strcmp(skey, str_elem);
+}
+
+inline Reference Map::operator[](const char *key) const {
+ auto keys = Keys();
+ // We can't pass keys.byte_width_ to the comparison function, so we have
+ // to pick the right one ahead of time.
+ int (*comp)(const void *, const void *) = nullptr;
+ switch (keys.byte_width_) {
+ case 1: comp = KeyCompare<uint8_t>; break;
+ case 2: comp = KeyCompare<uint16_t>; break;
+ case 4: comp = KeyCompare<uint32_t>; break;
+ case 8: comp = KeyCompare<uint64_t>; break;
+ }
+ auto res = std::bsearch(key, keys.data_, keys.size(), keys.byte_width_, comp);
+ if (!res) return Reference(nullptr, 1, NullPackedType());
+ auto i = (reinterpret_cast<uint8_t *>(res) - keys.data_) / keys.byte_width_;
+ return (*static_cast<const Vector *>(this))[i];
+}
+
+inline Reference Map::operator[](const std::string &key) const {
+ return (*this)[key.c_str()];
+}
+
+inline Reference GetRoot(const uint8_t *buffer, size_t size) {
+ // See Finish() below for the serialization counterpart of this.
+ // The root starts at the end of the buffer, so we parse backwards from there.
+ auto end = buffer + size;
+ auto byte_width = *--end;
+ auto packed_type = *--end;
+ end -= byte_width; // The root data item.
+ return Reference(end, byte_width, packed_type);
+}
+
+inline Reference GetRoot(const std::vector<uint8_t> &buffer) {
+ return GetRoot(flatbuffers::vector_data(buffer), buffer.size());
+}
+
+// Flags that configure how the Builder behaves.
+// The "Share" flags determine if the Builder automatically tries to pool
+// this type. Pooling can reduce the size of serialized data if there are
+// multiple maps of the same kind, at the expense of slightly slower
+// serialization (the cost of lookups) and more memory use (std::set).
+// By default this is on for keys, but off for strings.
+// Turn keys off if you have e.g. only one map.
+// Turn strings on if you expect many non-unique string values.
+// Additionally, sharing key vectors can save space if you have maps with
+// identical field populations.
+enum BuilderFlag {
+ BUILDER_FLAG_NONE = 0,
+ BUILDER_FLAG_SHARE_KEYS = 1,
+ BUILDER_FLAG_SHARE_STRINGS = 2,
+ BUILDER_FLAG_SHARE_KEYS_AND_STRINGS = 3,
+ BUILDER_FLAG_SHARE_KEY_VECTORS = 4,
+ BUILDER_FLAG_SHARE_ALL = 7,
+};
+
+class Builder FLATBUFFERS_FINAL_CLASS {
+ public:
+ Builder(size_t initial_size = 256,
+ BuilderFlag flags = BUILDER_FLAG_SHARE_KEYS)
+ : buf_(initial_size),
+ finished_(false),
+ flags_(flags),
+ force_min_bit_width_(BIT_WIDTH_8),
+ key_pool(KeyOffsetCompare(buf_)),
+ string_pool(StringOffsetCompare(buf_)) {
+ buf_.clear();
+ }
+
+ /// @brief Get the serialized buffer (after you call `Finish()`).
+ /// @return Returns a vector owned by this class.
+ const std::vector<uint8_t> &GetBuffer() const {
+ Finished();
+ return buf_;
+ }
+
+ // Size of the buffer. Does not include unfinished values.
+ size_t GetSize() const { return buf_.size(); }
+
+ // Reset all state so we can re-use the buffer.
+ void Clear() {
+ buf_.clear();
+ stack_.clear();
+ finished_ = false;
+ // flags_ remains as-is;
+ force_min_bit_width_ = BIT_WIDTH_8;
+ key_pool.clear();
+ string_pool.clear();
+ }
+
+ // All value constructing functions below have two versions: one that
+ // takes a key (for placement inside a map) and one that doesn't (for inside
+ // vectors and elsewhere).
+
+ void Null() { stack_.push_back(Value()); }
+ void Null(const char *key) {
+ Key(key);
+ Null();
+ }
+
+ void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); }
+ void Int(const char *key, int64_t i) {
+ Key(key);
+ Int(i);
+ }
+
+ void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); }
+ void UInt(const char *key, uint64_t u) {
+ Key(key);
+ UInt(u);
+ }
+
+ void Float(float f) { stack_.push_back(Value(f)); }
+ void Float(const char *key, float f) {
+ Key(key);
+ Float(f);
+ }
+
+ void Double(double f) { stack_.push_back(Value(f)); }
+ void Double(const char *key, double d) {
+ Key(key);
+ Double(d);
+ }
+
+ void Bool(bool b) { stack_.push_back(Value(b)); }
+ void Bool(const char *key, bool b) {
+ Key(key);
+ Bool(b);
+ }
+
+ void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); }
+ void IndirectInt(const char *key, int64_t i) {
+ Key(key);
+ IndirectInt(i);
+ }
+
+ void IndirectUInt(uint64_t u) {
+ PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u));
+ }
+ void IndirectUInt(const char *key, uint64_t u) {
+ Key(key);
+ IndirectUInt(u);
+ }
+
+ void IndirectFloat(float f) {
+ PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32);
+ }
+ void IndirectFloat(const char *key, float f) {
+ Key(key);
+ IndirectFloat(f);
+ }
+
+ void IndirectDouble(double f) {
+ PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f));
+ }
+ void IndirectDouble(const char *key, double d) {
+ Key(key);
+ IndirectDouble(d);
+ }
+
+ size_t Key(const char *str, size_t len) {
+ auto sloc = buf_.size();
+ WriteBytes(str, len + 1);
+ if (flags_ & BUILDER_FLAG_SHARE_KEYS) {
+ auto it = key_pool.find(sloc);
+ if (it != key_pool.end()) {
+ // Already in the buffer. Remove key we just serialized, and use
+ // existing offset instead.
+ buf_.resize(sloc);
+ sloc = *it;
+ } else {
+ key_pool.insert(sloc);
+ }
+ }
+ stack_.push_back(Value(static_cast<uint64_t>(sloc), FBT_KEY, BIT_WIDTH_8));
+ return sloc;
+ }
+
+ size_t Key(const char *str) { return Key(str, strlen(str)); }
+ size_t Key(const std::string &str) { return Key(str.c_str(), str.size()); }
+
+ size_t String(const char *str, size_t len) {
+ auto reset_to = buf_.size();
+ auto sloc = CreateBlob(str, len, 1, FBT_STRING);
+ if (flags_ & BUILDER_FLAG_SHARE_STRINGS) {
+ StringOffset so(sloc, len);
+ auto it = string_pool.find(so);
+ if (it != string_pool.end()) {
+ // Already in the buffer. Remove string we just serialized, and use
+ // existing offset instead.
+ buf_.resize(reset_to);
+ sloc = it->first;
+ stack_.back().u_ = sloc;
+ } else {
+ string_pool.insert(so);
+ }
+ }
+ return sloc;
+ }
+ size_t String(const char *str) { return String(str, strlen(str)); }
+ size_t String(const std::string &str) {
+ return String(str.c_str(), str.size());
+ }
+ void String(const flexbuffers::String &str) {
+ String(str.c_str(), str.length());
+ }
+
+ void String(const char *key, const char *str) {
+ Key(key);
+ String(str);
+ }
+ void String(const char *key, const std::string &str) {
+ Key(key);
+ String(str);
+ }
+ void String(const char *key, const flexbuffers::String &str) {
+ Key(key);
+ String(str);
+ }
+
+ size_t Blob(const void *data, size_t len) {
+ return CreateBlob(data, len, 0, FBT_BLOB);
+ }
+ size_t Blob(const std::vector<uint8_t> &v) {
+ return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, FBT_BLOB);
+ }
+
+ // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
+ // e.g. Vector etc. Also in overloaded versions.
+ // Also some FlatBuffers types?
+
+ size_t StartVector() { return stack_.size(); }
+ size_t StartVector(const char *key) {
+ Key(key);
+ return stack_.size();
+ }
+ size_t StartMap() { return stack_.size(); }
+ size_t StartMap(const char *key) {
+ Key(key);
+ return stack_.size();
+ }
+
+ // TODO(wvo): allow this to specify an aligment greater than the natural
+ // alignment.
+ size_t EndVector(size_t start, bool typed, bool fixed) {
+ auto vec = CreateVector(start, stack_.size() - start, 1, typed, fixed);
+ // Remove temp elements and return vector.
+ stack_.resize(start);
+ stack_.push_back(vec);
+ return static_cast<size_t>(vec.u_);
+ }
+
+ size_t EndMap(size_t start) {
+ // We should have interleaved keys and values on the stack.
+ // Make sure it is an even number:
+ auto len = stack_.size() - start;
+ FLATBUFFERS_ASSERT(!(len & 1));
+ len /= 2;
+ // Make sure keys are all strings:
+ for (auto key = start; key < stack_.size(); key += 2) {
+ FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY);
+ }
+ // Now sort values, so later we can do a binary seach lookup.
+ // We want to sort 2 array elements at a time.
+ struct TwoValue {
+ Value key;
+ Value val;
+ };
+ // TODO(wvo): strict aliasing?
+ // TODO(wvo): allow the caller to indicate the data is already sorted
+ // for maximum efficiency? With an assert to check sortedness to make sure
+ // we're not breaking binary search.
+ // Or, we can track if the map is sorted as keys are added which would be
+ // be quite cheap (cheaper than checking it here), so we can skip this
+ // step automatically when appliccable, and encourage people to write in
+ // sorted fashion.
+ // std::sort is typically already a lot faster on sorted data though.
+ auto dict =
+ reinterpret_cast<TwoValue *>(flatbuffers::vector_data(stack_) + start);
+ std::sort(dict, dict + len,
+ [&](const TwoValue &a, const TwoValue &b) -> bool {
+ auto as = reinterpret_cast<const char *>(
+ flatbuffers::vector_data(buf_) + a.key.u_);
+ auto bs = reinterpret_cast<const char *>(
+ flatbuffers::vector_data(buf_) + b.key.u_);
+ auto comp = strcmp(as, bs);
+ // If this assertion hits, you've added two keys with the same
+ // value to this map.
+ // TODO: Have to check for pointer equality, as some sort
+ // implementation apparently call this function with the same
+ // element?? Why?
+ FLATBUFFERS_ASSERT(comp || &a == &b);
+ return comp < 0;
+ });
+ // First create a vector out of all keys.
+ // TODO(wvo): if kBuilderFlagShareKeyVectors is true, see if we can share
+ // the first vector.
+ auto keys = CreateVector(start, len, 2, true, false);
+ auto vec = CreateVector(start + 1, len, 2, false, false, &keys);
+ // Remove temp elements and return map.
+ stack_.resize(start);
+ stack_.push_back(vec);
+ return static_cast<size_t>(vec.u_);
+ }
+
+ template<typename F> size_t Vector(F f) {
+ auto start = StartVector();
+ f();
+ return EndVector(start, false, false);
+ }
+ template<typename F, typename T> size_t Vector(F f, T &state) {
+ auto start = StartVector();
+ f(state);
+ return EndVector(start, false, false);
+ }
+ template<typename F> size_t Vector(const char *key, F f) {
+ auto start = StartVector(key);
+ f();
+ return EndVector(start, false, false);
+ }
+ template<typename F, typename T>
+ size_t Vector(const char *key, F f, T &state) {
+ auto start = StartVector(key);
+ f(state);
+ return EndVector(start, false, false);
+ }
+
+ template<typename T> void Vector(const T *elems, size_t len) {
+ if (flatbuffers::is_scalar<T>::value) {
+ // This path should be a lot quicker and use less space.
+ ScalarVector(elems, len, false);
+ } else {
+ auto start = StartVector();
+ for (size_t i = 0; i < len; i++) Add(elems[i]);
+ EndVector(start, false, false);
+ }
+ }
+ template<typename T>
+ void Vector(const char *key, const T *elems, size_t len) {
+ Key(key);
+ Vector(elems, len);
+ }
+ template<typename T> void Vector(const std::vector<T> &vec) {
+ Vector(flatbuffers::vector_data(vec), vec.size());
+ }
+
+ template<typename F> size_t TypedVector(F f) {
+ auto start = StartVector();
+ f();
+ return EndVector(start, true, false);
+ }
+ template<typename F, typename T> size_t TypedVector(F f, T &state) {
+ auto start = StartVector();
+ f(state);
+ return EndVector(start, true, false);
+ }
+ template<typename F> size_t TypedVector(const char *key, F f) {
+ auto start = StartVector(key);
+ f();
+ return EndVector(start, true, false);
+ }
+ template<typename F, typename T>
+ size_t TypedVector(const char *key, F f, T &state) {
+ auto start = StartVector(key);
+ f(state);
+ return EndVector(start, true, false);
+ }
+
+ template<typename T> size_t FixedTypedVector(const T *elems, size_t len) {
+ // We only support a few fixed vector lengths. Anything bigger use a
+ // regular typed vector.
+ FLATBUFFERS_ASSERT(len >= 2 && len <= 4);
+ // And only scalar values.
+ static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
+ return ScalarVector(elems, len, true);
+ }
+
+ template<typename T>
+ size_t FixedTypedVector(const char *key, const T *elems, size_t len) {
+ Key(key);
+ return FixedTypedVector(elems, len);
+ }
+
+ template<typename F> size_t Map(F f) {
+ auto start = StartMap();
+ f();
+ return EndMap(start);
+ }
+ template<typename F, typename T> size_t Map(F f, T &state) {
+ auto start = StartMap();
+ f(state);
+ return EndMap(start);
+ }
+ template<typename F> size_t Map(const char *key, F f) {
+ auto start = StartMap(key);
+ f();
+ return EndMap(start);
+ }
+ template<typename F, typename T> size_t Map(const char *key, F f, T &state) {
+ auto start = StartMap(key);
+ f(state);
+ return EndMap(start);
+ }
+ template<typename T> void Map(const std::map<std::string, T> &map) {
+ auto start = StartMap();
+ for (auto it = map.begin(); it != map.end(); ++it)
+ Add(it->first.c_str(), it->second);
+ EndMap(start);
+ }
+
+ // Overloaded Add that tries to call the correct function above.
+ void Add(int8_t i) { Int(i); }
+ void Add(int16_t i) { Int(i); }
+ void Add(int32_t i) { Int(i); }
+ void Add(int64_t i) { Int(i); }
+ void Add(uint8_t u) { UInt(u); }
+ void Add(uint16_t u) { UInt(u); }
+ void Add(uint32_t u) { UInt(u); }
+ void Add(uint64_t u) { UInt(u); }
+ void Add(float f) { Float(f); }
+ void Add(double d) { Double(d); }
+ void Add(bool b) { Bool(b); }
+ void Add(const char *str) { String(str); }
+ void Add(const std::string &str) { String(str); }
+ void Add(const flexbuffers::String &str) { String(str); }
+
+ template<typename T> void Add(const std::vector<T> &vec) { Vector(vec); }
+
+ template<typename T> void Add(const char *key, const T &t) {
+ Key(key);
+ Add(t);
+ }
+
+ template<typename T> void Add(const std::map<std::string, T> &map) {
+ Map(map);
+ }
+
+ template<typename T> void operator+=(const T &t) { Add(t); }
+
+ // This function is useful in combination with the Mutate* functions above.
+ // It forces elements of vectors and maps to have a minimum size, such that
+ // they can later be updated without failing.
+ // Call with no arguments to reset.
+ void ForceMinimumBitWidth(BitWidth bw = BIT_WIDTH_8) {
+ force_min_bit_width_ = bw;
+ }
+
+ void Finish() {
+ // If you hit this assert, you likely have objects that were never included
+ // in a parent. You need to have exactly one root to finish a buffer.
+ // Check your Start/End calls are matched, and all objects are inside
+ // some other object.
+ FLATBUFFERS_ASSERT(stack_.size() == 1);
+
+ // Write root value.
+ auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0));
+ WriteAny(stack_[0], byte_width);
+ // Write root type.
+ Write(stack_[0].StoredPackedType(), 1);
+ // Write root size. Normally determined by parent, but root has no parent :)
+ Write(byte_width, 1);
+
+ finished_ = true;
+ }
+
+ private:
+ void Finished() const {
+ // If you get this assert, you're attempting to get access a buffer
+ // which hasn't been finished yet. Be sure to call
+ // Builder::Finish with your root object.
+ FLATBUFFERS_ASSERT(finished_);
+ }
+
+ // Align to prepare for writing a scalar with a certain size.
+ uint8_t Align(BitWidth alignment) {
+ auto byte_width = 1U << alignment;
+ buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width),
+ 0);
+ return static_cast<uint8_t>(byte_width);
+ }
+
+ void WriteBytes(const void *val, size_t size) {
+ buf_.insert(buf_.end(), reinterpret_cast<const uint8_t *>(val),
+ reinterpret_cast<const uint8_t *>(val) + size);
+ }
+
+ template<typename T> void Write(T val, size_t byte_width) {
+ FLATBUFFERS_ASSERT(sizeof(T) >= byte_width);
+ val = flatbuffers::EndianScalar(val);
+ WriteBytes(&val, byte_width);
+ }
+
+ void WriteDouble(double f, uint8_t byte_width) {
+ switch (byte_width) {
+ case 8: Write(f, byte_width); break;
+ case 4: Write(static_cast<float>(f), byte_width); break;
+ // case 2: Write(static_cast<half>(f), byte_width); break;
+ // case 1: Write(static_cast<quarter>(f), byte_width); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+
+ void WriteOffset(uint64_t o, uint8_t byte_width) {
+ auto reloff = buf_.size() - o;
+ FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8));
+ Write(reloff, byte_width);
+ }
+
+ template<typename T> void PushIndirect(T val, Type type, BitWidth bit_width) {
+ auto byte_width = Align(bit_width);
+ auto iloc = buf_.size();
+ Write(val, byte_width);
+ stack_.push_back(Value(static_cast<uint64_t>(iloc), type, bit_width));
+ }
+
+ static BitWidth WidthB(size_t byte_width) {
+ switch (byte_width) {
+ case 1: return BIT_WIDTH_8;
+ case 2: return BIT_WIDTH_16;
+ case 4: return BIT_WIDTH_32;
+ case 8: return BIT_WIDTH_64;
+ default: FLATBUFFERS_ASSERT(false); return BIT_WIDTH_64;
+ }
+ }
+
+ template<typename T> static Type GetScalarType() {
+ static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types");
+ return flatbuffers::is_floating_point<T>::value
+ ? FBT_FLOAT
+ : flatbuffers::is_same<T, bool>::value
+ ? FBT_BOOL
+ : (flatbuffers::is_unsigned<T>::value ? FBT_UINT
+ : FBT_INT);
+ }
+
+ struct Value {
+ union {
+ int64_t i_;
+ uint64_t u_;
+ double f_;
+ };
+
+ Type type_;
+
+ // For scalars: of itself, for vector: of its elements, for string: length.
+ BitWidth min_bit_width_;
+
+ Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {}
+
+ Value(bool b)
+ : u_(static_cast<uint64_t>(b)),
+ type_(FBT_BOOL),
+ min_bit_width_(BIT_WIDTH_8) {}
+
+ Value(int64_t i, Type t, BitWidth bw)
+ : i_(i), type_(t), min_bit_width_(bw) {}
+ Value(uint64_t u, Type t, BitWidth bw)
+ : u_(u), type_(t), min_bit_width_(bw) {}
+
+ Value(float f) : f_(f), type_(FBT_FLOAT), min_bit_width_(BIT_WIDTH_32) {}
+ Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {}
+
+ uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
+ return PackedType(StoredWidth(parent_bit_width_), type_);
+ }
+
+ BitWidth ElemWidth(size_t buf_size, size_t elem_index) const {
+ if (IsInline(type_)) {
+ return min_bit_width_;
+ } else {
+ // We have an absolute offset, but want to store a relative offset
+ // elem_index elements beyond the current buffer end. Since whether
+ // the relative offset fits in a certain byte_width depends on
+ // the size of the elements before it (and their alignment), we have
+ // to test for each size in turn.
+ for (size_t byte_width = 1;
+ byte_width <= sizeof(flatbuffers::largest_scalar_t);
+ byte_width *= 2) {
+ // Where are we going to write this offset?
+ auto offset_loc = buf_size +
+ flatbuffers::PaddingBytes(buf_size, byte_width) +
+ elem_index * byte_width;
+ // Compute relative offset.
+ auto offset = offset_loc - u_;
+ // Does it fit?
+ auto bit_width = WidthU(offset);
+ if (static_cast<size_t>(static_cast<size_t>(1U) << bit_width) ==
+ byte_width)
+ return bit_width;
+ }
+ FLATBUFFERS_ASSERT(false); // Must match one of the sizes above.
+ return BIT_WIDTH_64;
+ }
+ }
+
+ BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
+ if (IsInline(type_)) {
+ return (std::max)(min_bit_width_, parent_bit_width_);
+ } else {
+ return min_bit_width_;
+ }
+ }
+ };
+
+ void WriteAny(const Value &val, uint8_t byte_width) {
+ switch (val.type_) {
+ case FBT_NULL:
+ case FBT_INT: Write(val.i_, byte_width); break;
+ case FBT_BOOL:
+ case FBT_UINT: Write(val.u_, byte_width); break;
+ case FBT_FLOAT: WriteDouble(val.f_, byte_width); break;
+ default: WriteOffset(val.u_, byte_width); break;
+ }
+ }
+
+ size_t CreateBlob(const void *data, size_t len, size_t trailing, Type type) {
+ auto bit_width = WidthU(len);
+ auto byte_width = Align(bit_width);
+ Write<uint64_t>(len, byte_width);
+ auto sloc = buf_.size();
+ WriteBytes(data, len + trailing);
+ stack_.push_back(Value(static_cast<uint64_t>(sloc), type, bit_width));
+ return sloc;
+ }
+
+ template<typename T>
+ size_t ScalarVector(const T *elems, size_t len, bool fixed) {
+ auto vector_type = GetScalarType<T>();
+ auto byte_width = sizeof(T);
+ auto bit_width = WidthB(byte_width);
+ // If you get this assert, you're trying to write a vector with a size
+ // field that is bigger than the scalars you're trying to write (e.g. a
+ // byte vector > 255 elements). For such types, write a "blob" instead.
+ // TODO: instead of asserting, could write vector with larger elements
+ // instead, though that would be wasteful.
+ FLATBUFFERS_ASSERT(WidthU(len) <= bit_width);
+ if (!fixed) Write<uint64_t>(len, byte_width);
+ auto vloc = buf_.size();
+ for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
+ stack_.push_back(Value(static_cast<uint64_t>(vloc),
+ ToTypedVector(vector_type, fixed ? len : 0),
+ bit_width));
+ return vloc;
+ }
+
+ Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
+ bool fixed, const Value *keys = nullptr) {
+ FLATBUFFERS_ASSERT(!fixed || typed); // typed=false, fixed=true combination is not supported.
+ // Figure out smallest bit width we can store this vector with.
+ auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len));
+ auto prefix_elems = 1;
+ if (keys) {
+ // If this vector is part of a map, we will pre-fix an offset to the keys
+ // to this vector.
+ bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0));
+ prefix_elems += 2;
+ }
+ Type vector_type = FBT_KEY;
+ // Check bit widths and types for all elements.
+ for (size_t i = start; i < stack_.size(); i += step) {
+ auto elem_width = stack_[i].ElemWidth(buf_.size(), i + prefix_elems);
+ bit_width = (std::max)(bit_width, elem_width);
+ if (typed) {
+ if (i == start) {
+ vector_type = stack_[i].type_;
+ } else {
+ // If you get this assert, you are writing a typed vector with
+ // elements that are not all the same type.
+ FLATBUFFERS_ASSERT(vector_type == stack_[i].type_);
+ }
+ }
+ }
+ // If you get this assert, your fixed types are not one of:
+ // Int / UInt / Float / Key.
+ FLATBUFFERS_ASSERT(!fixed || IsTypedVectorElementType(vector_type));
+ auto byte_width = Align(bit_width);
+ // Write vector. First the keys width/offset if available, and size.
+ if (keys) {
+ WriteOffset(keys->u_, byte_width);
+ Write<uint64_t>(1ULL << keys->min_bit_width_, byte_width);
+ }
+ if (!fixed) Write<uint64_t>(vec_len, byte_width);
+ // Then the actual data.
+ auto vloc = buf_.size();
+ for (size_t i = start; i < stack_.size(); i += step) {
+ WriteAny(stack_[i], byte_width);
+ }
+ // Then the types.
+ if (!typed) {
+ for (size_t i = start; i < stack_.size(); i += step) {
+ buf_.push_back(stack_[i].StoredPackedType(bit_width));
+ }
+ }
+ return Value(static_cast<uint64_t>(vloc),
+ keys ? FBT_MAP
+ : (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0)
+ : FBT_VECTOR),
+ bit_width);
+ }
+
+ // You shouldn't really be copying instances of this class.
+ Builder(const Builder &);
+ Builder &operator=(const Builder &);
+
+ std::vector<uint8_t> buf_;
+ std::vector<Value> stack_;
+
+ bool finished_;
+
+ BuilderFlag flags_;
+
+ BitWidth force_min_bit_width_;
+
+ struct KeyOffsetCompare {
+ explicit KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
+ bool operator()(size_t a, size_t b) const {
+ auto stra =
+ reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + a);
+ auto strb =
+ reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + b);
+ return strcmp(stra, strb) < 0;
+ }
+ const std::vector<uint8_t> *buf_;
+ };
+
+ typedef std::pair<size_t, size_t> StringOffset;
+ struct StringOffsetCompare {
+ explicit StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
+ bool operator()(const StringOffset &a, const StringOffset &b) const {
+ auto stra = reinterpret_cast<const char *>(
+ flatbuffers::vector_data(*buf_) + a.first);
+ auto strb = reinterpret_cast<const char *>(
+ flatbuffers::vector_data(*buf_) + b.first);
+ return strncmp(stra, strb, (std::min)(a.second, b.second) + 1) < 0;
+ }
+ const std::vector<uint8_t> *buf_;
+ };
+
+ typedef std::set<size_t, KeyOffsetCompare> KeyOffsetMap;
+ typedef std::set<StringOffset, StringOffsetCompare> StringOffsetMap;
+
+ KeyOffsetMap key_pool;
+ StringOffsetMap string_pool;
+};
+
+} // namespace flexbuffers
+
+# if defined(_MSC_VER)
+# pragma warning(pop)
+# endif
+
+#endif // FLATBUFFERS_FLEXBUFFERS_H_
diff --git a/include/flatbuffers/grpc.h b/include/flatbuffers/grpc.h
new file mode 100644
index 0000000..a75b67c
--- /dev/null
+++ b/include/flatbuffers/grpc.h
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_GRPC_H_
+#define FLATBUFFERS_GRPC_H_
+
+// Helper functionality to glue FlatBuffers and GRPC.
+
+#include "flatbuffers/flatbuffers.h"
+#include "grpc++/support/byte_buffer.h"
+#include "grpc/byte_buffer_reader.h"
+
+namespace flatbuffers {
+namespace grpc {
+
+// Message is a typed wrapper around a buffer that manages the underlying
+// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
+// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
+// is refcounted and ownership is be managed automatically.
+template<class T> class Message {
+ public:
+ Message() : slice_(grpc_empty_slice()) {}
+
+ Message(grpc_slice slice, bool add_ref)
+ : slice_(add_ref ? grpc_slice_ref(slice) : slice) {}
+
+ Message &operator=(const Message &other) = delete;
+
+ Message(Message &&other) : slice_(other.slice_) {
+ other.slice_ = grpc_empty_slice();
+ }
+
+ Message(const Message &other) = delete;
+
+ Message &operator=(Message &&other) {
+ grpc_slice_unref(slice_);
+ slice_ = other.slice_;
+ other.slice_ = grpc_empty_slice();
+ return *this;
+ }
+
+ ~Message() { grpc_slice_unref(slice_); }
+
+ const uint8_t *mutable_data() const { return GRPC_SLICE_START_PTR(slice_); }
+
+ const uint8_t *data() const { return GRPC_SLICE_START_PTR(slice_); }
+
+ size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
+
+ bool Verify() const {
+ Verifier verifier(data(), size());
+ return verifier.VerifyBuffer<T>(nullptr);
+ }
+
+ T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
+
+ const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
+
+ // This is only intended for serializer use, or if you know what you're doing
+ const grpc_slice &BorrowSlice() const { return slice_; }
+
+ private:
+ grpc_slice slice_;
+};
+
+class MessageBuilder;
+
+// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
+// refcounted slices to manage memory ownership. This makes it easy and
+// efficient to transfer buffers to gRPC.
+class SliceAllocator : public Allocator {
+ public:
+ SliceAllocator() : slice_(grpc_empty_slice()) {}
+
+ SliceAllocator(const SliceAllocator &other) = delete;
+ SliceAllocator &operator=(const SliceAllocator &other) = delete;
+
+ SliceAllocator(SliceAllocator &&other)
+ : slice_(grpc_empty_slice()) {
+ // default-construct and swap idiom
+ swap(other);
+ }
+
+ SliceAllocator &operator=(SliceAllocator &&other) {
+ // move-construct and swap idiom
+ SliceAllocator temp(std::move(other));
+ swap(temp);
+ return *this;
+ }
+
+ void swap(SliceAllocator &other) {
+ using std::swap;
+ swap(slice_, other.slice_);
+ }
+
+ virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
+
+ virtual uint8_t *allocate(size_t size) override {
+ FLATBUFFERS_ASSERT(GRPC_SLICE_IS_EMPTY(slice_));
+ slice_ = grpc_slice_malloc(size);
+ return GRPC_SLICE_START_PTR(slice_);
+ }
+
+ virtual void deallocate(uint8_t *p, size_t size) override {
+ FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
+ FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
+ grpc_slice_unref(slice_);
+ slice_ = grpc_empty_slice();
+ }
+
+ virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
+ size_t new_size, size_t in_use_back,
+ size_t in_use_front) override {
+ FLATBUFFERS_ASSERT(old_p == GRPC_SLICE_START_PTR(slice_));
+ FLATBUFFERS_ASSERT(old_size == GRPC_SLICE_LENGTH(slice_));
+ FLATBUFFERS_ASSERT(new_size > old_size);
+ grpc_slice old_slice = slice_;
+ grpc_slice new_slice = grpc_slice_malloc(new_size);
+ uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
+ memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
+ in_use_front);
+ slice_ = new_slice;
+ grpc_slice_unref(old_slice);
+ return new_p;
+ }
+
+ private:
+ grpc_slice &get_slice(uint8_t *p, size_t size) {
+ FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
+ FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
+ return slice_;
+ }
+
+ grpc_slice slice_;
+
+ friend class MessageBuilder;
+};
+
+// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
+// slice_allocator_ member is constructed before the FlatBufferBuilder, since
+// the allocator is used in the FlatBufferBuilder ctor.
+namespace detail {
+struct SliceAllocatorMember {
+ SliceAllocator slice_allocator_;
+};
+} // namespace detail
+
+// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
+// to allocate gRPC buffers.
+class MessageBuilder : private detail::SliceAllocatorMember,
+ public FlatBufferBuilder {
+ public:
+ explicit MessageBuilder(uoffset_t initial_size = 1024)
+ : FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
+
+ MessageBuilder(const MessageBuilder &other) = delete;
+ MessageBuilder &operator=(const MessageBuilder &other) = delete;
+
+ MessageBuilder(MessageBuilder &&other)
+ : FlatBufferBuilder(1024, &slice_allocator_, false) {
+ // Default construct and swap idiom.
+ Swap(other);
+ }
+
+ /// Create a MessageBuilder from a FlatBufferBuilder.
+ explicit MessageBuilder(FlatBufferBuilder &&src, void (*dealloc)(void*, size_t) = &DefaultAllocator::dealloc)
+ : FlatBufferBuilder(1024, &slice_allocator_, false) {
+ src.Swap(*this);
+ src.SwapBufAllocator(*this);
+ if (buf_.capacity()) {
+ uint8_t *buf = buf_.scratch_data(); // pointer to memory
+ size_t capacity = buf_.capacity(); // size of memory
+ slice_allocator_.slice_ = grpc_slice_new_with_len(buf, capacity, dealloc);
+ }
+ else {
+ slice_allocator_.slice_ = grpc_empty_slice();
+ }
+ }
+
+ /// Move-assign a FlatBufferBuilder to a MessageBuilder.
+ /// Only FlatBufferBuilder with default allocator (basically, nullptr) is supported.
+ MessageBuilder &operator=(FlatBufferBuilder &&src) {
+ // Move construct a temporary and swap
+ MessageBuilder temp(std::move(src));
+ Swap(temp);
+ return *this;
+ }
+
+ MessageBuilder &operator=(MessageBuilder &&other) {
+ // Move construct a temporary and swap
+ MessageBuilder temp(std::move(other));
+ Swap(temp);
+ return *this;
+ }
+
+ void Swap(MessageBuilder &other) {
+ slice_allocator_.swap(other.slice_allocator_);
+ FlatBufferBuilder::Swap(other);
+ // After swapping the FlatBufferBuilder, we swap back the allocator, which restores
+ // the original allocator back in place. This is necessary because MessageBuilder's
+ // allocator is its own member (SliceAllocatorMember). The allocator passed to
+ // FlatBufferBuilder::vector_downward must point to this member.
+ buf_.swap_allocator(other.buf_);
+ }
+
+ // Releases the ownership of the buffer pointer.
+ // Returns the size, offset, and the original grpc_slice that
+ // allocated the buffer. Also see grpc_slice_unref().
+ uint8_t *ReleaseRaw(size_t &size, size_t &offset, grpc_slice &slice) {
+ uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset);
+ slice = slice_allocator_.slice_;
+ slice_allocator_.slice_ = grpc_empty_slice();
+ return buf;
+ }
+
+ ~MessageBuilder() {}
+
+ // GetMessage extracts the subslice of the buffer corresponding to the
+ // flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
+ // ownership.
+ template<class T> Message<T> GetMessage() {
+ auto buf_data = buf_.scratch_data(); // pointer to memory
+ auto buf_size = buf_.capacity(); // size of memory
+ auto msg_data = buf_.data(); // pointer to msg
+ auto msg_size = buf_.size(); // size of msg
+ // Do some sanity checks on data/size
+ FLATBUFFERS_ASSERT(msg_data);
+ FLATBUFFERS_ASSERT(msg_size);
+ FLATBUFFERS_ASSERT(msg_data >= buf_data);
+ FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size);
+ // Calculate offsets from the buffer start
+ auto begin = msg_data - buf_data;
+ auto end = begin + msg_size;
+ // Get the slice we are working with (no refcount change)
+ grpc_slice slice = slice_allocator_.get_slice(buf_data, buf_size);
+ // Extract a subslice of the existing slice (increment refcount)
+ grpc_slice subslice = grpc_slice_sub(slice, begin, end);
+ // Wrap the subslice in a `Message<T>`, but don't increment refcount
+ Message<T> msg(subslice, false);
+ return msg;
+ }
+
+ template<class T> Message<T> ReleaseMessage() {
+ Message<T> msg = GetMessage<T>();
+ Reset();
+ return msg;
+ }
+
+ private:
+ // SliceAllocator slice_allocator_; // part of SliceAllocatorMember
+};
+
+} // namespace grpc
+} // namespace flatbuffers
+
+namespace grpc {
+
+template<class T> class SerializationTraits<flatbuffers::grpc::Message<T>> {
+ public:
+ static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg,
+ grpc_byte_buffer **buffer, bool *own_buffer) {
+ // We are passed in a `Message<T>`, which is a wrapper around a
+ // `grpc_slice`. We extract it here using `BorrowSlice()`. The const cast
+ // is necesary because the `grpc_raw_byte_buffer_create` func expects
+ // non-const slices in order to increment their refcounts.
+ grpc_slice *slice = const_cast<grpc_slice *>(&msg.BorrowSlice());
+ // Now use `grpc_raw_byte_buffer_create` to package the single slice into a
+ // `grpc_byte_buffer`, incrementing the refcount in the process.
+ *buffer = grpc_raw_byte_buffer_create(slice, 1);
+ *own_buffer = true;
+ return grpc::Status::OK;
+ }
+
+ // Deserialize by pulling the
+ static grpc::Status Deserialize(grpc_byte_buffer *buffer,
+ flatbuffers::grpc::Message<T> *msg) {
+ if (!buffer) {
+ return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
+ }
+ // Check if this is a single uncompressed slice.
+ if ((buffer->type == GRPC_BB_RAW) &&
+ (buffer->data.raw.compression == GRPC_COMPRESS_NONE) &&
+ (buffer->data.raw.slice_buffer.count == 1)) {
+ // If it is, then we can reference the `grpc_slice` directly.
+ grpc_slice slice = buffer->data.raw.slice_buffer.slices[0];
+ // We wrap a `Message<T>` around the slice, incrementing the refcount.
+ *msg = flatbuffers::grpc::Message<T>(slice, true);
+ } else {
+ // Otherwise, we need to use `grpc_byte_buffer_reader_readall` to read
+ // `buffer` into a single contiguous `grpc_slice`. The gRPC reader gives
+ // us back a new slice with the refcount already incremented.
+ grpc_byte_buffer_reader reader;
+ grpc_byte_buffer_reader_init(&reader, buffer);
+ grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
+ grpc_byte_buffer_reader_destroy(&reader);
+ // We wrap a `Message<T>` around the slice, but dont increment refcount
+ *msg = flatbuffers::grpc::Message<T>(slice, false);
+ }
+ grpc_byte_buffer_destroy(buffer);
+#if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
+ return ::grpc::Status::OK;
+#else
+ if (msg->Verify()) {
+ return ::grpc::Status::OK;
+ } else {
+ return ::grpc::Status(::grpc::StatusCode::INTERNAL,
+ "Message verification failed");
+ }
+#endif
+ }
+};
+
+} // namespace grpc
+
+#endif // FLATBUFFERS_GRPC_H_
diff --git a/include/flatbuffers/hash.h b/include/flatbuffers/hash.h
new file mode 100644
index 0000000..16536cb
--- /dev/null
+++ b/include/flatbuffers/hash.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_HASH_H_
+#define FLATBUFFERS_HASH_H_
+
+#include <cstdint>
+#include <cstring>
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace flatbuffers {
+
+template<typename T> struct FnvTraits {
+ static const T kFnvPrime;
+ static const T kOffsetBasis;
+};
+
+template<> struct FnvTraits<uint32_t> {
+ static const uint32_t kFnvPrime = 0x01000193;
+ static const uint32_t kOffsetBasis = 0x811C9DC5;
+};
+
+template<> struct FnvTraits<uint64_t> {
+ static const uint64_t kFnvPrime = 0x00000100000001b3ULL;
+ static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL;
+};
+
+template<typename T> T HashFnv1(const char *input) {
+ T hash = FnvTraits<T>::kOffsetBasis;
+ for (const char *c = input; *c; ++c) {
+ hash *= FnvTraits<T>::kFnvPrime;
+ hash ^= static_cast<unsigned char>(*c);
+ }
+ return hash;
+}
+
+template<typename T> T HashFnv1a(const char *input) {
+ T hash = FnvTraits<T>::kOffsetBasis;
+ for (const char *c = input; *c; ++c) {
+ hash ^= static_cast<unsigned char>(*c);
+ hash *= FnvTraits<T>::kFnvPrime;
+ }
+ return hash;
+}
+
+template <> inline uint16_t HashFnv1<uint16_t>(const char *input) {
+ uint32_t hash = HashFnv1<uint32_t>(input);
+ return (hash >> 16) ^ (hash & 0xffff);
+}
+
+template <> inline uint16_t HashFnv1a<uint16_t>(const char *input) {
+ uint32_t hash = HashFnv1a<uint32_t>(input);
+ return (hash >> 16) ^ (hash & 0xffff);
+}
+
+template <typename T> struct NamedHashFunction {
+ const char *name;
+
+ typedef T (*HashFunction)(const char *);
+ HashFunction function;
+};
+
+const NamedHashFunction<uint16_t> kHashFunctions16[] = {
+ { "fnv1_16", HashFnv1<uint16_t> },
+ { "fnv1a_16", HashFnv1a<uint16_t> },
+};
+
+const NamedHashFunction<uint32_t> kHashFunctions32[] = {
+ { "fnv1_32", HashFnv1<uint32_t> },
+ { "fnv1a_32", HashFnv1a<uint32_t> },
+};
+
+const NamedHashFunction<uint64_t> kHashFunctions64[] = {
+ { "fnv1_64", HashFnv1<uint64_t> },
+ { "fnv1a_64", HashFnv1a<uint64_t> },
+};
+
+inline NamedHashFunction<uint16_t>::HashFunction FindHashFunction16(
+ const char *name) {
+ std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]);
+ for (std::size_t i = 0; i < size; ++i) {
+ if (std::strcmp(name, kHashFunctions16[i].name) == 0) {
+ return kHashFunctions16[i].function;
+ }
+ }
+ return nullptr;
+}
+
+inline NamedHashFunction<uint32_t>::HashFunction FindHashFunction32(
+ const char *name) {
+ std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]);
+ for (std::size_t i = 0; i < size; ++i) {
+ if (std::strcmp(name, kHashFunctions32[i].name) == 0) {
+ return kHashFunctions32[i].function;
+ }
+ }
+ return nullptr;
+}
+
+inline NamedHashFunction<uint64_t>::HashFunction FindHashFunction64(
+ const char *name) {
+ std::size_t size = sizeof(kHashFunctions64) / sizeof(kHashFunctions64[0]);
+ for (std::size_t i = 0; i < size; ++i) {
+ if (std::strcmp(name, kHashFunctions64[i].name) == 0) {
+ return kHashFunctions64[i].function;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_HASH_H_
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
new file mode 100644
index 0000000..44e3566
--- /dev/null
+++ b/include/flatbuffers/idl.h
@@ -0,0 +1,1093 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_IDL_H_
+#define FLATBUFFERS_IDL_H_
+
+#include <map>
+#include <memory>
+#include <stack>
+
+#include "flatbuffers/base.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flexbuffers.h"
+#include "flatbuffers/hash.h"
+#include "flatbuffers/reflection.h"
+
+#if !defined(FLATBUFFERS_CPP98_STL)
+# include <functional>
+#endif // !defined(FLATBUFFERS_CPP98_STL)
+
+// This file defines the data types representing a parsed IDL (Interface
+// Definition Language) / schema file.
+
+// Limits maximum depth of nested objects.
+// Prevents stack overflow while parse flatbuffers or json.
+#if !defined(FLATBUFFERS_MAX_PARSING_DEPTH)
+# define FLATBUFFERS_MAX_PARSING_DEPTH 64
+#endif
+
+namespace flatbuffers {
+
+// The order of these matters for Is*() functions below.
+// Additionally, Parser::ParseType assumes bool..string is a contiguous range
+// of type tokens.
+// clang-format off
+#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
+ TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8, UByte) \
+ TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8, UByte) /* begin scalar/int */ \
+ TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool, Boolean) \
+ TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8, Byte) \
+ TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8, UByte) \
+ TD(SHORT, "short", int16_t, short, int16, short, int16, i16, Short) \
+ TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16, UShort) \
+ TD(INT, "int", int32_t, int, int32, int, int32, i32, Int) \
+ TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32, UInt) \
+ TD(LONG, "long", int64_t, long, int64, long, int64, i64, Long) \
+ TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64, ULong) /* end int */ \
+ TD(FLOAT, "float", float, float, float32, float, float32, f32, Float) /* begin float */ \
+ TD(DOUBLE, "double", double, double, float64, double, float64, f64, Double) /* end float/scalar */
+#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \
+ TD(STRING, "string", Offset<void>, int, int, StringOffset, int, unused, Int) \
+ TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused, Int) \
+ TD(STRUCT, "", Offset<void>, int, int, int, int, unused, Int) \
+ TD(UNION, "", Offset<void>, int, int, int, int, unused, Int)
+#define FLATBUFFERS_GEN_TYPE_ARRAY(TD) \
+ TD(ARRAY, "", int, int, int, int, int, unused, Int)
+// The fields are:
+// - enum
+// - FlatBuffers schema type.
+// - C++ type.
+// - Java type.
+// - Go type.
+// - C# / .Net type.
+// - Python type.
+// - Rust type.
+// - Kotlin type.
+
+// using these macros, we can now write code dealing with types just once, e.g.
+
+/*
+switch (type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ // do something specific to CTYPE here
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+}
+*/
+
+#define FLATBUFFERS_GEN_TYPES(TD) \
+ FLATBUFFERS_GEN_TYPES_SCALAR(TD) \
+ FLATBUFFERS_GEN_TYPES_POINTER(TD) \
+ FLATBUFFERS_GEN_TYPE_ARRAY(TD)
+
+// Create an enum for all the types above.
+#ifdef __GNUC__
+__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
+#endif
+enum BaseType {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, KTYPE) \
+ BASE_TYPE_ ## ENUM,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+};
+
+#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, KTYPE) \
+ static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \
+ "define largest_scalar_t as " #CTYPE);
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+#undef FLATBUFFERS_TD
+
+inline bool IsScalar (BaseType t) { return t >= BASE_TYPE_UTYPE &&
+ t <= BASE_TYPE_DOUBLE; }
+inline bool IsInteger(BaseType t) { return t >= BASE_TYPE_UTYPE &&
+ t <= BASE_TYPE_ULONG; }
+inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT ||
+ t == BASE_TYPE_DOUBLE; }
+inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG ||
+ t == BASE_TYPE_ULONG; }
+inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; }
+inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE &&
+ t <= BASE_TYPE_UCHAR; }
+
+inline bool IsUnsigned(BaseType t) {
+ return (t == BASE_TYPE_UTYPE) || (t == BASE_TYPE_UCHAR) ||
+ (t == BASE_TYPE_USHORT) || (t == BASE_TYPE_UINT) ||
+ (t == BASE_TYPE_ULONG);
+}
+
+// clang-format on
+
+extern const char *const kTypeNames[];
+extern const char kTypeSizes[];
+
+inline size_t SizeOf(BaseType t) { return kTypeSizes[t]; }
+
+struct StructDef;
+struct EnumDef;
+class Parser;
+
+// Represents any type in the IDL, which is a combination of the BaseType
+// and additional information for vectors/structs_.
+struct Type {
+ explicit Type(BaseType _base_type = BASE_TYPE_NONE, StructDef *_sd = nullptr,
+ EnumDef *_ed = nullptr, uint16_t _fixed_length = 0)
+ : base_type(_base_type),
+ element(BASE_TYPE_NONE),
+ struct_def(_sd),
+ enum_def(_ed),
+ fixed_length(_fixed_length) {}
+
+ bool operator==(const Type &o) {
+ return base_type == o.base_type && element == o.element &&
+ struct_def == o.struct_def && enum_def == o.enum_def;
+ }
+
+ Type VectorType() const {
+ return Type(element, struct_def, enum_def, fixed_length);
+ }
+
+ Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const;
+
+ bool Deserialize(const Parser &parser, const reflection::Type *type);
+
+ BaseType base_type;
+ BaseType element; // only set if t == BASE_TYPE_VECTOR
+ StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT
+ EnumDef *enum_def; // set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE,
+ // or for an integral type derived from an enum.
+ uint16_t fixed_length; // only set if t == BASE_TYPE_ARRAY
+};
+
+// Represents a parsed scalar value, it's type, and field offset.
+struct Value {
+ Value()
+ : constant("0"),
+ offset(static_cast<voffset_t>(~(static_cast<voffset_t>(0U)))) {}
+ Type type;
+ std::string constant;
+ voffset_t offset;
+};
+
+// Helper class that retains the original order of a set of identifiers and
+// also provides quick lookup.
+template<typename T> class SymbolTable {
+ public:
+ ~SymbolTable() {
+ for (auto it = vec.begin(); it != vec.end(); ++it) { delete *it; }
+ }
+
+ bool Add(const std::string &name, T *e) {
+ vector_emplace_back(&vec, e);
+ auto it = dict.find(name);
+ if (it != dict.end()) return true;
+ dict[name] = e;
+ return false;
+ }
+
+ void Move(const std::string &oldname, const std::string &newname) {
+ auto it = dict.find(oldname);
+ if (it != dict.end()) {
+ auto obj = it->second;
+ dict.erase(it);
+ dict[newname] = obj;
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ }
+
+ T *Lookup(const std::string &name) const {
+ auto it = dict.find(name);
+ return it == dict.end() ? nullptr : it->second;
+ }
+
+ public:
+ std::map<std::string, T *> dict; // quick lookup
+ std::vector<T *> vec; // Used to iterate in order of insertion
+};
+
+// A name space, as set in the schema.
+struct Namespace {
+ Namespace() : from_table(0) {}
+
+ // Given a (potentally unqualified) name, return the "fully qualified" name
+ // which has a full namespaced descriptor.
+ // With max_components you can request less than the number of components
+ // the current namespace has.
+ std::string GetFullyQualifiedName(const std::string &name,
+ size_t max_components = 1000) const;
+
+ std::vector<std::string> components;
+ size_t from_table; // Part of the namespace corresponds to a message/table.
+};
+
+inline bool operator<(const Namespace &a, const Namespace &b) {
+ size_t min_size = std::min(a.components.size(), b.components.size());
+ for (size_t i = 0; i < min_size; ++i) {
+ if (a.components[i] != b.components[i])
+ return a.components[i] < b.components[i];
+ }
+ return a.components.size() < b.components.size();
+}
+
+// Base class for all definition types (fields, structs_, enums_).
+struct Definition {
+ Definition()
+ : generated(false),
+ defined_namespace(nullptr),
+ serialized_location(0),
+ index(-1),
+ refcount(1) {}
+
+ flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
+ SerializeAttributes(FlatBufferBuilder *builder, const Parser &parser) const;
+
+ bool DeserializeAttributes(Parser &parser,
+ const Vector<Offset<reflection::KeyValue>> *attrs);
+
+ std::string name;
+ std::string file;
+ std::vector<std::string> doc_comment;
+ SymbolTable<Value> attributes;
+ bool generated; // did we already output code for this definition?
+ Namespace *defined_namespace; // Where it was defined.
+
+ // For use with Serialize()
+ uoffset_t serialized_location;
+ int index; // Inside the vector it is stored.
+ int refcount;
+};
+
+struct FieldDef : public Definition {
+ FieldDef()
+ : deprecated(false),
+ required(false),
+ key(false),
+ shared(false),
+ native_inline(false),
+ flexbuffer(false),
+ nested_flatbuffer(NULL),
+ padding(0) {}
+
+ Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
+ const Parser &parser) const;
+
+ bool Deserialize(Parser &parser, const reflection::Field *field);
+
+ Value value;
+ bool deprecated; // Field is allowed to be present in old data, but can't be.
+ // written in new data nor accessed in new code.
+ bool required; // Field must always be present.
+ bool key; // Field functions as a key for creating sorted vectors.
+ bool shared; // Field will be using string pooling (i.e. CreateSharedString)
+ // as default serialization behavior if field is a string.
+ bool native_inline; // Field will be defined inline (instead of as a pointer)
+ // for native tables if field is a struct.
+ bool flexbuffer; // This field contains FlexBuffer data.
+ StructDef *nested_flatbuffer; // This field contains nested FlatBuffer data.
+ size_t padding; // Bytes to always pad after this field.
+};
+
+struct StructDef : public Definition {
+ StructDef()
+ : fixed(false),
+ predecl(true),
+ sortbysize(true),
+ has_key(false),
+ minalign(1),
+ bytesize(0) {}
+
+ void PadLastField(size_t min_align) {
+ auto padding = PaddingBytes(bytesize, min_align);
+ bytesize += padding;
+ if (fields.vec.size()) fields.vec.back()->padding = padding;
+ }
+
+ Offset<reflection::Object> Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const;
+
+ bool Deserialize(Parser &parser, const reflection::Object *object);
+
+ SymbolTable<FieldDef> fields;
+
+ bool fixed; // If it's struct, not a table.
+ bool predecl; // If it's used before it was defined.
+ bool sortbysize; // Whether fields come in the declaration or size order.
+ bool has_key; // It has a key field.
+ size_t minalign; // What the whole object needs to be aligned to.
+ size_t bytesize; // Size if fixed.
+
+ flatbuffers::unique_ptr<std::string> original_location;
+};
+
+inline bool IsStruct(const Type &type) {
+ return type.base_type == BASE_TYPE_STRUCT && type.struct_def->fixed;
+}
+
+inline bool IsVector(const Type &type) {
+ return type.base_type == BASE_TYPE_VECTOR;
+}
+
+inline bool IsArray(const Type &type) {
+ return type.base_type == BASE_TYPE_ARRAY;
+}
+
+inline bool IsSeries(const Type &type) {
+ return IsVector(type) || IsArray(type);
+}
+
+inline bool IsEnum(const Type &type) {
+ return type.enum_def != nullptr && IsInteger(type.base_type);
+}
+
+inline size_t InlineSize(const Type &type) {
+ return IsStruct(type)
+ ? type.struct_def->bytesize
+ : (IsArray(type)
+ ? InlineSize(type.VectorType()) * type.fixed_length
+ : SizeOf(type.base_type));
+}
+
+inline size_t InlineAlignment(const Type &type) {
+ return IsStruct(type)
+ ? type.struct_def->minalign
+ : (SizeOf(IsArray(type) ? type.element : type.base_type));
+}
+
+struct EnumDef;
+struct EnumValBuilder;
+
+struct EnumVal {
+ Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
+
+ bool Deserialize(const Parser &parser, const reflection::EnumVal *val);
+
+ uint64_t GetAsUInt64() const { return static_cast<uint64_t>(value); }
+ int64_t GetAsInt64() const { return value; }
+ bool IsZero() const { return 0 == value; }
+ bool IsNonZero() const { return !IsZero(); }
+
+ std::string name;
+ std::vector<std::string> doc_comment;
+ Type union_type;
+
+ private:
+ friend EnumDef;
+ friend EnumValBuilder;
+ friend bool operator==(const EnumVal &lhs, const EnumVal &rhs);
+
+ EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {}
+ EnumVal() : value(0) {}
+
+ int64_t value;
+};
+
+struct EnumDef : public Definition {
+ EnumDef() : is_union(false), uses_multiple_type_instances(false) {}
+
+ Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const;
+
+ bool Deserialize(Parser &parser, const reflection::Enum *values);
+
+ template<typename T> void ChangeEnumValue(EnumVal *ev, T new_val);
+ void SortByValue();
+ void RemoveDuplicates();
+
+ std::string AllFlags() const;
+ const EnumVal *MinValue() const;
+ const EnumVal *MaxValue() const;
+ // Returns the number of integer steps from v1 to v2.
+ uint64_t Distance(const EnumVal *v1, const EnumVal *v2) const;
+ // Returns the number of integer steps from Min to Max.
+ uint64_t Distance() const { return Distance(MinValue(), MaxValue()); }
+
+ EnumVal *ReverseLookup(int64_t enum_idx,
+ bool skip_union_default = false) const;
+ EnumVal *FindByValue(const std::string &constant) const;
+
+ std::string ToString(const EnumVal &ev) const {
+ return IsUInt64() ? NumToString(ev.GetAsUInt64())
+ : NumToString(ev.GetAsInt64());
+ }
+
+ size_t size() const { return vals.vec.size(); }
+
+ const std::vector<EnumVal *> &Vals() const {
+ FLATBUFFERS_ASSERT(false == vals.vec.empty());
+ return vals.vec;
+ }
+
+ const EnumVal *Lookup(const std::string &enum_name) const {
+ return vals.Lookup(enum_name);
+ }
+
+ bool is_union;
+ // Type is a union which uses type aliases where at least one type is
+ // available under two different names.
+ bool uses_multiple_type_instances;
+ Type underlying_type;
+
+ private:
+ bool IsUInt64() const {
+ return (BASE_TYPE_ULONG == underlying_type.base_type);
+ }
+
+ friend EnumValBuilder;
+ SymbolTable<EnumVal> vals;
+};
+
+inline bool operator==(const EnumVal &lhs, const EnumVal &rhs) {
+ return lhs.value == rhs.value;
+}
+inline bool operator!=(const EnumVal &lhs, const EnumVal &rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool EqualByName(const Type &a, const Type &b) {
+ return a.base_type == b.base_type && a.element == b.element &&
+ (a.struct_def == b.struct_def ||
+ a.struct_def->name == b.struct_def->name) &&
+ (a.enum_def == b.enum_def || a.enum_def->name == b.enum_def->name);
+}
+
+struct RPCCall : public Definition {
+ Offset<reflection::RPCCall> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
+
+ bool Deserialize(Parser &parser, const reflection::RPCCall *call);
+
+ StructDef *request, *response;
+};
+
+struct ServiceDef : public Definition {
+ Offset<reflection::Service> Serialize(FlatBufferBuilder *builder, const Parser &parser) const;
+ bool Deserialize(Parser &parser, const reflection::Service *service);
+
+ SymbolTable<RPCCall> calls;
+};
+
+// Container of options that may apply to any of the source/text generators.
+struct IDLOptions {
+ bool strict_json;
+ bool skip_js_exports;
+ bool use_goog_js_export_format;
+ bool use_ES6_js_export_format;
+ bool output_default_scalars_in_json;
+ int indent_step;
+ bool output_enum_identifiers;
+ bool prefixed_enums;
+ bool scoped_enums;
+ bool include_dependence_headers;
+ bool mutable_buffer;
+ bool one_file;
+ bool proto_mode;
+ bool proto_oneof_union;
+ bool generate_all;
+ bool skip_unexpected_fields_in_json;
+ bool generate_name_strings;
+ bool generate_object_based_api;
+ bool gen_compare;
+ std::string cpp_object_api_pointer_type;
+ std::string cpp_object_api_string_type;
+ bool cpp_object_api_string_flexible_constructor;
+ bool gen_nullable;
+ bool gen_generated;
+ std::string object_prefix;
+ std::string object_suffix;
+ bool union_value_namespacing;
+ bool allow_non_utf8;
+ bool natural_utf8;
+ std::string include_prefix;
+ bool keep_include_path;
+ bool binary_schema_comments;
+ bool binary_schema_builtins;
+ bool skip_flatbuffers_import;
+ std::string go_import;
+ std::string go_namespace;
+ bool reexport_ts_modules;
+ bool js_ts_short_names;
+ bool protobuf_ascii_alike;
+ bool size_prefixed;
+ std::string root_type;
+ bool force_defaults;
+ std::vector<std::string> cpp_includes;
+
+ // Possible options for the more general generator below.
+ enum Language {
+ kJava = 1 << 0,
+ kCSharp = 1 << 1,
+ kGo = 1 << 2,
+ kCpp = 1 << 3,
+ kJs = 1 << 4,
+ kPython = 1 << 5,
+ kPhp = 1 << 6,
+ kJson = 1 << 7,
+ kBinary = 1 << 8,
+ kTs = 1 << 9,
+ kJsonSchema = 1 << 10,
+ kDart = 1 << 11,
+ kLua = 1 << 12,
+ kLobster = 1 << 13,
+ kRust = 1 << 14,
+ kKotlin = 1 << 15,
+ kMAX
+ };
+
+ Language lang;
+
+ enum MiniReflect { kNone, kTypes, kTypesAndNames };
+
+ MiniReflect mini_reflect;
+
+ // The corresponding language bit will be set if a language is included
+ // for code generation.
+ unsigned long lang_to_generate;
+
+ // If set (default behavior), empty string and vector fields will be set to
+ // nullptr to make the flatbuffer more compact.
+ bool set_empty_to_null;
+
+ IDLOptions()
+ : strict_json(false),
+ skip_js_exports(false),
+ use_goog_js_export_format(false),
+ use_ES6_js_export_format(false),
+ output_default_scalars_in_json(false),
+ indent_step(2),
+ output_enum_identifiers(true),
+ prefixed_enums(true),
+ scoped_enums(false),
+ include_dependence_headers(true),
+ mutable_buffer(false),
+ one_file(false),
+ proto_mode(false),
+ proto_oneof_union(false),
+ generate_all(false),
+ skip_unexpected_fields_in_json(false),
+ generate_name_strings(false),
+ generate_object_based_api(false),
+ gen_compare(false),
+ cpp_object_api_pointer_type("std::unique_ptr"),
+ cpp_object_api_string_flexible_constructor(false),
+ gen_nullable(false),
+ gen_generated(false),
+ object_suffix("T"),
+ union_value_namespacing(true),
+ allow_non_utf8(false),
+ natural_utf8(false),
+ keep_include_path(false),
+ binary_schema_comments(false),
+ binary_schema_builtins(false),
+ skip_flatbuffers_import(false),
+ reexport_ts_modules(true),
+ js_ts_short_names(false),
+ protobuf_ascii_alike(false),
+ size_prefixed(false),
+ force_defaults(false),
+ lang(IDLOptions::kJava),
+ mini_reflect(IDLOptions::kNone),
+ lang_to_generate(0),
+ set_empty_to_null(true) {}
+};
+
+// This encapsulates where the parser is in the current source file.
+struct ParserState {
+ ParserState()
+ : cursor_(nullptr),
+ line_start_(nullptr),
+ line_(0),
+ token_(-1),
+ attr_is_trivial_ascii_string_(true) {}
+
+ protected:
+ void ResetState(const char *source) {
+ cursor_ = source;
+ line_ = 0;
+ MarkNewLine();
+ }
+
+ void MarkNewLine() {
+ line_start_ = cursor_;
+ line_ += 1;
+ }
+
+ int64_t CursorPosition() const {
+ FLATBUFFERS_ASSERT(cursor_ && line_start_ && cursor_ >= line_start_);
+ return static_cast<int64_t>(cursor_ - line_start_);
+ }
+
+ const char *cursor_;
+ const char *line_start_;
+ int line_; // the current line being parsed
+ int token_;
+
+ // Flag: text in attribute_ is true ASCII string without escape
+ // sequences. Only printable ASCII (without [\t\r\n]).
+ // Used for number-in-string (and base64 string in future).
+ bool attr_is_trivial_ascii_string_;
+ std::string attribute_;
+ std::vector<std::string> doc_comment_;
+};
+
+// A way to make error propagation less error prone by requiring values to be
+// checked.
+// Once you create a value of this type you must either:
+// - Call Check() on it.
+// - Copy or assign it to another value.
+// Failure to do so leads to an assert.
+// This guarantees that this as return value cannot be ignored.
+class CheckedError {
+ public:
+ explicit CheckedError(bool error)
+ : is_error_(error), has_been_checked_(false) {}
+
+ CheckedError &operator=(const CheckedError &other) {
+ is_error_ = other.is_error_;
+ has_been_checked_ = false;
+ other.has_been_checked_ = true;
+ return *this;
+ }
+
+ CheckedError(const CheckedError &other) {
+ *this = other; // Use assignment operator.
+ }
+
+ ~CheckedError() { FLATBUFFERS_ASSERT(has_been_checked_); }
+
+ bool Check() {
+ has_been_checked_ = true;
+ return is_error_;
+ }
+
+ private:
+ bool is_error_;
+ mutable bool has_been_checked_;
+};
+
+// Additionally, in GCC we can get these errors statically, for additional
+// assurance:
+// clang-format off
+#ifdef __GNUC__
+#define FLATBUFFERS_CHECKED_ERROR CheckedError \
+ __attribute__((warn_unused_result))
+#else
+#define FLATBUFFERS_CHECKED_ERROR CheckedError
+#endif
+// clang-format on
+
+class Parser : public ParserState {
+ public:
+ explicit Parser(const IDLOptions &options = IDLOptions())
+ : current_namespace_(nullptr),
+ empty_namespace_(nullptr),
+ root_struct_def_(nullptr),
+ opts(options),
+ uses_flexbuffers_(false),
+ source_(nullptr),
+ anonymous_counter(0),
+ recurse_protection_counter(0) {
+ if (opts.force_defaults) {
+ builder_.ForceDefaults(true);
+ }
+ // Start out with the empty namespace being current.
+ empty_namespace_ = new Namespace();
+ namespaces_.push_back(empty_namespace_);
+ current_namespace_ = empty_namespace_;
+ known_attributes_["deprecated"] = true;
+ known_attributes_["required"] = true;
+ known_attributes_["key"] = true;
+ known_attributes_["shared"] = true;
+ known_attributes_["hash"] = true;
+ known_attributes_["id"] = true;
+ known_attributes_["force_align"] = true;
+ known_attributes_["bit_flags"] = true;
+ known_attributes_["original_order"] = true;
+ known_attributes_["nested_flatbuffer"] = true;
+ known_attributes_["csharp_partial"] = true;
+ known_attributes_["streaming"] = true;
+ known_attributes_["idempotent"] = true;
+ known_attributes_["cpp_type"] = true;
+ known_attributes_["cpp_ptr_type"] = true;
+ known_attributes_["cpp_ptr_type_get"] = true;
+ known_attributes_["cpp_str_type"] = true;
+ known_attributes_["cpp_str_flex_ctor"] = true;
+ known_attributes_["native_inline"] = true;
+ known_attributes_["native_custom_alloc"] = true;
+ known_attributes_["native_type"] = true;
+ known_attributes_["native_default"] = true;
+ known_attributes_["flexbuffer"] = true;
+ known_attributes_["private"] = true;
+ }
+
+ ~Parser() {
+ for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ // Parse the string containing either schema or JSON data, which will
+ // populate the SymbolTable's or the FlatBufferBuilder above.
+ // include_paths is used to resolve any include statements, and typically
+ // should at least include the project path (where you loaded source_ from).
+ // include_paths must be nullptr terminated if specified.
+ // If include_paths is nullptr, it will attempt to load from the current
+ // directory.
+ // If the source was loaded from a file and isn't an include file,
+ // supply its name in source_filename.
+ // All paths specified in this call must be in posix format, if you accept
+ // paths from user input, please call PosixPath on them first.
+ bool Parse(const char *_source, const char **include_paths = nullptr,
+ const char *source_filename = nullptr);
+
+ // Set the root type. May override the one set in the schema.
+ bool SetRootType(const char *name);
+
+ // Mark all definitions as already having code generated.
+ void MarkGenerated();
+
+ // Get the files recursively included by the given file. The returned
+ // container will have at least the given file.
+ std::set<std::string> GetIncludedFilesRecursive(
+ const std::string &file_name) const;
+
+ // Fills builder_ with a binary version of the schema parsed.
+ // See reflection/reflection.fbs
+ void Serialize();
+
+ // Deserialize a schema buffer
+ bool Deserialize(const uint8_t *buf, const size_t size);
+
+ // Fills internal structure as if the schema passed had been loaded by parsing
+ // with Parse except that included filenames will not be populated.
+ bool Deserialize(const reflection::Schema* schema);
+
+ Type* DeserializeType(const reflection::Type* type);
+
+ // Checks that the schema represented by this parser is a safe evolution
+ // of the schema provided. Returns non-empty error on any problems.
+ std::string ConformTo(const Parser &base);
+
+ // Similar to Parse(), but now only accepts JSON to be parsed into a
+ // FlexBuffer.
+ bool ParseFlexBuffer(const char *source, const char *source_filename,
+ flexbuffers::Builder *builder);
+
+ StructDef *LookupStruct(const std::string &id) const;
+
+ std::string UnqualifiedName(const std::string &fullQualifiedName);
+
+ FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
+
+ private:
+ void Message(const std::string &msg);
+ void Warning(const std::string &msg);
+ FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
+ FLATBUFFERS_CHECKED_ERROR Next();
+ FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
+ bool Is(int t) const;
+ bool IsIdent(const char *id) const;
+ FLATBUFFERS_CHECKED_ERROR Expect(int t);
+ std::string TokenToStringId(int t) const;
+ EnumDef *LookupEnum(const std::string &id);
+ FLATBUFFERS_CHECKED_ERROR ParseNamespacing(std::string *id,
+ std::string *last);
+ FLATBUFFERS_CHECKED_ERROR ParseTypeIdent(Type &type);
+ FLATBUFFERS_CHECKED_ERROR ParseType(Type &type);
+ FLATBUFFERS_CHECKED_ERROR AddField(StructDef &struct_def,
+ const std::string &name, const Type &type,
+ FieldDef **dest);
+ FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
+ FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
+ FLATBUFFERS_CHECKED_ERROR ParseComma();
+ FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
+ size_t parent_fieldn,
+ const StructDef *parent_struct_def,
+ uoffset_t count,
+ bool inside_vector = false);
+ template<typename F>
+ FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
+ const StructDef *struct_def,
+ F body);
+ FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
+ std::string *value, uoffset_t *ovalue);
+ void SerializeStruct(const StructDef &struct_def, const Value &val);
+ void SerializeStruct(FlatBufferBuilder &builder, const StructDef &struct_def,
+ const Value &val);
+ template<typename F>
+ FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(uoffset_t &count, F body);
+ FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue,
+ FieldDef *field, size_t fieldn);
+ FLATBUFFERS_CHECKED_ERROR ParseArray(Value &array);
+ FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
+ size_t fieldn,
+ const StructDef *parent_struct_def);
+ FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
+ FLATBUFFERS_CHECKED_ERROR TryTypedValue(const std::string *name, int dtoken, bool check, Value &e,
+ BaseType req, bool *destmatch);
+ FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
+ FLATBUFFERS_CHECKED_ERROR TokenError();
+ FLATBUFFERS_CHECKED_ERROR ParseSingleValue(const std::string *name, Value &e, bool check_now);
+ FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(const Type &type, std::string *result);
+ StructDef *LookupCreateStruct(const std::string &name,
+ bool create_if_new = true,
+ bool definition = false);
+ FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest);
+ FLATBUFFERS_CHECKED_ERROR ParseNamespace();
+ FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name,
+ StructDef **dest);
+ FLATBUFFERS_CHECKED_ERROR StartEnum(const std::string &name,
+ bool is_union,
+ EnumDef **dest);
+ FLATBUFFERS_CHECKED_ERROR ParseDecl();
+ FLATBUFFERS_CHECKED_ERROR ParseService();
+ FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def,
+ bool isextend, bool inside_oneof);
+ FLATBUFFERS_CHECKED_ERROR ParseProtoOption();
+ FLATBUFFERS_CHECKED_ERROR ParseProtoKey();
+ FLATBUFFERS_CHECKED_ERROR ParseProtoDecl();
+ FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
+ FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
+ FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
+ FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
+ FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
+ const char *source_filename);
+ FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source,
+ const char **include_paths,
+ const char *source_filename);
+ FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
+ const char **include_paths,
+ const char *source_filename,
+ const char *include_filename);
+ FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
+ StructDef *struct_def,
+ const char *suffix,
+ BaseType baseType);
+
+ bool SupportsAdvancedUnionFeatures() const;
+ bool SupportsAdvancedArrayFeatures() const;
+ Namespace *UniqueNamespace(Namespace *ns);
+
+ FLATBUFFERS_CHECKED_ERROR RecurseError();
+ template<typename F> CheckedError Recurse(F f);
+
+ public:
+ SymbolTable<Type> types_;
+ SymbolTable<StructDef> structs_;
+ SymbolTable<EnumDef> enums_;
+ SymbolTable<ServiceDef> services_;
+ std::vector<Namespace *> namespaces_;
+ Namespace *current_namespace_;
+ Namespace *empty_namespace_;
+ std::string error_; // User readable error_ if Parse() == false
+
+ FlatBufferBuilder builder_; // any data contained in the file
+ StructDef *root_struct_def_;
+ std::string file_identifier_;
+ std::string file_extension_;
+
+ std::map<std::string, std::string> included_files_;
+ std::map<std::string, std::set<std::string>> files_included_per_file_;
+ std::vector<std::string> native_included_files_;
+
+ std::map<std::string, bool> known_attributes_;
+
+ IDLOptions opts;
+ bool uses_flexbuffers_;
+
+ private:
+ const char *source_;
+
+ std::string file_being_parsed_;
+
+ std::vector<std::pair<Value, FieldDef *>> field_stack_;
+
+ int anonymous_counter;
+ int recurse_protection_counter;
+};
+
+// Utility functions for multiple generators:
+
+extern std::string MakeCamel(const std::string &in, bool first = true);
+
+// Generate text (JSON) from a given FlatBuffer, and a given Parser
+// object that has been populated with the corresponding schema.
+// If ident_step is 0, no indentation will be generated. Additionally,
+// if it is less than 0, no linefeeds will be generated either.
+// See idl_gen_text.cpp.
+// strict_json adds "quotes" around field names if true.
+// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8
+// byte arrays in String values), returns false.
+extern bool GenerateTextFromTable(const Parser &parser,
+ const void *table,
+ const std::string &tablename,
+ std::string *text);
+extern bool GenerateText(const Parser &parser,
+ const void *flatbuffer,
+ std::string *text);
+extern bool GenerateTextFile(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate binary files from a given FlatBuffer, and a given Parser
+// object that has been populated with the corresponding schema.
+// See idl_gen_general.cpp.
+extern bool GenerateBinary(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a C++ header from the definitions in the Parser object.
+// See idl_gen_cpp.
+extern bool GenerateCPP(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+extern bool GenerateDart(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate JavaScript or TypeScript code from the definitions in the Parser object.
+// See idl_gen_js.
+extern bool GenerateJSTS(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Go files from the definitions in the Parser object.
+// See idl_gen_go.cpp.
+extern bool GenerateGo(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Php code from the definitions in the Parser object.
+// See idl_gen_php.
+extern bool GeneratePhp(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Python files from the definitions in the Parser object.
+// See idl_gen_python.cpp.
+extern bool GeneratePython(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Lobster files from the definitions in the Parser object.
+// See idl_gen_lobster.cpp.
+extern bool GenerateLobster(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Lua files from the definitions in the Parser object.
+// See idl_gen_lua.cpp.
+extern bool GenerateLua(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Rust files from the definitions in the Parser object.
+// See idl_gen_rust.cpp.
+extern bool GenerateRust(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate Json schema file
+// See idl_gen_json_schema.cpp.
+extern bool GenerateJsonSchema(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+extern bool GenerateKotlin(const Parser &parser, const std::string &path,
+ const std::string &file_name);
+
+// Generate Java/C#/.. files from the definitions in the Parser object.
+// See idl_gen_general.cpp.
+extern bool GenerateGeneral(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a schema file from the internal representation, useful after
+// parsing a .proto schema.
+extern std::string GenerateFBS(const Parser &parser,
+ const std::string &file_name);
+extern bool GenerateFBS(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a make rule for the generated JavaScript or TypeScript code.
+// See idl_gen_js.cpp.
+extern std::string JSTSMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a make rule for the generated C++ header.
+// See idl_gen_cpp.cpp.
+extern std::string CPPMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a make rule for the generated Dart code
+// see idl_gen_dart.cpp
+extern std::string DartMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a make rule for the generated Rust code.
+// See idl_gen_rust.cpp.
+extern std::string RustMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a make rule for the generated Java/C#/... files.
+// See idl_gen_general.cpp.
+extern std::string GeneralMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate a make rule for the generated text (JSON) files.
+// See idl_gen_text.cpp.
+extern std::string TextMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_names);
+
+// Generate a make rule for the generated binary files.
+// See idl_gen_general.cpp.
+extern std::string BinaryMakeRule(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate GRPC Cpp interfaces.
+// See idl_gen_grpc.cpp.
+bool GenerateCppGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate GRPC Go interfaces.
+// See idl_gen_grpc.cpp.
+bool GenerateGoGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+// Generate GRPC Java classes.
+// See idl_gen_grpc.cpp
+bool GenerateJavaGRPC(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_IDL_H_
diff --git a/include/flatbuffers/minireflect.h b/include/flatbuffers/minireflect.h
new file mode 100644
index 0000000..9d648ec
--- /dev/null
+++ b/include/flatbuffers/minireflect.h
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_MINIREFLECT_H_
+#define FLATBUFFERS_MINIREFLECT_H_
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Utilities that can be used with the "mini reflection" tables present
+// in generated code with --reflect-types (only types) or --reflect-names
+// (also names).
+// This allows basic reflection functionality such as pretty-printing
+// that does not require the use of the schema parser or loading of binary
+// schema files at runtime (reflection.h).
+
+// For any of the functions below that take `const TypeTable *`, you pass
+// `FooTypeTable()` if the type of the root is `Foo`.
+
+// First, a generic iterator that can be used by multiple algorithms.
+
+struct IterationVisitor {
+ // These mark the scope of a table or struct.
+ virtual void StartSequence() {}
+ virtual void EndSequence() {}
+ // Called for each field regardless of wether it is present or not.
+ // If not present, val == nullptr. set_idx is the index of all set fields.
+ virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
+ ElementaryType /*type*/, bool /*is_vector*/,
+ const TypeTable * /*type_table*/, const char * /*name*/,
+ const uint8_t * /*val*/) {}
+ // Called for a value that is actually present, after a field, or as part
+ // of a vector.
+ virtual void UType(uint8_t, const char *) {}
+ virtual void Bool(bool) {}
+ virtual void Char(int8_t, const char *) {}
+ virtual void UChar(uint8_t, const char *) {}
+ virtual void Short(int16_t, const char *) {}
+ virtual void UShort(uint16_t, const char *) {}
+ virtual void Int(int32_t, const char *) {}
+ virtual void UInt(uint32_t, const char *) {}
+ virtual void Long(int64_t) {}
+ virtual void ULong(uint64_t) {}
+ virtual void Float(float) {}
+ virtual void Double(double) {}
+ virtual void String(const String *) {}
+ virtual void Unknown(const uint8_t *) {} // From a future version.
+ // These mark the scope of a vector.
+ virtual void StartVector() {}
+ virtual void EndVector() {}
+ virtual void Element(size_t /*i*/, ElementaryType /*type*/,
+ const TypeTable * /*type_table*/,
+ const uint8_t * /*val*/) {}
+ virtual ~IterationVisitor() {}
+};
+
+inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
+ switch (type) {
+ case ET_UTYPE:
+ case ET_BOOL:
+ case ET_CHAR:
+ case ET_UCHAR: return 1;
+ case ET_SHORT:
+ case ET_USHORT: return 2;
+ case ET_INT:
+ case ET_UINT:
+ case ET_FLOAT:
+ case ET_STRING: return 4;
+ case ET_LONG:
+ case ET_ULONG:
+ case ET_DOUBLE: return 8;
+ case ET_SEQUENCE:
+ switch (type_table->st) {
+ case ST_TABLE:
+ case ST_UNION: return 4;
+ case ST_STRUCT: return static_cast<size_t>(type_table->values[type_table->num_elems]);
+ default: FLATBUFFERS_ASSERT(false); return 1;
+ }
+ default: FLATBUFFERS_ASSERT(false); return 1;
+ }
+}
+
+inline int64_t LookupEnum(int64_t enum_val, const int64_t *values,
+ size_t num_values) {
+ if (!values) return enum_val;
+ for (size_t i = 0; i < num_values; i++) {
+ if (enum_val == values[i]) return static_cast<int64_t>(i);
+ }
+ return -1; // Unknown enum value.
+}
+
+template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
+ if (!type_table || !type_table->names) return nullptr;
+ auto i = LookupEnum(static_cast<int64_t>(tval), type_table->values,
+ type_table->num_elems);
+ if (i >= 0 && i < static_cast<int64_t>(type_table->num_elems)) {
+ return type_table->names[i];
+ }
+ return nullptr;
+}
+
+void IterateObject(const uint8_t *obj, const TypeTable *type_table,
+ IterationVisitor *visitor);
+
+inline void IterateValue(ElementaryType type, const uint8_t *val,
+ const TypeTable *type_table, const uint8_t *prev_val,
+ soffset_t vector_index, IterationVisitor *visitor) {
+ switch (type) {
+ case ET_UTYPE: {
+ auto tval = ReadScalar<uint8_t>(val);
+ visitor->UType(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_BOOL: {
+ visitor->Bool(ReadScalar<uint8_t>(val) != 0);
+ break;
+ }
+ case ET_CHAR: {
+ auto tval = ReadScalar<int8_t>(val);
+ visitor->Char(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_UCHAR: {
+ auto tval = ReadScalar<uint8_t>(val);
+ visitor->UChar(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_SHORT: {
+ auto tval = ReadScalar<int16_t>(val);
+ visitor->Short(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_USHORT: {
+ auto tval = ReadScalar<uint16_t>(val);
+ visitor->UShort(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_INT: {
+ auto tval = ReadScalar<int32_t>(val);
+ visitor->Int(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_UINT: {
+ auto tval = ReadScalar<uint32_t>(val);
+ visitor->UInt(tval, EnumName(tval, type_table));
+ break;
+ }
+ case ET_LONG: {
+ visitor->Long(ReadScalar<int64_t>(val));
+ break;
+ }
+ case ET_ULONG: {
+ visitor->ULong(ReadScalar<uint64_t>(val));
+ break;
+ }
+ case ET_FLOAT: {
+ visitor->Float(ReadScalar<float>(val));
+ break;
+ }
+ case ET_DOUBLE: {
+ visitor->Double(ReadScalar<double>(val));
+ break;
+ }
+ case ET_STRING: {
+ val += ReadScalar<uoffset_t>(val);
+ visitor->String(reinterpret_cast<const String *>(val));
+ break;
+ }
+ case ET_SEQUENCE: {
+ switch (type_table->st) {
+ case ST_TABLE:
+ val += ReadScalar<uoffset_t>(val);
+ IterateObject(val, type_table, visitor);
+ break;
+ case ST_STRUCT: IterateObject(val, type_table, visitor); break;
+ case ST_UNION: {
+ val += ReadScalar<uoffset_t>(val);
+ FLATBUFFERS_ASSERT(prev_val);
+ auto union_type = *prev_val; // Always a uint8_t.
+ if (vector_index >= 0) {
+ auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
+ union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
+ }
+ auto type_code_idx =
+ LookupEnum(union_type, type_table->values, type_table->num_elems);
+ if (type_code_idx >= 0 &&
+ type_code_idx < static_cast<int32_t>(type_table->num_elems)) {
+ auto type_code = type_table->type_codes[type_code_idx];
+ switch (type_code.base_type) {
+ case ET_SEQUENCE: {
+ auto ref = type_table->type_refs[type_code.sequence_ref]();
+ IterateObject(val, ref, visitor);
+ break;
+ }
+ case ET_STRING:
+ visitor->String(reinterpret_cast<const String *>(val));
+ break;
+ default: visitor->Unknown(val);
+ }
+ } else {
+ visitor->Unknown(val);
+ }
+ break;
+ }
+ case ST_ENUM: FLATBUFFERS_ASSERT(false); break;
+ }
+ break;
+ }
+ default: {
+ visitor->Unknown(val);
+ break;
+ }
+ }
+}
+
+inline void IterateObject(const uint8_t *obj, const TypeTable *type_table,
+ IterationVisitor *visitor) {
+ visitor->StartSequence();
+ const uint8_t *prev_val = nullptr;
+ size_t set_idx = 0;
+ for (size_t i = 0; i < type_table->num_elems; i++) {
+ auto type_code = type_table->type_codes[i];
+ auto type = static_cast<ElementaryType>(type_code.base_type);
+ auto is_vector = type_code.is_vector != 0;
+ auto ref_idx = type_code.sequence_ref;
+ const TypeTable *ref = nullptr;
+ if (ref_idx >= 0) { ref = type_table->type_refs[ref_idx](); }
+ auto name = type_table->names ? type_table->names[i] : nullptr;
+ const uint8_t *val = nullptr;
+ if (type_table->st == ST_TABLE) {
+ val = reinterpret_cast<const Table *>(obj)->GetAddressOf(
+ FieldIndexToOffset(static_cast<voffset_t>(i)));
+ } else {
+ val = obj + type_table->values[i];
+ }
+ visitor->Field(i, set_idx, type, is_vector, ref, name, val);
+ if (val) {
+ set_idx++;
+ if (is_vector) {
+ val += ReadScalar<uoffset_t>(val);
+ auto vec = reinterpret_cast<const Vector<uint8_t> *>(val);
+ visitor->StartVector();
+ auto elem_ptr = vec->Data();
+ for (size_t j = 0; j < vec->size(); j++) {
+ visitor->Element(j, type, ref, elem_ptr);
+ IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
+ visitor);
+ elem_ptr += InlineSize(type, ref);
+ }
+ visitor->EndVector();
+ } else {
+ IterateValue(type, val, ref, prev_val, -1, visitor);
+ }
+ }
+ prev_val = val;
+ }
+ visitor->EndSequence();
+}
+
+inline void IterateFlatBuffer(const uint8_t *buffer,
+ const TypeTable *type_table,
+ IterationVisitor *callback) {
+ IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
+}
+
+// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
+// the output generated by idl_gen_text.cpp.
+
+struct ToStringVisitor : public IterationVisitor {
+ std::string s;
+ std::string d;
+ bool q;
+ std::string in;
+ size_t indent_level;
+ bool vector_delimited;
+ ToStringVisitor(std::string delimiter, bool quotes, std::string indent,
+ bool vdelimited = true)
+ : d(delimiter),
+ q(quotes),
+ in(indent),
+ indent_level(0),
+ vector_delimited(vdelimited) {}
+ ToStringVisitor(std::string delimiter)
+ : d(delimiter),
+ q(false),
+ in(""),
+ indent_level(0),
+ vector_delimited(true) {}
+
+ void append_indent() {
+ for (size_t i = 0; i < indent_level; i++) { s += in; }
+ }
+
+ void StartSequence() {
+ s += "{";
+ s += d;
+ indent_level++;
+ }
+ void EndSequence() {
+ s += d;
+ indent_level--;
+ append_indent();
+ s += "}";
+ }
+ void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
+ bool /*is_vector*/, const TypeTable * /*type_table*/,
+ const char *name, const uint8_t *val) {
+ if (!val) return;
+ if (set_idx) {
+ s += ",";
+ s += d;
+ }
+ append_indent();
+ if (name) {
+ if (q) s += "\"";
+ s += name;
+ if (q) s += "\"";
+ s += ": ";
+ }
+ }
+ template<typename T> void Named(T x, const char *name) {
+ if (name) {
+ if (q) s += "\"";
+ s += name;
+ if (q) s += "\"";
+ } else {
+ s += NumToString(x);
+ }
+ }
+ void UType(uint8_t x, const char *name) { Named(x, name); }
+ void Bool(bool x) { s += x ? "true" : "false"; }
+ void Char(int8_t x, const char *name) { Named(x, name); }
+ void UChar(uint8_t x, const char *name) { Named(x, name); }
+ void Short(int16_t x, const char *name) { Named(x, name); }
+ void UShort(uint16_t x, const char *name) { Named(x, name); }
+ void Int(int32_t x, const char *name) { Named(x, name); }
+ void UInt(uint32_t x, const char *name) { Named(x, name); }
+ void Long(int64_t x) { s += NumToString(x); }
+ void ULong(uint64_t x) { s += NumToString(x); }
+ void Float(float x) { s += NumToString(x); }
+ void Double(double x) { s += NumToString(x); }
+ void String(const struct String *str) {
+ EscapeString(str->c_str(), str->size(), &s, true, false);
+ }
+ void Unknown(const uint8_t *) { s += "(?)"; }
+ void StartVector() {
+ s += "[";
+ if (vector_delimited) {
+ s += d;
+ indent_level++;
+ append_indent();
+ } else {
+ s += " ";
+ }
+ }
+ void EndVector() {
+ if (vector_delimited) {
+ s += d;
+ indent_level--;
+ append_indent();
+ } else {
+ s += " ";
+ }
+ s += "]";
+ }
+ void Element(size_t i, ElementaryType /*type*/,
+ const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
+ if (i) {
+ s += ",";
+ if (vector_delimited) {
+ s += d;
+ append_indent();
+ } else {
+ s += " ";
+ }
+ }
+ }
+};
+
+inline std::string FlatBufferToString(const uint8_t *buffer,
+ const TypeTable *type_table,
+ bool multi_line = false,
+ bool vector_delimited = true) {
+ ToStringVisitor tostring_visitor(multi_line ? "\n" : " ", false, "",
+ vector_delimited);
+ IterateFlatBuffer(buffer, type_table, &tostring_visitor);
+ return tostring_visitor.s;
+}
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_MINIREFLECT_H_
diff --git a/include/flatbuffers/reflection.h b/include/flatbuffers/reflection.h
new file mode 100644
index 0000000..580ae62
--- /dev/null
+++ b/include/flatbuffers/reflection.h
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_REFLECTION_H_
+#define FLATBUFFERS_REFLECTION_H_
+
+// This is somewhat of a circular dependency because flatc (and thus this
+// file) is needed to generate this header in the first place.
+// Should normally not be a problem since it can be generated by the
+// previous version of flatc whenever this code needs to change.
+// See reflection/generate_code.sh
+#include "flatbuffers/reflection_generated.h"
+
+// Helper functionality for reflection.
+
+namespace flatbuffers {
+
+// ------------------------- GETTERS -------------------------
+
+inline bool IsScalar(reflection::BaseType t) {
+ return t >= reflection::UType && t <= reflection::Double;
+}
+inline bool IsInteger(reflection::BaseType t) {
+ return t >= reflection::UType && t <= reflection::ULong;
+}
+inline bool IsFloat(reflection::BaseType t) {
+ return t == reflection::Float || t == reflection::Double;
+}
+inline bool IsLong(reflection::BaseType t) {
+ return t == reflection::Long || t == reflection::ULong;
+}
+
+// Size of a basic type, don't use with structs.
+inline size_t GetTypeSize(reflection::BaseType base_type) {
+ // This needs to correspond to the BaseType enum.
+ static size_t sizes[] = { 0, 1, 1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 4, 4, 4, 4 };
+ return sizes[base_type];
+}
+
+// Same as above, but now correctly returns the size of a struct if
+// the field (or vector element) is a struct.
+inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index,
+ const reflection::Schema &schema) {
+ if (base_type == reflection::Obj &&
+ schema.objects()->Get(type_index)->is_struct()) {
+ return schema.objects()->Get(type_index)->bytesize();
+ } else {
+ return GetTypeSize(base_type);
+ }
+}
+
+// Get the root, regardless of what type it is.
+inline Table *GetAnyRoot(uint8_t *flatbuf) {
+ return GetMutableRoot<Table>(flatbuf);
+}
+inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
+ return GetRoot<Table>(flatbuf);
+}
+
+// Get a field's default, if you know it's an integer, and its exact type.
+template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
+ return static_cast<T>(field.default_integer());
+}
+
+// Get a field's default, if you know it's floating point and its exact type.
+template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
+ return static_cast<T>(field.default_real());
+}
+
+// Get a field, if you know it's an integer, and its exact type.
+template<typename T>
+T GetFieldI(const Table &table, const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
+ return table.GetField<T>(field.offset(),
+ static_cast<T>(field.default_integer()));
+}
+
+// Get a field, if you know it's floating point and its exact type.
+template<typename T>
+T GetFieldF(const Table &table, const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type()));
+ return table.GetField<T>(field.offset(),
+ static_cast<T>(field.default_real()));
+}
+
+// Get a field, if you know it's a string.
+inline const String *GetFieldS(const Table &table,
+ const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String);
+ return table.GetPointer<const String *>(field.offset());
+}
+
+// Get a field, if you know it's a vector.
+template<typename T>
+Vector<T> *GetFieldV(const Table &table, const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector &&
+ sizeof(T) == GetTypeSize(field.type()->element()));
+ return table.GetPointer<Vector<T> *>(field.offset());
+}
+
+// Get a field, if you know it's a vector, generically.
+// To actually access elements, use the return value together with
+// field.type()->element() in any of GetAnyVectorElemI below etc.
+inline VectorOfAny *GetFieldAnyV(const Table &table,
+ const reflection::Field &field) {
+ return table.GetPointer<VectorOfAny *>(field.offset());
+}
+
+// Get a field, if you know it's a table.
+inline Table *GetFieldT(const Table &table, const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj ||
+ field.type()->base_type() == reflection::Union);
+ return table.GetPointer<Table *>(field.offset());
+}
+
+// Get a field, if you know it's a struct.
+inline const Struct *GetFieldStruct(const Table &table,
+ const reflection::Field &field) {
+ // TODO: This does NOT check if the field is a table or struct, but we'd need
+ // access to the schema to check the is_struct flag.
+ FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
+ return table.GetStruct<const Struct *>(field.offset());
+}
+
+// Get a structure's field, if you know it's a struct.
+inline const Struct *GetFieldStruct(const Struct &structure,
+ const reflection::Field &field) {
+ FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj);
+ return structure.GetStruct<const Struct *>(field.offset());
+}
+
+// Raw helper functions used below: get any value in memory as a 64bit int, a
+// double or a string.
+// All scalars get static_cast to an int64_t, strings use strtoull, every other
+// data type returns 0.
+int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data);
+// All scalars static cast to double, strings use strtod, every other data
+// type is 0.0.
+double GetAnyValueF(reflection::BaseType type, const uint8_t *data);
+// All scalars converted using stringstream, strings as-is, and all other
+// data types provide some level of debug-pretty-printing.
+std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
+ const reflection::Schema *schema, int type_index);
+
+// Get any table field as a 64bit int, regardless of what type it is.
+inline int64_t GetAnyFieldI(const Table &table,
+ const reflection::Field &field) {
+ auto field_ptr = table.GetAddressOf(field.offset());
+ return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr)
+ : field.default_integer();
+}
+
+// Get any table field as a double, regardless of what type it is.
+inline double GetAnyFieldF(const Table &table, const reflection::Field &field) {
+ auto field_ptr = table.GetAddressOf(field.offset());
+ return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr)
+ : field.default_real();
+}
+
+// Get any table field as a string, regardless of what type it is.
+// You may pass nullptr for the schema if you don't care to have fields that
+// are of table type pretty-printed.
+inline std::string GetAnyFieldS(const Table &table,
+ const reflection::Field &field,
+ const reflection::Schema *schema) {
+ auto field_ptr = table.GetAddressOf(field.offset());
+ return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema,
+ field.type()->index())
+ : "";
+}
+
+// Get any struct field as a 64bit int, regardless of what type it is.
+inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) {
+ return GetAnyValueI(field.type()->base_type(),
+ st.GetAddressOf(field.offset()));
+}
+
+// Get any struct field as a double, regardless of what type it is.
+inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) {
+ return GetAnyValueF(field.type()->base_type(),
+ st.GetAddressOf(field.offset()));
+}
+
+// Get any struct field as a string, regardless of what type it is.
+inline std::string GetAnyFieldS(const Struct &st,
+ const reflection::Field &field) {
+ return GetAnyValueS(field.type()->base_type(),
+ st.GetAddressOf(field.offset()), nullptr, -1);
+}
+
+// Get any vector element as a 64bit int, regardless of what type it is.
+inline int64_t GetAnyVectorElemI(const VectorOfAny *vec,
+ reflection::BaseType elem_type, size_t i) {
+ return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
+}
+
+// Get any vector element as a double, regardless of what type it is.
+inline double GetAnyVectorElemF(const VectorOfAny *vec,
+ reflection::BaseType elem_type, size_t i) {
+ return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i);
+}
+
+// Get any vector element as a string, regardless of what type it is.
+inline std::string GetAnyVectorElemS(const VectorOfAny *vec,
+ reflection::BaseType elem_type, size_t i) {
+ return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i,
+ nullptr, -1);
+}
+
+// Get a vector element that's a table/string/vector from a generic vector.
+// Pass Table/String/VectorOfAny as template parameter.
+// Warning: does no typechecking.
+template<typename T>
+T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) {
+ auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i;
+ return reinterpret_cast<T*>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr));
+}
+
+// Get the inline-address of a vector element. Useful for Structs (pass Struct
+// as template arg), or being able to address a range of scalars in-line.
+// Get elem_size from GetTypeSizeInline().
+// Note: little-endian data on all platforms, use EndianScalar() instead of
+// raw pointer access with scalars).
+template<typename T>
+T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i,
+ size_t elem_size) {
+ return reinterpret_cast<T *>(vec->Data() + elem_size * i);
+}
+
+// Similarly, for elements of tables.
+template<typename T>
+T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) {
+ return reinterpret_cast<T *>(table.GetAddressOf(field.offset()));
+}
+
+// Similarly, for elements of structs.
+template<typename T>
+T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) {
+ return reinterpret_cast<T *>(st.GetAddressOf(field.offset()));
+}
+
+// ------------------------- SETTERS -------------------------
+
+// Set any scalar field, if you know its exact type.
+template<typename T>
+bool SetField(Table *table, const reflection::Field &field, T val) {
+ reflection::BaseType type = field.type()->base_type();
+ if (!IsScalar(type)) { return false; }
+ FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type));
+ T def;
+ if (IsInteger(type)) {
+ def = GetFieldDefaultI<T>(field);
+ } else {
+ FLATBUFFERS_ASSERT(IsFloat(type));
+ def = GetFieldDefaultF<T>(field);
+ }
+ return table->SetField(field.offset(), val, def);
+}
+
+// Raw helper functions used below: set any value in memory as a 64bit int, a
+// double or a string.
+// These work for all scalar values, but do nothing for other data types.
+// To set a string, see SetString below.
+void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val);
+void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val);
+void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
+
+// Set any table field as a 64bit int, regardless of type what it is.
+inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
+ int64_t val) {
+ auto field_ptr = table->GetAddressOf(field.offset());
+ if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
+ SetAnyValueI(field.type()->base_type(), field_ptr, val);
+ return true;
+}
+
+// Set any table field as a double, regardless of what type it is.
+inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
+ double val) {
+ auto field_ptr = table->GetAddressOf(field.offset());
+ if (!field_ptr) return val == GetFieldDefaultF<double>(field);
+ SetAnyValueF(field.type()->base_type(), field_ptr, val);
+ return true;
+}
+
+// Set any table field as a string, regardless of what type it is.
+inline bool SetAnyFieldS(Table *table, const reflection::Field &field,
+ const char *val) {
+ auto field_ptr = table->GetAddressOf(field.offset());
+ if (!field_ptr) return false;
+ SetAnyValueS(field.type()->base_type(), field_ptr, val);
+ return true;
+}
+
+// Set any struct field as a 64bit int, regardless of type what it is.
+inline void SetAnyFieldI(Struct *st, const reflection::Field &field,
+ int64_t val) {
+ SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()),
+ val);
+}
+
+// Set any struct field as a double, regardless of type what it is.
+inline void SetAnyFieldF(Struct *st, const reflection::Field &field,
+ double val) {
+ SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()),
+ val);
+}
+
+// Set any struct field as a string, regardless of type what it is.
+inline void SetAnyFieldS(Struct *st, const reflection::Field &field,
+ const char *val) {
+ SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()),
+ val);
+}
+
+// Set any vector element as a 64bit int, regardless of type what it is.
+inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type,
+ size_t i, int64_t val) {
+ SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
+}
+
+// Set any vector element as a double, regardless of type what it is.
+inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type,
+ size_t i, double val) {
+ SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
+}
+
+// Set any vector element as a string, regardless of type what it is.
+inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type,
+ size_t i, const char *val) {
+ SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val);
+}
+
+// ------------------------- RESIZING SETTERS -------------------------
+
+// "smart" pointer for use with resizing vectors: turns a pointer inside
+// a vector into a relative offset, such that it is not affected by resizes.
+template<typename T, typename U> class pointer_inside_vector {
+ public:
+ pointer_inside_vector(T *ptr, std::vector<U> &vec)
+ : offset_(reinterpret_cast<uint8_t *>(ptr) -
+ reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec))),
+ vec_(vec) {}
+
+ T *operator*() const {
+ return reinterpret_cast<T *>(
+ reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec_)) + offset_);
+ }
+ T *operator->() const { return operator*(); }
+ void operator=(const pointer_inside_vector &piv);
+
+ private:
+ size_t offset_;
+ std::vector<U> &vec_;
+};
+
+// Helper to create the above easily without specifying template args.
+template<typename T, typename U>
+pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) {
+ return pointer_inside_vector<T, U>(ptr, vec);
+}
+
+inline const char *UnionTypeFieldSuffix() { return "_type"; }
+
+// Helper to figure out the actual table type a union refers to.
+inline const reflection::Object &GetUnionType(
+ const reflection::Schema &schema, const reflection::Object &parent,
+ const reflection::Field &unionfield, const Table &table) {
+ auto enumdef = schema.enums()->Get(unionfield.type()->index());
+ // TODO: this is clumsy and slow, but no other way to find it?
+ auto type_field = parent.fields()->LookupByKey(
+ (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
+ FLATBUFFERS_ASSERT(type_field);
+ auto union_type = GetFieldI<uint8_t>(table, *type_field);
+ auto enumval = enumdef->values()->LookupByKey(union_type);
+ return *enumval->object();
+}
+
+// Changes the contents of a string inside a FlatBuffer. FlatBuffer must
+// live inside a std::vector so we can resize the buffer if needed.
+// "str" must live inside "flatbuf" and may be invalidated after this call.
+// If your FlatBuffer's root table is not the schema's root table, you should
+// pass in your root_table type as well.
+void SetString(const reflection::Schema &schema, const std::string &val,
+ const String *str, std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table = nullptr);
+
+// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must
+// live inside a std::vector so we can resize the buffer if needed.
+// "vec" must live inside "flatbuf" and may be invalidated after this call.
+// If your FlatBuffer's root table is not the schema's root table, you should
+// pass in your root_table type as well.
+uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
+ const VectorOfAny *vec, uoffset_t num_elems,
+ uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table = nullptr);
+
+template<typename T>
+void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
+ const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table = nullptr) {
+ auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size());
+ auto newelems = ResizeAnyVector(
+ schema, newsize, reinterpret_cast<const VectorOfAny *>(vec), vec->size(),
+ static_cast<uoffset_t>(sizeof(T)), flatbuf, root_table);
+ // Set new elements to "val".
+ for (int i = 0; i < delta_elem; i++) {
+ auto loc = newelems + i * sizeof(T);
+ auto is_scalar = flatbuffers::is_scalar<T>::value;
+ if (is_scalar) {
+ WriteScalar(loc, val);
+ } else { // struct
+ *reinterpret_cast<T *>(loc) = val;
+ }
+ }
+}
+
+// Adds any new data (in the form of a new FlatBuffer) to an existing
+// FlatBuffer. This can be used when any of the above methods are not
+// sufficient, in particular for adding new tables and new fields.
+// This is potentially slightly less efficient than a FlatBuffer constructed
+// in one piece, since the new FlatBuffer doesn't share any vtables with the
+// existing one.
+// The return value can now be set using Vector::MutateOffset or SetFieldT
+// below.
+const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
+ const uint8_t *newbuf, size_t newlen);
+
+inline bool SetFieldT(Table *table, const reflection::Field &field,
+ const uint8_t *val) {
+ FLATBUFFERS_ASSERT(sizeof(uoffset_t) ==
+ GetTypeSize(field.type()->base_type()));
+ return table->SetPointer(field.offset(), val);
+}
+
+// ------------------------- COPYING -------------------------
+
+// Generic copying of tables from a FlatBuffer into a FlatBuffer builder.
+// Can be used to do any kind of merging/selecting you may want to do out
+// of existing buffers. Also useful to reconstruct a whole buffer if the
+// above resizing functionality has introduced garbage in a buffer you want
+// to remove.
+// Note: this does not deal with DAGs correctly. If the table passed forms a
+// DAG, the copy will be a tree instead (with duplicates). Strings can be
+// shared however, by passing true for use_string_pooling.
+
+Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
+ const reflection::Schema &schema,
+ const reflection::Object &objectdef,
+ const Table &table,
+ bool use_string_pooling = false);
+
+// Verifies the provided flatbuffer using reflection.
+// root should point to the root type for this flatbuffer.
+// buf should point to the start of flatbuffer data.
+// length specifies the size of the flatbuffer data.
+bool Verify(const reflection::Schema &schema, const reflection::Object &root,
+ const uint8_t *buf, size_t length);
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_REFLECTION_H_
diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h
new file mode 100644
index 0000000..0e73a0f
--- /dev/null
+++ b/include/flatbuffers/reflection_generated.h
@@ -0,0 +1,1195 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
+#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace reflection {
+
+struct Type;
+
+struct KeyValue;
+
+struct EnumVal;
+
+struct Enum;
+
+struct Field;
+
+struct Object;
+
+struct RPCCall;
+
+struct Service;
+
+struct Schema;
+
+enum BaseType {
+ None = 0,
+ UType = 1,
+ Bool = 2,
+ Byte = 3,
+ UByte = 4,
+ Short = 5,
+ UShort = 6,
+ Int = 7,
+ UInt = 8,
+ Long = 9,
+ ULong = 10,
+ Float = 11,
+ Double = 12,
+ String = 13,
+ Vector = 14,
+ Obj = 15,
+ Union = 16,
+ Array = 17
+};
+
+inline const BaseType (&EnumValuesBaseType())[18] {
+ static const BaseType values[] = {
+ None,
+ UType,
+ Bool,
+ Byte,
+ UByte,
+ Short,
+ UShort,
+ Int,
+ UInt,
+ Long,
+ ULong,
+ Float,
+ Double,
+ String,
+ Vector,
+ Obj,
+ Union,
+ Array
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesBaseType() {
+ static const char * const names[19] = {
+ "None",
+ "UType",
+ "Bool",
+ "Byte",
+ "UByte",
+ "Short",
+ "UShort",
+ "Int",
+ "UInt",
+ "Long",
+ "ULong",
+ "Float",
+ "Double",
+ "String",
+ "Vector",
+ "Obj",
+ "Union",
+ "Array",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameBaseType(BaseType e) {
+ if (e < None || e > Array) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesBaseType()[index];
+}
+
+struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_BASE_TYPE = 4,
+ VT_ELEMENT = 6,
+ VT_INDEX = 8,
+ VT_FIXED_LENGTH = 10
+ };
+ reflection::BaseType base_type() const {
+ return static_cast<reflection::BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0));
+ }
+ reflection::BaseType element() const {
+ return static_cast<reflection::BaseType>(GetField<int8_t>(VT_ELEMENT, 0));
+ }
+ int32_t index() const {
+ return GetField<int32_t>(VT_INDEX, -1);
+ }
+ uint16_t fixed_length() const {
+ return GetField<uint16_t>(VT_FIXED_LENGTH, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_BASE_TYPE) &&
+ VerifyField<int8_t>(verifier, VT_ELEMENT) &&
+ VerifyField<int32_t>(verifier, VT_INDEX) &&
+ VerifyField<uint16_t>(verifier, VT_FIXED_LENGTH) &&
+ verifier.EndTable();
+ }
+};
+
+struct TypeBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_base_type(reflection::BaseType base_type) {
+ fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0);
+ }
+ void add_element(reflection::BaseType element) {
+ fbb_.AddElement<int8_t>(Type::VT_ELEMENT, static_cast<int8_t>(element), 0);
+ }
+ void add_index(int32_t index) {
+ fbb_.AddElement<int32_t>(Type::VT_INDEX, index, -1);
+ }
+ void add_fixed_length(uint16_t fixed_length) {
+ fbb_.AddElement<uint16_t>(Type::VT_FIXED_LENGTH, fixed_length, 0);
+ }
+ explicit TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ TypeBuilder &operator=(const TypeBuilder &);
+ flatbuffers::Offset<Type> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Type>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Type> CreateType(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ reflection::BaseType base_type = reflection::None,
+ reflection::BaseType element = reflection::None,
+ int32_t index = -1,
+ uint16_t fixed_length = 0) {
+ TypeBuilder builder_(_fbb);
+ builder_.add_index(index);
+ builder_.add_fixed_length(fixed_length);
+ builder_.add_element(element);
+ builder_.add_base_type(base_type);
+ return builder_.Finish();
+}
+
+struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_KEY = 4,
+ VT_VALUE = 6
+ };
+ const flatbuffers::String *key() const {
+ return GetPointer<const flatbuffers::String *>(VT_KEY);
+ }
+ bool KeyCompareLessThan(const KeyValue *o) const {
+ return *key() < *o->key();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(key()->c_str(), val);
+ }
+ const flatbuffers::String *value() const {
+ return GetPointer<const flatbuffers::String *>(VT_VALUE);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_KEY) &&
+ verifier.VerifyString(key()) &&
+ VerifyOffset(verifier, VT_VALUE) &&
+ verifier.VerifyString(value()) &&
+ verifier.EndTable();
+ }
+};
+
+struct KeyValueBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_key(flatbuffers::Offset<flatbuffers::String> key) {
+ fbb_.AddOffset(KeyValue::VT_KEY, key);
+ }
+ void add_value(flatbuffers::Offset<flatbuffers::String> value) {
+ fbb_.AddOffset(KeyValue::VT_VALUE, value);
+ }
+ explicit KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ KeyValueBuilder &operator=(const KeyValueBuilder &);
+ flatbuffers::Offset<KeyValue> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<KeyValue>(end);
+ fbb_.Required(o, KeyValue::VT_KEY);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<KeyValue> CreateKeyValue(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> key = 0,
+ flatbuffers::Offset<flatbuffers::String> value = 0) {
+ KeyValueBuilder builder_(_fbb);
+ builder_.add_value(value);
+ builder_.add_key(key);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *key = nullptr,
+ const char *value = nullptr) {
+ auto key__ = key ? _fbb.CreateString(key) : 0;
+ auto value__ = value ? _fbb.CreateString(value) : 0;
+ return reflection::CreateKeyValue(
+ _fbb,
+ key__,
+ value__);
+}
+
+struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_VALUE = 6,
+ VT_OBJECT = 8,
+ VT_UNION_TYPE = 10,
+ VT_DOCUMENTATION = 12
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ int64_t value() const {
+ return GetField<int64_t>(VT_VALUE, 0);
+ }
+ bool KeyCompareLessThan(const EnumVal *o) const {
+ return value() < o->value();
+ }
+ int KeyCompareWithValue(int64_t val) const {
+ return static_cast<int>(value() > val) - static_cast<int>(value() < val);
+ }
+ const reflection::Object *object() const {
+ return GetPointer<const reflection::Object *>(VT_OBJECT);
+ }
+ const reflection::Type *union_type() const {
+ return GetPointer<const reflection::Type *>(VT_UNION_TYPE);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyField<int64_t>(verifier, VT_VALUE) &&
+ VerifyOffset(verifier, VT_OBJECT) &&
+ verifier.VerifyTable(object()) &&
+ VerifyOffset(verifier, VT_UNION_TYPE) &&
+ verifier.VerifyTable(union_type()) &&
+ VerifyOffset(verifier, VT_DOCUMENTATION) &&
+ verifier.VerifyVector(documentation()) &&
+ verifier.VerifyVectorOfStrings(documentation()) &&
+ verifier.EndTable();
+ }
+};
+
+struct EnumValBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(EnumVal::VT_NAME, name);
+ }
+ void add_value(int64_t value) {
+ fbb_.AddElement<int64_t>(EnumVal::VT_VALUE, value, 0);
+ }
+ void add_object(flatbuffers::Offset<reflection::Object> object) {
+ fbb_.AddOffset(EnumVal::VT_OBJECT, object);
+ }
+ void add_union_type(flatbuffers::Offset<reflection::Type> union_type) {
+ fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
+ }
+ void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
+ fbb_.AddOffset(EnumVal::VT_DOCUMENTATION, documentation);
+ }
+ explicit EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ EnumValBuilder &operator=(const EnumValBuilder &);
+ flatbuffers::Offset<EnumVal> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<EnumVal>(end);
+ fbb_.Required(o, EnumVal::VT_NAME);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<EnumVal> CreateEnumVal(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ int64_t value = 0,
+ flatbuffers::Offset<reflection::Object> object = 0,
+ flatbuffers::Offset<reflection::Type> union_type = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
+ EnumValBuilder builder_(_fbb);
+ builder_.add_value(value);
+ builder_.add_documentation(documentation);
+ builder_.add_union_type(union_type);
+ builder_.add_object(object);
+ builder_.add_name(name);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ int64_t value = 0,
+ flatbuffers::Offset<reflection::Object> object = 0,
+ flatbuffers::Offset<reflection::Type> union_type = 0,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
+ return reflection::CreateEnumVal(
+ _fbb,
+ name__,
+ value,
+ object,
+ union_type,
+ documentation__);
+}
+
+struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_VALUES = 6,
+ VT_IS_UNION = 8,
+ VT_UNDERLYING_TYPE = 10,
+ VT_ATTRIBUTES = 12,
+ VT_DOCUMENTATION = 14
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ bool KeyCompareLessThan(const Enum *o) const {
+ return *name() < *o->name();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(name()->c_str(), val);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>> *values() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>> *>(VT_VALUES);
+ }
+ bool is_union() const {
+ return GetField<uint8_t>(VT_IS_UNION, 0) != 0;
+ }
+ const reflection::Type *underlying_type() const {
+ return GetPointer<const reflection::Type *>(VT_UNDERLYING_TYPE);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffsetRequired(verifier, VT_VALUES) &&
+ verifier.VerifyVector(values()) &&
+ verifier.VerifyVectorOfTables(values()) &&
+ VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
+ VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
+ verifier.VerifyTable(underlying_type()) &&
+ VerifyOffset(verifier, VT_ATTRIBUTES) &&
+ verifier.VerifyVector(attributes()) &&
+ verifier.VerifyVectorOfTables(attributes()) &&
+ VerifyOffset(verifier, VT_DOCUMENTATION) &&
+ verifier.VerifyVector(documentation()) &&
+ verifier.VerifyVectorOfStrings(documentation()) &&
+ verifier.EndTable();
+ }
+};
+
+struct EnumBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Enum::VT_NAME, name);
+ }
+ void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>>> values) {
+ fbb_.AddOffset(Enum::VT_VALUES, values);
+ }
+ void add_is_union(bool is_union) {
+ fbb_.AddElement<uint8_t>(Enum::VT_IS_UNION, static_cast<uint8_t>(is_union), 0);
+ }
+ void add_underlying_type(flatbuffers::Offset<reflection::Type> underlying_type) {
+ fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type);
+ }
+ void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) {
+ fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes);
+ }
+ void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
+ fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation);
+ }
+ explicit EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ EnumBuilder &operator=(const EnumBuilder &);
+ flatbuffers::Offset<Enum> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Enum>(end);
+ fbb_.Required(o, Enum::VT_NAME);
+ fbb_.Required(o, Enum::VT_VALUES);
+ fbb_.Required(o, Enum::VT_UNDERLYING_TYPE);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Enum> CreateEnum(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>>> values = 0,
+ bool is_union = false,
+ flatbuffers::Offset<reflection::Type> underlying_type = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
+ EnumBuilder builder_(_fbb);
+ builder_.add_documentation(documentation);
+ builder_.add_attributes(attributes);
+ builder_.add_underlying_type(underlying_type);
+ builder_.add_values(values);
+ builder_.add_name(name);
+ builder_.add_is_union(is_union);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Enum> CreateEnumDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ const std::vector<flatbuffers::Offset<reflection::EnumVal>> *values = nullptr,
+ bool is_union = false,
+ flatbuffers::Offset<reflection::Type> underlying_type = 0,
+ const std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto values__ = values ? _fbb.CreateVector<flatbuffers::Offset<reflection::EnumVal>>(*values) : 0;
+ auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<reflection::KeyValue>>(*attributes) : 0;
+ auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
+ return reflection::CreateEnum(
+ _fbb,
+ name__,
+ values__,
+ is_union,
+ underlying_type,
+ attributes__,
+ documentation__);
+}
+
+struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_TYPE = 6,
+ VT_ID = 8,
+ VT_OFFSET = 10,
+ VT_DEFAULT_INTEGER = 12,
+ VT_DEFAULT_REAL = 14,
+ VT_DEPRECATED = 16,
+ VT_REQUIRED = 18,
+ VT_KEY = 20,
+ VT_ATTRIBUTES = 22,
+ VT_DOCUMENTATION = 24
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ bool KeyCompareLessThan(const Field *o) const {
+ return *name() < *o->name();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(name()->c_str(), val);
+ }
+ const reflection::Type *type() const {
+ return GetPointer<const reflection::Type *>(VT_TYPE);
+ }
+ uint16_t id() const {
+ return GetField<uint16_t>(VT_ID, 0);
+ }
+ uint16_t offset() const {
+ return GetField<uint16_t>(VT_OFFSET, 0);
+ }
+ int64_t default_integer() const {
+ return GetField<int64_t>(VT_DEFAULT_INTEGER, 0);
+ }
+ double default_real() const {
+ return GetField<double>(VT_DEFAULT_REAL, 0.0);
+ }
+ bool deprecated() const {
+ return GetField<uint8_t>(VT_DEPRECATED, 0) != 0;
+ }
+ bool required() const {
+ return GetField<uint8_t>(VT_REQUIRED, 0) != 0;
+ }
+ bool key() const {
+ return GetField<uint8_t>(VT_KEY, 0) != 0;
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffsetRequired(verifier, VT_TYPE) &&
+ verifier.VerifyTable(type()) &&
+ VerifyField<uint16_t>(verifier, VT_ID) &&
+ VerifyField<uint16_t>(verifier, VT_OFFSET) &&
+ VerifyField<int64_t>(verifier, VT_DEFAULT_INTEGER) &&
+ VerifyField<double>(verifier, VT_DEFAULT_REAL) &&
+ VerifyField<uint8_t>(verifier, VT_DEPRECATED) &&
+ VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
+ VerifyField<uint8_t>(verifier, VT_KEY) &&
+ VerifyOffset(verifier, VT_ATTRIBUTES) &&
+ verifier.VerifyVector(attributes()) &&
+ verifier.VerifyVectorOfTables(attributes()) &&
+ VerifyOffset(verifier, VT_DOCUMENTATION) &&
+ verifier.VerifyVector(documentation()) &&
+ verifier.VerifyVectorOfStrings(documentation()) &&
+ verifier.EndTable();
+ }
+};
+
+struct FieldBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Field::VT_NAME, name);
+ }
+ void add_type(flatbuffers::Offset<reflection::Type> type) {
+ fbb_.AddOffset(Field::VT_TYPE, type);
+ }
+ void add_id(uint16_t id) {
+ fbb_.AddElement<uint16_t>(Field::VT_ID, id, 0);
+ }
+ void add_offset(uint16_t offset) {
+ fbb_.AddElement<uint16_t>(Field::VT_OFFSET, offset, 0);
+ }
+ void add_default_integer(int64_t default_integer) {
+ fbb_.AddElement<int64_t>(Field::VT_DEFAULT_INTEGER, default_integer, 0);
+ }
+ void add_default_real(double default_real) {
+ fbb_.AddElement<double>(Field::VT_DEFAULT_REAL, default_real, 0.0);
+ }
+ void add_deprecated(bool deprecated) {
+ fbb_.AddElement<uint8_t>(Field::VT_DEPRECATED, static_cast<uint8_t>(deprecated), 0);
+ }
+ void add_required(bool required) {
+ fbb_.AddElement<uint8_t>(Field::VT_REQUIRED, static_cast<uint8_t>(required), 0);
+ }
+ void add_key(bool key) {
+ fbb_.AddElement<uint8_t>(Field::VT_KEY, static_cast<uint8_t>(key), 0);
+ }
+ void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) {
+ fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes);
+ }
+ void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
+ fbb_.AddOffset(Field::VT_DOCUMENTATION, documentation);
+ }
+ explicit FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ FieldBuilder &operator=(const FieldBuilder &);
+ flatbuffers::Offset<Field> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Field>(end);
+ fbb_.Required(o, Field::VT_NAME);
+ fbb_.Required(o, Field::VT_TYPE);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Field> CreateField(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<reflection::Type> type = 0,
+ uint16_t id = 0,
+ uint16_t offset = 0,
+ int64_t default_integer = 0,
+ double default_real = 0.0,
+ bool deprecated = false,
+ bool required = false,
+ bool key = false,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
+ FieldBuilder builder_(_fbb);
+ builder_.add_default_real(default_real);
+ builder_.add_default_integer(default_integer);
+ builder_.add_documentation(documentation);
+ builder_.add_attributes(attributes);
+ builder_.add_type(type);
+ builder_.add_name(name);
+ builder_.add_offset(offset);
+ builder_.add_id(id);
+ builder_.add_key(key);
+ builder_.add_required(required);
+ builder_.add_deprecated(deprecated);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Field> CreateFieldDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ flatbuffers::Offset<reflection::Type> type = 0,
+ uint16_t id = 0,
+ uint16_t offset = 0,
+ int64_t default_integer = 0,
+ double default_real = 0.0,
+ bool deprecated = false,
+ bool required = false,
+ bool key = false,
+ const std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<reflection::KeyValue>>(*attributes) : 0;
+ auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
+ return reflection::CreateField(
+ _fbb,
+ name__,
+ type,
+ id,
+ offset,
+ default_integer,
+ default_real,
+ deprecated,
+ required,
+ key,
+ attributes__,
+ documentation__);
+}
+
+struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_FIELDS = 6,
+ VT_IS_STRUCT = 8,
+ VT_MINALIGN = 10,
+ VT_BYTESIZE = 12,
+ VT_ATTRIBUTES = 14,
+ VT_DOCUMENTATION = 16
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ bool KeyCompareLessThan(const Object *o) const {
+ return *name() < *o->name();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(name()->c_str(), val);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::Field>> *fields() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Field>> *>(VT_FIELDS);
+ }
+ bool is_struct() const {
+ return GetField<uint8_t>(VT_IS_STRUCT, 0) != 0;
+ }
+ int32_t minalign() const {
+ return GetField<int32_t>(VT_MINALIGN, 0);
+ }
+ int32_t bytesize() const {
+ return GetField<int32_t>(VT_BYTESIZE, 0);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffsetRequired(verifier, VT_FIELDS) &&
+ verifier.VerifyVector(fields()) &&
+ verifier.VerifyVectorOfTables(fields()) &&
+ VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
+ VerifyField<int32_t>(verifier, VT_MINALIGN) &&
+ VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
+ VerifyOffset(verifier, VT_ATTRIBUTES) &&
+ verifier.VerifyVector(attributes()) &&
+ verifier.VerifyVectorOfTables(attributes()) &&
+ VerifyOffset(verifier, VT_DOCUMENTATION) &&
+ verifier.VerifyVector(documentation()) &&
+ verifier.VerifyVectorOfStrings(documentation()) &&
+ verifier.EndTable();
+ }
+};
+
+struct ObjectBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Object::VT_NAME, name);
+ }
+ void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Field>>> fields) {
+ fbb_.AddOffset(Object::VT_FIELDS, fields);
+ }
+ void add_is_struct(bool is_struct) {
+ fbb_.AddElement<uint8_t>(Object::VT_IS_STRUCT, static_cast<uint8_t>(is_struct), 0);
+ }
+ void add_minalign(int32_t minalign) {
+ fbb_.AddElement<int32_t>(Object::VT_MINALIGN, minalign, 0);
+ }
+ void add_bytesize(int32_t bytesize) {
+ fbb_.AddElement<int32_t>(Object::VT_BYTESIZE, bytesize, 0);
+ }
+ void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) {
+ fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes);
+ }
+ void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
+ fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation);
+ }
+ explicit ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ ObjectBuilder &operator=(const ObjectBuilder &);
+ flatbuffers::Offset<Object> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Object>(end);
+ fbb_.Required(o, Object::VT_NAME);
+ fbb_.Required(o, Object::VT_FIELDS);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Object> CreateObject(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Field>>> fields = 0,
+ bool is_struct = false,
+ int32_t minalign = 0,
+ int32_t bytesize = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
+ ObjectBuilder builder_(_fbb);
+ builder_.add_documentation(documentation);
+ builder_.add_attributes(attributes);
+ builder_.add_bytesize(bytesize);
+ builder_.add_minalign(minalign);
+ builder_.add_fields(fields);
+ builder_.add_name(name);
+ builder_.add_is_struct(is_struct);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Object> CreateObjectDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ const std::vector<flatbuffers::Offset<reflection::Field>> *fields = nullptr,
+ bool is_struct = false,
+ int32_t minalign = 0,
+ int32_t bytesize = 0,
+ const std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto fields__ = fields ? _fbb.CreateVector<flatbuffers::Offset<reflection::Field>>(*fields) : 0;
+ auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<reflection::KeyValue>>(*attributes) : 0;
+ auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
+ return reflection::CreateObject(
+ _fbb,
+ name__,
+ fields__,
+ is_struct,
+ minalign,
+ bytesize,
+ attributes__,
+ documentation__);
+}
+
+struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_REQUEST = 6,
+ VT_RESPONSE = 8,
+ VT_ATTRIBUTES = 10,
+ VT_DOCUMENTATION = 12
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ bool KeyCompareLessThan(const RPCCall *o) const {
+ return *name() < *o->name();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(name()->c_str(), val);
+ }
+ const reflection::Object *request() const {
+ return GetPointer<const reflection::Object *>(VT_REQUEST);
+ }
+ const reflection::Object *response() const {
+ return GetPointer<const reflection::Object *>(VT_RESPONSE);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffsetRequired(verifier, VT_REQUEST) &&
+ verifier.VerifyTable(request()) &&
+ VerifyOffsetRequired(verifier, VT_RESPONSE) &&
+ verifier.VerifyTable(response()) &&
+ VerifyOffset(verifier, VT_ATTRIBUTES) &&
+ verifier.VerifyVector(attributes()) &&
+ verifier.VerifyVectorOfTables(attributes()) &&
+ VerifyOffset(verifier, VT_DOCUMENTATION) &&
+ verifier.VerifyVector(documentation()) &&
+ verifier.VerifyVectorOfStrings(documentation()) &&
+ verifier.EndTable();
+ }
+};
+
+struct RPCCallBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(RPCCall::VT_NAME, name);
+ }
+ void add_request(flatbuffers::Offset<reflection::Object> request) {
+ fbb_.AddOffset(RPCCall::VT_REQUEST, request);
+ }
+ void add_response(flatbuffers::Offset<reflection::Object> response) {
+ fbb_.AddOffset(RPCCall::VT_RESPONSE, response);
+ }
+ void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) {
+ fbb_.AddOffset(RPCCall::VT_ATTRIBUTES, attributes);
+ }
+ void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
+ fbb_.AddOffset(RPCCall::VT_DOCUMENTATION, documentation);
+ }
+ explicit RPCCallBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ RPCCallBuilder &operator=(const RPCCallBuilder &);
+ flatbuffers::Offset<RPCCall> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<RPCCall>(end);
+ fbb_.Required(o, RPCCall::VT_NAME);
+ fbb_.Required(o, RPCCall::VT_REQUEST);
+ fbb_.Required(o, RPCCall::VT_RESPONSE);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<RPCCall> CreateRPCCall(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<reflection::Object> request = 0,
+ flatbuffers::Offset<reflection::Object> response = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
+ RPCCallBuilder builder_(_fbb);
+ builder_.add_documentation(documentation);
+ builder_.add_attributes(attributes);
+ builder_.add_response(response);
+ builder_.add_request(request);
+ builder_.add_name(name);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<RPCCall> CreateRPCCallDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ flatbuffers::Offset<reflection::Object> request = 0,
+ flatbuffers::Offset<reflection::Object> response = 0,
+ const std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<reflection::KeyValue>>(*attributes) : 0;
+ auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
+ return reflection::CreateRPCCall(
+ _fbb,
+ name__,
+ request,
+ response,
+ attributes__,
+ documentation__);
+}
+
+struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_CALLS = 6,
+ VT_ATTRIBUTES = 8,
+ VT_DOCUMENTATION = 10
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ bool KeyCompareLessThan(const Service *o) const {
+ return *name() < *o->name();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(name()->c_str(), val);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>> *calls() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>> *>(VT_CALLS);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffset(verifier, VT_CALLS) &&
+ verifier.VerifyVector(calls()) &&
+ verifier.VerifyVectorOfTables(calls()) &&
+ VerifyOffset(verifier, VT_ATTRIBUTES) &&
+ verifier.VerifyVector(attributes()) &&
+ verifier.VerifyVectorOfTables(attributes()) &&
+ VerifyOffset(verifier, VT_DOCUMENTATION) &&
+ verifier.VerifyVector(documentation()) &&
+ verifier.VerifyVectorOfStrings(documentation()) &&
+ verifier.EndTable();
+ }
+};
+
+struct ServiceBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Service::VT_NAME, name);
+ }
+ void add_calls(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>>> calls) {
+ fbb_.AddOffset(Service::VT_CALLS, calls);
+ }
+ void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) {
+ fbb_.AddOffset(Service::VT_ATTRIBUTES, attributes);
+ }
+ void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) {
+ fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation);
+ }
+ explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ ServiceBuilder &operator=(const ServiceBuilder &);
+ flatbuffers::Offset<Service> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Service>(end);
+ fbb_.Required(o, Service::VT_NAME);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Service> CreateService(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>>> calls = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) {
+ ServiceBuilder builder_(_fbb);
+ builder_.add_documentation(documentation);
+ builder_.add_attributes(attributes);
+ builder_.add_calls(calls);
+ builder_.add_name(name);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Service> CreateServiceDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ const std::vector<flatbuffers::Offset<reflection::RPCCall>> *calls = nullptr,
+ const std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto calls__ = calls ? _fbb.CreateVector<flatbuffers::Offset<reflection::RPCCall>>(*calls) : 0;
+ auto attributes__ = attributes ? _fbb.CreateVector<flatbuffers::Offset<reflection::KeyValue>>(*attributes) : 0;
+ auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0;
+ return reflection::CreateService(
+ _fbb,
+ name__,
+ calls__,
+ attributes__,
+ documentation__);
+}
+
+struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_OBJECTS = 4,
+ VT_ENUMS = 6,
+ VT_FILE_IDENT = 8,
+ VT_FILE_EXT = 10,
+ VT_ROOT_TABLE = 12,
+ VT_SERVICES = 14
+ };
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *>(VT_OBJECTS);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *>(VT_ENUMS);
+ }
+ const flatbuffers::String *file_ident() const {
+ return GetPointer<const flatbuffers::String *>(VT_FILE_IDENT);
+ }
+ const flatbuffers::String *file_ext() const {
+ return GetPointer<const flatbuffers::String *>(VT_FILE_EXT);
+ }
+ const reflection::Object *root_table() const {
+ return GetPointer<const reflection::Object *>(VT_ROOT_TABLE);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<reflection::Service>> *services() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Service>> *>(VT_SERVICES);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffsetRequired(verifier, VT_OBJECTS) &&
+ verifier.VerifyVector(objects()) &&
+ verifier.VerifyVectorOfTables(objects()) &&
+ VerifyOffsetRequired(verifier, VT_ENUMS) &&
+ verifier.VerifyVector(enums()) &&
+ verifier.VerifyVectorOfTables(enums()) &&
+ VerifyOffset(verifier, VT_FILE_IDENT) &&
+ verifier.VerifyString(file_ident()) &&
+ VerifyOffset(verifier, VT_FILE_EXT) &&
+ verifier.VerifyString(file_ext()) &&
+ VerifyOffset(verifier, VT_ROOT_TABLE) &&
+ verifier.VerifyTable(root_table()) &&
+ VerifyOffset(verifier, VT_SERVICES) &&
+ verifier.VerifyVector(services()) &&
+ verifier.VerifyVectorOfTables(services()) &&
+ verifier.EndTable();
+ }
+};
+
+struct SchemaBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>> objects) {
+ fbb_.AddOffset(Schema::VT_OBJECTS, objects);
+ }
+ void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>>> enums) {
+ fbb_.AddOffset(Schema::VT_ENUMS, enums);
+ }
+ void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) {
+ fbb_.AddOffset(Schema::VT_FILE_IDENT, file_ident);
+ }
+ void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) {
+ fbb_.AddOffset(Schema::VT_FILE_EXT, file_ext);
+ }
+ void add_root_table(flatbuffers::Offset<reflection::Object> root_table) {
+ fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table);
+ }
+ void add_services(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services) {
+ fbb_.AddOffset(Schema::VT_SERVICES, services);
+ }
+ explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ SchemaBuilder &operator=(const SchemaBuilder &);
+ flatbuffers::Offset<Schema> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Schema>(end);
+ fbb_.Required(o, Schema::VT_OBJECTS);
+ fbb_.Required(o, Schema::VT_ENUMS);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Schema> CreateSchema(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>> objects = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>>> enums = 0,
+ flatbuffers::Offset<flatbuffers::String> file_ident = 0,
+ flatbuffers::Offset<flatbuffers::String> file_ext = 0,
+ flatbuffers::Offset<reflection::Object> root_table = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services = 0) {
+ SchemaBuilder builder_(_fbb);
+ builder_.add_services(services);
+ builder_.add_root_table(root_table);
+ builder_.add_file_ext(file_ext);
+ builder_.add_file_ident(file_ident);
+ builder_.add_enums(enums);
+ builder_.add_objects(objects);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Schema> CreateSchemaDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<flatbuffers::Offset<reflection::Object>> *objects = nullptr,
+ const std::vector<flatbuffers::Offset<reflection::Enum>> *enums = nullptr,
+ const char *file_ident = nullptr,
+ const char *file_ext = nullptr,
+ flatbuffers::Offset<reflection::Object> root_table = 0,
+ const std::vector<flatbuffers::Offset<reflection::Service>> *services = nullptr) {
+ auto objects__ = objects ? _fbb.CreateVector<flatbuffers::Offset<reflection::Object>>(*objects) : 0;
+ auto enums__ = enums ? _fbb.CreateVector<flatbuffers::Offset<reflection::Enum>>(*enums) : 0;
+ auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0;
+ auto file_ext__ = file_ext ? _fbb.CreateString(file_ext) : 0;
+ auto services__ = services ? _fbb.CreateVector<flatbuffers::Offset<reflection::Service>>(*services) : 0;
+ return reflection::CreateSchema(
+ _fbb,
+ objects__,
+ enums__,
+ file_ident__,
+ file_ext__,
+ root_table,
+ services__);
+}
+
+inline const reflection::Schema *GetSchema(const void *buf) {
+ return flatbuffers::GetRoot<reflection::Schema>(buf);
+}
+
+inline const reflection::Schema *GetSizePrefixedSchema(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<reflection::Schema>(buf);
+}
+
+inline const char *SchemaIdentifier() {
+ return "BFBS";
+}
+
+inline bool SchemaBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(
+ buf, SchemaIdentifier());
+}
+
+inline bool VerifySchemaBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier());
+}
+
+inline bool VerifySizePrefixedSchemaBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<reflection::Schema>(SchemaIdentifier());
+}
+
+inline const char *SchemaExtension() {
+ return "bfbs";
+}
+
+inline void FinishSchemaBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<reflection::Schema> root) {
+ fbb.Finish(root, SchemaIdentifier());
+}
+
+inline void FinishSizePrefixedSchemaBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<reflection::Schema> root) {
+ fbb.FinishSizePrefixed(root, SchemaIdentifier());
+}
+
+} // namespace reflection
+
+#endif // FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
diff --git a/include/flatbuffers/registry.h b/include/flatbuffers/registry.h
new file mode 100644
index 0000000..9ea425b
--- /dev/null
+++ b/include/flatbuffers/registry.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_REGISTRY_H_
+#define FLATBUFFERS_REGISTRY_H_
+
+#include "flatbuffers/idl.h"
+
+namespace flatbuffers {
+
+// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
+// Simply pre-populate it with all schema filenames that may be in use, and
+// This class will look them up using the file_identifier declared in the
+// schema.
+class Registry {
+ public:
+ // Call this for all schemas that may be in use. The identifier has
+ // a function in the generated code, e.g. MonsterIdentifier().
+ void Register(const char *file_identifier, const char *schema_path) {
+ Schema schema;
+ schema.path_ = schema_path;
+ schemas_[file_identifier] = schema;
+ }
+
+ // Generate text from an arbitrary FlatBuffer by looking up its
+ // file_identifier in the registry.
+ bool FlatBufferToText(const uint8_t *flatbuf, size_t len, std::string *dest) {
+ // Get the identifier out of the buffer.
+ // If the buffer is truncated, exit.
+ if (len < sizeof(uoffset_t) + FlatBufferBuilder::kFileIdentifierLength) {
+ lasterror_ = "buffer truncated";
+ return false;
+ }
+ std::string ident(
+ reinterpret_cast<const char *>(flatbuf) + sizeof(uoffset_t),
+ FlatBufferBuilder::kFileIdentifierLength);
+ // Load and parse the schema.
+ Parser parser;
+ if (!LoadSchema(ident, &parser)) return false;
+ // Now we're ready to generate text.
+ if (!GenerateText(parser, flatbuf, dest)) {
+ lasterror_ = "unable to generate text for FlatBuffer binary";
+ return false;
+ }
+ return true;
+ }
+
+ // Converts a binary buffer to text using one of the schemas in the registry,
+ // use the file_identifier to indicate which.
+ // If DetachedBuffer::data() is null then parsing failed.
+ DetachedBuffer TextToFlatBuffer(const char *text,
+ const char *file_identifier) {
+ // Load and parse the schema.
+ Parser parser;
+ if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
+ // Parse the text.
+ if (!parser.Parse(text)) {
+ lasterror_ = parser.error_;
+ return DetachedBuffer();
+ }
+ // We have a valid FlatBuffer. Detach it from the builder and return.
+ return parser.builder_.Release();
+ }
+
+ // Modify any parsing / output options used by the other functions.
+ void SetOptions(const IDLOptions &opts) { opts_ = opts; }
+
+ // If schemas used contain include statements, call this function for every
+ // directory the parser should search them for.
+ void AddIncludeDirectory(const char *path) { include_paths_.push_back(path); }
+
+ // Returns a human readable error if any of the above functions fail.
+ const std::string &GetLastError() { return lasterror_; }
+
+ private:
+ bool LoadSchema(const std::string &ident, Parser *parser) {
+ // Find the schema, if not, exit.
+ auto it = schemas_.find(ident);
+ if (it == schemas_.end()) {
+ // Don't attach the identifier, since it may not be human readable.
+ lasterror_ = "identifier for this buffer not in the registry";
+ return false;
+ }
+ auto &schema = it->second;
+ // Load the schema from disk. If not, exit.
+ std::string schematext;
+ if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
+ lasterror_ = "could not load schema: " + schema.path_;
+ return false;
+ }
+ // Parse schema.
+ parser->opts = opts_;
+ if (!parser->Parse(schematext.c_str(), vector_data(include_paths_),
+ schema.path_.c_str())) {
+ lasterror_ = parser->error_;
+ return false;
+ }
+ return true;
+ }
+
+ struct Schema {
+ std::string path_;
+ // TODO(wvo) optionally cache schema file or parsed schema here.
+ };
+
+ std::string lasterror_;
+ IDLOptions opts_;
+ std::vector<const char *> include_paths_;
+ std::map<std::string, Schema> schemas_;
+};
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_REGISTRY_H_
diff --git a/include/flatbuffers/stl_emulation.h b/include/flatbuffers/stl_emulation.h
new file mode 100644
index 0000000..6f6e766
--- /dev/null
+++ b/include/flatbuffers/stl_emulation.h
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_STL_EMULATION_H_
+#define FLATBUFFERS_STL_EMULATION_H_
+
+// clang-format off
+
+#include <string>
+#include <type_traits>
+#include <vector>
+#include <memory>
+#include <limits>
+
+#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
+ #define FLATBUFFERS_CPP98_STL
+#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
+
+#if 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 {
+
+// Retrieve ::back() from a string in a way that is compatible with pre C++11
+// STLs (e.g stlport).
+inline char& string_back(std::string &value) {
+ return value[value.length() - 1];
+}
+
+inline char string_back(const std::string &value) {
+ return value[value.length() - 1];
+}
+
+// Helper method that retrieves ::data() from a vector in a way that is
+// compatible with pre C++11 STLs (e.g stlport).
+template <typename T> inline T *vector_data(std::vector<T> &vector) {
+ // In some debug environments, operator[] does bounds checking, so &vector[0]
+ // can't be used.
+ return vector.empty() ? nullptr : &vector[0];
+}
+
+template <typename T> inline const T *vector_data(
+ const std::vector<T> &vector) {
+ return vector.empty() ? nullptr : &vector[0];
+}
+
+template <typename T, typename V>
+inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
+ #if defined(FLATBUFFERS_CPP98_STL)
+ vector->push_back(data);
+ #else
+ vector->emplace_back(std::forward<V>(data));
+ #endif // defined(FLATBUFFERS_CPP98_STL)
+}
+
+#ifndef FLATBUFFERS_CPP98_STL
+ #if defined(FLATBUFFERS_TEMPLATES_ALIASES)
+ template <typename T>
+ using numeric_limits = std::numeric_limits<T>;
+ #else
+ template <typename T> class numeric_limits :
+ public std::numeric_limits<T> {};
+ #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
+#else
+ template <typename T> class numeric_limits :
+ public std::numeric_limits<T> {
+ public:
+ // Android NDK fix.
+ static T lowest() {
+ return std::numeric_limits<T>::min();
+ }
+ };
+
+ template <> class numeric_limits<float> :
+ public std::numeric_limits<float> {
+ public:
+ static float lowest() { return -FLT_MAX; }
+ };
+
+ template <> class numeric_limits<double> :
+ public std::numeric_limits<double> {
+ public:
+ static double lowest() { return -DBL_MAX; }
+ };
+
+ template <> class numeric_limits<unsigned long long> {
+ public:
+ static unsigned long long min() { return 0ULL; }
+ static unsigned long long max() { return ~0ULL; }
+ static unsigned long long lowest() {
+ return numeric_limits<unsigned long long>::min();
+ }
+ };
+
+ template <> class numeric_limits<long long> {
+ public:
+ static long long min() {
+ return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
+ }
+ static long long max() {
+ return static_cast<long long>(
+ (1ULL << ((sizeof(long long) << 3) - 1)) - 1);
+ }
+ static long long lowest() {
+ return numeric_limits<long long>::min();
+ }
+ };
+#endif // FLATBUFFERS_CPP98_STL
+
+#if defined(FLATBUFFERS_TEMPLATES_ALIASES)
+ #ifndef FLATBUFFERS_CPP98_STL
+ template <typename T> using is_scalar = std::is_scalar<T>;
+ template <typename T, typename U> using is_same = std::is_same<T,U>;
+ template <typename T> using is_floating_point = std::is_floating_point<T>;
+ template <typename T> using is_unsigned = std::is_unsigned<T>;
+ template <typename T> using make_unsigned = std::make_unsigned<T>;
+ #else
+ // Map C++ TR1 templates defined by stlport.
+ template <typename T> using is_scalar = std::tr1::is_scalar<T>;
+ template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
+ template <typename T> using is_floating_point =
+ std::tr1::is_floating_point<T>;
+ template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
+ // Android NDK doesn't have std::make_unsigned or std::tr1::make_unsigned.
+ template<typename T> struct make_unsigned {
+ static_assert(is_unsigned<T>::value, "Specialization not implemented!");
+ using type = T;
+ };
+ template<> struct make_unsigned<char> { using type = unsigned char; };
+ template<> struct make_unsigned<short> { using type = unsigned short; };
+ template<> struct make_unsigned<int> { using type = unsigned int; };
+ template<> struct make_unsigned<long> { using type = unsigned long; };
+ template<>
+ struct make_unsigned<long long> { using type = unsigned long long; };
+ #endif // !FLATBUFFERS_CPP98_STL
+#else
+ // MSVC 2010 doesn't support C++11 aliases.
+ template <typename T> struct is_scalar : public std::is_scalar<T> {};
+ template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
+ template <typename T> struct is_floating_point :
+ public std::is_floating_point<T> {};
+ template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
+ template <typename T> struct make_unsigned : public std::make_unsigned<T> {};
+#endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
+
+#ifndef FLATBUFFERS_CPP98_STL
+ #if defined(FLATBUFFERS_TEMPLATES_ALIASES)
+ template <class T> using unique_ptr = std::unique_ptr<T>;
+ #else
+ // MSVC 2010 doesn't support C++11 aliases.
+ // We're manually "aliasing" the class here as we want to bring unique_ptr
+ // into the flatbuffers namespace. We have unique_ptr in the flatbuffers
+ // namespace we have a completely independent implemenation (see below)
+ // for C++98 STL implementations.
+ template <class T> class unique_ptr : public std::unique_ptr<T> {
+ public:
+ unique_ptr() {}
+ explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
+ unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
+ unique_ptr(unique_ptr&& u) { *this = std::move(u); }
+ unique_ptr& operator=(std::unique_ptr<T>&& u) {
+ std::unique_ptr<T>::reset(u.release());
+ return *this;
+ }
+ unique_ptr& operator=(unique_ptr&& u) {
+ std::unique_ptr<T>::reset(u.release());
+ return *this;
+ }
+ unique_ptr& operator=(T* p) {
+ return std::unique_ptr<T>::operator=(p);
+ }
+ };
+ #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES)
+#else
+ // Very limited implementation of unique_ptr.
+ // This is provided simply to allow the C++ code generated from the default
+ // settings to function in C++98 environments with no modifications.
+ template <class T> class unique_ptr {
+ public:
+ typedef T element_type;
+
+ unique_ptr() : ptr_(nullptr) {}
+ explicit unique_ptr(T* p) : ptr_(p) {}
+ unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
+ unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
+ reset(const_cast<unique_ptr*>(&u)->release());
+ }
+ ~unique_ptr() { reset(); }
+
+ unique_ptr& operator=(const unique_ptr& u) {
+ reset(const_cast<unique_ptr*>(&u)->release());
+ return *this;
+ }
+
+ unique_ptr& operator=(unique_ptr&& u) {
+ reset(u.release());
+ return *this;
+ }
+
+ unique_ptr& operator=(T* p) {
+ reset(p);
+ return *this;
+ }
+
+ const T& operator*() const { return *ptr_; }
+ T* operator->() const { return ptr_; }
+ T* get() const noexcept { return ptr_; }
+ explicit operator bool() const { return ptr_ != nullptr; }
+
+ // modifiers
+ T* release() {
+ T* value = ptr_;
+ ptr_ = nullptr;
+ return value;
+ }
+
+ void reset(T* p = nullptr) {
+ T* value = ptr_;
+ ptr_ = p;
+ if (value) delete value;
+ }
+
+ void swap(unique_ptr& u) {
+ T* temp_ptr = ptr_;
+ ptr_ = u.ptr_;
+ u.ptr_ = temp_ptr;
+ }
+
+ private:
+ T* ptr_;
+ };
+
+ template <class T> bool operator==(const unique_ptr<T>& x,
+ const unique_ptr<T>& y) {
+ return x.get() == y.get();
+ }
+
+ template <class T, class D> bool operator==(const unique_ptr<T>& x,
+ const D* y) {
+ return static_cast<D*>(x.get()) == y;
+ }
+
+ template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
+ return reinterpret_cast<intptr_t>(x.get()) == y;
+ }
+#endif // !FLATBUFFERS_CPP98_STL
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_STL_EMULATION_H_
diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h
new file mode 100644
index 0000000..072fe9e
--- /dev/null
+++ b/include/flatbuffers/util.h
@@ -0,0 +1,657 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_UTIL_H_
+#define FLATBUFFERS_UTIL_H_
+
+#include "flatbuffers/base.h"
+
+#include <errno.h>
+
+#ifndef FLATBUFFERS_PREFER_PRINTF
+# include <sstream>
+#else // FLATBUFFERS_PREFER_PRINTF
+# include <float.h>
+# include <stdio.h>
+#endif // FLATBUFFERS_PREFER_PRINTF
+
+#include <iomanip>
+#include <string>
+
+namespace flatbuffers {
+
+// @locale-independent functions for ASCII characters set.
+
+// Fast checking that character lies in closed range: [a <= x <= b]
+// using one compare (conditional branch) operator.
+inline bool check_ascii_range(char x, char a, char b) {
+ FLATBUFFERS_ASSERT(a <= b);
+ // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`.
+ // The x, a, b will be promoted to int and subtracted without overflow.
+ return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a);
+}
+
+// Case-insensitive isalpha
+inline bool is_alpha(char c) {
+ // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
+ return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF);
+}
+
+// Check (case-insensitive) that `c` is equal to alpha.
+inline bool is_alpha_char(char c, char alpha) {
+ FLATBUFFERS_ASSERT(is_alpha(alpha));
+ // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF).
+ return ((c & 0xDF) == (alpha & 0xDF));
+}
+
+// https://en.cppreference.com/w/cpp/string/byte/isxdigit
+// isdigit and isxdigit are the only standard narrow character classification
+// functions that are not affected by the currently installed C locale. although
+// some implementations (e.g. Microsoft in 1252 codepage) may classify
+// additional single-byte characters as digits.
+inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); }
+
+inline bool is_xdigit(char c) {
+ // Replace by look-up table.
+ return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF);
+}
+
+// Case-insensitive isalnum
+inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); }
+
+// @end-locale-independent functions for ASCII character set
+
+#ifdef FLATBUFFERS_PREFER_PRINTF
+template<typename T> size_t IntToDigitCount(T t) {
+ size_t digit_count = 0;
+ // Count the sign for negative numbers
+ if (t < 0) digit_count++;
+ // Count a single 0 left of the dot for fractional numbers
+ if (-1 < t && t < 1) digit_count++;
+ // Count digits until fractional part
+ T eps = std::numeric_limits<float>::epsilon();
+ while (t <= (-1 + eps) || (1 - eps) <= t) {
+ t /= 10;
+ digit_count++;
+ }
+ return digit_count;
+}
+
+template<typename T> size_t NumToStringWidth(T t, int precision = 0) {
+ size_t string_width = IntToDigitCount(t);
+ // Count the dot for floating point numbers
+ if (precision) string_width += (precision + 1);
+ return string_width;
+}
+
+template<typename T>
+std::string NumToStringImplWrapper(T t, const char *fmt, int precision = 0) {
+ size_t string_width = NumToStringWidth(t, precision);
+ std::string s(string_width, 0x00);
+ // Allow snprintf to use std::string trailing null to detect buffer overflow
+ snprintf(const_cast<char *>(s.data()), (s.size() + 1), fmt, string_width, t);
+ return s;
+}
+#endif // FLATBUFFERS_PREFER_PRINTF
+
+// Convert an integer or floating point value to a string.
+// In contrast to std::stringstream, "char" values are
+// converted to a string of digits, and we don't use scientific notation.
+template<typename T> std::string NumToString(T t) {
+ // clang-format off
+
+ #ifndef FLATBUFFERS_PREFER_PRINTF
+ std::stringstream ss;
+ ss << t;
+ return ss.str();
+ #else // FLATBUFFERS_PREFER_PRINTF
+ auto v = static_cast<long long>(t);
+ return NumToStringImplWrapper(v, "%.*lld");
+ #endif // FLATBUFFERS_PREFER_PRINTF
+ // clang-format on
+}
+// Avoid char types used as character data.
+template<> inline std::string NumToString<signed char>(signed char t) {
+ return NumToString(static_cast<int>(t));
+}
+template<> inline std::string NumToString<unsigned char>(unsigned char t) {
+ return NumToString(static_cast<int>(t));
+}
+template<> inline std::string NumToString<char>(char t) {
+ return NumToString(static_cast<int>(t));
+}
+#if defined(FLATBUFFERS_CPP98_STL)
+template<> inline std::string NumToString<long long>(long long t) {
+ char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2
+ snprintf(buf, sizeof(buf), "%lld", t);
+ return std::string(buf);
+}
+
+template<>
+inline std::string NumToString<unsigned long long>(unsigned long long t) {
+ char buf[22]; // (log((1 << 63) - 1) / log(10)) + 1
+ snprintf(buf, sizeof(buf), "%llu", t);
+ return std::string(buf);
+}
+#endif // defined(FLATBUFFERS_CPP98_STL)
+
+// Special versions for floats/doubles.
+template<typename T> std::string FloatToString(T t, int precision) {
+ // clang-format off
+
+ #ifndef FLATBUFFERS_PREFER_PRINTF
+ // to_string() prints different numbers of digits for floats depending on
+ // platform and isn't available on Android, so we use stringstream
+ std::stringstream ss;
+ // Use std::fixed to suppress scientific notation.
+ ss << std::fixed;
+ // Default precision is 6, we want that to be higher for doubles.
+ ss << std::setprecision(precision);
+ ss << t;
+ auto s = ss.str();
+ #else // FLATBUFFERS_PREFER_PRINTF
+ auto v = static_cast<double>(t);
+ auto s = NumToStringImplWrapper(v, "%0.*f", precision);
+ #endif // FLATBUFFERS_PREFER_PRINTF
+ // clang-format on
+ // Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
+ auto p = s.find_last_not_of('0');
+ if (p != std::string::npos) {
+ // Strip trailing zeroes. If it is a whole number, keep one zero.
+ s.resize(p + (s[p] == '.' ? 2 : 1));
+ }
+ return s;
+}
+
+template<> inline std::string NumToString<double>(double t) {
+ return FloatToString(t, 12);
+}
+template<> inline std::string NumToString<float>(float t) {
+ return FloatToString(t, 6);
+}
+
+// Convert an integer value to a hexadecimal string.
+// The returned string length is always xdigits long, prefixed by 0 digits.
+// For example, IntToStringHex(0x23, 8) returns the string "00000023".
+inline std::string IntToStringHex(int i, int xdigits) {
+ FLATBUFFERS_ASSERT(i >= 0);
+ // clang-format off
+
+ #ifndef FLATBUFFERS_PREFER_PRINTF
+ std::stringstream ss;
+ ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase
+ << i;
+ return ss.str();
+ #else // FLATBUFFERS_PREFER_PRINTF
+ return NumToStringImplWrapper(i, "%.*X", xdigits);
+ #endif // FLATBUFFERS_PREFER_PRINTF
+ // clang-format on
+}
+
+// clang-format off
+// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}.
+#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
+ class ClassicLocale {
+ #ifdef _MSC_VER
+ typedef _locale_t locale_type;
+ #else
+ typedef locale_t locale_type; // POSIX.1-2008 locale_t type
+ #endif
+ ClassicLocale();
+ ~ClassicLocale();
+ locale_type locale_;
+ static ClassicLocale instance_;
+ public:
+ static locale_type Get() { return instance_.locale_; }
+ };
+
+ #ifdef _MSC_VER
+ #define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get())
+ #define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get())
+ #define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get())
+ #define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get())
+ #else
+ #define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get())
+ #define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get())
+ #define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get())
+ #define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get())
+ #endif
+#else
+ #define __strtod_impl(s, pe) strtod(s, pe)
+ #define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe))
+ #ifdef _MSC_VER
+ #define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b)
+ #define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b)
+ #else
+ #define __strtoull_impl(s, pe, b) strtoull(s, pe, b)
+ #define __strtoll_impl(s, pe, b) strtoll(s, pe, b)
+ #endif
+#endif
+
+inline void strtoval_impl(int64_t *val, const char *str, char **endptr,
+ int base) {
+ *val = __strtoll_impl(str, endptr, base);
+}
+
+inline void strtoval_impl(uint64_t *val, const char *str, char **endptr,
+ int base) {
+ *val = __strtoull_impl(str, endptr, base);
+}
+
+inline void strtoval_impl(double *val, const char *str, char **endptr) {
+ *val = __strtod_impl(str, endptr);
+}
+
+// UBSAN: double to float is safe if numeric_limits<float>::is_iec559 is true.
+__supress_ubsan__("float-cast-overflow")
+inline void strtoval_impl(float *val, const char *str, char **endptr) {
+ *val = __strtof_impl(str, endptr);
+}
+#undef __strtoull_impl
+#undef __strtoll_impl
+#undef __strtod_impl
+#undef __strtof_impl
+// clang-format on
+
+// Adaptor for strtoull()/strtoll().
+// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9),
+// while strtoll with base=0 interprets first leading zero as octal prefix.
+// In future, it is possible to add prefixed 0b0101.
+// 1) Checks errno code for overflow condition (out of range).
+// 2) If base <= 0, function try to detect base of number by prefix.
+//
+// Return value (like strtoull and strtoll, but reject partial result):
+// - If successful, an integer value corresponding to the str is returned.
+// - If full string conversion can't be performed, 0 is returned.
+// - If the converted value falls out of range of corresponding return type, a
+// range error occurs. In this case value MAX(T)/MIN(T) is returned.
+template<typename T>
+inline bool StringToIntegerImpl(T *val, const char *const str,
+ const int base = 0,
+ const bool check_errno = true) {
+ // T is int64_t or uint64_T
+ FLATBUFFERS_ASSERT(str);
+ if (base <= 0) {
+ auto s = str;
+ while (*s && !is_digit(*s)) s++;
+ if (s[0] == '0' && is_alpha_char(s[1], 'X'))
+ return StringToIntegerImpl(val, str, 16, check_errno);
+ // if a prefix not match, try base=10
+ return StringToIntegerImpl(val, str, 10, check_errno);
+ } else {
+ if (check_errno) errno = 0; // clear thread-local errno
+ auto endptr = str;
+ strtoval_impl(val, str, const_cast<char **>(&endptr), base);
+ if ((*endptr != '\0') || (endptr == str)) {
+ *val = 0; // erase partial result
+ return false; // invalid string
+ }
+ // errno is out-of-range, return MAX/MIN
+ if (check_errno && errno) return false;
+ return true;
+ }
+}
+
+template<typename T>
+inline bool StringToFloatImpl(T *val, const char *const str) {
+ // Type T must be either float or double.
+ FLATBUFFERS_ASSERT(str && val);
+ auto end = str;
+ strtoval_impl(val, str, const_cast<char **>(&end));
+ auto done = (end != str) && (*end == '\0');
+ if (!done) *val = 0; // erase partial result
+ return done;
+}
+
+// Convert a string to an instance of T.
+// Return value (matched with StringToInteger64Impl and strtod):
+// - If successful, a numeric value corresponding to the str is returned.
+// - If full string conversion can't be performed, 0 is returned.
+// - If the converted value falls out of range of corresponding return type, a
+// range error occurs. In this case value MAX(T)/MIN(T) is returned.
+template<typename T> inline bool StringToNumber(const char *s, T *val) {
+ FLATBUFFERS_ASSERT(s && val);
+ int64_t i64;
+ // The errno check isn't needed, will return MAX/MIN on overflow.
+ if (StringToIntegerImpl(&i64, s, 0, false)) {
+ const int64_t max = (flatbuffers::numeric_limits<T>::max)();
+ const int64_t min = flatbuffers::numeric_limits<T>::lowest();
+ if (i64 > max) {
+ *val = static_cast<T>(max);
+ return false;
+ }
+ if (i64 < min) {
+ // For unsigned types return max to distinguish from
+ // "no conversion can be performed" when 0 is returned.
+ *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min);
+ return false;
+ }
+ *val = static_cast<T>(i64);
+ return true;
+ }
+ *val = 0;
+ return false;
+}
+
+template<> inline bool StringToNumber<int64_t>(const char *str, int64_t *val) {
+ return StringToIntegerImpl(val, str);
+}
+
+template<>
+inline bool StringToNumber<uint64_t>(const char *str, uint64_t *val) {
+ if (!StringToIntegerImpl(val, str)) return false;
+ // The strtoull accepts negative numbers:
+ // If the minus sign was part of the input sequence, the numeric value
+ // calculated from the sequence of digits is negated as if by unary minus
+ // in the result type, which applies unsigned integer wraparound rules.
+ // Fix this behaviour (except -0).
+ if (*val) {
+ auto s = str;
+ while (*s && !is_digit(*s)) s++;
+ s = (s > str) ? (s - 1) : s; // step back to one symbol
+ if (*s == '-') {
+ // For unsigned types return the max to distinguish from
+ // "no conversion can be performed".
+ *val = (flatbuffers::numeric_limits<uint64_t>::max)();
+ return false;
+ }
+ }
+ return true;
+}
+
+template<> inline bool StringToNumber(const char *s, float *val) {
+ return StringToFloatImpl(val, s);
+}
+
+template<> inline bool StringToNumber(const char *s, double *val) {
+ return StringToFloatImpl(val, s);
+}
+
+inline int64_t StringToInt(const char *s, int base = 10) {
+ int64_t val;
+ return StringToIntegerImpl(&val, s, base) ? val : 0;
+}
+
+inline uint64_t StringToUInt(const char *s, int base = 10) {
+ uint64_t val;
+ return StringToIntegerImpl(&val, s, base) ? val : 0;
+}
+
+typedef bool (*LoadFileFunction)(const char *filename, bool binary,
+ std::string *dest);
+typedef bool (*FileExistsFunction)(const char *filename);
+
+LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function);
+
+FileExistsFunction SetFileExistsFunction(
+ FileExistsFunction file_exists_function);
+
+// Check if file "name" exists.
+bool FileExists(const char *name);
+
+// Check if "name" exists and it is also a directory.
+bool DirExists(const char *name);
+
+// Load file "name" into "buf" returning true if successful
+// false otherwise. If "binary" is false data is read
+// using ifstream's text mode, otherwise data is read with
+// no transcoding.
+bool LoadFile(const char *name, bool binary, std::string *buf);
+
+// Save data "buf" of length "len" bytes into a file
+// "name" returning true if successful, false otherwise.
+// If "binary" is false data is written using ifstream's
+// text mode, otherwise data is written with no
+// transcoding.
+bool SaveFile(const char *name, const char *buf, size_t len, bool binary);
+
+// Save data "buf" into file "name" returning true if
+// successful, false otherwise. If "binary" is false
+// data is written using ifstream's text mode, otherwise
+// data is written with no transcoding.
+inline bool SaveFile(const char *name, const std::string &buf, bool binary) {
+ return SaveFile(name, buf.c_str(), buf.size(), binary);
+}
+
+// Functionality for minimalistic portable path handling.
+
+// The functions below behave correctly regardless of whether posix ('/') or
+// Windows ('/' or '\\') separators are used.
+
+// Any new separators inserted are always posix.
+FLATBUFFERS_CONSTEXPR char kPathSeparator = '/';
+
+// Returns the path with the extension, if any, removed.
+std::string StripExtension(const std::string &filepath);
+
+// Returns the extension, if any.
+std::string GetExtension(const std::string &filepath);
+
+// Return the last component of the path, after the last separator.
+std::string StripPath(const std::string &filepath);
+
+// Strip the last component of the path + separator.
+std::string StripFileName(const std::string &filepath);
+
+// Concatenates a path with a filename, regardless of wether the path
+// ends in a separator or not.
+std::string ConCatPathFileName(const std::string &path,
+ const std::string &filename);
+
+// Replaces any '\\' separators with '/'
+std::string PosixPath(const char *path);
+
+// This function ensure a directory exists, by recursively
+// creating dirs for any parts of the path that don't exist yet.
+void EnsureDirExists(const std::string &filepath);
+
+// Obtains the absolute path from any other path.
+// Returns the input path if the absolute path couldn't be resolved.
+std::string AbsolutePath(const std::string &filepath);
+
+// To and from UTF-8 unicode conversion functions
+
+// Convert a unicode code point into a UTF-8 representation by appending it
+// to a string. Returns the number of bytes generated.
+inline int ToUTF8(uint32_t ucc, std::string *out) {
+ FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set.
+ // 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8
+ for (int i = 0; i < 6; i++) {
+ // Max bits this encoding can represent.
+ uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i);
+ if (ucc < (1u << max_bits)) { // does it fit?
+ // Remaining bits not encoded in the first byte, store 6 bits each
+ uint32_t remain_bits = i * 6;
+ // Store first byte:
+ (*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) |
+ (ucc >> remain_bits));
+ // Store remaining bytes:
+ for (int j = i - 1; j >= 0; j--) {
+ (*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80);
+ }
+ return i + 1; // Return the number of bytes added.
+ }
+ }
+ FLATBUFFERS_ASSERT(0); // Impossible to arrive here.
+ return -1;
+}
+
+// Converts whatever prefix of the incoming string corresponds to a valid
+// UTF-8 sequence into a unicode code. The incoming pointer will have been
+// advanced past all bytes parsed.
+// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in
+// this case).
+inline int FromUTF8(const char **in) {
+ int len = 0;
+ // Count leading 1 bits.
+ for (int mask = 0x80; mask >= 0x04; mask >>= 1) {
+ if (**in & mask) {
+ len++;
+ } else {
+ break;
+ }
+ }
+ if ((static_cast<unsigned char>(**in) << len) & 0x80)
+ return -1; // Bit after leading 1's must be 0.
+ if (!len) return *(*in)++;
+ // UTF-8 encoded values with a length are between 2 and 4 bytes.
+ if (len < 2 || len > 4) { return -1; }
+ // Grab initial bits of the code.
+ int ucc = *(*in)++ & ((1 << (7 - len)) - 1);
+ for (int i = 0; i < len - 1; i++) {
+ if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0.
+ ucc <<= 6;
+ ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code.
+ }
+ // UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for
+ // UTF-16 surrogate pairs).
+ if (ucc >= 0xD800 && ucc <= 0xDFFF) { return -1; }
+ // UTF-8 must represent code points in their shortest possible encoding.
+ switch (len) {
+ case 2:
+ // Two bytes of UTF-8 can represent code points from U+0080 to U+07FF.
+ if (ucc < 0x0080 || ucc > 0x07FF) { return -1; }
+ break;
+ case 3:
+ // Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF.
+ if (ucc < 0x0800 || ucc > 0xFFFF) { return -1; }
+ break;
+ case 4:
+ // Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF.
+ if (ucc < 0x10000 || ucc > 0x10FFFF) { return -1; }
+ break;
+ }
+ return ucc;
+}
+
+#ifndef FLATBUFFERS_PREFER_PRINTF
+// Wraps a string to a maximum length, inserting new lines where necessary. Any
+// existing whitespace will be collapsed down to a single space. A prefix or
+// suffix can be provided, which will be inserted before or after a wrapped
+// line, respectively.
+inline std::string WordWrap(const std::string in, size_t max_length,
+ const std::string wrapped_line_prefix,
+ const std::string wrapped_line_suffix) {
+ std::istringstream in_stream(in);
+ std::string wrapped, line, word;
+
+ in_stream >> word;
+ line = word;
+
+ while (in_stream >> word) {
+ if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) <
+ max_length) {
+ line += " " + word;
+ } else {
+ wrapped += line + wrapped_line_suffix + "\n";
+ line = wrapped_line_prefix + word;
+ }
+ }
+ wrapped += line;
+
+ return wrapped;
+}
+#endif // !FLATBUFFERS_PREFER_PRINTF
+
+inline bool EscapeString(const char *s, size_t length, std::string *_text,
+ bool allow_non_utf8, bool natural_utf8) {
+ std::string &text = *_text;
+ text += "\"";
+ for (uoffset_t i = 0; i < length; i++) {
+ char c = s[i];
+ switch (c) {
+ case '\n': text += "\\n"; break;
+ case '\t': text += "\\t"; break;
+ case '\r': text += "\\r"; break;
+ case '\b': text += "\\b"; break;
+ case '\f': text += "\\f"; break;
+ case '\"': text += "\\\""; break;
+ case '\\': text += "\\\\"; break;
+ default:
+ if (c >= ' ' && c <= '~') {
+ text += c;
+ } else {
+ // Not printable ASCII data. Let's see if it's valid UTF-8 first:
+ const char *utf8 = s + i;
+ int ucc = FromUTF8(&utf8);
+ if (ucc < 0) {
+ if (allow_non_utf8) {
+ text += "\\x";
+ text += IntToStringHex(static_cast<uint8_t>(c), 2);
+ } else {
+ // There are two cases here:
+ //
+ // 1) We reached here by parsing an IDL file. In that case,
+ // we previously checked for non-UTF-8, so we shouldn't reach
+ // here.
+ //
+ // 2) We reached here by someone calling GenerateText()
+ // on a previously-serialized flatbuffer. The data might have
+ // non-UTF-8 Strings, or might be corrupt.
+ //
+ // In both cases, we have to give up and inform the caller
+ // they have no JSON.
+ return false;
+ }
+ } else {
+ if (natural_utf8) {
+ // utf8 points to past all utf-8 bytes parsed
+ text.append(s + i, static_cast<size_t>(utf8 - s - i));
+ } else if (ucc <= 0xFFFF) {
+ // Parses as Unicode within JSON's \uXXXX range, so use that.
+ text += "\\u";
+ text += IntToStringHex(ucc, 4);
+ } else if (ucc <= 0x10FFFF) {
+ // Encode Unicode SMP values to a surrogate pair using two \u
+ // escapes.
+ uint32_t base = ucc - 0x10000;
+ auto high_surrogate = (base >> 10) + 0xD800;
+ auto low_surrogate = (base & 0x03FF) + 0xDC00;
+ text += "\\u";
+ text += IntToStringHex(high_surrogate, 4);
+ text += "\\u";
+ text += IntToStringHex(low_surrogate, 4);
+ }
+ // Skip past characters recognized.
+ i = static_cast<uoffset_t>(utf8 - s - 1);
+ }
+ }
+ break;
+ }
+ }
+ text += "\"";
+ return true;
+}
+
+// Remove paired quotes in a string: "text"|'text' -> text.
+std::string RemoveStringQuotes(const std::string &s);
+
+// Change th global C-locale to locale with name <locale_name>.
+// Returns an actual locale name in <_value>, useful if locale_name is "" or
+// null.
+bool SetGlobalTestLocale(const char *locale_name,
+ std::string *_value = nullptr);
+
+// Read (or test) a value of environment variable.
+bool ReadEnvironmentVariable(const char *var_name,
+ std::string *_value = nullptr);
+
+// MSVC specific: Send all assert reports to STDOUT to prevent CI hangs.
+void SetupDefaultCRTReportMode();
+
+} // namespace flatbuffers
+
+#endif // FLATBUFFERS_UTIL_H_
diff --git a/java/com/google/flatbuffers/ByteBufferUtil.java b/java/com/google/flatbuffers/ByteBufferUtil.java
new file mode 100644
index 0000000..624dc4e
--- /dev/null
+++ b/java/com/google/flatbuffers/ByteBufferUtil.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import static com.google.flatbuffers.Constants.*;
+
+import java.nio.ByteBuffer;
+
+/// @file
+/// @addtogroup flatbuffers_java_api
+/// @{
+
+/**
+ * Class that collects utility functions around `ByteBuffer`.
+ */
+public class ByteBufferUtil {
+
+ /**
+ * Extract the size prefix from a `ByteBuffer`.
+ *
+ * @param bb a size-prefixed buffer
+ * @return the size prefix
+ */
+ public static int getSizePrefix(ByteBuffer bb) {
+ return bb.getInt(bb.position());
+ }
+
+ /**
+ * Create a duplicate of a size-prefixed `ByteBuffer` that has its position
+ * advanced just past the size prefix.
+ *
+ * @param bb a size-prefixed buffer
+ * @return a new buffer on the same underlying data that has skipped the
+ * size prefix
+ */
+ public static ByteBuffer removeSizePrefix(ByteBuffer bb) {
+ ByteBuffer s = bb.duplicate();
+ s.position(s.position() + SIZE_PREFIX_LENGTH);
+ return s;
+ }
+
+}
+
+/// @}
diff --git a/java/com/google/flatbuffers/Constants.java b/java/com/google/flatbuffers/Constants.java
new file mode 100644
index 0000000..e974a80
--- /dev/null
+++ b/java/com/google/flatbuffers/Constants.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+/// @cond FLATBUFFERS_INTERNAL
+
+/**
+ * Class that holds shared constants
+ */
+public class Constants {
+ // Java doesn't seem to have these.
+ /** The number of bytes in an `byte`. */
+ static final int SIZEOF_BYTE = 1;
+ /** The number of bytes in a `short`. */
+ static final int SIZEOF_SHORT = 2;
+ /** The number of bytes in an `int`. */
+ static final int SIZEOF_INT = 4;
+ /** The number of bytes in an `float`. */
+ static final int SIZEOF_FLOAT = 4;
+ /** The number of bytes in an `long`. */
+ static final int SIZEOF_LONG = 8;
+ /** The number of bytes in an `double`. */
+ static final int SIZEOF_DOUBLE = 8;
+ /** The number of bytes in a file identifier. */
+ static final int FILE_IDENTIFIER_LENGTH = 4;
+ /** The number of bytes in a size prefix. */
+ public static final int SIZE_PREFIX_LENGTH = 4;
+ /** A version identifier to force a compile error if someone
+ accidentally tries to build generated code with a runtime of
+ two mismatched version. Versions need to always match, as
+ the runtime and generated code are modified in sync.
+ Changes to the Java implementation need to be sure to change
+ the version here and in the code generator on every possible
+ incompatible change */
+ public static void FLATBUFFERS_1_11_1() {}
+}
+
+/// @endcond
diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java
new file mode 100644
index 0000000..f224610
--- /dev/null
+++ b/java/com/google/flatbuffers/FlatBufferBuilder.java
@@ -0,0 +1,1012 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import static com.google.flatbuffers.Constants.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.*;
+import java.util.Arrays;
+
+/// @file
+/// @addtogroup flatbuffers_java_api
+/// @{
+
+/**
+ * Class that helps you build a FlatBuffer. See the section
+ * "Use in Java/C#" in the main FlatBuffers documentation.
+ */
+public class FlatBufferBuilder {
+ /// @cond FLATBUFFERS_INTERNAL
+ ByteBuffer bb; // Where we construct the FlatBuffer.
+ int space; // Remaining space in the ByteBuffer.
+ int minalign = 1; // Minimum alignment encountered so far.
+ int[] vtable = null; // The vtable for the current table.
+ int vtable_in_use = 0; // The amount of fields we're actually using.
+ boolean nested = false; // Whether we are currently serializing a table.
+ boolean finished = false; // Whether the buffer is finished.
+ int object_start; // Starting offset of the current struct/table.
+ int[] vtables = new int[16]; // List of offsets of all vtables.
+ int num_vtables = 0; // Number of entries in `vtables` in use.
+ int vector_num_elems = 0; // For the current vector being built.
+ boolean force_defaults = false; // False omits default values from the serialized data.
+ ByteBufferFactory bb_factory; // Factory for allocating the internal buffer
+ final Utf8 utf8; // UTF-8 encoder to use
+ /// @endcond
+
+ /**
+ * Start with a buffer of size `initial_size`, then grow as required.
+ *
+ * @param initial_size The initial size of the internal buffer to use.
+ * @param bb_factory The factory to be used for allocating the internal buffer
+ */
+ public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory) {
+ this(initial_size, bb_factory, null, Utf8.getDefault());
+ }
+
+ /**
+ * Start with a buffer of size `initial_size`, then grow as required.
+ *
+ * @param initial_size The initial size of the internal buffer to use.
+ * @param bb_factory The factory to be used for allocating the internal buffer
+ * @param existing_bb The byte buffer to reuse.
+ * @param utf8 The Utf8 codec
+ */
+ public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory,
+ ByteBuffer existing_bb, Utf8 utf8) {
+ if (initial_size <= 0) {
+ initial_size = 1;
+ }
+ space = initial_size;
+ this.bb_factory = bb_factory;
+ if (existing_bb != null) {
+ bb = existing_bb;
+ bb.clear();
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ } else {
+ bb = bb_factory.newByteBuffer(initial_size);
+ }
+ this.utf8 = utf8;
+ }
+
+ /**
+ * Start with a buffer of size `initial_size`, then grow as required.
+ *
+ * @param initial_size The initial size of the internal buffer to use.
+ */
+ public FlatBufferBuilder(int initial_size) {
+ this(initial_size, HeapByteBufferFactory.INSTANCE, null, Utf8.getDefault());
+ }
+
+ /**
+ * Start with a buffer of 1KiB, then grow as required.
+ */
+ public FlatBufferBuilder() {
+ this(1024);
+ }
+
+ /**
+ * Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder
+ * can still grow the buffer as necessary. User classes should make sure
+ * to call {@link #dataBuffer()} to obtain the resulting encoded message.
+ *
+ * @param existing_bb The byte buffer to reuse.
+ * @param bb_factory The factory to be used for allocating a new internal buffer if
+ * the existing buffer needs to grow
+ */
+ public FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory) {
+ this(existing_bb.capacity(), bb_factory, existing_bb, Utf8.getDefault());
+ }
+
+ /**
+ * Alternative constructor allowing reuse of {@link ByteBuffer}s. The builder
+ * can still grow the buffer as necessary. User classes should make sure
+ * to call {@link #dataBuffer()} to obtain the resulting encoded message.
+ *
+ * @param existing_bb The byte buffer to reuse.
+ */
+ public FlatBufferBuilder(ByteBuffer existing_bb) {
+ this(existing_bb, new HeapByteBufferFactory());
+ }
+
+ /**
+ * Alternative initializer that allows reusing this object on an existing
+ * `ByteBuffer`. This method resets the builder's internal state, but keeps
+ * objects that have been allocated for temporary storage.
+ *
+ * @param existing_bb The byte buffer to reuse.
+ * @param bb_factory The factory to be used for allocating a new internal buffer if
+ * the existing buffer needs to grow
+ * @return Returns `this`.
+ */
+ public FlatBufferBuilder init(ByteBuffer existing_bb, ByteBufferFactory bb_factory){
+ this.bb_factory = bb_factory;
+ bb = existing_bb;
+ bb.clear();
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ minalign = 1;
+ space = bb.capacity();
+ vtable_in_use = 0;
+ nested = false;
+ finished = false;
+ object_start = 0;
+ num_vtables = 0;
+ vector_num_elems = 0;
+ return this;
+ }
+
+ /**
+ * An interface that provides a user of the FlatBufferBuilder class the ability to specify
+ * the method in which the internal buffer gets allocated. This allows for alternatives
+ * to the default behavior, which is to allocate memory for a new byte-array
+ * backed `ByteBuffer` array inside the JVM.
+ *
+ * The FlatBufferBuilder class contains the HeapByteBufferFactory class to
+ * preserve the default behavior in the event that the user does not provide
+ * their own implementation of this interface.
+ */
+ public static abstract class ByteBufferFactory {
+ /**
+ * Create a `ByteBuffer` with a given capacity.
+ * The returned ByteBuf must have a ByteOrder.LITTLE_ENDIAN ByteOrder.
+ *
+ * @param capacity The size of the `ByteBuffer` to allocate.
+ * @return Returns the new `ByteBuffer` that was allocated.
+ */
+ public abstract ByteBuffer newByteBuffer(int capacity);
+
+ /**
+ * Release a ByteBuffer. Current {@link FlatBufferBuilder}
+ * released any reference to it, so it is safe to dispose the buffer
+ * or return it to a pool.
+ * It is not guaranteed that the buffer has been created
+ * with {@link #newByteBuffer(int) }.
+ *
+ * @param bb the buffer to release
+ */
+ public void releaseByteBuffer(ByteBuffer bb) {
+ }
+ }
+
+ /**
+ * An implementation of the ByteBufferFactory interface that is used when
+ * one is not provided by the user.
+ *
+ * Allocate memory for a new byte-array backed `ByteBuffer` array inside the JVM.
+ */
+ public static final class HeapByteBufferFactory extends ByteBufferFactory {
+
+ public static final HeapByteBufferFactory INSTANCE = new HeapByteBufferFactory();
+
+ @Override
+ public ByteBuffer newByteBuffer(int capacity) {
+ return ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN);
+ }
+ }
+
+ /**
+ * Reset the FlatBufferBuilder by purging all data that it holds.
+ */
+ public void clear(){
+ space = bb.capacity();
+ bb.clear();
+ minalign = 1;
+ while(vtable_in_use > 0) vtable[--vtable_in_use] = 0;
+ vtable_in_use = 0;
+ nested = false;
+ finished = false;
+ object_start = 0;
+ num_vtables = 0;
+ vector_num_elems = 0;
+ }
+
+ /**
+ * Doubles the size of the backing {@link ByteBuffer} and copies the old data towards the
+ * end of the new buffer (since we build the buffer backwards).
+ *
+ * @param bb The current buffer with the existing data.
+ * @param bb_factory The factory to be used for allocating the new internal buffer
+ * @return A new byte buffer with the old data copied copied to it. The data is
+ * located at the end of the buffer.
+ */
+ static ByteBuffer growByteBuffer(ByteBuffer bb, ByteBufferFactory bb_factory) {
+ int old_buf_size = bb.capacity();
+ if ((old_buf_size & 0xC0000000) != 0) // Ensure we don't grow beyond what fits in an int.
+ throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
+ int new_buf_size = old_buf_size == 0 ? 1 : old_buf_size << 1;
+ bb.position(0);
+ ByteBuffer nbb = bb_factory.newByteBuffer(new_buf_size);
+ nbb.position(new_buf_size - old_buf_size);
+ nbb.put(bb);
+ return nbb;
+ }
+
+ /**
+ * Offset relative to the end of the buffer.
+ *
+ * @return Offset relative to the end of the buffer.
+ */
+ public int offset() {
+ return bb.capacity() - space;
+ }
+
+ /**
+ * Add zero valued bytes to prepare a new entry to be added.
+ *
+ * @param byte_size Number of bytes to add.
+ */
+ public void pad(int byte_size) {
+ for (int i = 0; i < byte_size; i++) bb.put(--space, (byte)0);
+ }
+
+ /**
+ * Prepare to write an element of `size` after `additional_bytes`
+ * have been written, e.g. if you write a string, you need to align such
+ * the int length field is aligned to {@link com.google.flatbuffers.Constants#SIZEOF_INT}, and
+ * the string data follows it directly. If all you need to do is alignment, `additional_bytes`
+ * will be 0.
+ *
+ * @param size This is the of the new element to write.
+ * @param additional_bytes The padding size.
+ */
+ public void prep(int size, int additional_bytes) {
+ // Track the biggest thing we've ever aligned to.
+ if (size > minalign) minalign = size;
+ // Find the amount of alignment needed such that `size` is properly
+ // aligned after `additional_bytes`
+ int align_size = ((~(bb.capacity() - space + additional_bytes)) + 1) & (size - 1);
+ // Reallocate the buffer if needed.
+ while (space < align_size + size + additional_bytes) {
+ int old_buf_size = bb.capacity();
+ ByteBuffer old = bb;
+ bb = growByteBuffer(old, bb_factory);
+ if (old != bb) {
+ bb_factory.releaseByteBuffer(old);
+ }
+ space += bb.capacity() - old_buf_size;
+ }
+ pad(align_size);
+ }
+
+ /**
+ * Add a `boolean` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `boolean` to put into the buffer.
+ */
+ public void putBoolean(boolean x) { bb.put (space -= Constants.SIZEOF_BYTE, (byte)(x ? 1 : 0)); }
+
+ /**
+ * Add a `byte` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `byte` to put into the buffer.
+ */
+ public void putByte (byte x) { bb.put (space -= Constants.SIZEOF_BYTE, x); }
+
+ /**
+ * Add a `short` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `short` to put into the buffer.
+ */
+ public void putShort (short x) { bb.putShort (space -= Constants.SIZEOF_SHORT, x); }
+
+ /**
+ * Add an `int` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x An `int` to put into the buffer.
+ */
+ public void putInt (int x) { bb.putInt (space -= Constants.SIZEOF_INT, x); }
+
+ /**
+ * Add a `long` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `long` to put into the buffer.
+ */
+ public void putLong (long x) { bb.putLong (space -= Constants.SIZEOF_LONG, x); }
+
+ /**
+ * Add a `float` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `float` to put into the buffer.
+ */
+ public void putFloat (float x) { bb.putFloat (space -= Constants.SIZEOF_FLOAT, x); }
+
+ /**
+ * Add a `double` to the buffer, backwards from the current location. Doesn't align nor
+ * check for space.
+ *
+ * @param x A `double` to put into the buffer.
+ */
+ public void putDouble (double x) { bb.putDouble(space -= Constants.SIZEOF_DOUBLE, x); }
+ /// @endcond
+
+ /**
+ * Add a `boolean` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `boolean` to put into the buffer.
+ */
+ public void addBoolean(boolean x) { prep(Constants.SIZEOF_BYTE, 0); putBoolean(x); }
+
+ /**
+ * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `byte` to put into the buffer.
+ */
+ public void addByte (byte x) { prep(Constants.SIZEOF_BYTE, 0); putByte (x); }
+
+ /**
+ * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `short` to put into the buffer.
+ */
+ public void addShort (short x) { prep(Constants.SIZEOF_SHORT, 0); putShort (x); }
+
+ /**
+ * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x An `int` to put into the buffer.
+ */
+ public void addInt (int x) { prep(Constants.SIZEOF_INT, 0); putInt (x); }
+
+ /**
+ * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `long` to put into the buffer.
+ */
+ public void addLong (long x) { prep(Constants.SIZEOF_LONG, 0); putLong (x); }
+
+ /**
+ * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `float` to put into the buffer.
+ */
+ public void addFloat (float x) { prep(Constants.SIZEOF_FLOAT, 0); putFloat (x); }
+
+ /**
+ * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
+ *
+ * @param x A `double` to put into the buffer.
+ */
+ public void addDouble (double x) { prep(Constants.SIZEOF_DOUBLE, 0); putDouble (x); }
+
+ /**
+ * Adds on offset, relative to where it will be written.
+ *
+ * @param off The offset to add.
+ */
+ public void addOffset(int off) {
+ prep(SIZEOF_INT, 0); // Ensure alignment is already done.
+ assert off <= offset();
+ off = offset() - off + SIZEOF_INT;
+ putInt(off);
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * Start a new array/vector of objects. Users usually will not call
+ * this directly. The `FlatBuffers` compiler will create a start/end
+ * method for vector types in generated code.
+ * <p>
+ * The expected sequence of calls is:
+ * <ol>
+ * <li>Start the array using this method.</li>
+ * <li>Call {@link #addOffset(int)} `num_elems` number of times to set
+ * the offset of each element in the array.</li>
+ * <li>Call {@link #endVector()} to retrieve the offset of the array.</li>
+ * </ol>
+ * <p>
+ * For example, to create an array of strings, do:
+ * <pre>{@code
+ * // Need 10 strings
+ * FlatBufferBuilder builder = new FlatBufferBuilder(existingBuffer);
+ * int[] offsets = new int[10];
+ *
+ * for (int i = 0; i < 10; i++) {
+ * offsets[i] = fbb.createString(" " + i);
+ * }
+ *
+ * // Have the strings in the buffer, but don't have a vector.
+ * // Add a vector that references the newly created strings:
+ * builder.startVector(4, offsets.length, 4);
+ *
+ * // Add each string to the newly created vector
+ * // The strings are added in reverse order since the buffer
+ * // is filled in back to front
+ * for (int i = offsets.length - 1; i >= 0; i--) {
+ * builder.addOffset(offsets[i]);
+ * }
+ *
+ * // Finish off the vector
+ * int offsetOfTheVector = fbb.endVector();
+ * }</pre>
+ *
+ * @param elem_size The size of each element in the array.
+ * @param num_elems The number of elements in the array.
+ * @param alignment The alignment of the array.
+ */
+ public void startVector(int elem_size, int num_elems, int alignment) {
+ notNested();
+ vector_num_elems = num_elems;
+ prep(SIZEOF_INT, elem_size * num_elems);
+ prep(alignment, elem_size * num_elems); // Just in case alignment > int.
+ nested = true;
+ }
+
+ /**
+ * Finish off the creation of an array and all its elements. The array
+ * must be created with {@link #startVector(int, int, int)}.
+ *
+ * @return The offset at which the newly created array starts.
+ * @see #startVector(int, int, int)
+ */
+ public int endVector() {
+ if (!nested)
+ throw new AssertionError("FlatBuffers: endVector called without startVector");
+ nested = false;
+ putInt(vector_num_elems);
+ return offset();
+ }
+ /// @endcond
+
+ /**
+ * Create a new array/vector and return a ByteBuffer to be filled later.
+ * Call {@link #endVector} after this method to get an offset to the beginning
+ * of vector.
+ *
+ * @param elem_size the size of each element in bytes.
+ * @param num_elems number of elements in the vector.
+ * @param alignment byte alignment.
+ * @return ByteBuffer with position and limit set to the space allocated for the array.
+ */
+ public ByteBuffer createUnintializedVector(int elem_size, int num_elems, int alignment) {
+ int length = elem_size * num_elems;
+ startVector(elem_size, num_elems, alignment);
+
+ bb.position(space -= length);
+
+ // Slice and limit the copy vector to point to the 'array'
+ ByteBuffer copy = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
+ copy.limit(length);
+ return copy;
+ }
+
+ /**
+ * Create a vector of tables.
+ *
+ * @param offsets Offsets of the tables.
+ * @return Returns offset of the vector.
+ */
+ public int createVectorOfTables(int[] offsets) {
+ notNested();
+ startVector(Constants.SIZEOF_INT, offsets.length, Constants.SIZEOF_INT);
+ for(int i = offsets.length - 1; i >= 0; i--) addOffset(offsets[i]);
+ return endVector();
+ }
+
+ /**
+ * Create a vector of sorted by the key tables.
+ *
+ * @param obj Instance of the table subclass.
+ * @param offsets Offsets of the tables.
+ * @return Returns offset of the sorted vector.
+ */
+ public <T extends Table> int createSortedVectorOfTables(T obj, int[] offsets) {
+ obj.sortTables(offsets, bb);
+ return createVectorOfTables(offsets);
+ }
+
+ /**
+ * Encode the string `s` in the buffer using UTF-8. If {@code s} is
+ * already a {@link CharBuffer}, this method is allocation free.
+ *
+ * @param s The string to encode.
+ * @return The offset in the buffer where the encoded string starts.
+ */
+ public int createString(CharSequence s) {
+ int length = utf8.encodedLength(s);
+ addByte((byte)0);
+ startVector(1, length, 1);
+ bb.position(space -= length);
+ utf8.encodeUtf8(s, bb);
+ return endVector();
+ }
+
+ /**
+ * Create a string in the buffer from an already encoded UTF-8 string in a ByteBuffer.
+ *
+ * @param s An already encoded UTF-8 string as a `ByteBuffer`.
+ * @return The offset in the buffer where the encoded string starts.
+ */
+ public int createString(ByteBuffer s) {
+ int length = s.remaining();
+ addByte((byte)0);
+ startVector(1, length, 1);
+ bb.position(space -= length);
+ bb.put(s);
+ return endVector();
+ }
+
+ /**
+ * Create a byte array in the buffer.
+ *
+ * @param arr A source array with data
+ * @return The offset in the buffer where the encoded array starts.
+ */
+ public int createByteVector(byte[] arr) {
+ int length = arr.length;
+ startVector(1, length, 1);
+ bb.position(space -= length);
+ bb.put(arr);
+ return endVector();
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * Should not be accessing the final buffer before it is finished.
+ */
+ public void finished() {
+ if (!finished)
+ throw new AssertionError(
+ "FlatBuffers: you can only access the serialized buffer after it has been" +
+ " finished by FlatBufferBuilder.finish().");
+ }
+
+ /**
+ * Should not be creating any other object, string or vector
+ * while an object is being constructed.
+ */
+ public void notNested() {
+ if (nested)
+ throw new AssertionError("FlatBuffers: object serialization must not be nested.");
+ }
+
+ /**
+ * Structures are always stored inline, they need to be created right
+ * where they're used. You'll get this assertion failure if you
+ * created it elsewhere.
+ *
+ * @param obj The offset of the created object.
+ */
+ public void Nested(int obj) {
+ if (obj != offset())
+ throw new AssertionError("FlatBuffers: struct must be serialized inline.");
+ }
+
+ /**
+ * Start encoding a new object in the buffer. Users will not usually need to
+ * call this directly. The `FlatBuffers` compiler will generate helper methods
+ * that call this method internally.
+ * <p>
+ * For example, using the "Monster" code found on the "landing page". An
+ * object of type `Monster` can be created using the following code:
+ *
+ * <pre>{@code
+ * int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
+ * fbb.createString("test1"),
+ * fbb.createString("test2")
+ * });
+ *
+ * Monster.startMonster(fbb);
+ * Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
+ * Color.Green, (short)5, (byte)6));
+ * Monster.addHp(fbb, (short)80);
+ * Monster.addName(fbb, str);
+ * Monster.addInventory(fbb, inv);
+ * Monster.addTestType(fbb, (byte)Any.Monster);
+ * Monster.addTest(fbb, mon2);
+ * Monster.addTest4(fbb, test4);
+ * Monster.addTestarrayofstring(fbb, testArrayOfString);
+ * int mon = Monster.endMonster(fbb);
+ * }</pre>
+ * <p>
+ * Here:
+ * <ul>
+ * <li>The call to `Monster#startMonster(FlatBufferBuilder)` will call this
+ * method with the right number of fields set.</li>
+ * <li>`Monster#endMonster(FlatBufferBuilder)` will ensure {@link #endObject()} is called.</li>
+ * </ul>
+ * <p>
+ * It's not recommended to call this method directly. If it's called manually, you must ensure
+ * to audit all calls to it whenever fields are added or removed from your schema. This is
+ * automatically done by the code generated by the `FlatBuffers` compiler.
+ *
+ * @param numfields The number of fields found in this object.
+ */
+ public void startTable(int numfields) {
+ notNested();
+ if (vtable == null || vtable.length < numfields) vtable = new int[numfields];
+ vtable_in_use = numfields;
+ Arrays.fill(vtable, 0, vtable_in_use, 0);
+ nested = true;
+ object_start = offset();
+ }
+
+ /**
+ * Add a `boolean` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `boolean` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `boolean` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addBoolean(int o, boolean x, boolean d) { if(force_defaults || x != d) { addBoolean(x); slot(o); } }
+
+ /**
+ * Add a `byte` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `byte` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `byte` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addByte (int o, byte x, int d) { if(force_defaults || x != d) { addByte (x); slot(o); } }
+
+ /**
+ * Add a `short` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `short` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `short` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addShort (int o, short x, int d) { if(force_defaults || x != d) { addShort (x); slot(o); } }
+
+ /**
+ * Add an `int` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x An `int` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d An `int` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addInt (int o, int x, int d) { if(force_defaults || x != d) { addInt (x); slot(o); } }
+
+ /**
+ * Add a `long` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `long` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `long` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addLong (int o, long x, long d) { if(force_defaults || x != d) { addLong (x); slot(o); } }
+
+ /**
+ * Add a `float` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `float` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `float` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addFloat (int o, float x, double d) { if(force_defaults || x != d) { addFloat (x); slot(o); } }
+
+ /**
+ * Add a `double` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x A `double` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d A `double` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addDouble (int o, double x, double d) { if(force_defaults || x != d) { addDouble (x); slot(o); } }
+
+ /**
+ * Add an `offset` to a table at `o` into its vtable, with value `x` and default `d`.
+ *
+ * @param o The index into the vtable.
+ * @param x An `offset` to put into the buffer, depending on how defaults are handled. If
+ * `force_defaults` is `false`, compare `x` against the default value `d`. If `x` contains the
+ * default value, it can be skipped.
+ * @param d An `offset` default value to compare against when `force_defaults` is `false`.
+ */
+ public void addOffset (int o, int x, int d) { if(force_defaults || x != d) { addOffset (x); slot(o); } }
+
+ /**
+ * Add a struct to the table. Structs are stored inline, so nothing additional is being added.
+ *
+ * @param voffset The index into the vtable.
+ * @param x The offset of the created struct.
+ * @param d The default value is always `0`.
+ */
+ public void addStruct(int voffset, int x, int d) {
+ if(x != d) {
+ Nested(x);
+ slot(voffset);
+ }
+ }
+
+ /**
+ * Set the current vtable at `voffset` to the current location in the buffer.
+ *
+ * @param voffset The index into the vtable to store the offset relative to the end of the
+ * buffer.
+ */
+ public void slot(int voffset) {
+ vtable[voffset] = offset();
+ }
+
+ /**
+ * Finish off writing the object that is under construction.
+ *
+ * @return The offset to the object inside {@link #dataBuffer()}.
+ * @see #startTable(int)
+ */
+ public int endTable() {
+ if (vtable == null || !nested)
+ throw new AssertionError("FlatBuffers: endTable called without startTable");
+ addInt(0);
+ int vtableloc = offset();
+ // Write out the current vtable.
+ int i = vtable_in_use - 1;
+ // Trim trailing zeroes.
+ for (; i >= 0 && vtable[i] == 0; i--) {}
+ int trimmed_size = i + 1;
+ for (; i >= 0 ; i--) {
+ // Offset relative to the start of the table.
+ short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
+ addShort(off);
+ }
+
+ final int standard_fields = 2; // The fields below:
+ addShort((short)(vtableloc - object_start));
+ addShort((short)((trimmed_size + standard_fields) * SIZEOF_SHORT));
+
+ // Search for an existing vtable that matches the current one.
+ int existing_vtable = 0;
+ outer_loop:
+ for (i = 0; i < num_vtables; i++) {
+ int vt1 = bb.capacity() - vtables[i];
+ int vt2 = space;
+ short len = bb.getShort(vt1);
+ if (len == bb.getShort(vt2)) {
+ for (int j = SIZEOF_SHORT; j < len; j += SIZEOF_SHORT) {
+ if (bb.getShort(vt1 + j) != bb.getShort(vt2 + j)) {
+ continue outer_loop;
+ }
+ }
+ existing_vtable = vtables[i];
+ break outer_loop;
+ }
+ }
+
+ if (existing_vtable != 0) {
+ // Found a match:
+ // Remove the current vtable.
+ space = bb.capacity() - vtableloc;
+ // Point table to existing vtable.
+ bb.putInt(space, existing_vtable - vtableloc);
+ } else {
+ // No match:
+ // Add the location of the current vtable to the list of vtables.
+ if (num_vtables == vtables.length) vtables = Arrays.copyOf(vtables, num_vtables * 2);
+ vtables[num_vtables++] = offset();
+ // Point table to current vtable.
+ bb.putInt(bb.capacity() - vtableloc, offset() - vtableloc);
+ }
+
+ nested = false;
+ return vtableloc;
+ }
+
+ /**
+ * Checks that a required field has been set in a given table that has
+ * just been constructed.
+ *
+ * @param table The offset to the start of the table from the `ByteBuffer` capacity.
+ * @param field The offset to the field in the vtable.
+ */
+ public void required(int table, int field) {
+ int table_start = bb.capacity() - table;
+ int vtable_start = table_start - bb.getInt(table_start);
+ boolean ok = bb.getShort(vtable_start + field) != 0;
+ // If this fails, the caller will show what field needs to be set.
+ if (!ok)
+ throw new AssertionError("FlatBuffers: field " + field + " must be set");
+ }
+ /// @endcond
+
+ /**
+ * Finalize a buffer, pointing to the given `root_table`.
+ *
+ * @param root_table An offset to be added to the buffer.
+ * @param size_prefix Whether to prefix the size to the buffer.
+ */
+ protected void finish(int root_table, boolean size_prefix) {
+ prep(minalign, SIZEOF_INT + (size_prefix ? SIZEOF_INT : 0));
+ addOffset(root_table);
+ if (size_prefix) {
+ addInt(bb.capacity() - space);
+ }
+ bb.position(space);
+ finished = true;
+ }
+
+ /**
+ * Finalize a buffer, pointing to the given `root_table`.
+ *
+ * @param root_table An offset to be added to the buffer.
+ */
+ public void finish(int root_table) {
+ finish(root_table, false);
+ }
+
+ /**
+ * Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
+ *
+ * @param root_table An offset to be added to the buffer.
+ */
+ public void finishSizePrefixed(int root_table) {
+ finish(root_table, true);
+ }
+
+ /**
+ * Finalize a buffer, pointing to the given `root_table`.
+ *
+ * @param root_table An offset to be added to the buffer.
+ * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
+ * `root_table`.
+ * @param size_prefix Whether to prefix the size to the buffer.
+ */
+ protected void finish(int root_table, String file_identifier, boolean size_prefix) {
+ prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH + (size_prefix ? SIZEOF_INT : 0));
+ if (file_identifier.length() != FILE_IDENTIFIER_LENGTH)
+ throw new AssertionError("FlatBuffers: file identifier must be length " +
+ FILE_IDENTIFIER_LENGTH);
+ for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) {
+ addByte((byte)file_identifier.charAt(i));
+ }
+ finish(root_table, size_prefix);
+ }
+
+ /**
+ * Finalize a buffer, pointing to the given `root_table`.
+ *
+ * @param root_table An offset to be added to the buffer.
+ * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
+ * `root_table`.
+ */
+ public void finish(int root_table, String file_identifier) {
+ finish(root_table, file_identifier, false);
+ }
+
+ /**
+ * Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
+ *
+ * @param root_table An offset to be added to the buffer.
+ * @param file_identifier A FlatBuffer file identifier to be added to the buffer before
+ * `root_table`.
+ */
+ public void finishSizePrefixed(int root_table, String file_identifier) {
+ finish(root_table, file_identifier, true);
+ }
+
+ /**
+ * In order to save space, fields that are set to their default value
+ * don't get serialized into the buffer. Forcing defaults provides a
+ * way to manually disable this optimization.
+ *
+ * @param forceDefaults When set to `true`, always serializes default values.
+ * @return Returns `this`.
+ */
+ public FlatBufferBuilder forceDefaults(boolean forceDefaults){
+ this.force_defaults = forceDefaults;
+ return this;
+ }
+
+ /**
+ * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
+ * called `finish()`. The actual data starts at the ByteBuffer's current position,
+ * not necessarily at `0`.
+ *
+ * @return The {@link ByteBuffer} representing the FlatBuffer
+ */
+ public ByteBuffer dataBuffer() {
+ finished();
+ return bb;
+ }
+
+ /**
+ * The FlatBuffer data doesn't start at offset 0 in the {@link ByteBuffer}, but
+ * now the {@code ByteBuffer}'s position is set to that location upon {@link #finish(int)}.
+ *
+ * @return The {@link ByteBuffer#position() position} the data starts in {@link #dataBuffer()}
+ * @deprecated This method should not be needed anymore, but is left
+ * here for the moment to document this API change. It will be removed in the future.
+ */
+ @Deprecated
+ private int dataStart() {
+ finished();
+ return space;
+ }
+
+ /**
+ * A utility function to copy and return the ByteBuffer data from `start` to
+ * `start` + `length` as a `byte[]`.
+ *
+ * @param start Start copying at this offset.
+ * @param length How many bytes to copy.
+ * @return A range copy of the {@link #dataBuffer() data buffer}.
+ * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound.
+ */
+ public byte[] sizedByteArray(int start, int length){
+ finished();
+ byte[] array = new byte[length];
+ bb.position(start);
+ bb.get(array);
+ return array;
+ }
+
+ /**
+ * A utility function to copy and return the ByteBuffer data as a `byte[]`.
+ *
+ * @return A full copy of the {@link #dataBuffer() data buffer}.
+ */
+ public byte[] sizedByteArray() {
+ return sizedByteArray(space, bb.capacity() - space);
+ }
+
+ /**
+ * A utility function to return an InputStream to the ByteBuffer data
+ *
+ * @return An InputStream that starts at the beginning of the ByteBuffer data
+ * and can read to the end of it.
+ */
+ public InputStream sizedInputStream() {
+ finished();
+ ByteBuffer duplicate = bb.duplicate();
+ duplicate.position(space);
+ duplicate.limit(bb.capacity());
+ return new ByteBufferBackedInputStream(duplicate);
+ }
+
+ /**
+ * A class that allows a user to create an InputStream from a ByteBuffer.
+ */
+ static class ByteBufferBackedInputStream extends InputStream {
+
+ ByteBuffer buf;
+
+ public ByteBufferBackedInputStream(ByteBuffer buf) {
+ this.buf = buf;
+ }
+
+ public int read() throws IOException {
+ try {
+ return buf.get() & 0xFF;
+ } catch(BufferUnderflowException e) {
+ return -1;
+ }
+ }
+ }
+
+}
+
+/// @}
diff --git a/java/com/google/flatbuffers/Struct.java b/java/com/google/flatbuffers/Struct.java
new file mode 100644
index 0000000..c92164f
--- /dev/null
+++ b/java/com/google/flatbuffers/Struct.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import java.nio.ByteBuffer;
+
+/// @cond FLATBUFFERS_INTERNAL
+
+/**
+ * All structs in the generated code derive from this class, and add their own accessors.
+ */
+public class Struct {
+ /** Used to hold the position of the `bb` buffer. */
+ protected int bb_pos;
+ /** The underlying ByteBuffer to hold the data of the Struct. */
+ protected ByteBuffer bb;
+
+ /**
+ * Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
+ *
+ * This method exists primarily to allow recycling Table instances without risking memory leaks
+ * due to {@code ByteBuffer} references.
+ */
+ protected void __reset(int _i, ByteBuffer _bb) {
+ bb = _bb;
+ if (bb != null) {
+ bb_pos = _i;
+ } else {
+ bb_pos = 0;
+ }
+ }
+
+ /**
+ * Resets internal state with a null {@code ByteBuffer} and a zero position.
+ *
+ * This method exists primarily to allow recycling Struct instances without risking memory leaks
+ * due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
+ * again to a {@code ByteBuffer}.
+ *
+ * @param struct the instance to reset to initial state
+ */
+ public void __reset() {
+ __reset(0, null);
+ }
+}
+
+/// @endcond
diff --git a/java/com/google/flatbuffers/Table.java b/java/com/google/flatbuffers/Table.java
new file mode 100644
index 0000000..ff069f2
--- /dev/null
+++ b/java/com/google/flatbuffers/Table.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import static com.google.flatbuffers.Constants.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/// @cond FLATBUFFERS_INTERNAL
+
+/**
+ * All tables in the generated code derive from this class, and add their own accessors.
+ */
+public class Table {
+ public final static ThreadLocal<Charset> UTF8_CHARSET = new ThreadLocal<Charset>() {
+ @Override
+ protected Charset initialValue() {
+ return Charset.forName("UTF-8");
+ }
+ };
+ /** Used to hold the position of the `bb` buffer. */
+ protected int bb_pos;
+ /** The underlying ByteBuffer to hold the data of the Table. */
+ protected ByteBuffer bb;
+ /** Used to hold the vtable position. */
+ private int vtable_start;
+ /** Used to hold the vtable size. */
+ private int vtable_size;
+ Utf8 utf8 = Utf8.getDefault();
+
+ /**
+ * Get the underlying ByteBuffer.
+ *
+ * @return Returns the Table's ByteBuffer.
+ */
+ public ByteBuffer getByteBuffer() { return bb; }
+
+ /**
+ * Look up a field in the vtable.
+ *
+ * @param vtable_offset An `int` offset to the vtable in the Table's ByteBuffer.
+ * @return Returns an offset into the object, or `0` if the field is not present.
+ */
+ protected int __offset(int vtable_offset) {
+ return vtable_offset < vtable_size ? bb.getShort(vtable_start + vtable_offset) : 0;
+ }
+
+ protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
+ int vtable = bb.capacity() - offset;
+ return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
+ }
+
+ /**
+ * Retrieve a relative offset.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer containing the relative offset.
+ * @return Returns the relative offset stored at `offset`.
+ */
+ protected int __indirect(int offset) {
+ return offset + bb.getInt(offset);
+ }
+
+ protected static int __indirect(int offset, ByteBuffer bb) {
+ return offset + bb.getInt(offset);
+ }
+
+ /**
+ * Create a Java `String` from UTF-8 data stored inside the FlatBuffer.
+ *
+ * This allocates a new string and converts to wide chars upon each access,
+ * which is not very efficient. Instead, each FlatBuffer string also comes with an
+ * accessor based on __vector_as_bytebuffer below, which is much more efficient,
+ * assuming your Java program can handle UTF-8 data directly.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
+ */
+ protected String __string(int offset) {
+ offset += bb.getInt(offset);
+ int length = bb.getInt(offset);
+ return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length);
+ }
+
+ /**
+ * Get the length of a vector.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns the length of the vector whose offset is stored at `offset`.
+ */
+ protected int __vector_len(int offset) {
+ offset += bb_pos;
+ offset += bb.getInt(offset);
+ return bb.getInt(offset);
+ }
+
+ /**
+ * Get the start data of a vector.
+ *
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns the start of the vector data whose offset is stored at `offset`.
+ */
+ protected int __vector(int offset) {
+ offset += bb_pos;
+ return offset + bb.getInt(offset) + SIZEOF_INT; // data starts after the length
+ }
+
+ /**
+ * Get a whole vector as a ByteBuffer.
+ *
+ * This is efficient, since it only allocates a new {@link ByteBuffer} object,
+ * but does not actually copy the data, it still refers to the same bytes
+ * as the original ByteBuffer. Also useful with nested FlatBuffers, etc.
+ *
+ * @param vector_offset The position of the vector in the byte buffer
+ * @param elem_size The size of each element in the array
+ * @return The {@link ByteBuffer} for the array
+ */
+ protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) {
+ int o = __offset(vector_offset);
+ if (o == 0) return null;
+ ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+ int vectorstart = __vector(o);
+ bb.position(vectorstart);
+ bb.limit(vectorstart + __vector_len(o) * elem_size);
+ return bb;
+ }
+
+ /**
+ * Initialize vector as a ByteBuffer.
+ *
+ * This is more efficient than using duplicate, since it doesn't copy the data
+ * nor allocattes a new {@link ByteBuffer}, creating no garbage to be collected.
+ *
+ * @param bb The {@link ByteBuffer} for the array
+ * @param vector_offset The position of the vector in the byte buffer
+ * @param elem_size The size of each element in the array
+ * @return The {@link ByteBuffer} for the array
+ */
+ protected ByteBuffer __vector_in_bytebuffer(ByteBuffer bb, int vector_offset, int elem_size) {
+ int o = this.__offset(vector_offset);
+ if (o == 0) return null;
+ int vectorstart = __vector(o);
+ bb.rewind();
+ bb.limit(vectorstart + __vector_len(o) * elem_size);
+ bb.position(vectorstart);
+ return bb;
+ }
+
+ /**
+ * Initialize any Table-derived type to point to the union at the given `offset`.
+ *
+ * @param t A `Table`-derived type that should point to the union at `offset`.
+ * @param offset An `int` index into the Table's ByteBuffer.
+ * @return Returns the Table that points to the union at `offset`.
+ */
+ protected Table __union(Table t, int offset) {
+ offset += bb_pos;
+ t.bb_pos = offset + bb.getInt(offset);
+ t.bb = bb;
+ t.vtable_start = t.bb_pos - bb.getInt(t.bb_pos);
+ t.vtable_size = bb.getShort(t.vtable_start);
+ return t;
+ }
+
+ /**
+ * Check if a {@link ByteBuffer} contains a file identifier.
+ *
+ * @param bb A {@code ByteBuffer} to check if it contains the identifier
+ * `ident`.
+ * @param ident A `String` identifier of the FlatBuffer file.
+ * @return True if the buffer contains the file identifier
+ */
+ protected static boolean __has_identifier(ByteBuffer bb, String ident) {
+ if (ident.length() != FILE_IDENTIFIER_LENGTH)
+ throw new AssertionError("FlatBuffers: file identifier must be length " +
+ FILE_IDENTIFIER_LENGTH);
+ for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++) {
+ if (ident.charAt(i) != (char)bb.get(bb.position() + SIZEOF_INT + i)) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sort tables by the key.
+ *
+ * @param offsets An 'int' indexes of the tables into the bb.
+ * @param bb A {@code ByteBuffer} to get the tables.
+ */
+ protected void sortTables(int[] offsets, final ByteBuffer bb) {
+ Integer[] off = new Integer[offsets.length];
+ for (int i = 0; i < offsets.length; i++) off[i] = offsets[i];
+ java.util.Arrays.sort(off, new java.util.Comparator<Integer>() {
+ public int compare(Integer o1, Integer o2) {
+ return keysCompare(o1, o2, bb);
+ }
+ });
+ for (int i = 0; i < offsets.length; i++) offsets[i] = off[i];
+ }
+
+ /**
+ * Compare two tables by the key.
+ *
+ * @param o1 An 'Integer' index of the first key into the bb.
+ * @param o2 An 'Integer' index of the second key into the bb.
+ * @param bb A {@code ByteBuffer} to get the keys.
+ */
+ protected int keysCompare(Integer o1, Integer o2, ByteBuffer bb) { return 0; }
+
+ /**
+ * Compare two strings in the buffer.
+ *
+ * @param offset_1 An 'int' index of the first string into the bb.
+ * @param offset_2 An 'int' index of the second string into the bb.
+ * @param bb A {@code ByteBuffer} to get the strings.
+ */
+ protected static int compareStrings(int offset_1, int offset_2, ByteBuffer bb) {
+ offset_1 += bb.getInt(offset_1);
+ offset_2 += bb.getInt(offset_2);
+ int len_1 = bb.getInt(offset_1);
+ int len_2 = bb.getInt(offset_2);
+ int startPos_1 = offset_1 + SIZEOF_INT;
+ int startPos_2 = offset_2 + SIZEOF_INT;
+ int len = Math.min(len_1, len_2);
+ for(int i = 0; i < len; i++) {
+ if (bb.get(i + startPos_1) != bb.get(i + startPos_2))
+ return bb.get(i + startPos_1) - bb.get(i + startPos_2);
+ }
+ return len_1 - len_2;
+ }
+
+ /**
+ * Compare string from the buffer with the 'String' object.
+ *
+ * @param offset_1 An 'int' index of the first string into the bb.
+ * @param key Second string as a byte array.
+ * @param bb A {@code ByteBuffer} to get the first string.
+ */
+ protected static int compareStrings(int offset_1, byte[] key, ByteBuffer bb) {
+ offset_1 += bb.getInt(offset_1);
+ int len_1 = bb.getInt(offset_1);
+ int len_2 = key.length;
+ int startPos_1 = offset_1 + Constants.SIZEOF_INT;
+ int len = Math.min(len_1, len_2);
+ for (int i = 0; i < len; i++) {
+ if (bb.get(i + startPos_1) != key[i])
+ return bb.get(i + startPos_1) - key[i];
+ }
+ return len_1 - len_2;
+ }
+
+ /**
+ * Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
+ *
+ * This method exists primarily to allow recycling Table instances without risking memory leaks
+ * due to {@code ByteBuffer} references.
+ */
+ protected void __reset(int _i, ByteBuffer _bb) {
+ bb = _bb;
+ if (bb != null) {
+ bb_pos = _i;
+ vtable_start = bb_pos - bb.getInt(bb_pos);
+ vtable_size = bb.getShort(vtable_start);
+ } else {
+ bb_pos = 0;
+ vtable_start = 0;
+ vtable_size = 0;
+ }
+ }
+
+ /**
+ * Resets the internal state with a null {@code ByteBuffer} and a zero position.
+ *
+ * This method exists primarily to allow recycling Table instances without risking memory leaks
+ * due to {@code ByteBuffer} references. The instance will be unusable until it is assigned
+ * again to a {@code ByteBuffer}.
+ */
+ public void __reset() {
+ __reset(0, null);
+ }
+}
+
+/// @endcond
diff --git a/java/com/google/flatbuffers/Utf8.java b/java/com/google/flatbuffers/Utf8.java
new file mode 100644
index 0000000..efb6811
--- /dev/null
+++ b/java/com/google/flatbuffers/Utf8.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import java.nio.ByteBuffer;
+
+import static java.lang.Character.MIN_HIGH_SURROGATE;
+import static java.lang.Character.MIN_LOW_SURROGATE;
+import static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;
+
+public abstract class Utf8 {
+
+ /**
+ * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
+ * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
+ * both time and space.
+ *
+ * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+ * surrogates)
+ */
+ public abstract int encodedLength(CharSequence sequence);
+
+ /**
+ * Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
+ *
+ * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+ * and the capabilities of the platform.
+ *
+ * @param in the source string to be encoded
+ * @param out the target buffer to receive the encoded string.
+ */
+ public abstract void encodeUtf8(CharSequence in, ByteBuffer out);
+
+ /**
+ * Decodes the given UTF-8 portion of the {@link ByteBuffer} into a {@link String}.
+ *
+ * @throws IllegalArgumentException if the input is not valid UTF-8.
+ */
+ public abstract String decodeUtf8(ByteBuffer buffer, int offset, int length);
+
+ private static Utf8 DEFAULT;
+
+ /**
+ * Get the default UTF-8 processor.
+ * @return the default processor
+ */
+ public static Utf8 getDefault() {
+ if (DEFAULT == null) {
+ DEFAULT = new Utf8Safe();
+ }
+ return DEFAULT;
+ }
+
+ /**
+ * Set the default instance of the UTF-8 processor.
+ * @param instance the new instance to use
+ */
+ public static void setDefault(Utf8 instance) {
+ DEFAULT = instance;
+ }
+
+ /**
+ * Utility methods for decoding bytes into {@link String}. Callers are responsible for extracting
+ * bytes (possibly using Unsafe methods), and checking remaining bytes. All other UTF-8 validity
+ * checks and codepoint conversion happen in this class.
+ */
+ static class DecodeUtil {
+
+ /**
+ * Returns whether this is a single-byte codepoint (i.e., ASCII) with the form '0XXXXXXX'.
+ */
+ static boolean isOneByte(byte b) {
+ return b >= 0;
+ }
+
+ /**
+ * Returns whether this is a two-byte codepoint with the form '10XXXXXX'.
+ */
+ static boolean isTwoBytes(byte b) {
+ return b < (byte) 0xE0;
+ }
+
+ /**
+ * Returns whether this is a three-byte codepoint with the form '110XXXXX'.
+ */
+ static boolean isThreeBytes(byte b) {
+ return b < (byte) 0xF0;
+ }
+
+ static void handleOneByte(byte byte1, char[] resultArr, int resultPos) {
+ resultArr[resultPos] = (char) byte1;
+ }
+
+ static void handleTwoBytes(
+ byte byte1, byte byte2, char[] resultArr, int resultPos)
+ throws IllegalArgumentException {
+ // Simultaneously checks for illegal trailing-byte in leading position (<= '11000000') and
+ // overlong 2-byte, '11000001'.
+ if (byte1 < (byte) 0xC2) {
+ throw new IllegalArgumentException("Invalid UTF-8: Illegal leading byte in 2 bytes utf");
+ }
+ if (isNotTrailingByte(byte2)) {
+ throw new IllegalArgumentException("Invalid UTF-8: Illegal trailing byte in 2 bytes utf");
+ }
+ resultArr[resultPos] = (char) (((byte1 & 0x1F) << 6) | trailingByteValue(byte2));
+ }
+
+ static void handleThreeBytes(
+ byte byte1, byte byte2, byte byte3, char[] resultArr, int resultPos)
+ throws IllegalArgumentException {
+ if (isNotTrailingByte(byte2)
+ // overlong? 5 most significant bits must not all be zero
+ || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
+ // check for illegal surrogate codepoints
+ || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
+ || isNotTrailingByte(byte3)) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ resultArr[resultPos] = (char)
+ (((byte1 & 0x0F) << 12) | (trailingByteValue(byte2) << 6) | trailingByteValue(byte3));
+ }
+
+ static void handleFourBytes(
+ byte byte1, byte byte2, byte byte3, byte byte4, char[] resultArr, int resultPos)
+ throws IllegalArgumentException{
+ if (isNotTrailingByte(byte2)
+ // Check that 1 <= plane <= 16. Tricky optimized form of:
+ // valid 4-byte leading byte?
+ // if (byte1 > (byte) 0xF4 ||
+ // overlong? 4 most significant bits must not all be zero
+ // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
+ // codepoint larger than the highest code point (U+10FFFF)?
+ // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
+ || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
+ || isNotTrailingByte(byte3)
+ || isNotTrailingByte(byte4)) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ int codepoint = ((byte1 & 0x07) << 18)
+ | (trailingByteValue(byte2) << 12)
+ | (trailingByteValue(byte3) << 6)
+ | trailingByteValue(byte4);
+ resultArr[resultPos] = DecodeUtil.highSurrogate(codepoint);
+ resultArr[resultPos + 1] = DecodeUtil.lowSurrogate(codepoint);
+ }
+
+ /**
+ * Returns whether the byte is not a valid continuation of the form '10XXXXXX'.
+ */
+ private static boolean isNotTrailingByte(byte b) {
+ return b > (byte) 0xBF;
+ }
+
+ /**
+ * Returns the actual value of the trailing byte (removes the prefix '10') for composition.
+ */
+ private static int trailingByteValue(byte b) {
+ return b & 0x3F;
+ }
+
+ private static char highSurrogate(int codePoint) {
+ return (char) ((MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10))
+ + (codePoint >>> 10));
+ }
+
+ private static char lowSurrogate(int codePoint) {
+ return (char) (MIN_LOW_SURROGATE + (codePoint & 0x3ff));
+ }
+ }
+
+ // These UTF-8 handling methods are copied from Guava's Utf8Unsafe class with a modification to throw
+ // a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can
+ // fallback to more lenient behavior.
+ static class UnpairedSurrogateException extends IllegalArgumentException {
+ UnpairedSurrogateException(int index, int length) {
+ super("Unpaired surrogate at index " + index + " of " + length);
+ }
+ }
+}
diff --git a/java/com/google/flatbuffers/Utf8Old.java b/java/com/google/flatbuffers/Utf8Old.java
new file mode 100644
index 0000000..3dac714
--- /dev/null
+++ b/java/com/google/flatbuffers/Utf8Old.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * This class implements the Utf8 API using the Java Utf8 encoder. Use
+ * Utf8.setDefault(new Utf8Old()); to use it.
+ */
+public class Utf8Old extends Utf8 {
+
+ private static class Cache {
+ final CharsetEncoder encoder;
+ final CharsetDecoder decoder;
+ CharSequence lastInput = null;
+ ByteBuffer lastOutput = null;
+
+ Cache() {
+ encoder = StandardCharsets.UTF_8.newEncoder();
+ decoder = StandardCharsets.UTF_8.newDecoder();
+ }
+ }
+
+ private static final ThreadLocal<Cache> CACHE =
+ ThreadLocal.withInitial(() -> new Cache());
+
+ // Play some games so that the old encoder doesn't pay twice for computing
+ // the length of the encoded string.
+
+ @Override
+ public int encodedLength(CharSequence in) {
+ final Cache cache = CACHE.get();
+ int estimated = (int) (in.length() * cache.encoder.maxBytesPerChar());
+ if (cache.lastOutput == null || cache.lastOutput.capacity() < estimated) {
+ cache.lastOutput = ByteBuffer.allocate(Math.max(128, estimated));
+ }
+ cache.lastOutput.clear();
+ cache.lastInput = in;
+ CharBuffer wrap = (in instanceof CharBuffer) ?
+ (CharBuffer) in : CharBuffer.wrap(in);
+ CoderResult result = cache.encoder.encode(wrap, cache.lastOutput, true);
+ if (result.isError()) {
+ try {
+ result.throwException();
+ } catch (CharacterCodingException e) {
+ throw new IllegalArgumentException("bad character encoding", e);
+ }
+ }
+ cache.lastOutput.flip();
+ return cache.lastOutput.remaining();
+ }
+
+ @Override
+ public void encodeUtf8(CharSequence in, ByteBuffer out) {
+ final Cache cache = CACHE.get();
+ if (cache.lastInput != in) {
+ // Update the lastOutput to match our input, although flatbuffer should
+ // never take this branch.
+ encodedLength(in);
+ }
+ out.put(cache.lastOutput);
+ }
+
+ @Override
+ public String decodeUtf8(ByteBuffer buffer, int offset, int length) {
+ CharsetDecoder decoder = CACHE.get().decoder;
+ decoder.reset();
+ buffer = buffer.duplicate();
+ buffer.position(offset);
+ buffer.limit(offset + length);
+ try {
+ CharBuffer result = decoder.decode(buffer);
+ return result.toString();
+ } catch (CharacterCodingException e) {
+ throw new IllegalArgumentException("Bad encoding", e);
+ }
+ }
+}
diff --git a/java/com/google/flatbuffers/Utf8Safe.java b/java/com/google/flatbuffers/Utf8Safe.java
new file mode 100644
index 0000000..06ea420
--- /dev/null
+++ b/java/com/google/flatbuffers/Utf8Safe.java
@@ -0,0 +1,451 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.flatbuffers;
+
+import java.nio.ByteBuffer;
+import static java.lang.Character.MAX_SURROGATE;
+import static java.lang.Character.MIN_SUPPLEMENTARY_CODE_POINT;
+import static java.lang.Character.MIN_SURROGATE;
+import static java.lang.Character.isSurrogatePair;
+import static java.lang.Character.toCodePoint;
+
+/**
+ * A set of low-level, high-performance static utility methods related
+ * to the UTF-8 character encoding. This class has no dependencies
+ * outside of the core JDK libraries.
+ *
+ * <p>There are several variants of UTF-8. The one implemented by
+ * this class is the restricted definition of UTF-8 introduced in
+ * Unicode 3.1, which mandates the rejection of "overlong" byte
+ * sequences as well as rejection of 3-byte surrogate codepoint byte
+ * sequences. Note that the UTF-8 decoder included in Oracle's JDK
+ * has been modified to also reject "overlong" byte sequences, but (as
+ * of 2011) still accepts 3-byte surrogate codepoint byte sequences.
+ *
+ * <p>The byte sequences considered valid by this class are exactly
+ * those that can be roundtrip converted to Strings and back to bytes
+ * using the UTF-8 charset, without loss: <pre> {@code
+ * Arrays.equals(bytes, new String(bytes, Internal.UTF_8).getBytes(Internal.UTF_8))
+ * }</pre>
+ *
+ * <p>See the Unicode Standard,</br>
+ * Table 3-6. <em>UTF-8 Bit Distribution</em>,</br>
+ * Table 3-7. <em>Well Formed UTF-8 Byte Sequences</em>.
+ */
+final public class Utf8Safe extends Utf8 {
+
+ /**
+ * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string,
+ * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in
+ * both time and space.
+ *
+ * @throws IllegalArgumentException if {@code sequence} contains ill-formed UTF-16 (unpaired
+ * surrogates)
+ */
+ private static int computeEncodedLength(CharSequence sequence) {
+ // Warning to maintainers: this implementation is highly optimized.
+ int utf16Length = sequence.length();
+ int utf8Length = utf16Length;
+ int i = 0;
+
+ // This loop optimizes for pure ASCII.
+ while (i < utf16Length && sequence.charAt(i) < 0x80) {
+ i++;
+ }
+
+ // This loop optimizes for chars less than 0x800.
+ for (; i < utf16Length; i++) {
+ char c = sequence.charAt(i);
+ if (c < 0x800) {
+ utf8Length += ((0x7f - c) >>> 31); // branch free!
+ } else {
+ utf8Length += encodedLengthGeneral(sequence, i);
+ break;
+ }
+ }
+
+ if (utf8Length < utf16Length) {
+ // Necessary and sufficient condition for overflow because of maximum 3x expansion
+ throw new IllegalArgumentException("UTF-8 length does not fit in int: "
+ + (utf8Length + (1L << 32)));
+ }
+ return utf8Length;
+ }
+
+ private static int encodedLengthGeneral(CharSequence sequence, int start) {
+ int utf16Length = sequence.length();
+ int utf8Length = 0;
+ for (int i = start; i < utf16Length; i++) {
+ char c = sequence.charAt(i);
+ if (c < 0x800) {
+ utf8Length += (0x7f - c) >>> 31; // branch free!
+ } else {
+ utf8Length += 2;
+ // jdk7+: if (Character.isSurrogate(c)) {
+ if (Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) {
+ // Check that we have a well-formed surrogate pair.
+ int cp = Character.codePointAt(sequence, i);
+ if (cp < MIN_SUPPLEMENTARY_CODE_POINT) {
+ throw new Utf8Safe.UnpairedSurrogateException(i, utf16Length);
+ }
+ i++;
+ }
+ }
+ }
+ return utf8Length;
+ }
+
+ private static String decodeUtf8Array(byte[] bytes, int index, int size) {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
+ if ((index | size | bytes.length - index - size) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer length=%d, index=%d, size=%d", bytes.length, index, size));
+ }
+
+ int offset = index;
+ final int limit = offset + size;
+
+ // The longest possible resulting String is the same as the number of input bytes, when it is
+ // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+ char[] resultArr = new char[size];
+ int resultPos = 0;
+
+ // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+ // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+ while (offset < limit) {
+ byte b = bytes[offset];
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+
+ while (offset < limit) {
+ byte byte1 = bytes[offset++];
+ if (DecodeUtil.isOneByte(byte1)) {
+ DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+ // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+ // extra optimized loop to take care of these runs.
+ while (offset < limit) {
+ byte b = bytes[offset];
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+ } else if (DecodeUtil.isTwoBytes(byte1)) {
+ if (offset >= limit) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ DecodeUtil.handleTwoBytes(byte1, /* byte2 */ bytes[offset++], resultArr, resultPos++);
+ } else if (DecodeUtil.isThreeBytes(byte1)) {
+ if (offset >= limit - 1) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ DecodeUtil.handleThreeBytes(
+ byte1,
+ /* byte2 */ bytes[offset++],
+ /* byte3 */ bytes[offset++],
+ resultArr,
+ resultPos++);
+ } else {
+ if (offset >= limit - 2) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ DecodeUtil.handleFourBytes(
+ byte1,
+ /* byte2 */ bytes[offset++],
+ /* byte3 */ bytes[offset++],
+ /* byte4 */ bytes[offset++],
+ resultArr,
+ resultPos++);
+ // 4-byte case requires two chars.
+ resultPos++;
+ }
+ }
+
+ return new String(resultArr, 0, resultPos);
+ }
+
+ private static String decodeUtf8Buffer(ByteBuffer buffer, int offset,
+ int length) {
+ // Bitwise OR combines the sign bits so any negative value fails the check.
+ if ((offset | length | buffer.limit() - offset - length) < 0) {
+ throw new ArrayIndexOutOfBoundsException(
+ String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(),
+ offset, length));
+ }
+
+ final int limit = offset + length;
+
+ // The longest possible resulting String is the same as the number of input bytes, when it is
+ // all ASCII. For other cases, this over-allocates and we will truncate in the end.
+ char[] resultArr = new char[length];
+ int resultPos = 0;
+
+ // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this).
+ // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII).
+ while (offset < limit) {
+ byte b = buffer.get(offset);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+
+ while (offset < limit) {
+ byte byte1 = buffer.get(offset++);
+ if (DecodeUtil.isOneByte(byte1)) {
+ DecodeUtil.handleOneByte(byte1, resultArr, resultPos++);
+ // It's common for there to be multiple ASCII characters in a run mixed in, so add an
+ // extra optimized loop to take care of these runs.
+ while (offset < limit) {
+ byte b = buffer.get(offset);
+ if (!DecodeUtil.isOneByte(b)) {
+ break;
+ }
+ offset++;
+ DecodeUtil.handleOneByte(b, resultArr, resultPos++);
+ }
+ } else if (DecodeUtil.isTwoBytes(byte1)) {
+ if (offset >= limit) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ DecodeUtil.handleTwoBytes(
+ byte1, /* byte2 */ buffer.get(offset++), resultArr, resultPos++);
+ } else if (DecodeUtil.isThreeBytes(byte1)) {
+ if (offset >= limit - 1) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ DecodeUtil.handleThreeBytes(
+ byte1,
+ /* byte2 */ buffer.get(offset++),
+ /* byte3 */ buffer.get(offset++),
+ resultArr,
+ resultPos++);
+ } else {
+ if (offset >= limit - 2) {
+ throw new IllegalArgumentException("Invalid UTF-8");
+ }
+ DecodeUtil.handleFourBytes(
+ byte1,
+ /* byte2 */ buffer.get(offset++),
+ /* byte3 */ buffer.get(offset++),
+ /* byte4 */ buffer.get(offset++),
+ resultArr,
+ resultPos++);
+ // 4-byte case requires two chars.
+ resultPos++;
+ }
+ }
+
+ return new String(resultArr, 0, resultPos);
+ }
+
+ @Override
+ public int encodedLength(CharSequence in) {
+ return computeEncodedLength(in);
+ }
+
+ /**
+ * Decodes the given UTF-8 portion of the {@link ByteBuffer} into a {@link String}.
+ *
+ * @throws IllegalArgumentException if the input is not valid UTF-8.
+ */
+ @Override
+ public String decodeUtf8(ByteBuffer buffer, int offset, int length)
+ throws IllegalArgumentException {
+ if (buffer.hasArray()) {
+ return decodeUtf8Array(buffer.array(), buffer.arrayOffset() + offset, length);
+ } else {
+ return decodeUtf8Buffer(buffer, offset, length);
+ }
+ }
+
+
+ private static void encodeUtf8Buffer(CharSequence in, ByteBuffer out) {
+ final int inLength = in.length();
+ int outIx = out.position();
+ int inIx = 0;
+
+ // Since ByteBuffer.putXXX() already checks boundaries for us, no need to explicitly check
+ // access. Assume the buffer is big enough and let it handle the out of bounds exception
+ // if it occurs.
+ try {
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ for (char c; inIx < inLength && (c = in.charAt(inIx)) < 0x80; ++inIx) {
+ out.put(outIx + inIx, (byte) c);
+ }
+ if (inIx == inLength) {
+ // Successfully encoded the entire string.
+ out.position(outIx + inIx);
+ return;
+ }
+
+ outIx += inIx;
+ for (char c; inIx < inLength; ++inIx, ++outIx) {
+ c = in.charAt(inIx);
+ if (c < 0x80) {
+ // One byte (0xxx xxxx)
+ out.put(outIx, (byte) c);
+ } else if (c < 0x800) {
+ // Two bytes (110x xxxx 10xx xxxx)
+
+ // Benchmarks show put performs better than putShort here (for HotSpot).
+ out.put(outIx++, (byte) (0xC0 | (c >>> 6)));
+ out.put(outIx, (byte) (0x80 | (0x3F & c)));
+ } else if (c < MIN_SURROGATE || MAX_SURROGATE < c) {
+ // Three bytes (1110 xxxx 10xx xxxx 10xx xxxx)
+ // Maximum single-char code point is 0xFFFF, 16 bits.
+
+ // Benchmarks show put performs better than putShort here (for HotSpot).
+ out.put(outIx++, (byte) (0xE0 | (c >>> 12)));
+ out.put(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+ out.put(outIx, (byte) (0x80 | (0x3F & c)));
+ } else {
+ // Four bytes (1111 xxxx 10xx xxxx 10xx xxxx 10xx xxxx)
+
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
+ // bytes
+ final char low;
+ if (inIx + 1 == inLength || !isSurrogatePair(c, (low = in.charAt(++inIx)))) {
+ throw new UnpairedSurrogateException(inIx, inLength);
+ }
+ // TODO(nathanmittler): Consider using putInt() to improve performance.
+ int codePoint = toCodePoint(c, low);
+ out.put(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+ out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+ out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+ out.put(outIx, (byte) (0x80 | (0x3F & codePoint)));
+ }
+ }
+
+ // Successfully encoded the entire string.
+ out.position(outIx);
+ } catch (IndexOutOfBoundsException e) {
+ // TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
+
+ // If we failed in the outer ASCII loop, outIx will not have been updated. In this case,
+ // use inIx to determine the bad write index.
+ int badWriteIndex = out.position() + Math.max(inIx, outIx - out.position() + 1);
+ throw new ArrayIndexOutOfBoundsException(
+ "Failed writing " + in.charAt(inIx) + " at index " + badWriteIndex);
+ }
+ }
+
+ private static int encodeUtf8Array(CharSequence in, byte[] out,
+ int offset, int length) {
+ int utf16Length = in.length();
+ int j = offset;
+ int i = 0;
+ int limit = offset + length;
+ // Designed to take advantage of
+ // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
+ for (char c; i < utf16Length && i + j < limit && (c = in.charAt(i)) < 0x80; i++) {
+ out[j + i] = (byte) c;
+ }
+ if (i == utf16Length) {
+ return j + utf16Length;
+ }
+ j += i;
+ for (char c; i < utf16Length; i++) {
+ c = in.charAt(i);
+ if (c < 0x80 && j < limit) {
+ out[j++] = (byte) c;
+ } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes
+ out[j++] = (byte) ((0xF << 6) | (c >>> 6));
+ out[j++] = (byte) (0x80 | (0x3F & c));
+ } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) {
+ // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
+ out[j++] = (byte) ((0xF << 5) | (c >>> 12));
+ out[j++] = (byte) (0x80 | (0x3F & (c >>> 6)));
+ out[j++] = (byte) (0x80 | (0x3F & c));
+ } else if (j <= limit - 4) {
+ // Minimum code point represented by a surrogate pair is 0x10000, 17 bits,
+ // four UTF-8 bytes
+ final char low;
+ if (i + 1 == in.length()
+ || !Character.isSurrogatePair(c, (low = in.charAt(++i)))) {
+ throw new UnpairedSurrogateException((i - 1), utf16Length);
+ }
+ int codePoint = Character.toCodePoint(c, low);
+ out[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
+ out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12)));
+ out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6)));
+ out[j++] = (byte) (0x80 | (0x3F & codePoint));
+ } else {
+ // If we are surrogates and we're not a surrogate pair, always throw an
+ // UnpairedSurrogateException instead of an ArrayOutOfBoundsException.
+ if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
+ && (i + 1 == in.length()
+ || !Character.isSurrogatePair(c, in.charAt(i + 1)))) {
+ throw new UnpairedSurrogateException(i, utf16Length);
+ }
+ throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
+ }
+ }
+ return j;
+ }
+
+ /**
+ * Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding.
+ *
+ * <p>Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct)
+ * and the capabilities of the platform.
+ *
+ * @param in the source string to be encoded
+ * @param out the target buffer to receive the encoded string.
+ */
+ @Override
+ public void encodeUtf8(CharSequence in, ByteBuffer out) {
+ if (out.hasArray()) {
+ int start = out.arrayOffset();
+ int end = encodeUtf8Array(in, out.array(), start + out.position(),
+ out.remaining());
+ out.position(end - start);
+ } else {
+ encodeUtf8Buffer(in, out);
+ }
+ }
+
+ // These UTF-8 handling methods are copied from Guava's Utf8Unsafe class with
+ // a modification to throw a local exception. This exception can be caught
+ // to fallback to more lenient behavior.
+ static class UnpairedSurrogateException extends IllegalArgumentException {
+ UnpairedSurrogateException(int index, int length) {
+ super("Unpaired surrogate at index " + index + " of " + length);
+ }
+ }
+}
diff --git a/js/flatbuffers.js b/js/flatbuffers.js
new file mode 100644
index 0000000..461cd7a
--- /dev/null
+++ b/js/flatbuffers.js
@@ -0,0 +1,1259 @@
+/// @file
+/// @addtogroup flatbuffers_javascript_api
+/// @{
+/// @cond FLATBUFFERS_INTERNAL
+
+/**
+ * @fileoverview
+ *
+ * Need to suppress 'global this' error so the Node.js export line doesn't cause
+ * closure compile to error out.
+ * @suppress {globalThis}
+ */
+
+/**
+ * @const
+ * @namespace
+ */
+var flatbuffers = {};
+
+/**
+ * @typedef {number}
+ */
+flatbuffers.Offset;
+
+/**
+ * @typedef {{
+ * bb: flatbuffers.ByteBuffer,
+ * bb_pos: number
+ * }}
+ */
+flatbuffers.Table;
+
+/**
+ * @type {number}
+ * @const
+ */
+flatbuffers.SIZEOF_SHORT = 2;
+
+/**
+ * @type {number}
+ * @const
+ */
+flatbuffers.SIZEOF_INT = 4;
+
+/**
+ * @type {number}
+ * @const
+ */
+flatbuffers.FILE_IDENTIFIER_LENGTH = 4;
+
+/**
+ * @type {number}
+ * @const
+ */
+flatbuffers.SIZE_PREFIX_LENGTH = 4;
+
+/**
+ * @enum {number}
+ */
+flatbuffers.Encoding = {
+ UTF8_BYTES: 1,
+ UTF16_STRING: 2
+};
+
+/**
+ * @type {Int32Array}
+ * @const
+ */
+flatbuffers.int32 = new Int32Array(2);
+
+/**
+ * @type {Float32Array}
+ * @const
+ */
+flatbuffers.float32 = new Float32Array(flatbuffers.int32.buffer);
+
+/**
+ * @type {Float64Array}
+ * @const
+ */
+flatbuffers.float64 = new Float64Array(flatbuffers.int32.buffer);
+
+/**
+ * @type {boolean}
+ * @const
+ */
+flatbuffers.isLittleEndian = new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1;
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @constructor
+ * @param {number} low
+ * @param {number} high
+ */
+flatbuffers.Long = function(low, high) {
+ /**
+ * @type {number}
+ * @const
+ */
+ this.low = low | 0;
+
+ /**
+ * @type {number}
+ * @const
+ */
+ this.high = high | 0;
+};
+
+/**
+ * @param {number} low
+ * @param {number} high
+ * @returns {flatbuffers.Long}
+ */
+flatbuffers.Long.create = function(low, high) {
+ // Special-case zero to avoid GC overhead for default values
+ return low == 0 && high == 0 ? flatbuffers.Long.ZERO : new flatbuffers.Long(low, high);
+};
+
+/**
+ * @returns {number}
+ */
+flatbuffers.Long.prototype.toFloat64 = function() {
+ return (this.low >>> 0) + this.high * 0x100000000;
+};
+
+/**
+ * @param {flatbuffers.Long} other
+ * @returns {boolean}
+ */
+flatbuffers.Long.prototype.equals = function(other) {
+ return this.low == other.low && this.high == other.high;
+};
+
+/**
+ * @type {flatbuffers.Long}
+ * @const
+ */
+flatbuffers.Long.ZERO = new flatbuffers.Long(0, 0);
+
+/// @endcond
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Create a FlatBufferBuilder.
+ *
+ * @constructor
+ * @param {number=} opt_initial_size
+ */
+flatbuffers.Builder = function(opt_initial_size) {
+ if (!opt_initial_size) {
+ var initial_size = 1024;
+ } else {
+ var initial_size = opt_initial_size;
+ }
+
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ * @private
+ */
+ this.bb = flatbuffers.ByteBuffer.allocate(initial_size);
+
+ /**
+ * Remaining space in the ByteBuffer.
+ *
+ * @type {number}
+ * @private
+ */
+ this.space = initial_size;
+
+ /**
+ * Minimum alignment encountered so far.
+ *
+ * @type {number}
+ * @private
+ */
+ this.minalign = 1;
+
+ /**
+ * The vtable for the current table.
+ *
+ * @type {Array.<number>}
+ * @private
+ */
+ this.vtable = null;
+
+ /**
+ * The amount of fields we're actually using.
+ *
+ * @type {number}
+ * @private
+ */
+ this.vtable_in_use = 0;
+
+ /**
+ * Whether we are currently serializing a table.
+ *
+ * @type {boolean}
+ * @private
+ */
+ this.isNested = false;
+
+ /**
+ * Starting offset of the current struct/table.
+ *
+ * @type {number}
+ * @private
+ */
+ this.object_start = 0;
+
+ /**
+ * List of offsets of all vtables.
+ *
+ * @type {Array.<number>}
+ * @private
+ */
+ this.vtables = [];
+
+ /**
+ * For the current vector being built.
+ *
+ * @type {number}
+ * @private
+ */
+ this.vector_num_elems = 0;
+
+ /**
+ * False omits default values from the serialized data
+ *
+ * @type {boolean}
+ * @private
+ */
+ this.force_defaults = false;
+};
+
+flatbuffers.Builder.prototype.clear = function() {
+ this.bb.clear();
+ this.space = this.bb.capacity();
+ this.minalign = 1;
+ this.vtable = null;
+ this.vtable_in_use = 0;
+ this.isNested = false;
+ this.object_start = 0;
+ this.vtables = [];
+ this.vector_num_elems = 0;
+ this.force_defaults = false;
+};
+
+/**
+ * In order to save space, fields that are set to their default value
+ * don't get serialized into the buffer. Forcing defaults provides a
+ * way to manually disable this optimization.
+ *
+ * @param {boolean} forceDefaults true always serializes default values
+ */
+flatbuffers.Builder.prototype.forceDefaults = function(forceDefaults) {
+ this.force_defaults = forceDefaults;
+};
+
+/**
+ * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
+ * called finish(). The actual data starts at the ByteBuffer's current position,
+ * not necessarily at 0.
+ *
+ * @returns {flatbuffers.ByteBuffer}
+ */
+flatbuffers.Builder.prototype.dataBuffer = function() {
+ return this.bb;
+};
+
+/**
+ * Get the bytes representing the FlatBuffer. Only call this after you've
+ * called finish().
+ *
+ * @returns {Uint8Array}
+ */
+flatbuffers.Builder.prototype.asUint8Array = function() {
+ return this.bb.bytes().subarray(this.bb.position(), this.bb.position() + this.offset());
+};
+
+/// @cond FLATBUFFERS_INTERNAL
+/**
+ * Prepare to write an element of `size` after `additional_bytes` have been
+ * written, e.g. if you write a string, you need to align such the int length
+ * field is aligned to 4 bytes, and the string data follows it directly. If all
+ * you need to do is alignment, `additional_bytes` will be 0.
+ *
+ * @param {number} size This is the of the new element to write
+ * @param {number} additional_bytes The padding size
+ */
+flatbuffers.Builder.prototype.prep = function(size, additional_bytes) {
+ // Track the biggest thing we've ever aligned to.
+ if (size > this.minalign) {
+ this.minalign = size;
+ }
+
+ // Find the amount of alignment needed such that `size` is properly
+ // aligned after `additional_bytes`
+ var align_size = ((~(this.bb.capacity() - this.space + additional_bytes)) + 1) & (size - 1);
+
+ // Reallocate the buffer if needed.
+ while (this.space < align_size + size + additional_bytes) {
+ var old_buf_size = this.bb.capacity();
+ this.bb = flatbuffers.Builder.growByteBuffer(this.bb);
+ this.space += this.bb.capacity() - old_buf_size;
+ }
+
+ this.pad(align_size);
+};
+
+/**
+ * @param {number} byte_size
+ */
+flatbuffers.Builder.prototype.pad = function(byte_size) {
+ for (var i = 0; i < byte_size; i++) {
+ this.bb.writeInt8(--this.space, 0);
+ }
+};
+
+/**
+ * @param {number} value
+ */
+flatbuffers.Builder.prototype.writeInt8 = function(value) {
+ this.bb.writeInt8(this.space -= 1, value);
+};
+
+/**
+ * @param {number} value
+ */
+flatbuffers.Builder.prototype.writeInt16 = function(value) {
+ this.bb.writeInt16(this.space -= 2, value);
+};
+
+/**
+ * @param {number} value
+ */
+flatbuffers.Builder.prototype.writeInt32 = function(value) {
+ this.bb.writeInt32(this.space -= 4, value);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ */
+flatbuffers.Builder.prototype.writeInt64 = function(value) {
+ this.bb.writeInt64(this.space -= 8, value);
+};
+
+/**
+ * @param {number} value
+ */
+flatbuffers.Builder.prototype.writeFloat32 = function(value) {
+ this.bb.writeFloat32(this.space -= 4, value);
+};
+
+/**
+ * @param {number} value
+ */
+flatbuffers.Builder.prototype.writeFloat64 = function(value) {
+ this.bb.writeFloat64(this.space -= 8, value);
+};
+/// @endcond
+
+/**
+ * Add an `int8` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `int8` to add the the buffer.
+ */
+flatbuffers.Builder.prototype.addInt8 = function(value) {
+ this.prep(1, 0);
+ this.writeInt8(value);
+};
+
+/**
+ * Add an `int16` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `int16` to add the the buffer.
+ */
+flatbuffers.Builder.prototype.addInt16 = function(value) {
+ this.prep(2, 0);
+ this.writeInt16(value);
+};
+
+/**
+ * Add an `int32` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `int32` to add the the buffer.
+ */
+flatbuffers.Builder.prototype.addInt32 = function(value) {
+ this.prep(4, 0);
+ this.writeInt32(value);
+};
+
+/**
+ * Add an `int64` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {flatbuffers.Long} value The `int64` to add the the buffer.
+ */
+flatbuffers.Builder.prototype.addInt64 = function(value) {
+ this.prep(8, 0);
+ this.writeInt64(value);
+};
+
+/**
+ * Add a `float32` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `float32` to add the the buffer.
+ */
+flatbuffers.Builder.prototype.addFloat32 = function(value) {
+ this.prep(4, 0);
+ this.writeFloat32(value);
+};
+
+/**
+ * Add a `float64` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param {number} value The `float64` to add the the buffer.
+ */
+flatbuffers.Builder.prototype.addFloat64 = function(value) {
+ this.prep(8, 0);
+ this.writeFloat64(value);
+};
+
+/// @cond FLATBUFFERS_INTERNAL
+/**
+ * @param {number} voffset
+ * @param {number} value
+ * @param {number} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldInt8 = function(voffset, value, defaultValue) {
+ if (this.force_defaults || value != defaultValue) {
+ this.addInt8(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * @param {number} voffset
+ * @param {number} value
+ * @param {number} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldInt16 = function(voffset, value, defaultValue) {
+ if (this.force_defaults || value != defaultValue) {
+ this.addInt16(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * @param {number} voffset
+ * @param {number} value
+ * @param {number} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldInt32 = function(voffset, value, defaultValue) {
+ if (this.force_defaults || value != defaultValue) {
+ this.addInt32(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * @param {number} voffset
+ * @param {flatbuffers.Long} value
+ * @param {flatbuffers.Long} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldInt64 = function(voffset, value, defaultValue) {
+ if (this.force_defaults || !value.equals(defaultValue)) {
+ this.addInt64(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * @param {number} voffset
+ * @param {number} value
+ * @param {number} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldFloat32 = function(voffset, value, defaultValue) {
+ if (this.force_defaults || value != defaultValue) {
+ this.addFloat32(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * @param {number} voffset
+ * @param {number} value
+ * @param {number} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldFloat64 = function(voffset, value, defaultValue) {
+ if (this.force_defaults || value != defaultValue) {
+ this.addFloat64(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * @param {number} voffset
+ * @param {flatbuffers.Offset} value
+ * @param {flatbuffers.Offset} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldOffset = function(voffset, value, defaultValue) {
+ if (this.force_defaults || value != defaultValue) {
+ this.addOffset(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * Structs are stored inline, so nothing additional is being added. `d` is always 0.
+ *
+ * @param {number} voffset
+ * @param {flatbuffers.Offset} value
+ * @param {flatbuffers.Offset} defaultValue
+ */
+flatbuffers.Builder.prototype.addFieldStruct = function(voffset, value, defaultValue) {
+ if (value != defaultValue) {
+ this.nested(value);
+ this.slot(voffset);
+ }
+};
+
+/**
+ * Structures are always stored inline, they need to be created right
+ * where they're used. You'll get this assertion failure if you
+ * created it elsewhere.
+ *
+ * @param {flatbuffers.Offset} obj The offset of the created object
+ */
+flatbuffers.Builder.prototype.nested = function(obj) {
+ if (obj != this.offset()) {
+ throw new Error('FlatBuffers: struct must be serialized inline.');
+ }
+};
+
+/**
+ * Should not be creating any other object, string or vector
+ * while an object is being constructed
+ */
+flatbuffers.Builder.prototype.notNested = function() {
+ if (this.isNested) {
+ throw new Error('FlatBuffers: object serialization must not be nested.');
+ }
+};
+
+/**
+ * Set the current vtable at `voffset` to the current location in the buffer.
+ *
+ * @param {number} voffset
+ */
+flatbuffers.Builder.prototype.slot = function(voffset) {
+ this.vtable[voffset] = this.offset();
+};
+
+/**
+ * @returns {flatbuffers.Offset} Offset relative to the end of the buffer.
+ */
+flatbuffers.Builder.prototype.offset = function() {
+ return this.bb.capacity() - this.space;
+};
+
+/**
+ * Doubles the size of the backing ByteBuffer and copies the old data towards
+ * the end of the new buffer (since we build the buffer backwards).
+ *
+ * @param {flatbuffers.ByteBuffer} bb The current buffer with the existing data
+ * @returns {flatbuffers.ByteBuffer} A new byte buffer with the old data copied
+ * to it. The data is located at the end of the buffer.
+ *
+ * uint8Array.set() formally takes {Array<number>|ArrayBufferView}, so to pass
+ * it a uint8Array we need to suppress the type check:
+ * @suppress {checkTypes}
+ */
+flatbuffers.Builder.growByteBuffer = function(bb) {
+ var old_buf_size = bb.capacity();
+
+ // Ensure we don't grow beyond what fits in an int.
+ if (old_buf_size & 0xC0000000) {
+ throw new Error('FlatBuffers: cannot grow buffer beyond 2 gigabytes.');
+ }
+
+ var new_buf_size = old_buf_size << 1;
+ var nbb = flatbuffers.ByteBuffer.allocate(new_buf_size);
+ nbb.setPosition(new_buf_size - old_buf_size);
+ nbb.bytes().set(bb.bytes(), new_buf_size - old_buf_size);
+ return nbb;
+};
+/// @endcond
+
+/**
+ * Adds on offset, relative to where it will be written.
+ *
+ * @param {flatbuffers.Offset} offset The offset to add.
+ */
+flatbuffers.Builder.prototype.addOffset = function(offset) {
+ this.prep(flatbuffers.SIZEOF_INT, 0); // Ensure alignment is already done.
+ this.writeInt32(this.offset() - offset + flatbuffers.SIZEOF_INT);
+};
+
+/// @cond FLATBUFFERS_INTERNAL
+/**
+ * Start encoding a new object in the buffer. Users will not usually need to
+ * call this directly. The FlatBuffers compiler will generate helper methods
+ * that call this method internally.
+ *
+ * @param {number} numfields
+ */
+flatbuffers.Builder.prototype.startObject = function(numfields) {
+ this.notNested();
+ if (this.vtable == null) {
+ this.vtable = [];
+ }
+ this.vtable_in_use = numfields;
+ for (var i = 0; i < numfields; i++) {
+ this.vtable[i] = 0; // This will push additional elements as needed
+ }
+ this.isNested = true;
+ this.object_start = this.offset();
+};
+
+/**
+ * Finish off writing the object that is under construction.
+ *
+ * @returns {flatbuffers.Offset} The offset to the object inside `dataBuffer`
+ */
+flatbuffers.Builder.prototype.endObject = function() {
+ if (this.vtable == null || !this.isNested) {
+ throw new Error('FlatBuffers: endObject called without startObject');
+ }
+
+ this.addInt32(0);
+ var vtableloc = this.offset();
+
+ // Trim trailing zeroes.
+ var i = this.vtable_in_use - 1;
+ for (; i >= 0 && this.vtable[i] == 0; i--) {}
+ var trimmed_size = i + 1;
+
+ // Write out the current vtable.
+ for (; i >= 0; i--) {
+ // Offset relative to the start of the table.
+ this.addInt16(this.vtable[i] != 0 ? vtableloc - this.vtable[i] : 0);
+ }
+
+ var standard_fields = 2; // The fields below:
+ this.addInt16(vtableloc - this.object_start);
+ var len = (trimmed_size + standard_fields) * flatbuffers.SIZEOF_SHORT;
+ this.addInt16(len);
+
+ // Search for an existing vtable that matches the current one.
+ var existing_vtable = 0;
+ var vt1 = this.space;
+outer_loop:
+ for (i = 0; i < this.vtables.length; i++) {
+ var vt2 = this.bb.capacity() - this.vtables[i];
+ if (len == this.bb.readInt16(vt2)) {
+ for (var j = flatbuffers.SIZEOF_SHORT; j < len; j += flatbuffers.SIZEOF_SHORT) {
+ if (this.bb.readInt16(vt1 + j) != this.bb.readInt16(vt2 + j)) {
+ continue outer_loop;
+ }
+ }
+ existing_vtable = this.vtables[i];
+ break;
+ }
+ }
+
+ if (existing_vtable) {
+ // Found a match:
+ // Remove the current vtable.
+ this.space = this.bb.capacity() - vtableloc;
+
+ // Point table to existing vtable.
+ this.bb.writeInt32(this.space, existing_vtable - vtableloc);
+ } else {
+ // No match:
+ // Add the location of the current vtable to the list of vtables.
+ this.vtables.push(this.offset());
+
+ // Point table to current vtable.
+ this.bb.writeInt32(this.bb.capacity() - vtableloc, this.offset() - vtableloc);
+ }
+
+ this.isNested = false;
+ return vtableloc;
+};
+/// @endcond
+
+/**
+ * Finalize a buffer, poiting to the given `root_table`.
+ *
+ * @param {flatbuffers.Offset} root_table
+ * @param {string=} opt_file_identifier
+ * @param {boolean=} opt_size_prefix
+ */
+flatbuffers.Builder.prototype.finish = function(root_table, opt_file_identifier, opt_size_prefix) {
+ var size_prefix = opt_size_prefix ? flatbuffers.SIZE_PREFIX_LENGTH : 0;
+ if (opt_file_identifier) {
+ var file_identifier = opt_file_identifier;
+ this.prep(this.minalign, flatbuffers.SIZEOF_INT +
+ flatbuffers.FILE_IDENTIFIER_LENGTH + size_prefix);
+ if (file_identifier.length != flatbuffers.FILE_IDENTIFIER_LENGTH) {
+ throw new Error('FlatBuffers: file identifier must be length ' +
+ flatbuffers.FILE_IDENTIFIER_LENGTH);
+ }
+ for (var i = flatbuffers.FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) {
+ this.writeInt8(file_identifier.charCodeAt(i));
+ }
+ }
+ this.prep(this.minalign, flatbuffers.SIZEOF_INT + size_prefix);
+ this.addOffset(root_table);
+ if (size_prefix) {
+ this.addInt32(this.bb.capacity() - this.space);
+ }
+ this.bb.setPosition(this.space);
+};
+
+/**
+ * Finalize a size prefixed buffer, pointing to the given `root_table`.
+ *
+ * @param {flatbuffers.Offset} root_table
+ * @param {string=} opt_file_identifier
+ */
+flatbuffers.Builder.prototype.finishSizePrefixed = function (root_table, opt_file_identifier) {
+ this.finish(root_table, opt_file_identifier, true);
+};
+
+/// @cond FLATBUFFERS_INTERNAL
+/**
+ * This checks a required field has been set in a given table that has
+ * just been constructed.
+ *
+ * @param {flatbuffers.Offset} table
+ * @param {number} field
+ */
+flatbuffers.Builder.prototype.requiredField = function(table, field) {
+ var table_start = this.bb.capacity() - table;
+ var vtable_start = table_start - this.bb.readInt32(table_start);
+ var ok = this.bb.readInt16(vtable_start + field) != 0;
+
+ // If this fails, the caller will show what field needs to be set.
+ if (!ok) {
+ throw new Error('FlatBuffers: field ' + field + ' must be set');
+ }
+};
+
+/**
+ * Start a new array/vector of objects. Users usually will not call
+ * this directly. The FlatBuffers compiler will create a start/end
+ * method for vector types in generated code.
+ *
+ * @param {number} elem_size The size of each element in the array
+ * @param {number} num_elems The number of elements in the array
+ * @param {number} alignment The alignment of the array
+ */
+flatbuffers.Builder.prototype.startVector = function(elem_size, num_elems, alignment) {
+ this.notNested();
+ this.vector_num_elems = num_elems;
+ this.prep(flatbuffers.SIZEOF_INT, elem_size * num_elems);
+ this.prep(alignment, elem_size * num_elems); // Just in case alignment > int.
+};
+
+/**
+ * Finish off the creation of an array and all its elements. The array must be
+ * created with `startVector`.
+ *
+ * @returns {flatbuffers.Offset} The offset at which the newly created array
+ * starts.
+ */
+flatbuffers.Builder.prototype.endVector = function() {
+ this.writeInt32(this.vector_num_elems);
+ return this.offset();
+};
+/// @endcond
+
+/**
+ * Encode the string `s` in the buffer using UTF-8. If a Uint8Array is passed
+ * instead of a string, it is assumed to contain valid UTF-8 encoded data.
+ *
+ * @param {string|Uint8Array} s The string to encode
+ * @return {flatbuffers.Offset} The offset in the buffer where the encoded string starts
+ */
+flatbuffers.Builder.prototype.createString = function(s) {
+ if (s instanceof Uint8Array) {
+ var utf8 = s;
+ } else {
+ var utf8 = [];
+ var i = 0;
+
+ while (i < s.length) {
+ var codePoint;
+
+ // Decode UTF-16
+ var a = s.charCodeAt(i++);
+ if (a < 0xD800 || a >= 0xDC00) {
+ codePoint = a;
+ } else {
+ var b = s.charCodeAt(i++);
+ codePoint = (a << 10) + b + (0x10000 - (0xD800 << 10) - 0xDC00);
+ }
+
+ // Encode UTF-8
+ if (codePoint < 0x80) {
+ utf8.push(codePoint);
+ } else {
+ if (codePoint < 0x800) {
+ utf8.push(((codePoint >> 6) & 0x1F) | 0xC0);
+ } else {
+ if (codePoint < 0x10000) {
+ utf8.push(((codePoint >> 12) & 0x0F) | 0xE0);
+ } else {
+ utf8.push(
+ ((codePoint >> 18) & 0x07) | 0xF0,
+ ((codePoint >> 12) & 0x3F) | 0x80);
+ }
+ utf8.push(((codePoint >> 6) & 0x3F) | 0x80);
+ }
+ utf8.push((codePoint & 0x3F) | 0x80);
+ }
+ }
+ }
+
+ this.addInt8(0);
+ this.startVector(1, utf8.length, 1);
+ this.bb.setPosition(this.space -= utf8.length);
+ for (var i = 0, offset = this.space, bytes = this.bb.bytes(); i < utf8.length; i++) {
+ bytes[offset++] = utf8[i];
+ }
+ return this.endVector();
+};
+
+/**
+ * A helper function to avoid generated code depending on this file directly.
+ *
+ * @param {number} low
+ * @param {number} high
+ * @returns {flatbuffers.Long}
+ */
+flatbuffers.Builder.prototype.createLong = function(low, high) {
+ return flatbuffers.Long.create(low, high);
+};
+////////////////////////////////////////////////////////////////////////////////
+/// @cond FLATBUFFERS_INTERNAL
+/**
+ * Create a new ByteBuffer with a given array of bytes (`Uint8Array`).
+ *
+ * @constructor
+ * @param {Uint8Array} bytes
+ */
+flatbuffers.ByteBuffer = function(bytes) {
+ /**
+ * @type {Uint8Array}
+ * @private
+ */
+ this.bytes_ = bytes;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.position_ = 0;
+};
+
+/**
+ * Create and allocate a new ByteBuffer with a given size.
+ *
+ * @param {number} byte_size
+ * @returns {flatbuffers.ByteBuffer}
+ */
+flatbuffers.ByteBuffer.allocate = function(byte_size) {
+ return new flatbuffers.ByteBuffer(new Uint8Array(byte_size));
+};
+
+flatbuffers.ByteBuffer.prototype.clear = function() {
+ this.position_ = 0;
+};
+
+/**
+ * Get the underlying `Uint8Array`.
+ *
+ * @returns {Uint8Array}
+ */
+flatbuffers.ByteBuffer.prototype.bytes = function() {
+ return this.bytes_;
+};
+
+/**
+ * Get the buffer's position.
+ *
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.position = function() {
+ return this.position_;
+};
+
+/**
+ * Set the buffer's position.
+ *
+ * @param {number} position
+ */
+flatbuffers.ByteBuffer.prototype.setPosition = function(position) {
+ this.position_ = position;
+};
+
+/**
+ * Get the buffer's capacity.
+ *
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.capacity = function() {
+ return this.bytes_.length;
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readInt8 = function(offset) {
+ return this.readUint8(offset) << 24 >> 24;
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readUint8 = function(offset) {
+ return this.bytes_[offset];
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readInt16 = function(offset) {
+ return this.readUint16(offset) << 16 >> 16;
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readUint16 = function(offset) {
+ return this.bytes_[offset] | this.bytes_[offset + 1] << 8;
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readInt32 = function(offset) {
+ return this.bytes_[offset] | this.bytes_[offset + 1] << 8 | this.bytes_[offset + 2] << 16 | this.bytes_[offset + 3] << 24;
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readUint32 = function(offset) {
+ return this.readInt32(offset) >>> 0;
+};
+
+/**
+ * @param {number} offset
+ * @returns {flatbuffers.Long}
+ */
+flatbuffers.ByteBuffer.prototype.readInt64 = function(offset) {
+ return new flatbuffers.Long(this.readInt32(offset), this.readInt32(offset + 4));
+};
+
+/**
+ * @param {number} offset
+ * @returns {flatbuffers.Long}
+ */
+flatbuffers.ByteBuffer.prototype.readUint64 = function(offset) {
+ return new flatbuffers.Long(this.readUint32(offset), this.readUint32(offset + 4));
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readFloat32 = function(offset) {
+ flatbuffers.int32[0] = this.readInt32(offset);
+ return flatbuffers.float32[0];
+};
+
+/**
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.readFloat64 = function(offset) {
+ flatbuffers.int32[flatbuffers.isLittleEndian ? 0 : 1] = this.readInt32(offset);
+ flatbuffers.int32[flatbuffers.isLittleEndian ? 1 : 0] = this.readInt32(offset + 4);
+ return flatbuffers.float64[0];
+};
+
+/**
+ * @param {number} offset
+ * @param {number|boolean} value
+ */
+flatbuffers.ByteBuffer.prototype.writeInt8 = function(offset, value) {
+ this.bytes_[offset] = /** @type {number} */(value);
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint8 = function(offset, value) {
+ this.bytes_[offset] = value;
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeInt16 = function(offset, value) {
+ this.bytes_[offset] = value;
+ this.bytes_[offset + 1] = value >> 8;
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint16 = function(offset, value) {
+ this.bytes_[offset] = value;
+ this.bytes_[offset + 1] = value >> 8;
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) {
+ this.bytes_[offset] = value;
+ this.bytes_[offset + 1] = value >> 8;
+ this.bytes_[offset + 2] = value >> 16;
+ this.bytes_[offset + 3] = value >> 24;
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint32 = function(offset, value) {
+ this.bytes_[offset] = value;
+ this.bytes_[offset + 1] = value >> 8;
+ this.bytes_[offset + 2] = value >> 16;
+ this.bytes_[offset + 3] = value >> 24;
+};
+
+/**
+ * @param {number} offset
+ * @param {flatbuffers.Long} value
+ */
+flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) {
+ this.writeInt32(offset, value.low);
+ this.writeInt32(offset + 4, value.high);
+};
+
+/**
+ * @param {number} offset
+ * @param {flatbuffers.Long} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint64 = function(offset, value) {
+ this.writeUint32(offset, value.low);
+ this.writeUint32(offset + 4, value.high);
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeFloat32 = function(offset, value) {
+ flatbuffers.float32[0] = value;
+ this.writeInt32(offset, flatbuffers.int32[0]);
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeFloat64 = function(offset, value) {
+ flatbuffers.float64[0] = value;
+ this.writeInt32(offset, flatbuffers.int32[flatbuffers.isLittleEndian ? 0 : 1]);
+ this.writeInt32(offset + 4, flatbuffers.int32[flatbuffers.isLittleEndian ? 1 : 0]);
+};
+
+/**
+ * Return the file identifier. Behavior is undefined for FlatBuffers whose
+ * schema does not include a file_identifier (likely points at padding or the
+ * start of a the root vtable).
+ * @returns {string}
+ */
+flatbuffers.ByteBuffer.prototype.getBufferIdentifier = function() {
+ if (this.bytes_.length < this.position_ + flatbuffers.SIZEOF_INT +
+ flatbuffers.FILE_IDENTIFIER_LENGTH) {
+ throw new Error(
+ 'FlatBuffers: ByteBuffer is too short to contain an identifier.');
+ }
+ var result = "";
+ for (var i = 0; i < flatbuffers.FILE_IDENTIFIER_LENGTH; i++) {
+ result += String.fromCharCode(
+ this.readInt8(this.position_ + flatbuffers.SIZEOF_INT + i));
+ }
+ return result;
+};
+
+/**
+ * Look up a field in the vtable, return an offset into the object, or 0 if the
+ * field is not present.
+ *
+ * @param {number} bb_pos
+ * @param {number} vtable_offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.__offset = function(bb_pos, vtable_offset) {
+ var vtable = bb_pos - this.readInt32(bb_pos);
+ return vtable_offset < this.readInt16(vtable) ? this.readInt16(vtable + vtable_offset) : 0;
+};
+
+/**
+ * Initialize any Table-derived type to point to the union at the given offset.
+ *
+ * @param {flatbuffers.Table} t
+ * @param {number} offset
+ * @returns {flatbuffers.Table}
+ */
+flatbuffers.ByteBuffer.prototype.__union = function(t, offset) {
+ t.bb_pos = offset + this.readInt32(offset);
+ t.bb = this;
+ return t;
+};
+
+/**
+ * Create a JavaScript string from UTF-8 data stored inside the FlatBuffer.
+ * This allocates a new string and converts to wide chars upon each access.
+ *
+ * To avoid the conversion to UTF-16, pass flatbuffers.Encoding.UTF8_BYTES as
+ * the "optionalEncoding" argument. This is useful for avoiding conversion to
+ * and from UTF-16 when the data will just be packaged back up in another
+ * FlatBuffer later on.
+ *
+ * @param {number} offset
+ * @param {flatbuffers.Encoding=} opt_encoding Defaults to UTF16_STRING
+ * @returns {string|Uint8Array}
+ */
+flatbuffers.ByteBuffer.prototype.__string = function(offset, opt_encoding) {
+ offset += this.readInt32(offset);
+
+ var length = this.readInt32(offset);
+ var result = '';
+ var i = 0;
+
+ offset += flatbuffers.SIZEOF_INT;
+
+ if (opt_encoding === flatbuffers.Encoding.UTF8_BYTES) {
+ return this.bytes_.subarray(offset, offset + length);
+ }
+
+ while (i < length) {
+ var codePoint;
+
+ // Decode UTF-8
+ var a = this.readUint8(offset + i++);
+ if (a < 0xC0) {
+ codePoint = a;
+ } else {
+ var b = this.readUint8(offset + i++);
+ if (a < 0xE0) {
+ codePoint =
+ ((a & 0x1F) << 6) |
+ (b & 0x3F);
+ } else {
+ var c = this.readUint8(offset + i++);
+ if (a < 0xF0) {
+ codePoint =
+ ((a & 0x0F) << 12) |
+ ((b & 0x3F) << 6) |
+ (c & 0x3F);
+ } else {
+ var d = this.readUint8(offset + i++);
+ codePoint =
+ ((a & 0x07) << 18) |
+ ((b & 0x3F) << 12) |
+ ((c & 0x3F) << 6) |
+ (d & 0x3F);
+ }
+ }
+ }
+
+ // Encode UTF-16
+ if (codePoint < 0x10000) {
+ result += String.fromCharCode(codePoint);
+ } else {
+ codePoint -= 0x10000;
+ result += String.fromCharCode(
+ (codePoint >> 10) + 0xD800,
+ (codePoint & ((1 << 10) - 1)) + 0xDC00);
+ }
+ }
+
+ return result;
+};
+
+/**
+ * Retrieve the relative offset stored at "offset"
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.__indirect = function(offset) {
+ return offset + this.readInt32(offset);
+};
+
+/**
+ * Get the start of data of a vector whose offset is stored at "offset" in this object.
+ *
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.__vector = function(offset) {
+ return offset + this.readInt32(offset) + flatbuffers.SIZEOF_INT; // data starts after the length
+};
+
+/**
+ * Get the length of a vector whose offset is stored at "offset" in this object.
+ *
+ * @param {number} offset
+ * @returns {number}
+ */
+flatbuffers.ByteBuffer.prototype.__vector_len = function(offset) {
+ return this.readInt32(offset + this.readInt32(offset));
+};
+
+/**
+ * @param {string} ident
+ * @returns {boolean}
+ */
+flatbuffers.ByteBuffer.prototype.__has_identifier = function(ident) {
+ if (ident.length != flatbuffers.FILE_IDENTIFIER_LENGTH) {
+ throw new Error('FlatBuffers: file identifier must be length ' +
+ flatbuffers.FILE_IDENTIFIER_LENGTH);
+ }
+ for (var i = 0; i < flatbuffers.FILE_IDENTIFIER_LENGTH; i++) {
+ if (ident.charCodeAt(i) != this.readInt8(this.position_ + flatbuffers.SIZEOF_INT + i)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+/**
+ * A helper function to avoid generated code depending on this file directly.
+ *
+ * @param {number} low
+ * @param {number} high
+ * @returns {flatbuffers.Long}
+ */
+flatbuffers.ByteBuffer.prototype.createLong = function(low, high) {
+ return flatbuffers.Long.create(low, high);
+};
+
+// Exports for Node.js and RequireJS
+this.flatbuffers = flatbuffers;
+
+/// @endcond
+/// @}
diff --git a/lobster/flatbuffers.lobster b/lobster/flatbuffers.lobster
new file mode 100644
index 0000000..0f1c15d
--- /dev/null
+++ b/lobster/flatbuffers.lobster
@@ -0,0 +1,284 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import std
+
+namespace flatbuffers
+
+class handle:
+ buf_:string
+ pos_:int
+
+// More strongly typed than a naked int, at no cost.
+struct offset:
+ o:int
+
+enum sizeof:
+ sz_8 = 1
+ sz_16 = 2
+ sz_32 = 4
+ sz_64 = 8
+ sz_voffset = 2
+ sz_uoffset = 4
+ sz_soffset = 4
+ sz_metadata_fields = 2
+
+class builder:
+ buf = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ current_vtable:[int] = []
+ head = 0
+ minalign = 1
+ object_end = 0
+ vtables:[int] = []
+ nested = false
+ finished = false
+
+ // Optionally call this right after creating the builder for a larger initial buffer.
+ def Initial(initial_size:int):
+ buf = "\x00".repeat_string(initial_size)
+
+ def Start():
+ // Get the start of useful data in the underlying byte buffer.
+ return buf.length - head
+
+ def Offset():
+ // Offset relative to the end of the buffer.
+ return offset { head }
+
+ // Returns a copy of the part of the buffer containing only the finished FlatBuffer
+ def SizedCopy():
+ assert finished
+ return buf.substring(Start(), -1)
+
+ def StartNesting():
+ assert not nested
+ nested = true
+
+ def EndNesting():
+ assert nested
+ nested = false
+
+ def StartObject(numfields):
+ StartNesting()
+ current_vtable = map(numfields): 0
+ object_end = head
+ minalign = 1
+
+ def EndObject():
+ EndNesting()
+ // Prepend a zero scalar to the object. Later in this function we'll
+ // write an offset here that points to the object's vtable:
+ PrependInt32(0)
+ let object_offset = head
+ // Write out new vtable speculatively.
+ let vtable_size = (current_vtable.length + sz_metadata_fields) * sz_voffset
+ while current_vtable.length:
+ let o = current_vtable.pop()
+ PrependVOffsetT(if o: object_offset - o else: 0)
+ // The two metadata fields are written last.
+ // First, store the object bytesize:
+ PrependVOffsetT(object_offset - object_end)
+ // Second, store the vtable bytesize:
+ PrependVOffsetT(vtable_size)
+ // Search backwards through existing vtables, because similar vtables
+ // are likely to have been recently appended. See
+ // BenchmarkVtableDeduplication for a case in which this heuristic
+ // saves about 30% of the time used in writing objects with duplicate
+ // tables.
+ def find_existing_table():
+ reverse(vtables) vt2_offset:
+ // Find the other vtable:
+ let vt2_start = buf.length - vt2_offset
+ let vt2_len = buf.read_int16_le(vt2_start)
+ // Compare the other vtable to the one under consideration.
+ // If they are equal, return the offset:
+ if vtable_size == vt2_len and
+ not compare_substring(buf, Start(), buf, vt2_start, vtable_size):
+ return vt2_offset
+ return 0
+ let existing_vtable = find_existing_table()
+ if existing_vtable:
+ // Found a duplicate vtable, remove the one we wrote.
+ head = object_offset
+ // Write the offset to the found vtable in the
+ // already-allocated offset at the beginning of this object:
+ buf.write_int32_le(Start(), existing_vtable - object_offset)
+ else:
+ // Did not find a vtable, so keep the one we wrote.
+ // Next, write the offset to the new vtable in the
+ // already-allocated offset at the beginning of this object:
+ buf.write_int32_le(buf.length - object_offset, head - object_offset)
+ // Finally, store this vtable in memory for future
+ // deduplication:
+ vtables.push(head)
+ return offset { object_offset }
+
+ def Pad(n):
+ for(n):
+ buf, head = buf.write_int8_le_back(head, 0)
+
+ def Prep(size, additional_bytes):
+ // Track the biggest thing we've ever aligned to.
+ if size > minalign:
+ minalign = size
+ // Find the amount of alignment needed such that `size` is properly
+ // aligned after `additionalBytes`:
+ let align_size = ((~(head + additional_bytes)) + 1) & (size - 1)
+ Pad(align_size)
+
+ def PrependUOffsetTRelative(off:offset):
+ // Prepends an unsigned offset into vector data, relative to where it will be written.
+ Prep(sz_uoffset, 0)
+ assert off.o <= head
+ PlaceUOffsetT(head - off.o + sz_uoffset)
+
+ def StartVector(elem_size, num_elems, alignment):
+ // Initializes bookkeeping for writing a new vector.
+ StartNesting()
+ Prep(sz_32, elem_size * num_elems)
+ Prep(alignment, elem_size * num_elems) // In case alignment > int.
+ return Offset()
+
+ def EndVector(vector_num_elems):
+ EndNesting()
+ // we already made space for this, so write without PrependUint32
+ PlaceUOffsetT(vector_num_elems)
+ return Offset()
+
+ def CreateString(s:string):
+ // writes a null-terminated byte string.
+ StartNesting()
+ Prep(sz_32, s.length + 1)
+ buf, head = buf.write_substring_back(head, s, true)
+ return EndVector(s.length)
+
+ def CreateByteVector(s:string):
+ // writes a non-null-terminated byte string.
+ StartNesting()
+ Prep(sz_32, s.length)
+ buf, head = buf.write_substring_back(head, s, false)
+ return EndVector(s.length)
+
+ def Slot(slotnum):
+ assert nested
+ while current_vtable.length <= slotnum: current_vtable.push(0)
+ current_vtable[slotnum] = head
+
+ def __Finish(root_table:offset, size_prefix:int):
+ // Finish finalizes a buffer, pointing to the given root_table
+ assert not finished
+ assert not nested
+ var prep_size = sz_32
+ if size_prefix:
+ prep_size += sz_32
+ Prep(minalign, prep_size)
+ PrependUOffsetTRelative(root_table)
+ if size_prefix:
+ PrependInt32(head)
+ finished = true
+ return Start()
+
+ def Finish(root_table:offset):
+ return __Finish(root_table, false)
+
+ def FinishSizePrefixed(root_table:offset):
+ return __Finish(root_table, true)
+
+ def PrependBool(x):
+ buf, head = buf.write_int8_le_back(head, x)
+
+ def PrependByte(x):
+ buf, head = buf.write_int8_le_back(head, x)
+
+ def PrependUint8(x):
+ buf, head = buf.write_int8_le_back(head, x)
+
+ def PrependUint16(x):
+ Prep(sz_16, 0)
+ buf, head = buf.write_int16_le_back(head, x)
+
+ def PrependUint32(x):
+ Prep(sz_32, 0)
+ buf, head = buf.write_int32_le_back(head, x)
+
+ def PrependUint64(x):
+ Prep(sz_64, 0)
+ buf, head = buf.write_int64_le_back(head, x)
+
+ def PrependInt8(x):
+ buf, head = buf.write_int8_le_back(head, x)
+
+ def PrependInt16(x):
+ Prep(sz_16, 0)
+ buf, head = buf.write_int16_le_back(head, x)
+
+ def PrependInt32(x):
+ Prep(sz_32, 0)
+ buf, head = buf.write_int32_le_back(head, x)
+
+ def PrependInt64(x):
+ Prep(sz_64, 0)
+ buf, head = buf.write_int64_le_back(head, x)
+
+ def PrependFloat32(x):
+ Prep(sz_32, 0)
+ buf, head = buf.write_float32_le_back(head, x)
+
+ def PrependFloat64(x):
+ Prep(sz_64, 0)
+ buf, head = buf.write_float64_le_back(head, x)
+
+ def PrependVOffsetT(x):
+ Prep(sz_voffset, 0)
+ buf, head = buf.write_int16_le_back(head, x)
+
+ def PlaceVOffsetT(x):
+ buf, head = buf.write_int16_le_back(head, x)
+
+ def PlaceSOffsetT(x):
+ buf, head = buf.write_int32_le_back(head, x)
+
+ def PlaceUOffsetT(x):
+ buf, head = buf.write_int32_le_back(head, x)
+
+ def PrependSlot(o:int, x, d, f):
+ if x != d:
+ f(x)
+ Slot(o)
+
+ def PrependBoolSlot(o, x, d): PrependSlot(o, x, d): PrependBool(_)
+ def PrependByteSlot(o, x, d): PrependSlot(o, x, d): PrependByte(_)
+ def PrependUint8Slot(o, x, d): PrependSlot(o, x, d): PrependUint8(_)
+ def PrependUint16Slot(o, x, d): PrependSlot(o, x, d): PrependUint16(_)
+ def PrependUint32Slot(o, x, d): PrependSlot(o, x, d): PrependUint32(_)
+ def PrependUint64Slot(o, x, d): PrependSlot(o, x, d): PrependUint64(_)
+ def PrependInt8Slot(o, x, d): PrependSlot(o, x, d): PrependInt8(_)
+ def PrependInt16Slot(o, x, d): PrependSlot(o, x, d): PrependInt16(_)
+ def PrependInt32Slot(o, x, d): PrependSlot(o, x, d): PrependInt32(_)
+ def PrependInt64Slot(o, x, d): PrependSlot(o, x, d): PrependInt64(_)
+ def PrependFloat32Slot(o, x, d): PrependSlot(o, x, d): PrependFloat32(_)
+ def PrependFloat64Slot(o, x, d): PrependSlot(o, x, d): PrependFloat64(_)
+
+ def PrependUOffsetTRelativeSlot(o:int, x:offset):
+ if x.o:
+ PrependUOffsetTRelative(x)
+ Slot(o)
+
+ def PrependStructSlot(v:int, x:offset):
+ if x.o:
+ // Structs are always stored inline, so need to be created right
+ // where they are used. You'll get this error if you created it
+ // elsewhere.
+ assert x.o == head
+ Slot(v)
diff --git a/lua/flatbuffers.lua b/lua/flatbuffers.lua
new file mode 100644
index 0000000..1c85c4e
--- /dev/null
+++ b/lua/flatbuffers.lua
@@ -0,0 +1,8 @@
+local m = {}
+
+m.Builder = require("flatbuffers.builder").New
+m.N = require("flatbuffers.numTypes")
+m.view = require("flatbuffers.view")
+m.binaryArray = require("flatbuffers.binaryarray")
+
+return m
\ No newline at end of file
diff --git a/lua/flatbuffers/binaryarray.lua b/lua/flatbuffers/binaryarray.lua
new file mode 100644
index 0000000..bf728cd
--- /dev/null
+++ b/lua/flatbuffers/binaryarray.lua
@@ -0,0 +1,123 @@
+local m = {} -- the module table
+
+local mt = {} -- the module metatable
+
+-- given a binary array, set a metamethod to return its length
+-- (e.g., #binaryArray, calls this)
+function mt:__len()
+ return self.size
+end
+
+-- Create a new binary array of an initial size
+function m.New(sizeOrString)
+ -- the array storage itself
+ local o = {}
+
+ if type(sizeOrString) == "string" then
+ o.str = sizeOrString
+ o.size = #sizeOrString
+ elseif type(sizeOrString) == "number" then
+ o.data = {}
+ o.size = sizeOrString
+ else
+ error("Expect a integer size value or string to construct a binary array")
+ end
+ -- set the inheritance
+ setmetatable(o, {__index = mt, __len = mt.__len})
+ return o
+end
+
+-- Get a slice of the binary array from start to end position
+function mt:Slice(startPos, endPos)
+ startPos = startPos or 0
+ endPos = endPos or self.size
+ local d = self.data
+ if d then
+ -- if the self.data is defined, we are building the buffer
+ -- in a Lua table
+
+ -- new table to store the slice components
+ local b = {}
+
+ -- starting with the startPos, put all
+ -- values into the new table to be concat later
+ -- updated the startPos based on the size of the
+ -- value
+ while startPos < endPos do
+ local v = d[startPos] or '/0'
+ table.insert(b, v)
+ startPos = startPos + #v
+ end
+
+ -- combine the table of strings into one string
+ -- this is faster than doing a bunch of concats by themselves
+ return table.concat(b)
+ else
+ -- n.b start/endPos are 0-based incoming, so need to convert
+ -- correctly. in python a slice includes start -> end - 1
+ return self.str:sub(startPos+1, endPos)
+ end
+end
+
+-- Grow the binary array to a new size, placing the exisiting data
+-- at then end of the new array
+function mt:Grow(newsize)
+ -- the new table to store the data
+ local newT = {}
+
+ -- the offset to be applied to existing entries
+ local offset = newsize - self.size
+
+ -- loop over all the current entries and
+ -- add them to the new table at the correct
+ -- offset location
+ local d = self.data
+ for i,data in pairs(d) do
+ newT[i + offset] = data
+ end
+
+ -- update this storage with the new table and size
+ self.data = newT
+ self.size = newsize
+end
+
+-- memorization for padding strings
+local pads = {}
+
+-- pad the binary with n \0 bytes at the starting position
+function mt:Pad(n, startPos)
+ -- use memorization to avoid creating a bunch of strings
+ -- all the time
+ local s = pads[n]
+ if not s then
+ s = string.rep('\0', n)
+ pads[n] = s
+ end
+
+ -- store the padding string at the start position in the
+ -- Lua table
+ self.data[startPos] = s
+end
+
+-- Sets the binary array value at the specified position
+function mt:Set(value, position)
+ self.data[position] = value
+end
+
+-- locals for slightly faster access
+local sunpack = string.unpack
+local spack = string.pack
+
+-- Pack the data into a binary representation
+function m.Pack(fmt, ...)
+ return spack(fmt, ...)
+end
+
+-- Unpack the data from a binary representation in
+-- a Lua value
+function m.Unpack(fmt, s, pos)
+ return sunpack(fmt, s.str, pos + 1)
+end
+
+-- Return the binary array module
+return m
\ No newline at end of file
diff --git a/lua/flatbuffers/builder.lua b/lua/flatbuffers/builder.lua
new file mode 100644
index 0000000..2fb2220
--- /dev/null
+++ b/lua/flatbuffers/builder.lua
@@ -0,0 +1,369 @@
+local N = require("flatbuffers.numTypes")
+local ba = require("flatbuffers.binaryarray")
+local compat = require("flatbuffers.compat")
+
+local m = {}
+
+local mt = {}
+
+-- get locals for faster access
+local VOffsetT = N.VOffsetT
+local UOffsetT = N.UOffsetT
+local SOffsetT = N.SOffsetT
+local Bool = N.Bool
+local Uint8 = N.Uint8
+local Uint16 = N.Uint16
+local Uint32 = N.Uint32
+local Uint64 = N.Uint64
+local Int8 = N.Int8
+local Int16 = N.Int16
+local Int32 = N.Int32
+local Int64 = N.Int64
+local Float32 = N.Float32
+local Float64 = N.Float64
+
+local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB
+local VtableMetadataFields = 2
+
+local getAlignSize = compat.GetAlignSize
+
+local function vtableEqual(a, objectStart, b)
+ UOffsetT:EnforceNumber(objectStart)
+ if (#a * VOffsetT.bytewidth) ~= #b then
+ return false
+ end
+
+ for i, elem in ipairs(a) do
+ local x = string.unpack(VOffsetT.packFmt, b, 1 + (i - 1) * VOffsetT.bytewidth)
+ if x ~= 0 or elem ~= 0 then
+ local y = objectStart - elem
+ if x ~= y then
+ return false
+ end
+ end
+ end
+ return true
+end
+
+function m.New(initialSize)
+ assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE)
+ local o =
+ {
+ finished = false,
+ bytes = ba.New(initialSize),
+ nested = false,
+ head = initialSize,
+ minalign = 1,
+ vtables = {}
+ }
+ setmetatable(o, {__index = mt})
+ return o
+end
+
+function mt:Output(full)
+ assert(self.finished, "Builder Not Finished")
+ if full then
+ return self.bytes:Slice()
+ else
+ return self.bytes:Slice(self.head)
+ end
+end
+
+function mt:StartObject(numFields)
+ assert(not self.nested)
+
+ local vtable = {}
+
+ for _=1,numFields do
+ table.insert(vtable, 0)
+ end
+
+ self.currentVTable = vtable
+ self.objectEnd = self:Offset()
+ self.nested = true
+end
+
+function mt:WriteVtable()
+ self:PrependSOffsetTRelative(0)
+ local objectOffset = self:Offset()
+
+ local exisitingVTable
+ local i = #self.vtables
+ while i >= 1 do
+ if self.vtables[i] == 0 then
+ table.remove(self.vtables,i)
+ end
+ i = i - 1
+ end
+
+ i = #self.vtables
+ while i >= 1 do
+
+ local vt2Offset = self.vtables[i]
+ local vt2Start = #self.bytes - vt2Offset
+ local vt2lenstr = self.bytes:Slice(vt2Start, vt2Start+1)
+ local vt2Len = string.unpack(VOffsetT.packFmt, vt2lenstr, 1)
+
+ local metadata = VtableMetadataFields * VOffsetT.bytewidth
+ local vt2End = vt2Start + vt2Len
+ local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End)
+
+ if vtableEqual(self.currentVTable, objectOffset, vt2) then
+ exisitingVTable = vt2Offset
+ break
+ end
+
+ i = i - 1
+ end
+
+ if not exisitingVTable then
+ i = #self.currentVTable
+ while i >= 1 do
+ local off = 0
+ local a = self.currentVTable[i]
+ if a and a ~= 0 then
+ off = objectOffset - a
+ end
+ self:PrependVOffsetT(off)
+
+ i = i - 1
+ end
+
+ local objectSize = objectOffset - self.objectEnd
+ self:PrependVOffsetT(objectSize)
+
+ local vBytes = #self.currentVTable + VtableMetadataFields
+ vBytes = vBytes * VOffsetT.bytewidth
+ self:PrependVOffsetT(vBytes)
+
+ local objectStart = #self.bytes - objectOffset
+ self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart)
+
+ table.insert(self.vtables, self:Offset())
+ else
+ local objectStart = #self.bytes - objectOffset
+ self.head = objectStart
+ self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head)
+ end
+
+ self.currentVTable = nil
+ return objectOffset
+end
+
+function mt:EndObject()
+ assert(self.nested)
+ self.nested = false
+ return self:WriteVtable()
+end
+
+local function growByteBuffer(self, desiredSize)
+ local s = #self.bytes
+ assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes")
+ local newsize = s
+ repeat
+ newsize = math.min(newsize * 2, MAX_BUFFER_SIZE)
+ if newsize == 0 then newsize = 1 end
+ until newsize > desiredSize
+
+ self.bytes:Grow(newsize)
+end
+
+function mt:Head()
+ return self.head
+end
+
+function mt:Offset()
+ return #self.bytes - self.head
+end
+
+function mt:Pad(n)
+ if n > 0 then
+ -- pads are 8-bit, so skip the bytewidth lookup
+ local h = self.head - n -- UInt8
+ self.head = h
+ self.bytes:Pad(n, h)
+ end
+end
+
+function mt:Prep(size, additionalBytes)
+ if size > self.minalign then
+ self.minalign = size
+ end
+
+ local h = self.head
+
+ local k = #self.bytes - h + additionalBytes
+ local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size)
+
+ local desiredSize = alignsize + size + additionalBytes
+
+ while self.head < desiredSize do
+ local oldBufSize = #self.bytes
+ growByteBuffer(self, desiredSize)
+ local updatedHead = self.head + #self.bytes - oldBufSize
+ self.head = updatedHead
+ end
+
+ self:Pad(alignsize)
+end
+
+function mt:PrependSOffsetTRelative(off)
+ self:Prep(SOffsetT.bytewidth, 0)
+ assert(off <= self:Offset(), "Offset arithmetic error")
+ local off2 = self:Offset() - off + SOffsetT.bytewidth
+ self:Place(off2, SOffsetT)
+end
+
+function mt:PrependUOffsetTRelative(off)
+ self:Prep(UOffsetT.bytewidth, 0)
+ local soffset = self:Offset()
+ if off <= soffset then
+ local off2 = soffset - off + UOffsetT.bytewidth
+ self:Place(off2, UOffsetT)
+ else
+ error("Offset arithmetic error")
+ end
+end
+
+function mt:StartVector(elemSize, numElements, alignment)
+ assert(not self.nested)
+ self.nested = true
+ self:Prep(Uint32.bytewidth, elemSize * numElements)
+ self:Prep(alignment, elemSize * numElements)
+ return self:Offset()
+end
+
+function mt:EndVector(vectorNumElements)
+ assert(self.nested)
+ self.nested = false
+ self:Place(vectorNumElements, UOffsetT)
+ return self:Offset()
+end
+
+function mt:CreateString(s)
+ assert(not self.nested)
+ self.nested = true
+
+ assert(type(s) == "string")
+
+ self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth)
+ self:Place(0, Uint8)
+
+ local l = #s
+ self.head = self.head - l
+
+ self.bytes:Set(s, self.head, self.head + l)
+
+ return self:EndVector(#s)
+end
+
+function mt:CreateByteVector(x)
+ assert(not self.nested)
+ self.nested = true
+ self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth)
+
+ local l = #x
+ self.head = self.head - l
+
+ self.bytes:Set(x, self.head, self.head + l)
+
+ return self:EndVector(#x)
+end
+
+function mt:Slot(slotnum)
+ assert(self.nested)
+ -- n.b. slot number is 0-based
+ self.currentVTable[slotnum + 1] = self:Offset()
+end
+
+local function finish(self, rootTable, sizePrefix)
+ UOffsetT:EnforceNumber(rootTable)
+ local prepSize = UOffsetT.bytewidth
+ if sizePrefix then
+ prepSize = prepSize + Int32.bytewidth
+ end
+
+ self:Prep(self.minalign, prepSize)
+ self:PrependUOffsetTRelative(rootTable)
+ if sizePrefix then
+ local size = #self.bytes - self.head
+ Int32:EnforceNumber(size)
+ self:PrependInt32(size)
+ end
+ self.finished = true
+ return self.head
+end
+
+function mt:Finish(rootTable)
+ return finish(self, rootTable, false)
+end
+
+function mt:FinishSizePrefixed(rootTable)
+ return finish(self, rootTable, true)
+end
+
+function mt:Prepend(flags, off)
+ self:Prep(flags.bytewidth, 0)
+ self:Place(off, flags)
+end
+
+function mt:PrependSlot(flags, o, x, d)
+ flags:EnforceNumber(x)
+ flags:EnforceNumber(d)
+ if x ~= d then
+ self:Prepend(flags, x)
+ self:Slot(o)
+ end
+end
+
+function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end
+function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end
+function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end
+function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end
+function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end
+function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end
+function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end
+function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end
+function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end
+function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end
+function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end
+function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end
+
+function mt:PrependUOffsetTRelativeSlot(o,x,d)
+ if x~=d then
+ self:PrependUOffsetTRelative(x)
+ self:Slot(o)
+ end
+end
+
+function mt:PrependStructSlot(v,x,d)
+ UOffsetT:EnforceNumber(d)
+ if x~=d then
+ UOffsetT:EnforceNumber(x)
+ assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.")
+ self:Slot(v)
+ end
+end
+
+function mt:PrependBool(x) self:Prepend(Bool, x) end
+function mt:PrependByte(x) self:Prepend(Uint8, x) end
+function mt:PrependUint8(x) self:Prepend(Uint8, x) end
+function mt:PrependUint16(x) self:Prepend(Uint16, x) end
+function mt:PrependUint32(x) self:Prepend(Uint32, x) end
+function mt:PrependUint64(x) self:Prepend(Uint64, x) end
+function mt:PrependInt8(x) self:Prepend(Int8, x) end
+function mt:PrependInt16(x) self:Prepend(Int16, x) end
+function mt:PrependInt32(x) self:Prepend(Int32, x) end
+function mt:PrependInt64(x) self:Prepend(Int64, x) end
+function mt:PrependFloat32(x) self:Prepend(Float32, x) end
+function mt:PrependFloat64(x) self:Prepend(Float64, x) end
+function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end
+
+function mt:Place(x, flags)
+ local d = flags:EnforceNumberAndPack(x)
+ local h = self.head - flags.bytewidth
+ self.head = h
+ self.bytes:Set(d, h)
+end
+
+return m
diff --git a/lua/flatbuffers/compat.lua b/lua/flatbuffers/compat.lua
new file mode 100644
index 0000000..89c992b
--- /dev/null
+++ b/lua/flatbuffers/compat.lua
@@ -0,0 +1,17 @@
+local m = {}
+
+local getAlignSize
+if _VERSION == "Lua 5.3" then
+ getAlignSize = function(k, size)
+ return ((~k) + 1) & (size - 1)
+ end
+else
+ getAlignSize = function(self, size, additionalBytes)
+ local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1
+ return bit32.band(alignsize,(size - 1))
+ end
+end
+
+m.GetAlignSize = getAlignSize
+
+return m
\ No newline at end of file
diff --git a/lua/flatbuffers/numTypes.lua b/lua/flatbuffers/numTypes.lua
new file mode 100644
index 0000000..8fec21c
--- /dev/null
+++ b/lua/flatbuffers/numTypes.lua
@@ -0,0 +1,204 @@
+local m = {}
+
+local ba = require("flatbuffers.binaryarray")
+
+local bpack = ba.Pack
+local bunpack = ba.Unpack
+
+local type_mt = {}
+
+function type_mt:Pack(value)
+ return bpack(self.packFmt, value)
+end
+
+function type_mt:Unpack(buf, pos)
+ return bunpack(self.packFmt, buf, pos)
+end
+
+function type_mt:ValidNumber(n)
+ if not self.min_value and not self.max_value then return true end
+ return self.min_value <= n and n <= self.max_value
+end
+
+function type_mt:EnforceNumber(n)
+ -- duplicate code since the overhead of function calls
+ -- for such a popular method is time consuming
+ if not self.min_value and not self.max_value then
+ return
+ end
+
+ if self.min_value <= n and n <= self.max_value then
+ return
+ end
+
+ error("Number is not in the valid range")
+end
+
+function type_mt:EnforceNumberAndPack(n)
+ return bpack(self.packFmt, n)
+end
+
+function type_mt:ConvertType(n, otherType)
+ assert(self.bytewidth == otherType.bytewidth, "Cannot convert between types of different widths")
+ if self == otherType then
+ return n
+ end
+ return otherType:Unpack(self:Pack(n))
+end
+
+local bool_mt =
+{
+ bytewidth = 1,
+ min_value = false,
+ max_value = true,
+ lua_type = type(true),
+ name = "bool",
+ packFmt = "<I1",
+ Pack = function(self, value) return value and "1" or "0" end,
+ Unpack = function(self, buf, pos) return buf[pos] == "1" end,
+ ValidNumber = function(self, n) return true end, -- anything is a valid boolean in Lua
+ EnforceNumber = function(self, n) end, -- anything is a valid boolean in Lua
+ EnforceNumberAndPack = function(self, n) return self:Pack(value) end,
+}
+
+local uint8_mt =
+{
+ bytewidth = 1,
+ min_value = 0,
+ max_value = 2^8-1,
+ lua_type = type(1),
+ name = "uint8",
+ packFmt = "<I1"
+}
+
+local uint16_mt =
+{
+ bytewidth = 2,
+ min_value = 0,
+ max_value = 2^16-1,
+ lua_type = type(1),
+ name = "uint16",
+ packFmt = "<I2"
+}
+
+local uint32_mt =
+{
+ bytewidth = 4,
+ min_value = 0,
+ max_value = 2^32-1,
+ lua_type = type(1),
+ name = "uint32",
+ packFmt = "<I4"
+}
+
+local uint64_mt =
+{
+ bytewidth = 8,
+ min_value = 0,
+ max_value = 2^64-1,
+ lua_type = type(1),
+ name = "uint64",
+ packFmt = "<I8"
+}
+
+local int8_mt =
+{
+ bytewidth = 1,
+ min_value = -2^7,
+ max_value = 2^7-1,
+ lua_type = type(1),
+ name = "int8",
+ packFmt = "<i1"
+}
+
+local int16_mt =
+{
+ bytewidth = 2,
+ min_value = -2^15,
+ max_value = 2^15-1,
+ lua_type = type(1),
+ name = "int16",
+ packFmt = "<i2"
+}
+
+local int32_mt =
+{
+ bytewidth = 4,
+ min_value = -2^31,
+ max_value = 2^31-1,
+ lua_type = type(1),
+ name = "int32",
+ packFmt = "<i4"
+}
+
+local int64_mt =
+{
+ bytewidth = 8,
+ min_value = -2^63,
+ max_value = 2^63-1,
+ lua_type = type(1),
+ name = "int64",
+ packFmt = "<i8"
+}
+
+local float32_mt =
+{
+ bytewidth = 4,
+ min_value = nil,
+ max_value = nil,
+ lua_type = type(1.0),
+ name = "float32",
+ packFmt = "<f"
+}
+
+local float64_mt =
+{
+ bytewidth = 8,
+ min_value = nil,
+ max_value = nil,
+ lua_type = type(1.0),
+ name = "float64",
+ packFmt = "<d"
+}
+
+-- register the base class
+setmetatable(bool_mt, {__index = type_mt})
+setmetatable(uint8_mt, {__index = type_mt})
+setmetatable(uint16_mt, {__index = type_mt})
+setmetatable(uint32_mt, {__index = type_mt})
+setmetatable(uint64_mt, {__index = type_mt})
+setmetatable(int8_mt, {__index = type_mt})
+setmetatable(int16_mt, {__index = type_mt})
+setmetatable(int32_mt, {__index = type_mt})
+setmetatable(int64_mt, {__index = type_mt})
+setmetatable(float32_mt, {__index = type_mt})
+setmetatable(float64_mt, {__index = type_mt})
+
+
+m.Uint8 = uint8_mt
+m.Uint16 = uint16_mt
+m.Uint32 = uint32_mt
+m.Uint64 = uint64_mt
+m.Int8 = int8_mt
+m.Int16 = int16_mt
+m.Int32 = int32_mt
+m.Int64 = int64_mt
+m.Float32 = float32_mt
+m.Float64 = float64_mt
+
+m.UOffsetT = uint32_mt
+m.VOffsetT = uint16_mt
+m.SOffsetT = int32_mt
+
+local GenerateTypes = function(listOfTypes)
+ for _,t in pairs(listOfTypes) do
+ t.Pack = function(self, value) return bpack(self.packFmt, value) end
+ t.Unpack = function(self, buf, pos) return bunpack(self.packFmt, buf, pos) end
+ end
+end
+
+GenerateTypes(m)
+
+-- explicitly execute after GenerateTypes call, as we don't want to define a Pack/Unpack function for it.
+m.Bool = bool_mt
+return m
diff --git a/lua/flatbuffers/view.lua b/lua/flatbuffers/view.lua
new file mode 100644
index 0000000..da0f8bf
--- /dev/null
+++ b/lua/flatbuffers/view.lua
@@ -0,0 +1,97 @@
+local m = {}
+local mt = {}
+
+local mt_name = "flatbuffers.view.mt"
+
+local N = require("flatbuffers.numTypes")
+local binaryarray = require("flatbuffers.binaryarray")
+
+function m.New(buf, pos)
+ N.UOffsetT:EnforceNumber(pos)
+
+ -- need to convert from a string buffer into
+ -- a binary array
+
+ local o = {
+ bytes = type(buf) == "string" and binaryarray.New(buf) or buf,
+ pos = pos
+ }
+ setmetatable(o, {__index = mt, __metatable = mt_name})
+ return o
+end
+
+function mt:Offset(vtableOffset)
+ local vtable = self.pos - self:Get(N.SOffsetT, self.pos)
+ local vtableEnd = self:Get(N.VOffsetT, vtable)
+ if vtableOffset < vtableEnd then
+ return self:Get(N.VOffsetT, vtable + vtableOffset)
+ end
+ return 0
+end
+
+function mt:Indirect(off)
+ N.UOffsetT:EnforceNumber(off)
+ return off + N.UOffsetT:Unpack(self.bytes, off)
+end
+
+function mt:String(off)
+ N.UOffsetT:EnforceNumber(off)
+ off = off + N.UOffsetT:Unpack(self.bytes, off)
+ local start = off + N.UOffsetT.bytewidth
+ local length = N.UOffsetT:Unpack(self.bytes, off)
+ return self.bytes:Slice(start, start+length)
+end
+
+function mt:VectorLen(off)
+ N.UOffsetT:EnforceNumber(off)
+ off = off + self.pos
+ off = off + N.UOffsetT:Unpack(self.bytes, off)
+ return N.UOffsetT:Unpack(self.bytes, off)
+end
+
+function mt:Vector(off)
+ N.UOffsetT:EnforceNumber(off)
+
+ off = off + self.pos
+ local x = off + self:Get(N.UOffsetT, off)
+ x = x + N.UOffsetT.bytewidth
+ return x
+end
+
+function mt:Union(t2, off)
+ assert(getmetatable(t2) == mt_name)
+ N.UOffsetT:EnforceNumber(off)
+
+ off = off + self.pos
+ t2.pos = off + self:Get(N.UOffsetT, off)
+ t2.bytes = self.bytes
+end
+
+function mt:Get(flags, off)
+ N.UOffsetT:EnforceNumber(off)
+ return flags:Unpack(self.bytes, off)
+end
+
+function mt:GetSlot(slot, d, validatorFlags)
+ N.VOffsetT:EnforceNumber(slot)
+ if validatorFlags then
+ validatorFlags:EnforceNumber(d)
+ end
+ local off = self:Offset(slot)
+ if off == 0 then
+ return d
+ end
+ return self:Get(validatorFlags, self.pos + off)
+end
+
+function mt:GetVOffsetTSlot(slot, d)
+ N.VOffsetT:EnforceNumber(slot)
+ N.VOffsetT:EnforceNumber(d)
+ local off = self:Offset(slot)
+ if off == 0 then
+ return d
+ end
+ return off
+end
+
+return m
\ No newline at end of file
diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs
new file mode 100644
index 0000000..5e212dd
--- /dev/null
+++ b/net/FlatBuffers/ByteBuffer.cs
@@ -0,0 +1,891 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// There are 3 #defines that have an impact on performance / features of this ByteBuffer implementation
+//
+// UNSAFE_BYTEBUFFER
+// This will use unsafe code to manipulate the underlying byte array. This
+// can yield a reasonable performance increase.
+//
+// BYTEBUFFER_NO_BOUNDS_CHECK
+// This will disable the bounds check asserts to the byte array. This can
+// yield a small performance gain in normal code..
+//
+// ENABLE_SPAN_T
+// This will enable reading and writing blocks of memory with a Span<T> instead if just
+// T[]. You can also enable writing directly to shared memory or other types of memory
+// by providing a custom implementation of ByteBufferAllocator.
+// ENABLE_SPAN_T also requires UNSAFE_BYTEBUFFER to be defined
+//
+// Using UNSAFE_BYTEBUFFER and BYTEBUFFER_NO_BOUNDS_CHECK together can yield a
+// performance gain of ~15% for some operations, however doing so is potentially
+// dangerous. Do so at your own risk!
+//
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+#if ENABLE_SPAN_T
+using System.Buffers.Binary;
+#endif
+
+#if ENABLE_SPAN_T && !UNSAFE_BYTEBUFFER
+#error ENABLE_SPAN_T requires UNSAFE_BYTEBUFFER to also be defined
+#endif
+
+namespace FlatBuffers
+{
+ public abstract class ByteBufferAllocator
+ {
+#if ENABLE_SPAN_T
+ public abstract Span<byte> Span { get; }
+ public abstract ReadOnlySpan<byte> ReadOnlySpan { get; }
+ public abstract Memory<byte> Memory { get; }
+ public abstract ReadOnlyMemory<byte> ReadOnlyMemory { get; }
+
+#else
+ public byte[] Buffer
+ {
+ get;
+ protected set;
+ }
+#endif
+
+ public int Length
+ {
+ get;
+ protected set;
+ }
+
+ public abstract void GrowFront(int newSize);
+ }
+
+ public sealed class ByteArrayAllocator : ByteBufferAllocator
+ {
+ private byte[] _buffer;
+
+ public ByteArrayAllocator(byte[] buffer)
+ {
+ _buffer = buffer;
+ InitBuffer();
+ }
+
+ public override void GrowFront(int newSize)
+ {
+ if ((Length & 0xC0000000) != 0)
+ throw new Exception(
+ "ByteBuffer: cannot grow buffer beyond 2 gigabytes.");
+
+ if (newSize < Length)
+ throw new Exception("ByteBuffer: cannot truncate buffer.");
+
+ byte[] newBuffer = new byte[newSize];
+ System.Buffer.BlockCopy(_buffer, 0, newBuffer, newSize - Length, Length);
+ _buffer = newBuffer;
+ InitBuffer();
+ }
+
+#if ENABLE_SPAN_T
+ public override Span<byte> Span => _buffer;
+ public override ReadOnlySpan<byte> ReadOnlySpan => _buffer;
+ public override Memory<byte> Memory => _buffer;
+ public override ReadOnlyMemory<byte> ReadOnlyMemory => _buffer;
+#endif
+
+ private void InitBuffer()
+ {
+ Length = _buffer.Length;
+#if !ENABLE_SPAN_T
+ Buffer = _buffer;
+#endif
+ }
+ }
+
+ /// <summary>
+ /// Class to mimic Java's ByteBuffer which is used heavily in Flatbuffers.
+ /// </summary>
+ public class ByteBuffer
+ {
+ private ByteBufferAllocator _buffer;
+ private int _pos; // Must track start of the buffer.
+
+ public ByteBuffer(ByteBufferAllocator allocator, int position)
+ {
+ _buffer = allocator;
+ _pos = position;
+ }
+
+ public ByteBuffer(int size) : this(new byte[size]) { }
+
+ public ByteBuffer(byte[] buffer) : this(buffer, 0) { }
+
+ public ByteBuffer(byte[] buffer, int pos)
+ {
+ _buffer = new ByteArrayAllocator(buffer);
+ _pos = pos;
+ }
+
+ public int Position
+ {
+ get { return _pos; }
+ set { _pos = value; }
+ }
+
+ public int Length { get { return _buffer.Length; } }
+
+ public void Reset()
+ {
+ _pos = 0;
+ }
+
+ // Create a new ByteBuffer on the same underlying data.
+ // The new ByteBuffer's position will be same as this buffer's.
+ public ByteBuffer Duplicate()
+ {
+ return new ByteBuffer(_buffer, Position);
+ }
+
+ // Increases the size of the ByteBuffer, and copies the old data towards
+ // the end of the new buffer.
+ public void GrowFront(int newSize)
+ {
+ _buffer.GrowFront(newSize);
+ }
+
+ public byte[] ToArray(int pos, int len)
+ {
+ return ToArray<byte>(pos, len);
+ }
+
+ /// <summary>
+ /// A lookup of type sizes. Used instead of Marshal.SizeOf() which has additional
+ /// overhead, but also is compatible with generic functions for simplified code.
+ /// </summary>
+ private static Dictionary<Type, int> genericSizes = new Dictionary<Type, int>()
+ {
+ { typeof(bool), sizeof(bool) },
+ { typeof(float), sizeof(float) },
+ { typeof(double), sizeof(double) },
+ { typeof(sbyte), sizeof(sbyte) },
+ { typeof(byte), sizeof(byte) },
+ { typeof(short), sizeof(short) },
+ { typeof(ushort), sizeof(ushort) },
+ { typeof(int), sizeof(int) },
+ { typeof(uint), sizeof(uint) },
+ { typeof(ulong), sizeof(ulong) },
+ { typeof(long), sizeof(long) },
+ };
+
+ /// <summary>
+ /// Get the wire-size (in bytes) of a type supported by flatbuffers.
+ /// </summary>
+ /// <param name="t">The type to get the wire size of</param>
+ /// <returns></returns>
+ public static int SizeOf<T>()
+ {
+ return genericSizes[typeof(T)];
+ }
+
+ /// <summary>
+ /// Checks if the Type provided is supported as scalar value
+ /// </summary>
+ /// <typeparam name="T">The Type to check</typeparam>
+ /// <returns>True if the type is a scalar type that is supported, falsed otherwise</returns>
+ public static bool IsSupportedType<T>()
+ {
+ return genericSizes.ContainsKey(typeof(T));
+ }
+
+ /// <summary>
+ /// Get the wire-size (in bytes) of an typed array
+ /// </summary>
+ /// <typeparam name="T">The type of the array</typeparam>
+ /// <param name="x">The array to get the size of</param>
+ /// <returns>The number of bytes the array takes on wire</returns>
+ public static int ArraySize<T>(T[] x)
+ {
+ return SizeOf<T>() * x.Length;
+ }
+
+#if ENABLE_SPAN_T
+ public static int ArraySize<T>(Span<T> x)
+ {
+ return SizeOf<T>() * x.Length;
+ }
+#endif
+
+ // Get a portion of the buffer casted into an array of type T, given
+ // the buffer position and length.
+#if ENABLE_SPAN_T
+ public T[] ToArray<T>(int pos, int len)
+ where T : struct
+ {
+ AssertOffsetAndLength(pos, len);
+ return MemoryMarshal.Cast<byte, T>(_buffer.ReadOnlySpan.Slice(pos)).Slice(0, len).ToArray();
+ }
+#else
+ public T[] ToArray<T>(int pos, int len)
+ where T : struct
+ {
+ AssertOffsetAndLength(pos, len);
+ T[] arr = new T[len];
+ Buffer.BlockCopy(_buffer.Buffer, pos, arr, 0, ArraySize(arr));
+ return arr;
+ }
+#endif
+
+ public byte[] ToSizedArray()
+ {
+ return ToArray<byte>(Position, Length - Position);
+ }
+
+ public byte[] ToFullArray()
+ {
+ return ToArray<byte>(0, Length);
+ }
+
+#if ENABLE_SPAN_T
+ public ReadOnlyMemory<byte> ToReadOnlyMemory(int pos, int len)
+ {
+ return _buffer.ReadOnlyMemory.Slice(pos, len);
+ }
+
+ public Memory<byte> ToMemory(int pos, int len)
+ {
+ return _buffer.Memory.Slice(pos, len);
+ }
+
+ public Span<byte> ToSpan(int pos, int len)
+ {
+ return _buffer.Span.Slice(pos, len);
+ }
+#else
+ public ArraySegment<byte> ToArraySegment(int pos, int len)
+ {
+ return new ArraySegment<byte>(_buffer.Buffer, pos, len);
+ }
+
+ public MemoryStream ToMemoryStream(int pos, int len)
+ {
+ return new MemoryStream(_buffer.Buffer, pos, len);
+ }
+#endif
+
+#if !UNSAFE_BYTEBUFFER
+ // Pre-allocated helper arrays for convertion.
+ private float[] floathelper = new[] { 0.0f };
+ private int[] inthelper = new[] { 0 };
+ private double[] doublehelper = new[] { 0.0 };
+ private ulong[] ulonghelper = new[] { 0UL };
+#endif // !UNSAFE_BYTEBUFFER
+
+ // Helper functions for the unsafe version.
+ static public ushort ReverseBytes(ushort input)
+ {
+ return (ushort)(((input & 0x00FFU) << 8) |
+ ((input & 0xFF00U) >> 8));
+ }
+ static public uint ReverseBytes(uint input)
+ {
+ return ((input & 0x000000FFU) << 24) |
+ ((input & 0x0000FF00U) << 8) |
+ ((input & 0x00FF0000U) >> 8) |
+ ((input & 0xFF000000U) >> 24);
+ }
+ static public ulong ReverseBytes(ulong input)
+ {
+ return (((input & 0x00000000000000FFUL) << 56) |
+ ((input & 0x000000000000FF00UL) << 40) |
+ ((input & 0x0000000000FF0000UL) << 24) |
+ ((input & 0x00000000FF000000UL) << 8) |
+ ((input & 0x000000FF00000000UL) >> 8) |
+ ((input & 0x0000FF0000000000UL) >> 24) |
+ ((input & 0x00FF000000000000UL) >> 40) |
+ ((input & 0xFF00000000000000UL) >> 56));
+ }
+
+#if !UNSAFE_BYTEBUFFER
+ // Helper functions for the safe (but slower) version.
+ protected void WriteLittleEndian(int offset, int count, ulong data)
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ _buffer.Buffer[offset + i] = (byte)(data >> i * 8);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < count; i++)
+ {
+ _buffer.Buffer[offset + count - 1 - i] = (byte)(data >> i * 8);
+ }
+ }
+ }
+
+ protected ulong ReadLittleEndian(int offset, int count)
+ {
+ AssertOffsetAndLength(offset, count);
+ ulong r = 0;
+ if (BitConverter.IsLittleEndian)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ r |= (ulong)_buffer.Buffer[offset + i] << i * 8;
+ }
+ }
+ else
+ {
+ for (int i = 0; i < count; i++)
+ {
+ r |= (ulong)_buffer.Buffer[offset + count - 1 - i] << i * 8;
+ }
+ }
+ return r;
+ }
+#endif // !UNSAFE_BYTEBUFFER
+
+ private void AssertOffsetAndLength(int offset, int length)
+ {
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ if (offset < 0 ||
+ offset > _buffer.Length - length)
+ throw new ArgumentOutOfRangeException();
+#endif
+ }
+
+#if ENABLE_SPAN_T
+
+ public void PutSbyte(int offset, sbyte value)
+ {
+ AssertOffsetAndLength(offset, sizeof(sbyte));
+ _buffer.Span[offset] = (byte)value;
+ }
+
+ public void PutByte(int offset, byte value)
+ {
+ AssertOffsetAndLength(offset, sizeof(byte));
+ _buffer.Span[offset] = value;
+ }
+
+ public void PutByte(int offset, byte value, int count)
+ {
+ AssertOffsetAndLength(offset, sizeof(byte) * count);
+ Span<byte> span = _buffer.Span.Slice(offset, count);
+ for (var i = 0; i < span.Length; ++i)
+ span[i] = value;
+ }
+#else
+ public void PutSbyte(int offset, sbyte value)
+ {
+ AssertOffsetAndLength(offset, sizeof(sbyte));
+ _buffer.Buffer[offset] = (byte)value;
+ }
+
+ public void PutByte(int offset, byte value)
+ {
+ AssertOffsetAndLength(offset, sizeof(byte));
+ _buffer.Buffer[offset] = value;
+ }
+
+ public void PutByte(int offset, byte value, int count)
+ {
+ AssertOffsetAndLength(offset, sizeof(byte) * count);
+ for (var i = 0; i < count; ++i)
+ _buffer.Buffer[offset + i] = value;
+ }
+#endif
+
+ // this method exists in order to conform with Java ByteBuffer standards
+ public void Put(int offset, byte value)
+ {
+ PutByte(offset, value);
+ }
+
+#if ENABLE_SPAN_T
+ public unsafe void PutStringUTF8(int offset, string value)
+ {
+ AssertOffsetAndLength(offset, value.Length);
+ fixed (char* s = value)
+ {
+ fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.Span))
+ {
+ Encoding.UTF8.GetBytes(s, value.Length, buffer + offset, Length - offset);
+ }
+ }
+ }
+#else
+ public void PutStringUTF8(int offset, string value)
+ {
+ AssertOffsetAndLength(offset, value.Length);
+ Encoding.UTF8.GetBytes(value, 0, value.Length,
+ _buffer.Buffer, offset);
+ }
+#endif
+
+#if UNSAFE_BYTEBUFFER
+ // Unsafe but more efficient versions of Put*.
+ public void PutShort(int offset, short value)
+ {
+ PutUshort(offset, (ushort)value);
+ }
+
+ public unsafe void PutUshort(int offset, ushort value)
+ {
+ AssertOffsetAndLength(offset, sizeof(ushort));
+#if ENABLE_SPAN_T
+ Span<byte> span = _buffer.Span.Slice(offset);
+ BinaryPrimitives.WriteUInt16LittleEndian(span, value);
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+ {
+ *(ushort*)(ptr + offset) = BitConverter.IsLittleEndian
+ ? value
+ : ReverseBytes(value);
+ }
+#endif
+ }
+
+ public void PutInt(int offset, int value)
+ {
+ PutUint(offset, (uint)value);
+ }
+
+ public unsafe void PutUint(int offset, uint value)
+ {
+ AssertOffsetAndLength(offset, sizeof(uint));
+#if ENABLE_SPAN_T
+ Span<byte> span = _buffer.Span.Slice(offset);
+ BinaryPrimitives.WriteUInt32LittleEndian(span, value);
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+ {
+ *(uint*)(ptr + offset) = BitConverter.IsLittleEndian
+ ? value
+ : ReverseBytes(value);
+ }
+#endif
+ }
+
+ public unsafe void PutLong(int offset, long value)
+ {
+ PutUlong(offset, (ulong)value);
+ }
+
+ public unsafe void PutUlong(int offset, ulong value)
+ {
+ AssertOffsetAndLength(offset, sizeof(ulong));
+#if ENABLE_SPAN_T
+ Span<byte> span = _buffer.Span.Slice(offset);
+ BinaryPrimitives.WriteUInt64LittleEndian(span, value);
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+ {
+ *(ulong*)(ptr + offset) = BitConverter.IsLittleEndian
+ ? value
+ : ReverseBytes(value);
+ }
+#endif
+ }
+
+ public unsafe void PutFloat(int offset, float value)
+ {
+ AssertOffsetAndLength(offset, sizeof(float));
+#if ENABLE_SPAN_T
+ fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span))
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+#endif
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ *(float*)(ptr + offset) = value;
+ }
+ else
+ {
+ *(uint*)(ptr + offset) = ReverseBytes(*(uint*)(&value));
+ }
+ }
+ }
+
+ public unsafe void PutDouble(int offset, double value)
+ {
+ AssertOffsetAndLength(offset, sizeof(double));
+#if ENABLE_SPAN_T
+ fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.Span))
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+#endif
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ *(double*)(ptr + offset) = value;
+ }
+ else
+ {
+ *(ulong*)(ptr + offset) = ReverseBytes(*(ulong*)(&value));
+ }
+ }
+ }
+#else // !UNSAFE_BYTEBUFFER
+ // Slower versions of Put* for when unsafe code is not allowed.
+ public void PutShort(int offset, short value)
+ {
+ AssertOffsetAndLength(offset, sizeof(short));
+ WriteLittleEndian(offset, sizeof(short), (ulong)value);
+ }
+
+ public void PutUshort(int offset, ushort value)
+ {
+ AssertOffsetAndLength(offset, sizeof(ushort));
+ WriteLittleEndian(offset, sizeof(ushort), (ulong)value);
+ }
+
+ public void PutInt(int offset, int value)
+ {
+ AssertOffsetAndLength(offset, sizeof(int));
+ WriteLittleEndian(offset, sizeof(int), (ulong)value);
+ }
+
+ public void PutUint(int offset, uint value)
+ {
+ AssertOffsetAndLength(offset, sizeof(uint));
+ WriteLittleEndian(offset, sizeof(uint), (ulong)value);
+ }
+
+ public void PutLong(int offset, long value)
+ {
+ AssertOffsetAndLength(offset, sizeof(long));
+ WriteLittleEndian(offset, sizeof(long), (ulong)value);
+ }
+
+ public void PutUlong(int offset, ulong value)
+ {
+ AssertOffsetAndLength(offset, sizeof(ulong));
+ WriteLittleEndian(offset, sizeof(ulong), value);
+ }
+
+ public void PutFloat(int offset, float value)
+ {
+ AssertOffsetAndLength(offset, sizeof(float));
+ floathelper[0] = value;
+ Buffer.BlockCopy(floathelper, 0, inthelper, 0, sizeof(float));
+ WriteLittleEndian(offset, sizeof(float), (ulong)inthelper[0]);
+ }
+
+ public void PutDouble(int offset, double value)
+ {
+ AssertOffsetAndLength(offset, sizeof(double));
+ doublehelper[0] = value;
+ Buffer.BlockCopy(doublehelper, 0, ulonghelper, 0, sizeof(double));
+ WriteLittleEndian(offset, sizeof(double), ulonghelper[0]);
+ }
+
+#endif // UNSAFE_BYTEBUFFER
+
+#if ENABLE_SPAN_T
+ public sbyte GetSbyte(int index)
+ {
+ AssertOffsetAndLength(index, sizeof(sbyte));
+ return (sbyte)_buffer.ReadOnlySpan[index];
+ }
+
+ public byte Get(int index)
+ {
+ AssertOffsetAndLength(index, sizeof(byte));
+ return _buffer.ReadOnlySpan[index];
+ }
+#else
+ public sbyte GetSbyte(int index)
+ {
+ AssertOffsetAndLength(index, sizeof(sbyte));
+ return (sbyte)_buffer.Buffer[index];
+ }
+
+ public byte Get(int index)
+ {
+ AssertOffsetAndLength(index, sizeof(byte));
+ return _buffer.Buffer[index];
+ }
+#endif
+
+#if ENABLE_SPAN_T
+ public unsafe string GetStringUTF8(int startPos, int len)
+ {
+ fixed (byte* buffer = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan.Slice(startPos)))
+ {
+ return Encoding.UTF8.GetString(buffer, len);
+ }
+ }
+#else
+ public string GetStringUTF8(int startPos, int len)
+ {
+ return Encoding.UTF8.GetString(_buffer.Buffer, startPos, len);
+ }
+#endif
+
+#if UNSAFE_BYTEBUFFER
+ // Unsafe but more efficient versions of Get*.
+ public short GetShort(int offset)
+ {
+ return (short)GetUshort(offset);
+ }
+
+ public unsafe ushort GetUshort(int offset)
+ {
+ AssertOffsetAndLength(offset, sizeof(ushort));
+#if ENABLE_SPAN_T
+ ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
+ return BinaryPrimitives.ReadUInt16LittleEndian(span);
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+ {
+ return BitConverter.IsLittleEndian
+ ? *(ushort*)(ptr + offset)
+ : ReverseBytes(*(ushort*)(ptr + offset));
+ }
+#endif
+ }
+
+ public int GetInt(int offset)
+ {
+ return (int)GetUint(offset);
+ }
+
+ public unsafe uint GetUint(int offset)
+ {
+ AssertOffsetAndLength(offset, sizeof(uint));
+#if ENABLE_SPAN_T
+ ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
+ return BinaryPrimitives.ReadUInt32LittleEndian(span);
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+ {
+ return BitConverter.IsLittleEndian
+ ? *(uint*)(ptr + offset)
+ : ReverseBytes(*(uint*)(ptr + offset));
+ }
+#endif
+ }
+
+ public long GetLong(int offset)
+ {
+ return (long)GetUlong(offset);
+ }
+
+ public unsafe ulong GetUlong(int offset)
+ {
+ AssertOffsetAndLength(offset, sizeof(ulong));
+#if ENABLE_SPAN_T
+ ReadOnlySpan<byte> span = _buffer.ReadOnlySpan.Slice(offset);
+ return BinaryPrimitives.ReadUInt64LittleEndian(span);
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+ {
+ return BitConverter.IsLittleEndian
+ ? *(ulong*)(ptr + offset)
+ : ReverseBytes(*(ulong*)(ptr + offset));
+ }
+#endif
+ }
+
+ public unsafe float GetFloat(int offset)
+ {
+ AssertOffsetAndLength(offset, sizeof(float));
+#if ENABLE_SPAN_T
+ fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan))
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+#endif
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return *(float*)(ptr + offset);
+ }
+ else
+ {
+ uint uvalue = ReverseBytes(*(uint*)(ptr + offset));
+ return *(float*)(&uvalue);
+ }
+ }
+ }
+
+ public unsafe double GetDouble(int offset)
+ {
+ AssertOffsetAndLength(offset, sizeof(double));
+#if ENABLE_SPAN_T
+ fixed (byte* ptr = &MemoryMarshal.GetReference(_buffer.ReadOnlySpan))
+#else
+ fixed (byte* ptr = _buffer.Buffer)
+#endif
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return *(double*)(ptr + offset);
+ }
+ else
+ {
+ ulong uvalue = ReverseBytes(*(ulong*)(ptr + offset));
+ return *(double*)(&uvalue);
+ }
+ }
+ }
+#else // !UNSAFE_BYTEBUFFER
+ // Slower versions of Get* for when unsafe code is not allowed.
+ public short GetShort(int index)
+ {
+ return (short)ReadLittleEndian(index, sizeof(short));
+ }
+
+ public ushort GetUshort(int index)
+ {
+ return (ushort)ReadLittleEndian(index, sizeof(ushort));
+ }
+
+ public int GetInt(int index)
+ {
+ return (int)ReadLittleEndian(index, sizeof(int));
+ }
+
+ public uint GetUint(int index)
+ {
+ return (uint)ReadLittleEndian(index, sizeof(uint));
+ }
+
+ public long GetLong(int index)
+ {
+ return (long)ReadLittleEndian(index, sizeof(long));
+ }
+
+ public ulong GetUlong(int index)
+ {
+ return ReadLittleEndian(index, sizeof(ulong));
+ }
+
+ public float GetFloat(int index)
+ {
+ int i = (int)ReadLittleEndian(index, sizeof(float));
+ inthelper[0] = i;
+ Buffer.BlockCopy(inthelper, 0, floathelper, 0, sizeof(float));
+ return floathelper[0];
+ }
+
+ public double GetDouble(int index)
+ {
+ ulong i = ReadLittleEndian(index, sizeof(double));
+ // There's Int64BitsToDouble but it uses unsafe code internally.
+ ulonghelper[0] = i;
+ Buffer.BlockCopy(ulonghelper, 0, doublehelper, 0, sizeof(double));
+ return doublehelper[0];
+ }
+#endif // UNSAFE_BYTEBUFFER
+
+ /// <summary>
+ /// Copies an array of type T into this buffer, ending at the given
+ /// offset into this buffer. The starting offset is calculated based on the length
+ /// of the array and is the value returned.
+ /// </summary>
+ /// <typeparam name="T">The type of the input data (must be a struct)</typeparam>
+ /// <param name="offset">The offset into this buffer where the copy will end</param>
+ /// <param name="x">The array to copy data from</param>
+ /// <returns>The 'start' location of this buffer now, after the copy completed</returns>
+ public int Put<T>(int offset, T[] x)
+ where T : struct
+ {
+ if (x == null)
+ {
+ throw new ArgumentNullException("Cannot put a null array");
+ }
+
+ if (x.Length == 0)
+ {
+ throw new ArgumentException("Cannot put an empty array");
+ }
+
+ if (!IsSupportedType<T>())
+ {
+ throw new ArgumentException("Cannot put an array of type "
+ + typeof(T) + " into this buffer");
+ }
+
+ if (BitConverter.IsLittleEndian)
+ {
+ int numBytes = ByteBuffer.ArraySize(x);
+ offset -= numBytes;
+ AssertOffsetAndLength(offset, numBytes);
+ // if we are LE, just do a block copy
+#if ENABLE_SPAN_T
+ MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
+#else
+ Buffer.BlockCopy(x, 0, _buffer.Buffer, offset, numBytes);
+#endif
+ }
+ else
+ {
+ throw new NotImplementedException("Big Endian Support not implemented yet " +
+ "for putting typed arrays");
+ // if we are BE, we have to swap each element by itself
+ //for(int i = x.Length - 1; i >= 0; i--)
+ //{
+ // todo: low priority, but need to genericize the Put<T>() functions
+ //}
+ }
+ return offset;
+ }
+
+#if ENABLE_SPAN_T
+ public int Put<T>(int offset, Span<T> x)
+ where T : struct
+ {
+ if (x.Length == 0)
+ {
+ throw new ArgumentException("Cannot put an empty array");
+ }
+
+ if (!IsSupportedType<T>())
+ {
+ throw new ArgumentException("Cannot put an array of type "
+ + typeof(T) + " into this buffer");
+ }
+
+ if (BitConverter.IsLittleEndian)
+ {
+ int numBytes = ByteBuffer.ArraySize(x);
+ offset -= numBytes;
+ AssertOffsetAndLength(offset, numBytes);
+ // if we are LE, just do a block copy
+ MemoryMarshal.Cast<T, byte>(x).CopyTo(_buffer.Span.Slice(offset, numBytes));
+ }
+ else
+ {
+ throw new NotImplementedException("Big Endian Support not implemented yet " +
+ "for putting typed arrays");
+ // if we are BE, we have to swap each element by itself
+ //for(int i = x.Length - 1; i >= 0; i--)
+ //{
+ // todo: low priority, but need to genericize the Put<T>() functions
+ //}
+ }
+ return offset;
+ }
+#endif
+ }
+}
diff --git a/net/FlatBuffers/ByteBufferUtil.cs b/net/FlatBuffers/ByteBufferUtil.cs
new file mode 100644
index 0000000..66e8266
--- /dev/null
+++ b/net/FlatBuffers/ByteBufferUtil.cs
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// Class that collects utility functions around `ByteBuffer`.
+ /// </summary>
+ public class ByteBufferUtil
+ {
+ // Extract the size prefix from a `ByteBuffer`.
+ public static int GetSizePrefix(ByteBuffer bb) {
+ return bb.GetInt(bb.Position);
+ }
+
+ // Create a duplicate of a size-prefixed `ByteBuffer` that has its position
+ // advanced just past the size prefix.
+ public static ByteBuffer RemoveSizePrefix(ByteBuffer bb) {
+ ByteBuffer s = bb.Duplicate();
+ s.Position += FlatBufferConstants.SizePrefixLength;
+ return s;
+ }
+ }
+}
diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs
new file mode 100644
index 0000000..27c16b3
--- /dev/null
+++ b/net/FlatBuffers/FlatBufferBuilder.cs
@@ -0,0 +1,842 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+/// @file
+/// @addtogroup flatbuffers_csharp_api
+/// @{
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// Responsible for building up and accessing a FlatBuffer formatted byte
+ /// array (via ByteBuffer).
+ /// </summary>
+ public class FlatBufferBuilder
+ {
+ private int _space;
+ private ByteBuffer _bb;
+ private int _minAlign = 1;
+
+ // The vtable for the current table (if _vtableSize >= 0)
+ private int[] _vtable = new int[16];
+ // The size of the vtable. -1 indicates no vtable
+ private int _vtableSize = -1;
+ // Starting offset of the current struct/table.
+ private int _objectStart;
+ // List of offsets of all vtables.
+ private int[] _vtables = new int[16];
+ // Number of entries in `vtables` in use.
+ private int _numVtables = 0;
+ // For the current vector being built.
+ private int _vectorNumElems = 0;
+
+ // For CreateSharedString
+ private Dictionary<string, StringOffset> _sharedStringMap = null;
+
+ /// <summary>
+ /// Create a FlatBufferBuilder with a given initial size.
+ /// </summary>
+ /// <param name="initialSize">
+ /// The initial size to use for the internal buffer.
+ /// </param>
+ public FlatBufferBuilder(int initialSize)
+ {
+ if (initialSize <= 0)
+ throw new ArgumentOutOfRangeException("initialSize",
+ initialSize, "Must be greater than zero");
+ _space = initialSize;
+ _bb = new ByteBuffer(initialSize);
+ }
+
+ /// <summary>
+ /// Create a FlatBufferBuilder backed by the pased in ByteBuffer
+ /// </summary>
+ /// <param name="buffer">The ByteBuffer to write to</param>
+ public FlatBufferBuilder(ByteBuffer buffer)
+ {
+ _bb = buffer;
+ _space = buffer.Length;
+ buffer.Reset();
+ }
+
+ /// <summary>
+ /// Reset the FlatBufferBuilder by purging all data that it holds.
+ /// </summary>
+ public void Clear()
+ {
+ _space = _bb.Length;
+ _bb.Reset();
+ _minAlign = 1;
+ while (_vtableSize > 0) _vtable[--_vtableSize] = 0;
+ _vtableSize = -1;
+ _objectStart = 0;
+ _numVtables = 0;
+ _vectorNumElems = 0;
+ }
+
+ /// <summary>
+ /// Gets and sets a Boolean to disable the optimization when serializing
+ /// default values to a Table.
+ ///
+ /// In order to save space, fields that are set to their default value
+ /// don't get serialized into the buffer.
+ /// </summary>
+ public bool ForceDefaults { get; set; }
+
+ /// @cond FLATBUFFERS_INTERNAL
+
+ public int Offset { get { return _bb.Length - _space; } }
+
+ public void Pad(int size)
+ {
+ _bb.PutByte(_space -= size, 0, size);
+ }
+
+ // Doubles the size of the ByteBuffer, and copies the old data towards
+ // the end of the new buffer (since we build the buffer backwards).
+ void GrowBuffer()
+ {
+ _bb.GrowFront(_bb.Length << 1);
+ }
+
+ // Prepare to write an element of `size` after `additional_bytes`
+ // have been written, e.g. if you write a string, you need to align
+ // such the int length field is aligned to SIZEOF_INT, and the string
+ // data follows it directly.
+ // If all you need to do is align, `additional_bytes` will be 0.
+ public void Prep(int size, int additionalBytes)
+ {
+ // Track the biggest thing we've ever aligned to.
+ if (size > _minAlign)
+ _minAlign = size;
+ // Find the amount of alignment needed such that `size` is properly
+ // aligned after `additional_bytes`
+ var alignSize =
+ ((~((int)_bb.Length - _space + additionalBytes)) + 1) &
+ (size - 1);
+ // Reallocate the buffer if needed.
+ while (_space < alignSize + size + additionalBytes)
+ {
+ var oldBufSize = (int)_bb.Length;
+ GrowBuffer();
+ _space += (int)_bb.Length - oldBufSize;
+
+ }
+ if (alignSize > 0)
+ Pad(alignSize);
+ }
+
+ public void PutBool(bool x)
+ {
+ _bb.PutByte(_space -= sizeof(byte), (byte)(x ? 1 : 0));
+ }
+
+ public void PutSbyte(sbyte x)
+ {
+ _bb.PutSbyte(_space -= sizeof(sbyte), x);
+ }
+
+ public void PutByte(byte x)
+ {
+ _bb.PutByte(_space -= sizeof(byte), x);
+ }
+
+ public void PutShort(short x)
+ {
+ _bb.PutShort(_space -= sizeof(short), x);
+ }
+
+ public void PutUshort(ushort x)
+ {
+ _bb.PutUshort(_space -= sizeof(ushort), x);
+ }
+
+ public void PutInt(int x)
+ {
+ _bb.PutInt(_space -= sizeof(int), x);
+ }
+
+ public void PutUint(uint x)
+ {
+ _bb.PutUint(_space -= sizeof(uint), x);
+ }
+
+ public void PutLong(long x)
+ {
+ _bb.PutLong(_space -= sizeof(long), x);
+ }
+
+ public void PutUlong(ulong x)
+ {
+ _bb.PutUlong(_space -= sizeof(ulong), x);
+ }
+
+ public void PutFloat(float x)
+ {
+ _bb.PutFloat(_space -= sizeof(float), x);
+ }
+
+ /// <summary>
+ /// Puts an array of type T into this builder at the
+ /// current offset
+ /// </summary>
+ /// <typeparam name="T">The type of the input data </typeparam>
+ /// <param name="x">The array to copy data from</param>
+ public void Put<T>(T[] x)
+ where T : struct
+ {
+ _space = _bb.Put(_space, x);
+ }
+
+#if ENABLE_SPAN_T
+ /// <summary>
+ /// Puts a span of type T into this builder at the
+ /// current offset
+ /// </summary>
+ /// <typeparam name="T">The type of the input data </typeparam>
+ /// <param name="x">The span to copy data from</param>
+ public void Put<T>(Span<T> x)
+ where T : struct
+ {
+ _space = _bb.Put(_space, x);
+ }
+#endif
+
+ public void PutDouble(double x)
+ {
+ _bb.PutDouble(_space -= sizeof(double), x);
+ }
+ /// @endcond
+
+ /// <summary>
+ /// Add a `bool` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `bool` to add to the buffer.</param>
+ public void AddBool(bool x) { Prep(sizeof(byte), 0); PutBool(x); }
+
+ /// <summary>
+ /// Add a `sbyte` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `sbyte` to add to the buffer.</param>
+ public void AddSbyte(sbyte x) { Prep(sizeof(sbyte), 0); PutSbyte(x); }
+
+ /// <summary>
+ /// Add a `byte` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `byte` to add to the buffer.</param>
+ public void AddByte(byte x) { Prep(sizeof(byte), 0); PutByte(x); }
+
+ /// <summary>
+ /// Add a `short` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `short` to add to the buffer.</param>
+ public void AddShort(short x) { Prep(sizeof(short), 0); PutShort(x); }
+
+ /// <summary>
+ /// Add an `ushort` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `ushort` to add to the buffer.</param>
+ public void AddUshort(ushort x) { Prep(sizeof(ushort), 0); PutUshort(x); }
+
+ /// <summary>
+ /// Add an `int` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `int` to add to the buffer.</param>
+ public void AddInt(int x) { Prep(sizeof(int), 0); PutInt(x); }
+
+ /// <summary>
+ /// Add an `uint` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `uint` to add to the buffer.</param>
+ public void AddUint(uint x) { Prep(sizeof(uint), 0); PutUint(x); }
+
+ /// <summary>
+ /// Add a `long` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `long` to add to the buffer.</param>
+ public void AddLong(long x) { Prep(sizeof(long), 0); PutLong(x); }
+
+ /// <summary>
+ /// Add an `ulong` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `ulong` to add to the buffer.</param>
+ public void AddUlong(ulong x) { Prep(sizeof(ulong), 0); PutUlong(x); }
+
+ /// <summary>
+ /// Add a `float` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `float` to add to the buffer.</param>
+ public void AddFloat(float x) { Prep(sizeof(float), 0); PutFloat(x); }
+
+ /// <summary>
+ /// Add an array of type T to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <typeparam name="T">The type of the input data</typeparam>
+ /// <param name="x">The array to copy data from</param>
+ public void Add<T>(T[] x)
+ where T : struct
+ {
+ if (x == null)
+ {
+ throw new ArgumentNullException("Cannot add a null array");
+ }
+
+ if( x.Length == 0)
+ {
+ // don't do anything if the array is empty
+ return;
+ }
+
+ if(!ByteBuffer.IsSupportedType<T>())
+ {
+ throw new ArgumentException("Cannot add this Type array to the builder");
+ }
+
+ int size = ByteBuffer.SizeOf<T>();
+ // Need to prep on size (for data alignment) and then we pass the
+ // rest of the length (minus 1) as additional bytes
+ Prep(size, size * (x.Length - 1));
+ Put(x);
+ }
+
+#if ENABLE_SPAN_T
+ /// <summary>
+ /// Add a span of type T to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <typeparam name="T">The type of the input data</typeparam>
+ /// <param name="x">The span to copy data from</param>
+ public void Add<T>(Span<T> x)
+ where T : struct
+ {
+ if (!ByteBuffer.IsSupportedType<T>())
+ {
+ throw new ArgumentException("Cannot add this Type array to the builder");
+ }
+
+ int size = ByteBuffer.SizeOf<T>();
+ // Need to prep on size (for data alignment) and then we pass the
+ // rest of the length (minus 1) as additional bytes
+ Prep(size, size * (x.Length - 1));
+ Put(x);
+ }
+#endif
+
+ /// <summary>
+ /// Add a `double` to the buffer (aligns the data and grows if necessary).
+ /// </summary>
+ /// <param name="x">The `double` to add to the buffer.</param>
+ public void AddDouble(double x) { Prep(sizeof(double), 0);
+ PutDouble(x); }
+
+ /// <summary>
+ /// Adds an offset, relative to where it will be written.
+ /// </summary>
+ /// <param name="off">The offset to add to the buffer.</param>
+ public void AddOffset(int off)
+ {
+ Prep(sizeof(int), 0); // Ensure alignment is already done.
+ if (off > Offset)
+ throw new ArgumentException();
+
+ off = Offset - off + sizeof(int);
+ PutInt(off);
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ public void StartVector(int elemSize, int count, int alignment)
+ {
+ NotNested();
+ _vectorNumElems = count;
+ Prep(sizeof(int), elemSize * count);
+ Prep(alignment, elemSize * count); // Just in case alignment > int.
+ }
+ /// @endcond
+
+ /// <summary>
+ /// Writes data necessary to finish a vector construction.
+ /// </summary>
+ public VectorOffset EndVector()
+ {
+ PutInt(_vectorNumElems);
+ return new VectorOffset(Offset);
+ }
+
+ /// <summary>
+ /// Creates a vector of tables.
+ /// </summary>
+ /// <param name="offsets">Offsets of the tables.</param>
+ public VectorOffset CreateVectorOfTables<T>(Offset<T>[] offsets) where T : struct
+ {
+ NotNested();
+ StartVector(sizeof(int), offsets.Length, sizeof(int));
+ for (int i = offsets.Length - 1; i >= 0; i--) AddOffset(offsets[i].Value);
+ return EndVector();
+ }
+
+ /// @cond FLATBUFFERS_INTENRAL
+ public void Nested(int obj)
+ {
+ // Structs are always stored inline, so need to be created right
+ // where they are used. You'll get this assert if you created it
+ // elsewhere.
+ if (obj != Offset)
+ throw new Exception(
+ "FlatBuffers: struct must be serialized inline.");
+ }
+
+ public void NotNested()
+ {
+ // You should not be creating any other objects or strings/vectors
+ // while an object is being constructed
+ if (_vtableSize >= 0)
+ throw new Exception(
+ "FlatBuffers: object serialization must not be nested.");
+ }
+
+ public void StartTable(int numfields)
+ {
+ if (numfields < 0)
+ throw new ArgumentOutOfRangeException("Flatbuffers: invalid numfields");
+
+ NotNested();
+
+ if (_vtable.Length < numfields)
+ _vtable = new int[numfields];
+
+ _vtableSize = numfields;
+ _objectStart = Offset;
+ }
+
+
+ // Set the current vtable at `voffset` to the current location in the
+ // buffer.
+ public void Slot(int voffset)
+ {
+ if (voffset >= _vtableSize)
+ throw new IndexOutOfRangeException("Flatbuffers: invalid voffset");
+
+ _vtable[voffset] = Offset;
+ }
+
+ /// <summary>
+ /// Adds a Boolean to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddBool(int o, bool x, bool d) { if (ForceDefaults || x != d) { AddBool(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a SByte to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddSbyte(int o, sbyte x, sbyte d) { if (ForceDefaults || x != d) { AddSbyte(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a Byte to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddByte(int o, byte x, byte d) { if (ForceDefaults || x != d) { AddByte(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a Int16 to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddShort(int o, short x, int d) { if (ForceDefaults || x != d) { AddShort(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a UInt16 to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddUshort(int o, ushort x, ushort d) { if (ForceDefaults || x != d) { AddUshort(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds an Int32 to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddInt(int o, int x, int d) { if (ForceDefaults || x != d) { AddInt(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a UInt32 to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddUint(int o, uint x, uint d) { if (ForceDefaults || x != d) { AddUint(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds an Int64 to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddLong(int o, long x, long d) { if (ForceDefaults || x != d) { AddLong(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a UInt64 to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddUlong(int o, ulong x, ulong d) { if (ForceDefaults || x != d) { AddUlong(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a Single to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddFloat(int o, float x, double d) { if (ForceDefaults || x != d) { AddFloat(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a Double to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// and <see cref="ForceDefaults"/> is false, the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddDouble(int o, double x, double d) { if (ForceDefaults || x != d) { AddDouble(x); Slot(o); } }
+
+ /// <summary>
+ /// Adds a buffer offset to the Table at index `o` in its vtable using the value `x` and default `d`
+ /// </summary>
+ /// <param name="o">The index into the vtable</param>
+ /// <param name="x">The value to put into the buffer. If the value is equal to the default
+ /// the value will be skipped.</param>
+ /// <param name="d">The default value to compare the value against</param>
+ public void AddOffset(int o, int x, int d) { if (x != d) { AddOffset(x); Slot(o); } }
+ /// @endcond
+
+ /// <summary>
+ /// Encode the string `s` in the buffer using UTF-8.
+ /// </summary>
+ /// <param name="s">The string to encode.</param>
+ /// <returns>
+ /// The offset in the buffer where the encoded string starts.
+ /// </returns>
+ public StringOffset CreateString(string s)
+ {
+ NotNested();
+ AddByte(0);
+ var utf8StringLen = Encoding.UTF8.GetByteCount(s);
+ StartVector(1, utf8StringLen, 1);
+ _bb.PutStringUTF8(_space -= utf8StringLen, s);
+ return new StringOffset(EndVector().Value);
+ }
+
+
+#if ENABLE_SPAN_T
+ /// <summary>
+ /// Creates a string in the buffer from a Span containing
+ /// a UTF8 string.
+ /// </summary>
+ /// <param name="chars">the UTF8 string to add to the buffer</param>
+ /// <returns>
+ /// The offset in the buffer where the encoded string starts.
+ /// </returns>
+ public StringOffset CreateUTF8String(Span<byte> chars)
+ {
+ NotNested();
+ AddByte(0);
+ var utf8StringLen = chars.Length;
+ StartVector(1, utf8StringLen, 1);
+ _space = _bb.Put(_space, chars);
+ return new StringOffset(EndVector().Value);
+ }
+#endif
+
+ /// <summary>
+ /// Store a string in the buffer, which can contain any binary data.
+ /// If a string with this exact contents has already been serialized before,
+ /// instead simply returns the offset of the existing string.
+ /// </summary>
+ /// <param name="s">The string to encode.</param>
+ /// <returns>
+ /// The offset in the buffer where the encoded string starts.
+ /// </returns>
+ public StringOffset CreateSharedString(string s)
+ {
+ if (_sharedStringMap == null)
+ {
+ _sharedStringMap = new Dictionary<string, StringOffset>();
+ }
+
+ if (_sharedStringMap.ContainsKey(s))
+ {
+ return _sharedStringMap[s];
+ }
+
+ var stringOffset = CreateString(s);
+ _sharedStringMap.Add(s, stringOffset);
+ return stringOffset;
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ // Structs are stored inline, so nothing additional is being added.
+ // `d` is always 0.
+ public void AddStruct(int voffset, int x, int d)
+ {
+ if (x != d)
+ {
+ Nested(x);
+ Slot(voffset);
+ }
+ }
+
+ public int EndTable()
+ {
+ if (_vtableSize < 0)
+ throw new InvalidOperationException(
+ "Flatbuffers: calling EndTable without a StartTable");
+
+ AddInt((int)0);
+ var vtableloc = Offset;
+ // Write out the current vtable.
+ int i = _vtableSize - 1;
+ // Trim trailing zeroes.
+ for (; i >= 0 && _vtable[i] == 0; i--) {}
+ int trimmedSize = i + 1;
+ for (; i >= 0 ; i--) {
+ // Offset relative to the start of the table.
+ short off = (short)(_vtable[i] != 0
+ ? vtableloc - _vtable[i]
+ : 0);
+ AddShort(off);
+
+ // clear out written entry
+ _vtable[i] = 0;
+ }
+
+ const int standardFields = 2; // The fields below:
+ AddShort((short)(vtableloc - _objectStart));
+ AddShort((short)((trimmedSize + standardFields) *
+ sizeof(short)));
+
+ // Search for an existing vtable that matches the current one.
+ int existingVtable = 0;
+ for (i = 0; i < _numVtables; i++) {
+ int vt1 = _bb.Length - _vtables[i];
+ int vt2 = _space;
+ short len = _bb.GetShort(vt1);
+ if (len == _bb.GetShort(vt2)) {
+ for (int j = sizeof(short); j < len; j += sizeof(short)) {
+ if (_bb.GetShort(vt1 + j) != _bb.GetShort(vt2 + j)) {
+ goto endLoop;
+ }
+ }
+ existingVtable = _vtables[i];
+ break;
+ }
+
+ endLoop: { }
+ }
+
+ if (existingVtable != 0) {
+ // Found a match:
+ // Remove the current vtable.
+ _space = _bb.Length - vtableloc;
+ // Point table to existing vtable.
+ _bb.PutInt(_space, existingVtable - vtableloc);
+ } else {
+ // No match:
+ // Add the location of the current vtable to the list of
+ // vtables.
+ if (_numVtables == _vtables.Length)
+ {
+ // Arrays.CopyOf(vtables num_vtables * 2);
+ var newvtables = new int[ _numVtables * 2];
+ Array.Copy(_vtables, newvtables, _vtables.Length);
+
+ _vtables = newvtables;
+ };
+ _vtables[_numVtables++] = Offset;
+ // Point table to current vtable.
+ _bb.PutInt(_bb.Length - vtableloc, Offset - vtableloc);
+ }
+
+ _vtableSize = -1;
+ return vtableloc;
+ }
+
+ // This checks a required field has been set in a given table that has
+ // just been constructed.
+ public void Required(int table, int field)
+ {
+ int table_start = _bb.Length - table;
+ int vtable_start = table_start - _bb.GetInt(table_start);
+ bool ok = _bb.GetShort(vtable_start + field) != 0;
+ // If this fails, the caller will show what field needs to be set.
+ if (!ok)
+ throw new InvalidOperationException("FlatBuffers: field " + field +
+ " must be set");
+ }
+ /// @endcond
+
+ /// <summary>
+ /// Finalize a buffer, pointing to the given `root_table`.
+ /// </summary>
+ /// <param name="rootTable">
+ /// An offset to be added to the buffer.
+ /// </param>
+ /// <param name="sizePrefix">
+ /// Whether to prefix the size to the buffer.
+ /// </param>
+ protected void Finish(int rootTable, bool sizePrefix)
+ {
+ Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0));
+ AddOffset(rootTable);
+ if (sizePrefix) {
+ AddInt(_bb.Length - _space);
+ }
+ _bb.Position = _space;
+ }
+
+ /// <summary>
+ /// Finalize a buffer, pointing to the given `root_table`.
+ /// </summary>
+ /// <param name="rootTable">
+ /// An offset to be added to the buffer.
+ /// </param>
+ public void Finish(int rootTable)
+ {
+ Finish(rootTable, false);
+ }
+
+ /// <summary>
+ /// Finalize a buffer, pointing to the given `root_table`, with the size prefixed.
+ /// </summary>
+ /// <param name="rootTable">
+ /// An offset to be added to the buffer.
+ /// </param>
+ public void FinishSizePrefixed(int rootTable)
+ {
+ Finish(rootTable, true);
+ }
+
+ /// <summary>
+ /// Get the ByteBuffer representing the FlatBuffer.
+ /// </summary>
+ /// <remarks>
+ /// This is typically only called after you call `Finish()`.
+ /// The actual data starts at the ByteBuffer's current position,
+ /// not necessarily at `0`.
+ /// </remarks>
+ /// <returns>
+ /// Returns the ByteBuffer for this FlatBuffer.
+ /// </returns>
+ public ByteBuffer DataBuffer { get { return _bb; } }
+
+ /// <summary>
+ /// A utility function to copy and return the ByteBuffer data as a
+ /// `byte[]`.
+ /// </summary>
+ /// <returns>
+ /// A full copy of the FlatBuffer data.
+ /// </returns>
+ public byte[] SizedByteArray()
+ {
+ return _bb.ToSizedArray();
+ }
+
+ /// <summary>
+ /// Finalize a buffer, pointing to the given `rootTable`.
+ /// </summary>
+ /// <param name="rootTable">
+ /// An offset to be added to the buffer.
+ /// </param>
+ /// <param name="fileIdentifier">
+ /// A FlatBuffer file identifier to be added to the buffer before
+ /// `root_table`.
+ /// </param>
+ /// <param name="sizePrefix">
+ /// Whether to prefix the size to the buffer.
+ /// </param>
+ protected void Finish(int rootTable, string fileIdentifier, bool sizePrefix)
+ {
+ Prep(_minAlign, sizeof(int) + (sizePrefix ? sizeof(int) : 0) +
+ FlatBufferConstants.FileIdentifierLength);
+ if (fileIdentifier.Length !=
+ FlatBufferConstants.FileIdentifierLength)
+ throw new ArgumentException(
+ "FlatBuffers: file identifier must be length " +
+ FlatBufferConstants.FileIdentifierLength,
+ "fileIdentifier");
+ for (int i = FlatBufferConstants.FileIdentifierLength - 1; i >= 0;
+ i--)
+ {
+ AddByte((byte)fileIdentifier[i]);
+ }
+ Finish(rootTable, sizePrefix);
+ }
+
+ /// <summary>
+ /// Finalize a buffer, pointing to the given `rootTable`.
+ /// </summary>
+ /// <param name="rootTable">
+ /// An offset to be added to the buffer.
+ /// </param>
+ /// <param name="fileIdentifier">
+ /// A FlatBuffer file identifier to be added to the buffer before
+ /// `root_table`.
+ /// </param>
+ public void Finish(int rootTable, string fileIdentifier)
+ {
+ Finish(rootTable, fileIdentifier, false);
+ }
+
+ /// <summary>
+ /// Finalize a buffer, pointing to the given `rootTable`, with the size prefixed.
+ /// </summary>
+ /// <param name="rootTable">
+ /// An offset to be added to the buffer.
+ /// </param>
+ /// <param name="fileIdentifier">
+ /// A FlatBuffer file identifier to be added to the buffer before
+ /// `root_table`.
+ /// </param>
+ public void FinishSizePrefixed(int rootTable, string fileIdentifier)
+ {
+ Finish(rootTable, fileIdentifier, true);
+ }
+ }
+}
+
+/// @}
diff --git a/net/FlatBuffers/FlatBufferConstants.cs b/net/FlatBuffers/FlatBufferConstants.cs
new file mode 100644
index 0000000..730d7ef
--- /dev/null
+++ b/net/FlatBuffers/FlatBufferConstants.cs
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace FlatBuffers
+{
+ public static class FlatBufferConstants
+ {
+ public const int FileIdentifierLength = 4;
+ public const int SizePrefixLength = 4;
+ /** A version identifier to force a compile error if someone
+ accidentally tries to build generated code with a runtime of
+ two mismatched version. Versions need to always match, as
+ the runtime and generated code are modified in sync.
+ Changes to the C# implementation need to be sure to change
+ the version here and in the code generator on every possible
+ incompatible change */
+ public static void FLATBUFFERS_1_11_1() {}
+ }
+}
diff --git a/net/FlatBuffers/FlatBuffers.Core.csproj b/net/FlatBuffers/FlatBuffers.Core.csproj
new file mode 100644
index 0000000..4285dd7
--- /dev/null
+++ b/net/FlatBuffers/FlatBuffers.Core.csproj
@@ -0,0 +1,19 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Remove="Properties\**" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <EmbeddedResource Remove="Properties\**" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <None Remove="Properties\**" />
+ </ItemGroup>
+
+</Project>
diff --git a/net/FlatBuffers/FlatBuffers.csproj b/net/FlatBuffers/FlatBuffers.csproj
new file mode 100644
index 0000000..a029094
--- /dev/null
+++ b/net/FlatBuffers/FlatBuffers.csproj
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{28C00774-1E73-4A75-AD8F-844CD21A064D}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>FlatBuffers</RootNamespace>
+ <AssemblyName>FlatBuffers</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ByteBuffer.cs" />
+ <Compile Include="FlatBufferBuilder.cs" />
+ <Compile Include="FlatBufferConstants.cs" />
+ <Compile Include="IFlatbufferObject.cs" />
+ <Compile Include="Offset.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Struct.cs" />
+ <Compile Include="Table.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
\ No newline at end of file
diff --git a/net/FlatBuffers/IFlatbufferObject.cs b/net/FlatBuffers/IFlatbufferObject.cs
new file mode 100644
index 0000000..6a15aba
--- /dev/null
+++ b/net/FlatBuffers/IFlatbufferObject.cs
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// This is the base for both structs and tables.
+ /// </summary>
+ public interface IFlatbufferObject
+ {
+ void __init(int _i, ByteBuffer _bb);
+
+ ByteBuffer ByteBuffer { get; }
+ }
+}
diff --git a/net/FlatBuffers/Offset.cs b/net/FlatBuffers/Offset.cs
new file mode 100644
index 0000000..2b17cec
--- /dev/null
+++ b/net/FlatBuffers/Offset.cs
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// Offset class for typesafe assignments.
+ /// </summary>
+ public struct Offset<T> where T : struct
+ {
+ public int Value;
+ public Offset(int value)
+ {
+ Value = value;
+ }
+ }
+
+ public struct StringOffset
+ {
+ public int Value;
+ public StringOffset(int value)
+ {
+ Value = value;
+ }
+ }
+
+ public struct VectorOffset
+ {
+ public int Value;
+ public VectorOffset(int value)
+ {
+ Value = value;
+ }
+ }
+}
diff --git a/net/FlatBuffers/Properties/AssemblyInfo.cs b/net/FlatBuffers/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1edfac4
--- /dev/null
+++ b/net/FlatBuffers/Properties/AssemblyInfo.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FlatBuffers")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FlatBuffers")]
+[assembly: AssemblyCopyright("Copyright (c) 2015 Google Inc")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("91c32e64-ef20-47df-9c9f-cec9207bc6df")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/net/FlatBuffers/Struct.cs b/net/FlatBuffers/Struct.cs
new file mode 100644
index 0000000..4f7fac9
--- /dev/null
+++ b/net/FlatBuffers/Struct.cs
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// All structs in the generated code derive from this class, and add their own accessors.
+ /// </summary>
+ public struct Struct
+ {
+ public int bb_pos { get; private set; }
+ public ByteBuffer bb { get; private set; }
+
+ // Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
+ public Struct(int _i, ByteBuffer _bb)
+ {
+ bb = _bb;
+ bb_pos = _i;
+ }
+ }
+}
diff --git a/net/FlatBuffers/Table.cs b/net/FlatBuffers/Table.cs
new file mode 100644
index 0000000..e10ba95
--- /dev/null
+++ b/net/FlatBuffers/Table.cs
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Text;
+
+namespace FlatBuffers
+{
+ /// <summary>
+ /// All tables in the generated code derive from this struct, and add their own accessors.
+ /// </summary>
+ public struct Table
+ {
+ public int bb_pos { get; private set; }
+ public ByteBuffer bb { get; private set; }
+
+ public ByteBuffer ByteBuffer { get { return bb; } }
+
+ // Re-init the internal state with an external buffer {@code ByteBuffer} and an offset within.
+ public Table(int _i, ByteBuffer _bb)
+ {
+ bb = _bb;
+ bb_pos = _i;
+ }
+
+ // Look up a field in the vtable, return an offset into the object, or 0 if the field is not
+ // present.
+ public int __offset(int vtableOffset)
+ {
+ int vtable = bb_pos - bb.GetInt(bb_pos);
+ return vtableOffset < bb.GetShort(vtable) ? (int)bb.GetShort(vtable + vtableOffset) : 0;
+ }
+
+ public static int __offset(int vtableOffset, int offset, ByteBuffer bb)
+ {
+ int vtable = bb.Length - offset;
+ return (int)bb.GetShort(vtable + vtableOffset - bb.GetInt(vtable)) + vtable;
+ }
+
+ // Retrieve the relative offset stored at "offset"
+ public int __indirect(int offset)
+ {
+ return offset + bb.GetInt(offset);
+ }
+
+ public static int __indirect(int offset, ByteBuffer bb)
+ {
+ return offset + bb.GetInt(offset);
+ }
+
+ // Create a .NET String from UTF-8 data stored inside the flatbuffer.
+ public string __string(int offset)
+ {
+ offset += bb.GetInt(offset);
+ var len = bb.GetInt(offset);
+ var startPos = offset + sizeof(int);
+ return bb.GetStringUTF8(startPos, len);
+ }
+
+ // Get the length of a vector whose offset is stored at "offset" in this object.
+ public int __vector_len(int offset)
+ {
+ offset += bb_pos;
+ offset += bb.GetInt(offset);
+ return bb.GetInt(offset);
+ }
+
+ // Get the start of data of a vector whose offset is stored at "offset" in this object.
+ public int __vector(int offset)
+ {
+ offset += bb_pos;
+ return offset + bb.GetInt(offset) + sizeof(int); // data starts after the length
+ }
+
+#if ENABLE_SPAN_T
+ // Get the data of a vector whoses offset is stored at "offset" in this object as an
+ // Spant<byte>. If the vector is not present in the ByteBuffer,
+ // then an empty span will be returned.
+ public Span<byte> __vector_as_span(int offset)
+ {
+ var o = this.__offset(offset);
+ if (0 == o)
+ {
+ return new Span<byte>();
+ }
+
+ var pos = this.__vector(o);
+ var len = this.__vector_len(o);
+ return bb.ToSpan(pos, len);
+ }
+#else
+ // Get the data of a vector whoses offset is stored at "offset" in this object as an
+ // ArraySegment<byte>. If the vector is not present in the ByteBuffer,
+ // then a null value will be returned.
+ public ArraySegment<byte>? __vector_as_arraysegment(int offset)
+ {
+ var o = this.__offset(offset);
+ if (0 == o)
+ {
+ return null;
+ }
+
+ var pos = this.__vector(o);
+ var len = this.__vector_len(o);
+ return bb.ToArraySegment(pos, len);
+ }
+#endif
+
+ // Get the data of a vector whoses offset is stored at "offset" in this object as an
+ // T[]. If the vector is not present in the ByteBuffer, then a null value will be
+ // returned.
+ public T[] __vector_as_array<T>(int offset)
+ where T : struct
+ {
+ if(!BitConverter.IsLittleEndian)
+ {
+ throw new NotSupportedException("Getting typed arrays on a Big Endian " +
+ "system is not support");
+ }
+
+ var o = this.__offset(offset);
+ if (0 == o)
+ {
+ return null;
+ }
+
+ var pos = this.__vector(o);
+ var len = this.__vector_len(o);
+ return bb.ToArray<T>(pos, len);
+ }
+
+ // Initialize any Table-derived type to point to the union at the given offset.
+ public T __union<T>(int offset) where T : struct, IFlatbufferObject
+ {
+ offset += bb_pos;
+ T t = new T();
+ t.__init(offset + bb.GetInt(offset), bb);
+ return t;
+ }
+
+ public static bool __has_identifier(ByteBuffer bb, string ident)
+ {
+ if (ident.Length != FlatBufferConstants.FileIdentifierLength)
+ throw new ArgumentException("FlatBuffers: file identifier must be length " + FlatBufferConstants.FileIdentifierLength, "ident");
+
+ for (var i = 0; i < FlatBufferConstants.FileIdentifierLength; i++)
+ {
+ if (ident[i] != (char)bb.Get(bb.Position + sizeof(int) + i)) return false;
+ }
+
+ return true;
+ }
+
+ // Compare strings in the ByteBuffer.
+ public static int CompareStrings(int offset_1, int offset_2, ByteBuffer bb)
+ {
+ offset_1 += bb.GetInt(offset_1);
+ offset_2 += bb.GetInt(offset_2);
+ var len_1 = bb.GetInt(offset_1);
+ var len_2 = bb.GetInt(offset_2);
+ var startPos_1 = offset_1 + sizeof(int);
+ var startPos_2 = offset_2 + sizeof(int);
+ var len = Math.Min(len_1, len_2);
+ for(int i = 0; i < len; i++) {
+ byte b1 = bb.Get(i + startPos_1);
+ byte b2 = bb.Get(i + startPos_2);
+ if (b1 != b2)
+ return b1 - b2;
+ }
+ return len_1 - len_2;
+ }
+
+ // Compare string from the ByteBuffer with the string object
+ public static int CompareStrings(int offset_1, byte[] key, ByteBuffer bb)
+ {
+ offset_1 += bb.GetInt(offset_1);
+ var len_1 = bb.GetInt(offset_1);
+ var len_2 = key.Length;
+ var startPos_1 = offset_1 + sizeof(int);
+ var len = Math.Min(len_1, len_2);
+ for (int i = 0; i < len; i++) {
+ byte b = bb.Get(i + startPos_1);
+ if (b != key[i])
+ return b - key[i];
+ }
+ return len_1 - len_2;
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..f95e754
--- /dev/null
+++ b/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "flatbuffers",
+ "version": "1.11.0",
+ "description": "Memory Efficient Serialization Library",
+ "files": [
+ "js/flatbuffers.js",
+ "js/flatbuffers.mjs"
+ ],
+ "main": "js/flatbuffers",
+ "module": "js/flatbuffers.mjs",
+ "directories": {
+ "doc": "docs",
+ "test": "tests"
+ },
+ "scripts": {
+ "test": "tests/JavaScriptTest.sh",
+ "append-esm-export": "sed \"s/this.flatbuffers = flatbuffers;/export { flatbuffers };/\" js/flatbuffers.js > js/flatbuffers.mjs",
+ "prepublishOnly": "npm run append-esm-export"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/google/flatbuffers.git"
+ },
+ "keywords": [
+ "flatbuffers"
+ ],
+ "author": "The FlatBuffers project",
+ "license": "SEE LICENSE IN LICENSE.txt",
+ "bugs": {
+ "url": "https://github.com/google/flatbuffers/issues"
+ },
+ "homepage": "https://google.github.io/flatbuffers/",
+ "dependencies": {}
+}
diff --git a/php/ByteBuffer.php b/php/ByteBuffer.php
new file mode 100644
index 0000000..9929a7d
--- /dev/null
+++ b/php/ByteBuffer.php
@@ -0,0 +1,493 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\FlatBuffers;
+
+class ByteBuffer
+{
+ /**
+ * @var string $_buffer;
+ */
+ public $_buffer;
+
+ /**
+ * @var int $_pos;
+ */
+ private $_pos;
+
+ /**
+ * @var bool $_is_little_endian
+ */
+ private static $_is_little_endian = null;
+
+ public static function wrap($bytes)
+ {
+ $bb = new ByteBuffer(0);
+ $bb->_buffer = $bytes;
+
+ return $bb;
+ }
+
+ /**
+ * @param $size
+ */
+ public function __construct($size)
+ {
+ $this->_buffer = str_repeat("\0", $size);
+ }
+
+ /**
+ * @return int
+ */
+ public function capacity()
+ {
+ return strlen($this->_buffer);
+ }
+
+ /**
+ * @return int
+ */
+ public function getPosition()
+ {
+ return $this->_pos;
+ }
+
+ /**
+ * @param $pos
+ */
+ public function setPosition($pos)
+ {
+ $this->_pos = $pos;
+ }
+
+ /**
+ *
+ */
+ public function reset()
+ {
+ $this->_pos = 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function length()
+ {
+ return strlen($this->_buffer);
+ }
+
+ /**
+ * @return string
+ */
+ public function data()
+ {
+ return substr($this->_buffer, $this->_pos);
+ }
+
+ /**
+ * @return bool
+ */
+ public static function isLittleEndian()
+ {
+ if (ByteBuffer::$_is_little_endian === null) {
+ ByteBuffer::$_is_little_endian = unpack('S', "\x01\x00")[1] === 1;
+ }
+
+ return ByteBuffer::$_is_little_endian;
+ }
+
+ /**
+ * write little endian value to the buffer.
+ *
+ * @param $offset
+ * @param $count byte length
+ * @param $data actual values
+ */
+ public function writeLittleEndian($offset, $count, $data)
+ {
+ if (ByteBuffer::isLittleEndian()) {
+ for ($i = 0; $i < $count; $i++) {
+ $this->_buffer[$offset + $i] = chr($data >> $i * 8);
+ }
+ } else {
+ for ($i = 0; $i < $count; $i++) {
+ $this->_buffer[$offset + $count - 1 - $i] = chr($data >> $i * 8);
+ }
+ }
+ }
+
+ /**
+ * read little endian value from the buffer
+ *
+ * @param $offset
+ * @param $count acutal size
+ * @return int
+ */
+ public function readLittleEndian($offset, $count, $force_bigendian = false)
+ {
+ $this->assertOffsetAndLength($offset, $count);
+ $r = 0;
+
+ if (ByteBuffer::isLittleEndian() && $force_bigendian == false) {
+ for ($i = 0; $i < $count; $i++) {
+ $r |= ord($this->_buffer[$offset + $i]) << $i * 8;
+ }
+ } else {
+ for ($i = 0; $i < $count; $i++) {
+ $r |= ord($this->_buffer[$offset + $count -1 - $i]) << $i * 8;
+ }
+ }
+
+ return $r;
+ }
+
+ /**
+ * @param $offset
+ * @param $length
+ */
+ public function assertOffsetAndLength($offset, $length)
+ {
+ if ($offset < 0 ||
+ $offset >= strlen($this->_buffer) ||
+ $offset + $length > strlen($this->_buffer)) {
+ throw new \OutOfRangeException(sprintf("offset: %d, length: %d, buffer; %d", $offset, $length, strlen($this->_buffer)));
+ }
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ * @return mixed
+ */
+ public function putSbyte($offset, $value)
+ {
+ self::validateValue(-128, 127, $value, "sbyte");
+
+ $length = strlen($value);
+ $this->assertOffsetAndLength($offset, $length);
+ return $this->_buffer[$offset] = $value;
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ * @return mixed
+ */
+ public function putByte($offset, $value)
+ {
+ self::validateValue(0, 255, $value, "byte");
+
+ $length = strlen($value);
+ $this->assertOffsetAndLength($offset, $length);
+ return $this->_buffer[$offset] = $value;
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function put($offset, $value)
+ {
+ $length = strlen($value);
+ $this->assertOffsetAndLength($offset, $length);
+ for ($i = 0; $i < $length; $i++) {
+ $this->_buffer[$offset + $i] = $value[$i];
+ }
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putShort($offset, $value)
+ {
+ self::validateValue(-32768, 32767, $value, "short");
+
+ $this->assertOffsetAndLength($offset, 2);
+ $this->writeLittleEndian($offset, 2, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putUshort($offset, $value)
+ {
+ self::validateValue(0, 65535, $value, "short");
+
+ $this->assertOffsetAndLength($offset, 2);
+ $this->writeLittleEndian($offset, 2, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putInt($offset, $value)
+ {
+ // 2147483647 = (1 << 31) -1 = Maximum signed 32-bit int
+ // -2147483648 = -1 << 31 = Minimum signed 32-bit int
+ self::validateValue(-2147483648, 2147483647, $value, "int");
+
+ $this->assertOffsetAndLength($offset, 4);
+ $this->writeLittleEndian($offset, 4, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putUint($offset, $value)
+ {
+ // NOTE: We can't put big integer value. this is PHP limitation.
+ // 4294967295 = (1 << 32) -1 = Maximum unsigned 32-bin int
+ self::validateValue(0, 4294967295, $value, "uint", " php has big numbers limitation. check your PHP_INT_MAX");
+
+ $this->assertOffsetAndLength($offset, 4);
+ $this->writeLittleEndian($offset, 4, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putLong($offset, $value)
+ {
+ // NOTE: We can't put big integer value. this is PHP limitation.
+ self::validateValue(~PHP_INT_MAX, PHP_INT_MAX, $value, "long", " php has big numbers limitation. check your PHP_INT_MAX");
+
+ $this->assertOffsetAndLength($offset, 8);
+ $this->writeLittleEndian($offset, 8, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putUlong($offset, $value)
+ {
+ // NOTE: We can't put big integer value. this is PHP limitation.
+ self::validateValue(0, PHP_INT_MAX, $value, "long", " php has big numbers limitation. check your PHP_INT_MAX");
+
+ $this->assertOffsetAndLength($offset, 8);
+ $this->writeLittleEndian($offset, 8, $value);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putFloat($offset, $value)
+ {
+ $this->assertOffsetAndLength($offset, 4);
+
+ $floathelper = pack("f", $value);
+ $v = unpack("V", $floathelper);
+ $this->writeLittleEndian($offset, 4, $v[1]);
+ }
+
+ /**
+ * @param $offset
+ * @param $value
+ */
+ public function putDouble($offset, $value)
+ {
+ $this->assertOffsetAndLength($offset, 8);
+
+ $floathelper = pack("d", $value);
+ $v = unpack("V*", $floathelper);
+
+ $this->writeLittleEndian($offset, 4, $v[1]);
+ $this->writeLittleEndian($offset + 4, 4, $v[2]);
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getByte($index)
+ {
+ return ord($this->_buffer[$index]);
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getSbyte($index)
+ {
+ $v = unpack("c", $this->_buffer[$index]);
+ return $v[1];
+ }
+
+ /**
+ * @param $buffer
+ */
+ public function getX(&$buffer)
+ {
+ for ($i = $this->_pos, $j = 0; $j < strlen($buffer); $i++, $j++) {
+ $buffer[$j] = $this->_buffer[$i];
+ }
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function get($index)
+ {
+ $this->assertOffsetAndLength($index, 1);
+ return $this->_buffer[$index];
+ }
+
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getBool($index)
+ {
+ return (bool)ord($this->_buffer[$index]);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getShort($index)
+ {
+ $result = $this->readLittleEndian($index, 2);
+
+ $sign = $index + (ByteBuffer::isLittleEndian() ? 1 : 0);
+ $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80;
+
+ // 65536 = 1 << 16 = Maximum unsigned 16-bit int
+ return $issigned ? $result - 65536 : $result;
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getUShort($index)
+ {
+ return $this->readLittleEndian($index, 2);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getInt($index)
+ {
+ $result = $this->readLittleEndian($index, 4);
+
+ $sign = $index + (ByteBuffer::isLittleEndian() ? 3 : 0);
+ $issigned = isset($this->_buffer[$sign]) && ord($this->_buffer[$sign]) & 0x80;
+
+ if (PHP_INT_SIZE > 4) {
+ // 4294967296 = 1 << 32 = Maximum unsigned 32-bit int
+ return $issigned ? $result - 4294967296 : $result;
+ } else {
+ // 32bit / Windows treated number as signed integer.
+ return $result;
+ }
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getUint($index)
+ {
+ return $this->readLittleEndian($index, 4);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getLong($index)
+ {
+ return $this->readLittleEndian($index, 8);
+ }
+
+ /**
+ * @param $index
+ * @return int
+ */
+ public function getUlong($index)
+ {
+ return $this->readLittleEndian($index, 8);
+ }
+
+ /**
+ * @param $index
+ * @return mixed
+ */
+ public function getFloat($index)
+ {
+ $i = $this->readLittleEndian($index, 4);
+
+ return self::convertHelper(self::__FLOAT, $i);
+ }
+
+ /**
+ * @param $index
+ * @return float
+ */
+ public function getDouble($index)
+ {
+ $i = $this->readLittleEndian($index, 4);
+ $i2 = $this->readLittleEndian($index + 4, 4);
+
+ return self::convertHelper(self::__DOUBLE, $i, $i2);
+ }
+
+ const __SHORT = 1;
+ const __INT = 2;
+ const __LONG = 3;
+ const __FLOAT = 4;
+ const __DOUBLE = 5;
+ private static function convertHelper($type, $value, $value2 = null) {
+ // readLittleEndian construct unsigned integer value from bytes. we have to encode this value to
+ // correct bytes, and decode as expected types with `unpack` function.
+ // then it returns correct type value.
+ // see also: http://php.net/manual/en/function.pack.php
+
+ switch ($type) {
+ case self::__FLOAT:
+ $inthelper = pack("V", $value);
+ $v = unpack("f", $inthelper);
+ return $v[1];
+ break;
+ case self::__DOUBLE:
+ $inthelper = pack("VV", $value, $value2);
+ $v = unpack("d", $inthelper);
+ return $v[1];
+ break;
+ default:
+ throw new \Exception(sprintf("unexpected type %d specified", $type));
+ }
+ }
+
+ private static function validateValue($min, $max, $value, $type, $additional_notes = "") {
+ if(!($min <= $value && $value <= $max)) {
+ throw new \InvalidArgumentException(sprintf("bad number %s for type %s.%s", $value, $type, $additional_notes));
+ }
+ }
+}
diff --git a/php/Constants.php b/php/Constants.php
new file mode 100644
index 0000000..ef3730d
--- /dev/null
+++ b/php/Constants.php
@@ -0,0 +1,25 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\FlatBuffers;
+
+class Constants
+{
+ const SIZEOF_SHORT = 2;
+ const SIZEOF_INT = 4;
+ const FILE_IDENTIFIER_LENGTH = 4;
+}
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
new file mode 100644
index 0000000..4fbc2bc
--- /dev/null
+++ b/php/FlatbufferBuilder.php
@@ -0,0 +1,977 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/// @file
+/// @addtogroup flatbuffers_php_api
+/// @{
+
+namespace Google\FlatBuffers;
+
+final class FlatbufferBuilder
+{
+ /**
+ * Internal ByteBuffer for the FlatBuffer data.
+ * @var ByteBuffer $bb
+ */
+ public $bb;
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * @var int $space
+ */
+ protected $space;
+
+ /**
+ * @var int $minalign
+ */
+ protected $minalign = 1;
+
+ /**
+ * @var array $vtable
+ */
+ protected $vtable;
+
+ /**
+ * @var int $vtable_in_use
+ */
+ protected $vtable_in_use = 0;
+
+ /**
+ * @var bool $nested
+ */
+ protected $nested = false;
+
+ /**
+ * @var int $object_start
+ */
+ protected $object_start;
+
+ /**
+ * @var array $vtables
+ */
+ protected $vtables = array();
+
+ /**
+ * @var int $num_vtables
+ */
+ protected $num_vtables = 0;
+
+ /**
+ * @var int $vector_num_elems
+ */
+ protected $vector_num_elems = 0;
+
+ /**
+ * @var bool $force_defaults
+ */
+ protected $force_defaults = false;
+ /// @endcond
+
+ /**
+ * Create a FlatBufferBuilder with a given initial size.
+ *
+ * @param $initial_size initial byte buffer size.
+ */
+ public function __construct($initial_size)
+ {
+ if ($initial_size <= 0) {
+ $initial_size = 1;
+ }
+ $this->space = $initial_size;
+ $this->bb = $this->newByteBuffer($initial_size);
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * create new bytebuffer
+ *
+ * @param $size
+ * @return ByteBuffer
+ */
+ private function newByteBuffer($size)
+ {
+ return new ByteBuffer($size);
+ }
+
+ /**
+ * Returns the current ByteBuffer offset.
+ *
+ * @return int
+ */
+ public function offset()
+ {
+ return $this->bb->capacity() - $this->space;
+ }
+
+ /**
+ * padding buffer
+ *
+ * @param $byte_size
+ */
+ public function pad($byte_size)
+ {
+ for ($i = 0; $i < $byte_size; $i++) {
+ $this->bb->putByte(--$this->space, "\0");
+ }
+ }
+
+ /**
+ * prepare bytebuffer
+ *
+ * @param $size
+ * @param $additional_bytes
+ * @throws \Exception
+ */
+ public function prep($size, $additional_bytes)
+ {
+ if ($size > $this->minalign) {
+ $this->minalign = $size;
+ }
+
+ $align_size = ((~($this->bb->capacity() - $this->space + $additional_bytes)) + 1) & ($size - 1);
+ while ($this->space < $align_size + $size + $additional_bytes) {
+ $old_buf_size = $this->bb->capacity();
+ $this->bb = $this->growByteBuffer($this->bb);
+ $this->space += $this->bb->capacity() - $old_buf_size;
+ }
+
+ $this->pad($align_size);
+ }
+
+ /**
+ * @param ByteBuffer $bb
+ * @return ByteBuffer
+ * @throws \Exception
+ */
+ private static function growByteBuffer(ByteBuffer $bb)
+ {
+ $old_buf_size = $bb->capacity();
+ if (($old_buf_size & 0xC0000000) != 0) {
+ throw new \Exception("FlatBuffers: cannot grow buffer beyond 2 gigabytes");
+ }
+ $new_buf_size = $old_buf_size << 1;
+
+ $bb->setPosition(0);
+ $nbb = new ByteBuffer($new_buf_size);
+
+ $nbb->setPosition($new_buf_size - $old_buf_size);
+
+ // TODO(chobie): is this little bit faster?
+ //$nbb->_buffer = substr_replace($nbb->_buffer, $bb->_buffer, $new_buf_size - $old_buf_size, strlen($bb->_buffer));
+ for ($i = $new_buf_size - $old_buf_size, $j = 0; $j < strlen($bb->_buffer); $i++, $j++) {
+ $nbb->_buffer[$i] = $bb->_buffer[$j];
+ }
+
+ return $nbb;
+ }
+
+ /**
+ * @param $x
+ */
+ public function putBool($x)
+ {
+ $this->bb->put($this->space -= 1, chr((int)(bool)($x)));
+ }
+
+ /**
+ * @param $x
+ */
+ public function putByte($x)
+ {
+ $this->bb->put($this->space -= 1, chr($x));
+ }
+
+ /**
+ * @param $x
+ */
+ public function putSbyte($x)
+ {
+ $this->bb->put($this->space -= 1, chr($x));
+ }
+
+ /**
+ * @param $x
+ */
+ public function putShort($x)
+ {
+ $this->bb->putShort($this->space -= 2, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putUshort($x)
+ {
+ $this->bb->putUshort($this->space -= 2, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putInt($x)
+ {
+ $this->bb->putInt($this->space -= 4, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putUint($x)
+ {
+ if ($x > PHP_INT_MAX) {
+ throw new \InvalidArgumentException("your platform can't handle uint correctly. use 64bit machine.");
+ }
+
+ $this->bb->putUint($this->space -= 4, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putLong($x)
+ {
+ if ($x > PHP_INT_MAX) {
+ throw new \InvalidArgumentException("Your platform can't handle long correctly. Use a 64bit machine.");
+ }
+
+ $this->bb->putLong($this->space -= 8, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putUlong($x)
+ {
+ if ($x > PHP_INT_MAX) {
+ throw new \InvalidArgumentException("Your platform can't handle ulong correctly. This is a php limitation. Please wait for the extension release.");
+ }
+
+ $this->bb->putUlong($this->space -= 8, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putFloat($x)
+ {
+ $this->bb->putFloat($this->space -= 4, $x);
+ }
+
+ /**
+ * @param $x
+ */
+ public function putDouble($x)
+ {
+ $this->bb->putDouble($this->space -= 8, $x);
+ }
+
+ /**
+ * @param $off
+ */
+ public function putOffset($off)
+ {
+ $new_off = $this->offset() - $off + Constants::SIZEOF_INT;
+ $this->putInt($new_off);
+ }
+ /// @endcond
+
+ /**
+ * Add a `bool` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `bool` to add to the buffer.
+ */
+ public function addBool($x)
+ {
+ $this->prep(1, 0);
+ $this->putBool($x);
+ }
+
+ /**
+ * Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `byte` to add to the buffer.
+ */
+ public function addByte($x)
+ {
+ $this->prep(1, 0);
+ $this->putByte($x);
+ }
+
+ /**
+ * Add a `signed byte` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `signed byte` to add to the buffer.
+ */
+ public function addSbyte($x)
+ {
+ $this->prep(1, 0);
+ $this->putSbyte($x);
+ }
+
+ /**
+ * Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `short` to add to the buffer.
+ */
+ public function addShort($x)
+ {
+ $this->prep(2, 0);
+ $this->putShort($x);
+ }
+
+ /**
+ * Add an `unsigned short` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `unsigned short` to add to the buffer.
+ */
+ public function addUshort($x)
+ {
+ $this->prep(2, 0);
+ $this->putUshort($x);
+ }
+
+ /**
+ * Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `int` to add to the buffer.
+ */
+ public function addInt($x)
+ {
+ $this->prep(4, 0);
+ $this->putInt($x);
+ }
+
+ /**
+ * Add an `unsigned int` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `unsigned int` to add to the buffer.
+ */
+ public function addUint($x)
+ {
+ $this->prep(4, 0);
+ $this->putUint($x);
+ }
+
+ /**
+ * Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `long` to add to the buffer.
+ */
+ public function addLong($x)
+ {
+ $this->prep(8, 0);
+ $this->putLong($x);
+ }
+
+ /**
+ * Add an `unsigned long` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `unsigned long` to add to the buffer.
+ */
+ public function addUlong($x)
+ {
+ $this->prep(8, 0);
+ $this->putUlong($x);
+ }
+
+ /**
+ * Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `float` to add to the buffer.
+ */
+ public function addFloat($x)
+ {
+ $this->prep(4, 0);
+ $this->putFloat($x);
+ }
+
+ /**
+ * Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
+ * @param $x The `double` to add to the buffer.
+ */
+ public function addDouble($x)
+ {
+ $this->prep(8, 0);
+ $this->putDouble($x);
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addBoolX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addBool($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addByteX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addByte($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addSbyteX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addSbyte($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addShortX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addShort($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addUshortX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addUshort($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addIntX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addInt($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addUintX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addUint($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addLongX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addLong($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addUlongX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addUlong($x);
+ $this->slot($o);
+ }
+ }
+
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addFloatX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addFloat($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ */
+ public function addDoubleX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addDouble($x);
+ $this->slot($o);
+ }
+ }
+
+ /**
+ * @param $o
+ * @param $x
+ * @param $d
+ * @throws \Exception
+ */
+ public function addOffsetX($o, $x, $d)
+ {
+ if ($this->force_defaults || $x != $d) {
+ $this->addOffset($x);
+ $this->slot($o);
+ }
+ }
+ /// @endcond
+
+ /**
+ * Adds on offset, relative to where it will be written.
+ * @param $off The offset to add to the buffer.
+ * @throws \Exception Throws an exception if `$off` is greater than the underlying ByteBuffer's
+ * offest.
+ */
+ public function addOffset($off)
+ {
+ $this->prep(Constants::SIZEOF_INT, 0); // Ensure alignment is already done
+ if ($off > $this->offset()) {
+ throw new \Exception("");
+ }
+ $this->putOffset($off);
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * @param $elem_size
+ * @param $num_elems
+ * @param $alignment
+ * @throws \Exception
+ */
+ public function startVector($elem_size, $num_elems, $alignment)
+ {
+ $this->notNested();
+ $this->vector_num_elems = $num_elems;
+ $this->prep(Constants::SIZEOF_INT, $elem_size * $num_elems);
+ $this->prep($alignment, $elem_size * $num_elems); // Just in case alignemnt > int;
+ }
+
+ /**
+ * @return int
+ */
+ public function endVector()
+ {
+ $this->putUint($this->vector_num_elems);
+ return $this->offset();
+ }
+
+ protected function is_utf8($bytes)
+ {
+ if (function_exists('mb_detect_encoding')) {
+ return (bool) mb_detect_encoding($bytes, 'UTF-8', true);
+ }
+
+ $len = strlen($bytes);
+ if ($len < 1) {
+ /* NOTE: always return 1 when passed string is null */
+ return true;
+ }
+
+ for ($j = 0, $i = 0; $i < $len; $i++) {
+ // check ACII
+ if ($bytes[$j] == "\x09" ||
+ $bytes[$j] == "\x0A" ||
+ $bytes[$j] == "\x0D" ||
+ ($bytes[$j] >= "\x20" && $bytes[$j] <= "\x7E")) {
+ $j++;
+ continue;
+ }
+
+ /* non-overlong 2-byte */
+ if ((($i+1) <= $len) &&
+ ($bytes[$j] >= "\xC2" && $bytes[$j] <= "\xDF" &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF"))) {
+ $j += 2;
+ $i++;
+ continue;
+ }
+
+ /* excluding overlongs */
+ if ((($i + 2) <= $len) &&
+ $bytes[$j] == "\xE0" &&
+ ($bytes[$j+1] >= "\xA0" && $bytes[$j+1] <= "\xBF" &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
+ $bytes += 3;
+ $i +=2;
+ continue;
+ }
+
+ /* straight 3-byte */
+ if ((($i+2) <= $len) &&
+ (($bytes[$j] >= "\xE1" && $bytes[$j] <= "\xEC") ||
+ $bytes[$j] == "\xEE" ||
+ $bytes[$j] = "\xEF") &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF") &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF")) {
+ $j += 3;
+ $i += 2;
+ continue;
+ }
+
+ /* excluding surrogates */
+ if ((($i+2) <= $len) &&
+ $bytes[$j] == "\xED" &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x9f" &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF"))) {
+ $j += 3;
+ $i += 2;
+ continue;
+ }
+
+ /* planes 1-3 */
+ if ((($i + 3) <= $len) &&
+ $bytes[$j] == "\xF0" &&
+ ($bytes[$j+1] >= "\x90" && $bytes[$j+1] <= "\xBF") &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
+ ($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")) {
+ $j += 4;
+ $i += 3;
+ continue;
+ }
+
+
+ /* planes 4-15 */
+ if ((($i+3) <= $len) &&
+ $bytes[$j] >= "\xF1" && $bytes[$j] <= "\xF3" &&
+ $bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\xBF" &&
+ $bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF" &&
+ $bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF"
+ ) {
+ $j += 4;
+ $i += 3;
+ continue;
+ }
+
+ /* plane 16 */
+ if ((($i+3) <= $len) &&
+ $bytes[$j] == "\xF4" &&
+ ($bytes[$j+1] >= "\x80" && $bytes[$j+1] <= "\x8F") &&
+ ($bytes[$j+2] >= "\x80" && $bytes[$j+2] <= "\xBF") &&
+ ($bytes[$j+3] >= "\x80" && $bytes[$j+3] <= "\xBF")
+ ) {
+ $bytes += 4;
+ $i += 3;
+ continue;
+ }
+
+
+ return false;
+ }
+
+ return true;
+ }
+ /// @endcond
+
+ /**
+ * Encode the string `$s` in the buffer using UTF-8.
+ * @param string $s The string to encode.
+ * @return int The offset in the buffer where the encoded string starts.
+ * @throws InvalidArgumentException Thrown if the input string `$s` is not
+ * UTF-8.
+ */
+ public function createString($s)
+ {
+ if (!$this->is_utf8($s)) {
+ throw new \InvalidArgumentException("string must be utf-8 encoded value.");
+ }
+
+ $this->notNested();
+ $this->addByte(0); // null terminated
+ $this->startVector(1, strlen($s), 1);
+ $this->space -= strlen($s);
+ for ($i = $this->space, $j = 0 ; $j < strlen($s) ; $i++, $j++) {
+ $this->bb->_buffer[$i] = $s[$j];
+ }
+ return $this->endVector();
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * @throws \Exception
+ */
+ public function notNested()
+ {
+ if ($this->nested) {
+ throw new \Exception("FlatBuffers; object serialization must not be nested");
+ }
+ }
+
+ /**
+ * @param $obj
+ * @throws \Exception
+ */
+ public function nested($obj)
+ {
+ if ($obj != $this->offset()) {
+ throw new \Exception("FlatBuffers: struct must be serialized inline");
+ }
+ }
+
+ /**
+ * @param $numfields
+ * @throws \Exception
+ */
+ public function startObject($numfields)
+ {
+ $this->notNested();
+ if ($this->vtable == null || count($this->vtable) < $numfields) {
+ $this->vtable = array();
+ }
+
+ $this->vtable_in_use = $numfields;
+ for ($i = 0; $i < $numfields; $i++) {
+ $this->vtable[$i] = 0;
+ }
+
+ $this->nested = true;
+ $this->object_start = $this->offset();
+ }
+
+ /**
+ * @param $voffset
+ * @param $x
+ * @param $d
+ * @throws \Exception
+ */
+ public function addStructX($voffset, $x, $d)
+ {
+ if ($x != $d) {
+ $this->nested($x);
+ $this->slot($voffset);
+ }
+ }
+
+ /**
+ * @param $voffset
+ * @param $x
+ * @param $d
+ * @throws \Exception
+ */
+ public function addStruct($voffset, $x, $d)
+ {
+ if ($x != $d) {
+ $this->nested($x);
+ $this->slot($voffset);
+ }
+ }
+
+ /**
+ * @param $voffset
+ */
+ public function slot($voffset)
+ {
+ $this->vtable[$voffset] = $this->offset();
+ }
+
+ /**
+ * @return int
+ * @throws \Exception
+ */
+ public function endObject()
+ {
+ if ($this->vtable == null || !$this->nested) {
+ throw new \Exception("FlatBuffers: endObject called without startObject");
+ }
+
+ $this->addInt(0);
+ $vtableloc = $this->offset();
+
+ $i = $this->vtable_in_use -1;
+ // Trim trailing zeroes.
+ for (; $i >= 0 && $this->vtable[$i] == 0; $i--) {}
+ $trimmed_size = $i + 1;
+ for (; $i >= 0; $i--) {
+ $off = ($this->vtable[$i] != 0) ? $vtableloc - $this->vtable[$i] : 0;
+ $this->addShort($off);
+ }
+
+ $standard_fields = 2; // the fields below
+ $this->addShort($vtableloc - $this->object_start);
+ $this->addShort(($trimmed_size + $standard_fields) * Constants::SIZEOF_SHORT);
+
+ // search for an existing vtable that matches the current one.
+ $existing_vtable = 0;
+
+ for ($i = 0; $i < $this->num_vtables; $i++) {
+ $vt1 = $this->bb->capacity() - $this->vtables[$i];
+ $vt2 = $this->space;
+
+ $len = $this->bb->getShort($vt1);
+
+ if ($len == $this->bb->getShort($vt2)) {
+ for ($j = Constants::SIZEOF_SHORT; $j < $len; $j += Constants::SIZEOF_SHORT) {
+ if ($this->bb->getShort($vt1 + $j) != $this->bb->getShort($vt2 + $j)) {
+ continue 2;
+ }
+ }
+ $existing_vtable = $this->vtables[$i];
+ break;
+ }
+ }
+
+ if ($existing_vtable != 0) {
+ // Found a match:
+ // Remove the current vtable
+ $this->space = $this->bb->capacity() - $vtableloc;
+ $this->bb->putInt($this->space, $existing_vtable - $vtableloc);
+ } else {
+ // No Match:
+ // Add the location of the current vtable to the list of vtables
+ if ($this->num_vtables == count($this->vtables)) {
+ $vtables = $this->vtables;
+ $this->vtables = array();
+ // copy of
+ for ($i = 0; $i < count($vtables) * 2; $i++) {
+ $this->vtables[$i] = ($i < count($vtables)) ? $vtables[$i] : 0;
+ }
+ }
+ $this->vtables[$this->num_vtables++] = $this->offset();
+ $this->bb->putInt($this->bb->capacity() - $vtableloc, $this->offset() - $vtableloc);
+ }
+
+ $this->nested = false;
+ $this->vtable = null;
+ return $vtableloc;
+ }
+
+ /**
+ * @param $table
+ * @param $field
+ * @throws \Exception
+ */
+ public function required($table, $field)
+ {
+ $table_start = $this->bb->capacity() - $table;
+ $vtable_start = $table_start - $this->bb->getInt($table_start);
+ $ok = $this->bb->getShort($vtable_start + $field) != 0;
+
+ if (!$ok) {
+ throw new \Exception("FlatBuffers: field " . $field . " must be set");
+ }
+ }
+ /// @endcond
+
+ /**
+ * Finalize a buffer, pointing to the given `$root_table`.
+ * @param $root_table An offest to be added to the buffer.
+ * @param $file_identifier A FlatBuffer file identifier to be added to the
+ * buffer before `$root_table`. This defaults to `null`.
+ * @throws InvalidArgumentException Thrown if an invalid `$identifier` is
+ * given, where its length is not equal to
+ * `Constants::FILE_IDENTIFIER_LENGTH`.
+ */
+ public function finish($root_table, $identifier = null)
+ {
+ if ($identifier == null) {
+ $this->prep($this->minalign, Constants::SIZEOF_INT);
+ $this->addOffset($root_table);
+ $this->bb->setPosition($this->space);
+ } else {
+ $this->prep($this->minalign, Constants::SIZEOF_INT + Constants::FILE_IDENTIFIER_LENGTH);
+ if (strlen($identifier) != Constants::FILE_IDENTIFIER_LENGTH) {
+ throw new \InvalidArgumentException(
+ sprintf("FlatBuffers: file identifier must be length %d",
+ Constants::FILE_IDENTIFIER_LENGTH));
+ }
+
+ for ($i = Constants::FILE_IDENTIFIER_LENGTH - 1; $i >= 0;
+ $i--) {
+ $this->addByte(ord($identifier[$i]));
+ }
+ $this->finish($root_table);
+ }
+ }
+
+ /**
+ * In order to save space, fields that are set to their default value don't
+ * get serialized into the buffer.
+ * @param bool $forceDefaults When set to `true`, always serializes default
+ * values.
+ */
+ public function forceDefaults($forceDefaults)
+ {
+ $this->force_defaults = $forceDefaults;
+ }
+
+ /**
+ * Get the ByteBuffer representing the FlatBuffer.
+ * @return ByteBuffer The ByteBuffer containing the FlatBuffer data.
+ */
+ public function dataBuffer()
+ {
+ return $this->bb;
+ }
+
+ /// @cond FLATBUFFERS_INTERNAL
+ /**
+ * @return int
+ */
+ public function dataStart()
+ {
+ return $this->space;
+ }
+ /// @endcond
+
+ /**
+ * Utility function to copy and return the FlatBuffer data from the
+ * underlying ByteBuffer.
+ * @return string A string (representing a byte[]) that contains a copy
+ * of the FlatBuffer data.
+ */
+ public function sizedByteArray()
+ {
+ $start = $this->space;
+ $length = $this->bb->capacity() - $this->space;
+
+ $result = str_repeat("\0", $length);
+ $this->bb->setPosition($start);
+ $this->bb->getX($result);
+
+ return $result;
+ }
+}
+
+/// @}
diff --git a/php/Struct.php b/php/Struct.php
new file mode 100644
index 0000000..cd7652e
--- /dev/null
+++ b/php/Struct.php
@@ -0,0 +1,41 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\FlatBuffers;
+
+abstract class Struct
+{
+ /**
+ * @var int $bb_pos
+ */
+ protected $bb_pos;
+
+ /**
+ * @var ByteBuffer $bb
+ */
+ protected $bb;
+
+ public function setByteBufferPos($pos)
+ {
+ $this->bb_pos = $pos;
+ }
+
+ public function setByteBuffer($bb)
+ {
+ $this->bb = $bb;
+ }
+}
diff --git a/php/Table.php b/php/Table.php
new file mode 100644
index 0000000..bf6fe21
--- /dev/null
+++ b/php/Table.php
@@ -0,0 +1,145 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\FlatBuffers;
+
+abstract class Table
+{
+ /**
+ * @var int $bb_pos
+ */
+ protected $bb_pos;
+ /**
+ * @var ByteBuffer $bb
+ */
+ protected $bb;
+
+ public function __construct()
+ {
+ }
+
+ public function setByteBufferPos($pos)
+ {
+ $this->bb_pos = $pos;
+ }
+
+ public function setByteBuffer($bb)
+ {
+ $this->bb = $bb;
+ }
+
+ /**
+ * returns actual vtable offset
+ *
+ * @param $vtable_offset
+ * @return int offset > 0 means exist value. 0 means not exist
+ */
+ protected function __offset($vtable_offset)
+ {
+ $vtable = $this->bb_pos - $this->bb->getInt($this->bb_pos);
+ return $vtable_offset < $this->bb->getShort($vtable) ? $this->bb->getShort($vtable + $vtable_offset) : 0;
+ }
+
+ /**
+ * @param $offset
+ * @return mixed
+ */
+ protected function __indirect($offset)
+ {
+ return $offset + $this->bb->getInt($offset);
+ }
+
+ /**
+ * fetch utf8 encoded string.
+ *
+ * @param $offset
+ * @return string
+ */
+ protected function __string($offset)
+ {
+ $offset += $this->bb->getInt($offset);
+ $len = $this->bb->getInt($offset);
+ $startPos = $offset + Constants::SIZEOF_INT;
+ return substr($this->bb->_buffer, $startPos, $len);
+ }
+
+ /**
+ * @param $offset
+ * @return int
+ */
+ protected function __vector_len($offset)
+ {
+ $offset += $this->bb_pos;
+ $offset += $this->bb->getInt($offset);
+ return $this->bb->getInt($offset);
+ }
+
+ /**
+ * @param $offset
+ * @return int
+ */
+ protected function __vector($offset)
+ {
+ $offset += $this->bb_pos;
+ // data starts after the length
+ return $offset + $this->bb->getInt($offset) + Constants::SIZEOF_INT;
+ }
+
+ protected function __vector_as_bytes($vector_offset, $elem_size=1)
+ {
+ $o = $this->__offset($vector_offset);
+ if ($o == 0) {
+ return null;
+ }
+
+ return substr($this->bb->_buffer, $this->__vector($o), $this->__vector_len($o) * $elem_size);
+ }
+
+ /**
+ * @param Table $table
+ * @param int $offset
+ * @return Table
+ */
+ protected function __union($table, $offset)
+ {
+ $offset += $this->bb_pos;
+ $table->setByteBufferPos($offset + $this->bb->getInt($offset));
+ $table->setByteBuffer($this->bb);
+ return $table;
+ }
+
+ /**
+ * @param ByteBuffer $bb
+ * @param string $ident
+ * @return bool
+ * @throws \ArgumentException
+ */
+ protected static function __has_identifier($bb, $ident)
+ {
+ if (strlen($ident) != Constants::FILE_IDENTIFIER_LENGTH) {
+ throw new \ArgumentException("FlatBuffers: file identifier must be length " . Constants::FILE_IDENTIFIER_LENGTH);
+ }
+
+ for ($i = 0; $i < 4; $i++) {
+ if ($ident[$i] != $bb->get($bb->getPosition() + Constants::SIZEOF_INT + $i)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..cb410cc
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.google.flatbuffers</groupId>
+ <artifactId>flatbuffers-java</artifactId>
+ <version>1.11.1</version>
+ <packaging>bundle</packaging>
+ <name>FlatBuffers Java API</name>
+ <description>
+ Memory Efficient Serialization Library
+ </description>
+ <developers>
+ <developer>
+ <name>Wouter van Oortmerssen</name>
+ </developer>
+ </developers>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <url>https://github.com/google/flatbuffers</url>
+ <licenses>
+ <license>
+ <name>Apache License V2.0</name>
+ <url>https://raw.githubusercontent.com/google/flatbuffers/master/LICENSE.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <url>https://github.com/google/flatbuffers</url>
+ <connection>
+ scm:git:https://github.com/google/flatbuffers.git
+ </connection>
+ <tag>HEAD</tag>
+ </scm>
+ <dependencies>
+ </dependencies>
+ <distributionManagement>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ </distributionManagement>
+ <build>
+ <sourceDirectory>java</sourceDirectory>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ </configuration>
+ <version>3.2</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ <version>2.18.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.3</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <configuration>
+ <additionalparam>-Xdoclint:none</additionalparam>
+ <additionalOptions>-Xdoclint:none</additionalOptions>
+ </configuration>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>3.0.1</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.7</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>ossrh</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>true</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.3</version>
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ <useReleaseProfile>false</useReleaseProfile>
+ <releaseProfiles>release</releaseProfiles>
+ <goals>deploy</goals>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
+
diff --git a/python/.gitignore b/python/.gitignore
new file mode 100644
index 0000000..a771946
--- /dev/null
+++ b/python/.gitignore
@@ -0,0 +1,2 @@
+/dist/
+/*.egg-info/
diff --git a/python/__init__.py b/python/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/__init__.py
diff --git a/python/flatbuffers/__init__.py b/python/flatbuffers/__init__.py
new file mode 100644
index 0000000..d14872a
--- /dev/null
+++ b/python/flatbuffers/__init__.py
@@ -0,0 +1,17 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from .builder import Builder
+from .table import Table
+from .compat import range_func as compat_range
diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py
new file mode 100644
index 0000000..d04ee85
--- /dev/null
+++ b/python/flatbuffers/builder.py
@@ -0,0 +1,755 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from . import number_types as N
+from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags)
+
+from . import encode
+from . import packer
+
+from . import compat
+from .compat import range_func
+from .compat import memoryview_type
+from .compat import import_numpy, NumpyRequiredForThisFeature
+
+np = import_numpy()
+## @file
+## @addtogroup flatbuffers_python_api
+## @{
+
+## @cond FLATBUFFERS_INTERNAL
+class OffsetArithmeticError(RuntimeError):
+ """
+ Error caused by an Offset arithmetic error. Probably caused by bad
+ writing of fields. This is considered an unreachable situation in
+ normal circumstances.
+ """
+ pass
+
+
+class IsNotNestedError(RuntimeError):
+ """
+ Error caused by using a Builder to write Object data when not inside
+ an Object.
+ """
+ pass
+
+
+class IsNestedError(RuntimeError):
+ """
+ Error caused by using a Builder to begin an Object when an Object is
+ already being built.
+ """
+ pass
+
+
+class StructIsNotInlineError(RuntimeError):
+ """
+ Error caused by using a Builder to write a Struct at a location that
+ is not the current Offset.
+ """
+ pass
+
+
+class BuilderSizeError(RuntimeError):
+ """
+ Error caused by causing a Builder to exceed the hardcoded limit of 2
+ gigabytes.
+ """
+ pass
+
+class BuilderNotFinishedError(RuntimeError):
+ """
+ Error caused by not calling `Finish` before calling `Output`.
+ """
+ pass
+
+
+# VtableMetadataFields is the count of metadata fields in each vtable.
+VtableMetadataFields = 2
+## @endcond
+
+class Builder(object):
+ """ A Builder is used to construct one or more FlatBuffers.
+
+ Typically, Builder objects will be used from code generated by the `flatc`
+ compiler.
+
+ A Builder constructs byte buffers in a last-first manner for simplicity and
+ performance during reading.
+
+ Internally, a Builder is a state machine for creating FlatBuffer objects.
+
+ It holds the following internal state:
+ - Bytes: an array of bytes.
+ - current_vtable: a list of integers.
+ - vtables: a hash of vtable entries.
+
+ Attributes:
+ Bytes: The internal `bytearray` for the Builder.
+ finished: A boolean determining if the Builder has been finalized.
+ """
+
+ ## @cond FLATBUFFERS_INTENRAL
+ __slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd",
+ "vtables", "nested", "finished")
+
+ """Maximum buffer size constant, in bytes.
+
+ Builder will never allow it's buffer grow over this size.
+ Currently equals 2Gb.
+ """
+ MAX_BUFFER_SIZE = 2**31
+ ## @endcond
+
+ def __init__(self, initialSize):
+ """Initializes a Builder of size `initial_size`.
+
+ The internal buffer is grown as needed.
+ """
+
+ if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE):
+ msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes."
+ raise BuilderSizeError(msg)
+
+ self.Bytes = bytearray(initialSize)
+ ## @cond FLATBUFFERS_INTERNAL
+ self.current_vtable = None
+ self.head = UOffsetTFlags.py_type(initialSize)
+ self.minalign = 1
+ self.objectEnd = None
+ self.vtables = {}
+ self.nested = False
+ ## @endcond
+ self.finished = False
+
+
+ def Output(self):
+ """Return the portion of the buffer that has been used for writing data.
+
+ This is the typical way to access the FlatBuffer data inside the
+ builder. If you try to access `Builder.Bytes` directly, you would need
+ to manually index it with `Head()`, since the buffer is constructed
+ backwards.
+
+ It raises BuilderNotFinishedError if the buffer has not been finished
+ with `Finish`.
+ """
+
+ if not self.finished:
+ raise BuilderNotFinishedError()
+
+ return self.Bytes[self.Head():]
+
+ ## @cond FLATBUFFERS_INTERNAL
+ def StartObject(self, numfields):
+ """StartObject initializes bookkeeping for writing a new object."""
+
+ self.assertNotNested()
+
+ # use 32-bit offsets so that arithmetic doesn't overflow.
+ self.current_vtable = [0 for _ in range_func(numfields)]
+ self.objectEnd = self.Offset()
+ self.nested = True
+
+ def WriteVtable(self):
+ """
+ WriteVtable serializes the vtable for the current object, if needed.
+
+ Before writing out the vtable, this checks pre-existing vtables for
+ equality to this one. If an equal vtable is found, point the object to
+ the existing vtable and return.
+
+ Because vtable values are sensitive to alignment of object data, not
+ all logically-equal vtables will be deduplicated.
+
+ A vtable has the following format:
+ <VOffsetT: size of the vtable in bytes, including this value>
+ <VOffsetT: size of the object in bytes, including the vtable offset>
+ <VOffsetT: offset for a field> * N, where N is the number of fields
+ in the schema for this type. Includes deprecated fields.
+ Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide.
+
+ An object has the following format:
+ <SOffsetT: offset to this object's vtable (may be negative)>
+ <byte: data>+
+ """
+
+ # Prepend a zero scalar to the object. Later in this function we'll
+ # write an offset here that points to the object's vtable:
+ self.PrependSOffsetTRelative(0)
+
+ objectOffset = self.Offset()
+
+ vtKey = []
+ trim = True
+ for elem in reversed(self.current_vtable):
+ if elem == 0:
+ if trim:
+ continue
+ else:
+ elem = objectOffset - elem
+ trim = False
+
+ vtKey.append(elem)
+
+ vtKey = tuple(vtKey)
+ vt2Offset = self.vtables.get(vtKey)
+ if vt2Offset is None:
+ # Did not find a vtable, so write this one to the buffer.
+
+ # Write out the current vtable in reverse , because
+ # serialization occurs in last-first order:
+ i = len(self.current_vtable) - 1
+ trailing = 0
+ trim = True
+ while i >= 0:
+ off = 0
+ elem = self.current_vtable[i]
+ i -= 1
+
+ if elem == 0:
+ if trim:
+ trailing += 1
+ continue
+ else:
+ # Forward reference to field;
+ # use 32bit number to ensure no overflow:
+ off = objectOffset - elem
+ trim = False
+
+ self.PrependVOffsetT(off)
+
+ # The two metadata fields are written last.
+
+ # First, store the object bytesize:
+ objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd)
+ self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize))
+
+ # Second, store the vtable bytesize:
+ vBytes = len(self.current_vtable) - trailing + VtableMetadataFields
+ vBytes *= N.VOffsetTFlags.bytewidth
+ self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes))
+
+ # Next, write the offset to the new vtable in the
+ # already-allocated SOffsetT at the beginning of this object:
+ objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
+ encode.Write(packer.soffset, self.Bytes, objectStart,
+ SOffsetTFlags.py_type(self.Offset() - objectOffset))
+
+ # Finally, store this vtable in memory for future
+ # deduplication:
+ self.vtables[vtKey] = self.Offset()
+ else:
+ # Found a duplicate vtable.
+ objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
+ self.head = UOffsetTFlags.py_type(objectStart)
+
+ # Write the offset to the found vtable in the
+ # already-allocated SOffsetT at the beginning of this object:
+ encode.Write(packer.soffset, self.Bytes, self.Head(),
+ SOffsetTFlags.py_type(vt2Offset - objectOffset))
+
+ self.current_vtable = None
+ return objectOffset
+
+ def EndObject(self):
+ """EndObject writes data necessary to finish object construction."""
+ self.assertNested()
+ self.nested = False
+ return self.WriteVtable()
+
+ def growByteBuffer(self):
+ """Doubles the size of the byteslice, and copies the old data towards
+ the end of the new buffer (since we build the buffer backwards)."""
+ if len(self.Bytes) == Builder.MAX_BUFFER_SIZE:
+ msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes"
+ raise BuilderSizeError(msg)
+
+ newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE)
+ if newSize == 0:
+ newSize = 1
+ bytes2 = bytearray(newSize)
+ bytes2[newSize-len(self.Bytes):] = self.Bytes
+ self.Bytes = bytes2
+ ## @endcond
+
+ def Head(self):
+ """Get the start of useful data in the underlying byte buffer.
+
+ Note: unlike other functions, this value is interpreted as from the
+ left.
+ """
+ ## @cond FLATBUFFERS_INTERNAL
+ return self.head
+ ## @endcond
+
+ ## @cond FLATBUFFERS_INTERNAL
+ def Offset(self):
+ """Offset relative to the end of the buffer."""
+ return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
+
+ def Pad(self, n):
+ """Pad places zeros at the current offset."""
+ for i in range_func(n):
+ self.Place(0, N.Uint8Flags)
+
+ def Prep(self, size, additionalBytes):
+ """
+ Prep prepares to write an element of `size` after `additional_bytes`
+ have been written, e.g. if you write a string, you need to align
+ such the int length field is aligned to SizeInt32, and the string
+ data follows it directly.
+ If all you need to do is align, `additionalBytes` will be 0.
+ """
+
+ # Track the biggest thing we've ever aligned to.
+ if size > self.minalign:
+ self.minalign = size
+
+ # Find the amount of alignment needed such that `size` is properly
+ # aligned after `additionalBytes`:
+ alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1
+ alignSize &= (size - 1)
+
+ # Reallocate the buffer if needed:
+ while self.Head() < alignSize+size+additionalBytes:
+ oldBufSize = len(self.Bytes)
+ self.growByteBuffer()
+ updated_head = self.head + len(self.Bytes) - oldBufSize
+ self.head = UOffsetTFlags.py_type(updated_head)
+ self.Pad(alignSize)
+
+ def PrependSOffsetTRelative(self, off):
+ """
+ PrependSOffsetTRelative prepends an SOffsetT, relative to where it
+ will be written.
+ """
+
+ # Ensure alignment is already done:
+ self.Prep(N.SOffsetTFlags.bytewidth, 0)
+ if not (off <= self.Offset()):
+ msg = "flatbuffers: Offset arithmetic error."
+ raise OffsetArithmeticError(msg)
+ off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
+ self.PlaceSOffsetT(off2)
+ ## @endcond
+
+ def PrependUOffsetTRelative(self, off):
+ """Prepends an unsigned offset into vector data, relative to where it
+ will be written.
+ """
+
+ # Ensure alignment is already done:
+ self.Prep(N.UOffsetTFlags.bytewidth, 0)
+ if not (off <= self.Offset()):
+ msg = "flatbuffers: Offset arithmetic error."
+ raise OffsetArithmeticError(msg)
+ off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
+ self.PlaceUOffsetT(off2)
+
+ ## @cond FLATBUFFERS_INTERNAL
+ def StartVector(self, elemSize, numElems, alignment):
+ """
+ StartVector initializes bookkeeping for writing a new vector.
+
+ A vector has the following format:
+ - <UOffsetT: number of elements in this vector>
+ - <T: data>+, where T is the type of elements of this vector.
+ """
+
+ self.assertNotNested()
+ self.nested = True
+ self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems)
+ self.Prep(alignment, elemSize*numElems) # In case alignment > int.
+ return self.Offset()
+ ## @endcond
+
+ def EndVector(self, vectorNumElems):
+ """EndVector writes data necessary to finish vector construction."""
+
+ self.assertNested()
+ ## @cond FLATBUFFERS_INTERNAL
+ self.nested = False
+ ## @endcond
+ # we already made space for this, so write without PrependUint32
+ self.PlaceUOffsetT(vectorNumElems)
+ return self.Offset()
+
+ def CreateString(self, s, encoding='utf-8', errors='strict'):
+ """CreateString writes a null-terminated byte string as a vector."""
+
+ self.assertNotNested()
+ ## @cond FLATBUFFERS_INTERNAL
+ self.nested = True
+ ## @endcond
+
+ if isinstance(s, compat.string_types):
+ x = s.encode(encoding, errors)
+ elif isinstance(s, compat.binary_types):
+ x = s
+ else:
+ raise TypeError("non-string passed to CreateString")
+
+ self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth)
+ self.Place(0, N.Uint8Flags)
+
+ l = UOffsetTFlags.py_type(len(s))
+ ## @cond FLATBUFFERS_INTERNAL
+ self.head = UOffsetTFlags.py_type(self.Head() - l)
+ ## @endcond
+ self.Bytes[self.Head():self.Head()+l] = x
+
+ return self.EndVector(len(x))
+
+ def CreateByteVector(self, x):
+ """CreateString writes a byte vector."""
+
+ self.assertNotNested()
+ ## @cond FLATBUFFERS_INTERNAL
+ self.nested = True
+ ## @endcond
+
+ if not isinstance(x, compat.binary_types):
+ raise TypeError("non-byte vector passed to CreateByteVector")
+
+ self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth)
+
+ l = UOffsetTFlags.py_type(len(x))
+ ## @cond FLATBUFFERS_INTERNAL
+ self.head = UOffsetTFlags.py_type(self.Head() - l)
+ ## @endcond
+ self.Bytes[self.Head():self.Head()+l] = x
+
+ return self.EndVector(len(x))
+
+ def CreateNumpyVector(self, x):
+ """CreateNumpyVector writes a numpy array into the buffer."""
+
+ if np is None:
+ # Numpy is required for this feature
+ raise NumpyRequiredForThisFeature("Numpy was not found.")
+
+ if not isinstance(x, np.ndarray):
+ raise TypeError("non-numpy-ndarray passed to CreateNumpyVector")
+
+ if x.dtype.kind not in ['b', 'i', 'u', 'f']:
+ raise TypeError("numpy-ndarray holds elements of unsupported datatype")
+
+ if x.ndim > 1:
+ raise TypeError("multidimensional-ndarray passed to CreateNumpyVector")
+
+ self.StartVector(x.itemsize, x.size, x.dtype.alignment)
+
+ # Ensure little endian byte ordering
+ if x.dtype.str[0] == "<":
+ x_lend = x
+ else:
+ x_lend = x.byteswap(inplace=False)
+
+ # Calculate total length
+ l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size)
+ ## @cond FLATBUFFERS_INTERNAL
+ self.head = UOffsetTFlags.py_type(self.Head() - l)
+ ## @endcond
+
+ # tobytes ensures c_contiguous ordering
+ self.Bytes[self.Head():self.Head()+l] = x_lend.tobytes(order='C')
+
+ return self.EndVector(x.size)
+
+ ## @cond FLATBUFFERS_INTERNAL
+ def assertNested(self):
+ """
+ Check that we are in the process of building an object.
+ """
+
+ if not self.nested:
+ raise IsNotNestedError()
+
+ def assertNotNested(self):
+ """
+ Check that no other objects are being built while making this
+ object. If not, raise an exception.
+ """
+
+ if self.nested:
+ raise IsNestedError()
+
+ def assertStructIsInline(self, obj):
+ """
+ Structs are always stored inline, so need to be created right
+ where they are used. You'll get this error if you created it
+ elsewhere.
+ """
+
+ N.enforce_number(obj, N.UOffsetTFlags)
+ if obj != self.Offset():
+ msg = ("flatbuffers: Tried to write a Struct at an Offset that "
+ "is different from the current Offset of the Builder.")
+ raise StructIsNotInlineError(msg)
+
+ def Slot(self, slotnum):
+ """
+ Slot sets the vtable key `voffset` to the current location in the
+ buffer.
+
+ """
+ self.assertNested()
+ self.current_vtable[slotnum] = self.Offset()
+ ## @endcond
+
+ def __Finish(self, rootTable, sizePrefix, file_identifier=None):
+ """Finish finalizes a buffer, pointing to the given `rootTable`."""
+ N.enforce_number(rootTable, N.UOffsetTFlags)
+
+ if file_identifier is not None:
+ self.Prep(N.UOffsetTFlags.bytewidth, N.Uint8Flags.bytewidth*4)
+
+ # Convert bytes object file_identifier to an array of 4 8-bit integers,
+ # and use big-endian to enforce size compliance.
+ # https://docs.python.org/2/library/struct.html#format-characters
+ file_identifier = N.struct.unpack(">BBBB", file_identifier)
+ for i in range(encode.FILE_IDENTIFIER_LENGTH-1, -1, -1):
+ # Place the bytes of the file_identifer in reverse order:
+ self.Place(file_identifier[i], N.Uint8Flags)
+
+ self.PrependUOffsetTRelative(rootTable)
+ if sizePrefix:
+ size = len(self.Bytes) - self.Head()
+ N.enforce_number(size, N.Int32Flags)
+ self.PrependInt32(size)
+ self.finished = True
+ return self.Head()
+
+ def Finish(self, rootTable, file_identifier=None):
+ """Finish finalizes a buffer, pointing to the given `rootTable`."""
+ return self.__Finish(rootTable, False, file_identifier=file_identifier)
+
+ def FinishSizePrefixed(self, rootTable, file_identifier=None):
+ """
+ Finish finalizes a buffer, pointing to the given `rootTable`,
+ with the size prefixed.
+ """
+ return self.__Finish(rootTable, True, file_identifier=file_identifier)
+
+ ## @cond FLATBUFFERS_INTERNAL
+ def Prepend(self, flags, off):
+ self.Prep(flags.bytewidth, 0)
+ self.Place(off, flags)
+
+ def PrependSlot(self, flags, o, x, d):
+ N.enforce_number(x, flags)
+ N.enforce_number(d, flags)
+ if x != d:
+ self.Prepend(flags, x)
+ self.Slot(o)
+
+ def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args)
+
+ def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
+
+ def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
+
+ def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args)
+
+ def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args)
+
+ def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args)
+
+ def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args)
+
+ def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args)
+
+ def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args)
+
+ def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args)
+
+ def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags,
+ *args)
+
+ def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags,
+ *args)
+
+ def PrependUOffsetTRelativeSlot(self, o, x, d):
+ """
+ PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at
+ vtable slot `o`. If value `x` equals default `d`, then the slot will
+ be set to zero and no other data will be written.
+ """
+
+ if x != d:
+ self.PrependUOffsetTRelative(x)
+ self.Slot(o)
+
+ def PrependStructSlot(self, v, x, d):
+ """
+ PrependStructSlot prepends a struct onto the object at vtable slot `o`.
+ Structs are stored inline, so nothing additional is being added.
+ In generated code, `d` is always 0.
+ """
+
+ N.enforce_number(d, N.UOffsetTFlags)
+ if x != d:
+ self.assertStructIsInline(x)
+ self.Slot(v)
+
+ ## @endcond
+
+ def PrependBool(self, x):
+ """Prepend a `bool` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.BoolFlags, x)
+
+ def PrependByte(self, x):
+ """Prepend a `byte` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint8Flags, x)
+
+ def PrependUint8(self, x):
+ """Prepend an `uint8` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint8Flags, x)
+
+ def PrependUint16(self, x):
+ """Prepend an `uint16` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint16Flags, x)
+
+ def PrependUint32(self, x):
+ """Prepend an `uint32` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint32Flags, x)
+
+ def PrependUint64(self, x):
+ """Prepend an `uint64` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Uint64Flags, x)
+
+ def PrependInt8(self, x):
+ """Prepend an `int8` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int8Flags, x)
+
+ def PrependInt16(self, x):
+ """Prepend an `int16` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int16Flags, x)
+
+ def PrependInt32(self, x):
+ """Prepend an `int32` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int32Flags, x)
+
+ def PrependInt64(self, x):
+ """Prepend an `int64` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Int64Flags, x)
+
+ def PrependFloat32(self, x):
+ """Prepend a `float32` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Float32Flags, x)
+
+ def PrependFloat64(self, x):
+ """Prepend a `float64` to the Builder buffer.
+
+ Note: aligns and checks for space.
+ """
+ self.Prepend(N.Float64Flags, x)
+
+##############################################################
+
+ ## @cond FLATBUFFERS_INTERNAL
+ def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x)
+
+ def Place(self, x, flags):
+ """
+ Place prepends a value specified by `flags` to the Builder,
+ without checking for available space.
+ """
+
+ N.enforce_number(x, flags)
+ self.head = self.head - flags.bytewidth
+ encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
+
+ def PlaceVOffsetT(self, x):
+ """PlaceVOffsetT prepends a VOffsetT to the Builder, without checking
+ for space.
+ """
+ N.enforce_number(x, N.VOffsetTFlags)
+ self.head = self.head - N.VOffsetTFlags.bytewidth
+ encode.Write(packer.voffset, self.Bytes, self.Head(), x)
+
+ def PlaceSOffsetT(self, x):
+ """PlaceSOffsetT prepends a SOffsetT to the Builder, without checking
+ for space.
+ """
+ N.enforce_number(x, N.SOffsetTFlags)
+ self.head = self.head - N.SOffsetTFlags.bytewidth
+ encode.Write(packer.soffset, self.Bytes, self.Head(), x)
+
+ def PlaceUOffsetT(self, x):
+ """PlaceUOffsetT prepends a UOffsetT to the Builder, without checking
+ for space.
+ """
+ N.enforce_number(x, N.UOffsetTFlags)
+ self.head = self.head - N.UOffsetTFlags.bytewidth
+ encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
+ ## @endcond
+
+## @cond FLATBUFFERS_INTERNAL
+def vtableEqual(a, objectStart, b):
+ """vtableEqual compares an unwritten vtable to a written vtable."""
+
+ N.enforce_number(objectStart, N.UOffsetTFlags)
+
+ if len(a) * N.VOffsetTFlags.bytewidth != len(b):
+ return False
+
+ for i, elem in enumerate(a):
+ x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth)
+
+ # Skip vtable entries that indicate a default value.
+ if x == 0 and elem == 0:
+ pass
+ else:
+ y = objectStart - elem
+ if x != y:
+ return False
+ return True
+## @endcond
+## @}
diff --git a/python/flatbuffers/compat.py b/python/flatbuffers/compat.py
new file mode 100644
index 0000000..2fc9cca
--- /dev/null
+++ b/python/flatbuffers/compat.py
@@ -0,0 +1,81 @@
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+""" A tiny version of `six` to help with backwards compability. Also includes
+ compatibility helpers for numpy. """
+
+import sys
+import imp
+
+PY2 = sys.version_info[0] == 2
+PY26 = sys.version_info[0:2] == (2, 6)
+PY27 = sys.version_info[0:2] == (2, 7)
+PY275 = sys.version_info[0:3] >= (2, 7, 5)
+PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
+
+if PY3:
+ string_types = (str,)
+ binary_types = (bytes,bytearray)
+ range_func = range
+ memoryview_type = memoryview
+ struct_bool_decl = "?"
+else:
+ string_types = (unicode,)
+ if PY26 or PY27:
+ binary_types = (str,bytearray)
+ else:
+ binary_types = (str,)
+ range_func = xrange
+ if PY26 or (PY27 and not PY275):
+ memoryview_type = buffer
+ struct_bool_decl = "<b"
+ else:
+ memoryview_type = memoryview
+ struct_bool_decl = "?"
+
+# Helper functions to facilitate making numpy optional instead of required
+
+def import_numpy():
+ """
+ Returns the numpy module if it exists on the system,
+ otherwise returns None.
+ """
+ try:
+ imp.find_module('numpy')
+ numpy_exists = True
+ except ImportError:
+ numpy_exists = False
+
+ if numpy_exists:
+ # We do this outside of try/except block in case numpy exists
+ # but is not installed correctly. We do not want to catch an
+ # incorrect installation which would manifest as an
+ # ImportError.
+ import numpy as np
+ else:
+ np = None
+
+ return np
+
+
+class NumpyRequiredForThisFeature(RuntimeError):
+ """
+ Error raised when user tries to use a feature that
+ requires numpy without having numpy installed.
+ """
+ pass
+
+
+# NOTE: Future Jython support may require code here (look at `six`).
diff --git a/python/flatbuffers/encode.py b/python/flatbuffers/encode.py
new file mode 100644
index 0000000..c4f1a59
--- /dev/null
+++ b/python/flatbuffers/encode.py
@@ -0,0 +1,42 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from . import number_types as N
+from . import packer
+from .compat import memoryview_type
+from .compat import import_numpy, NumpyRequiredForThisFeature
+
+np = import_numpy()
+
+FILE_IDENTIFIER_LENGTH=4
+
+def Get(packer_type, buf, head):
+ """ Get decodes a value at buf[head] using `packer_type`. """
+ return packer_type.unpack_from(memoryview_type(buf), head)[0]
+
+
+def GetVectorAsNumpy(numpy_type, buf, count, offset):
+ """ GetVecAsNumpy decodes values starting at buf[head] as
+ `numpy_type`, where `numpy_type` is a numpy dtype. """
+ if np is not None:
+ # TODO: could set .flags.writeable = False to make users jump through
+ # hoops before modifying...
+ return np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)
+ else:
+ raise NumpyRequiredForThisFeature('Numpy was not found.')
+
+
+def Write(packer_type, buf, head, n):
+ """ Write encodes `n` at buf[head] using `packer_type`. """
+ packer_type.pack_into(buf, head, n)
diff --git a/python/flatbuffers/number_types.py b/python/flatbuffers/number_types.py
new file mode 100644
index 0000000..47942ff
--- /dev/null
+++ b/python/flatbuffers/number_types.py
@@ -0,0 +1,181 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import collections
+import struct
+
+from . import packer
+from .compat import import_numpy, NumpyRequiredForThisFeature
+
+np = import_numpy()
+
+# For reference, see:
+# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
+
+# These classes could be collections.namedtuple instances, but those are new
+# in 2.6 and we want to work towards 2.5 compatability.
+
+class BoolFlags(object):
+ bytewidth = 1
+ min_val = False
+ max_val = True
+ py_type = bool
+ name = "bool"
+ packer_type = packer.boolean
+
+
+class Uint8Flags(object):
+ bytewidth = 1
+ min_val = 0
+ max_val = (2**8) - 1
+ py_type = int
+ name = "uint8"
+ packer_type = packer.uint8
+
+
+class Uint16Flags(object):
+ bytewidth = 2
+ min_val = 0
+ max_val = (2**16) - 1
+ py_type = int
+ name = "uint16"
+ packer_type = packer.uint16
+
+
+class Uint32Flags(object):
+ bytewidth = 4
+ min_val = 0
+ max_val = (2**32) - 1
+ py_type = int
+ name = "uint32"
+ packer_type = packer.uint32
+
+
+class Uint64Flags(object):
+ bytewidth = 8
+ min_val = 0
+ max_val = (2**64) - 1
+ py_type = int
+ name = "uint64"
+ packer_type = packer.uint64
+
+
+class Int8Flags(object):
+ bytewidth = 1
+ min_val = -(2**7)
+ max_val = (2**7) - 1
+ py_type = int
+ name = "int8"
+ packer_type = packer.int8
+
+
+class Int16Flags(object):
+ bytewidth = 2
+ min_val = -(2**15)
+ max_val = (2**15) - 1
+ py_type = int
+ name = "int16"
+ packer_type = packer.int16
+
+
+class Int32Flags(object):
+ bytewidth = 4
+ min_val = -(2**31)
+ max_val = (2**31) - 1
+ py_type = int
+ name = "int32"
+ packer_type = packer.int32
+
+
+class Int64Flags(object):
+ bytewidth = 8
+ min_val = -(2**63)
+ max_val = (2**63) - 1
+ py_type = int
+ name = "int64"
+ packer_type = packer.int64
+
+
+class Float32Flags(object):
+ bytewidth = 4
+ min_val = None
+ max_val = None
+ py_type = float
+ name = "float32"
+ packer_type = packer.float32
+
+
+class Float64Flags(object):
+ bytewidth = 8
+ min_val = None
+ max_val = None
+ py_type = float
+ name = "float64"
+ packer_type = packer.float64
+
+
+class SOffsetTFlags(Int32Flags):
+ pass
+
+
+class UOffsetTFlags(Uint32Flags):
+ pass
+
+
+class VOffsetTFlags(Uint16Flags):
+ pass
+
+
+def valid_number(n, flags):
+ if flags.min_val is None and flags.max_val is None:
+ return True
+ return flags.min_val <= n <= flags.max_val
+
+
+def enforce_number(n, flags):
+ if flags.min_val is None and flags.max_val is None:
+ return
+ if not flags.min_val <= n <= flags.max_val:
+ raise TypeError("bad number %s for type %s" % (str(n), flags.name))
+
+
+def float32_to_uint32(n):
+ packed = struct.pack("<1f", n)
+ (converted,) = struct.unpack("<1L", packed)
+ return converted
+
+
+def uint32_to_float32(n):
+ packed = struct.pack("<1L", n)
+ (unpacked,) = struct.unpack("<1f", packed)
+ return unpacked
+
+
+def float64_to_uint64(n):
+ packed = struct.pack("<1d", n)
+ (converted,) = struct.unpack("<1Q", packed)
+ return converted
+
+
+def uint64_to_float64(n):
+ packed = struct.pack("<1Q", n)
+ (unpacked,) = struct.unpack("<1d", packed)
+ return unpacked
+
+
+def to_numpy_type(number_type):
+ if np is not None:
+ return np.dtype(number_type.name).newbyteorder('<')
+ else:
+ raise NumpyRequiredForThisFeature('Numpy was not found.')
diff --git a/python/flatbuffers/packer.py b/python/flatbuffers/packer.py
new file mode 100644
index 0000000..20ee9f1
--- /dev/null
+++ b/python/flatbuffers/packer.py
@@ -0,0 +1,42 @@
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Provide pre-compiled struct packers for encoding and decoding.
+
+See: https://docs.python.org/2/library/struct.html#format-characters
+"""
+
+import struct
+from . import compat
+
+
+boolean = struct.Struct(compat.struct_bool_decl)
+
+uint8 = struct.Struct("<B")
+uint16 = struct.Struct("<H")
+uint32 = struct.Struct("<I")
+uint64 = struct.Struct("<Q")
+
+int8 = struct.Struct("<b")
+int16 = struct.Struct("<h")
+int32 = struct.Struct("<i")
+int64 = struct.Struct("<q")
+
+float32 = struct.Struct("<f")
+float64 = struct.Struct("<d")
+
+uoffset = uint32
+soffset = int32
+voffset = uint16
diff --git a/python/flatbuffers/table.py b/python/flatbuffers/table.py
new file mode 100644
index 0000000..adc76ca
--- /dev/null
+++ b/python/flatbuffers/table.py
@@ -0,0 +1,129 @@
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from . import encode
+from . import number_types as N
+
+
+class Table(object):
+ """Table wraps a byte slice and provides read access to its data.
+
+ The variable `Pos` indicates the root of the FlatBuffers object therein."""
+
+ __slots__ = ("Bytes", "Pos")
+
+ def __init__(self, buf, pos):
+ N.enforce_number(pos, N.UOffsetTFlags)
+
+ self.Bytes = buf
+ self.Pos = pos
+
+ def Offset(self, vtableOffset):
+ """Offset provides access into the Table's vtable.
+
+ Deprecated fields are ignored by checking the vtable's length."""
+
+ vtable = self.Pos - self.Get(N.SOffsetTFlags, self.Pos)
+ vtableEnd = self.Get(N.VOffsetTFlags, vtable)
+ if vtableOffset < vtableEnd:
+ return self.Get(N.VOffsetTFlags, vtable + vtableOffset)
+ return 0
+
+ def Indirect(self, off):
+ """Indirect retrieves the relative offset stored at `offset`."""
+ N.enforce_number(off, N.UOffsetTFlags)
+ return off + encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
+
+ def String(self, off):
+ """String gets a string from data stored inside the flatbuffer."""
+ N.enforce_number(off, N.UOffsetTFlags)
+ off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
+ start = off + N.UOffsetTFlags.bytewidth
+ length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
+ return bytes(self.Bytes[start:start+length])
+
+ def VectorLen(self, off):
+ """VectorLen retrieves the length of the vector whose offset is stored
+ at "off" in this object."""
+ N.enforce_number(off, N.UOffsetTFlags)
+
+ off += self.Pos
+ off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
+ ret = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
+ return ret
+
+ def Vector(self, off):
+ """Vector retrieves the start of data of the vector whose offset is
+ stored at "off" in this object."""
+ N.enforce_number(off, N.UOffsetTFlags)
+
+ off += self.Pos
+ x = off + self.Get(N.UOffsetTFlags, off)
+ # data starts after metadata containing the vector length
+ x += N.UOffsetTFlags.bytewidth
+ return x
+
+ def Union(self, t2, off):
+ """Union initializes any Table-derived type to point to the union at
+ the given offset."""
+ assert type(t2) is Table
+ N.enforce_number(off, N.UOffsetTFlags)
+
+ off += self.Pos
+ t2.Pos = off + self.Get(N.UOffsetTFlags, off)
+ t2.Bytes = self.Bytes
+
+ def Get(self, flags, off):
+ """
+ Get retrieves a value of the type specified by `flags` at the
+ given offset.
+ """
+ N.enforce_number(off, N.UOffsetTFlags)
+ return flags.py_type(encode.Get(flags.packer_type, self.Bytes, off))
+
+ def GetSlot(self, slot, d, validator_flags):
+ N.enforce_number(slot, N.VOffsetTFlags)
+ if validator_flags is not None:
+ N.enforce_number(d, validator_flags)
+ off = self.Offset(slot)
+ if off == 0:
+ return d
+ return self.Get(validator_flags, self.Pos + off)
+
+ def GetVectorAsNumpy(self, flags, off):
+ """
+ GetVectorAsNumpy returns the vector that starts at `Vector(off)`
+ as a numpy array with the type specified by `flags`. The array is
+ a `view` into Bytes, so modifying the returned array will
+ modify Bytes in place.
+ """
+ offset = self.Vector(off)
+ length = self.VectorLen(off) # TODO: length accounts for bytewidth, right?
+ numpy_dtype = N.to_numpy_type(flags)
+ return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset)
+
+ def GetVOffsetTSlot(self, slot, d):
+ """
+ GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
+ points to. If the vtable value is zero, the default value `d`
+ will be returned.
+ """
+
+ N.enforce_number(slot, N.VOffsetTFlags)
+ N.enforce_number(d, N.VOffsetTFlags)
+
+ off = self.Offset(slot)
+ if off == 0:
+ return d
+ return off
diff --git a/python/flatbuffers/util.py b/python/flatbuffers/util.py
new file mode 100644
index 0000000..a5a7838
--- /dev/null
+++ b/python/flatbuffers/util.py
@@ -0,0 +1,43 @@
+# Copyright 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from . import encode
+from . import number_types
+from . import packer
+
+def GetSizePrefix(buf, offset):
+ """Extract the size prefix from a buffer."""
+ return encode.Get(packer.int32, buf, offset)
+
+def GetBufferIdentifier(buf, offset, size_prefixed=False):
+ """Extract the file_identifier from a buffer"""
+ if size_prefixed:
+ # increase offset by size of UOffsetTFlags
+ offset += number_types.UOffsetTFlags.bytewidth
+ # increase offset by size of root table pointer
+ offset += number_types.UOffsetTFlags.bytewidth
+ # end of FILE_IDENTIFIER
+ end = offset + encode.FILE_IDENTIFIER_LENGTH
+ return buf[offset:end]
+
+def BufferHasIdentifier(buf, offset, file_identifier, size_prefixed=False):
+ got = GetBufferIdentifier(buf, offset, size_prefixed=size_prefixed)
+ return got == file_identifier
+
+def RemoveSizePrefix(buf, offset):
+ """
+ Create a slice of a size-prefixed buffer that has
+ its position advanced just past the size prefix.
+ """
+ return buf, offset + number_types.Int32Flags.bytewidth
diff --git a/python/setup.cfg b/python/setup.cfg
new file mode 100644
index 0000000..3c6e79c
--- /dev/null
+++ b/python/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal=1
diff --git a/python/setup.py b/python/setup.py
new file mode 100644
index 0000000..b3fc566
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,71 @@
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+from datetime import datetime
+from setuptools import setup
+
+
+def version():
+ version = os.getenv('VERSION', None)
+ if version:
+ # Most git tags are prefixed with 'v' (example: v1.2.3) this is
+ # never desirable for artifact repositories, so we strip the
+ # leading 'v' if it's present.
+ return version[1:] if version.startswith('v') else version
+ else:
+ # Default version is an ISO8601 compiliant datetime. PyPI doesn't allow
+ # the colon ':' character in its versions, and time is required to allow
+ # for multiple publications to master in one day. This datetime string
+ # uses the "basic" ISO8601 format for both its date and time components
+ # to avoid issues with the colon character (ISO requires that date and
+ # time components of a date-time string must be uniformly basic or
+ # extended, which is why the date component does not have dashes.
+ #
+ # Publications using datetime versions should only be made from master
+ # to represent the HEAD moving forward.
+ version = datetime.utcnow().strftime('%Y%m%d%H%M%S')
+ print("VERSION environment variable not set, using datetime instead: {}"
+ .format(version))
+
+ return version
+
+setup(
+ name='flatbuffers',
+ version=version(),
+ license='Apache 2.0',
+ author='FlatBuffers Contributors',
+ author_email='me@rwinslow.com',
+ url='https://google.github.io/flatbuffers/',
+ long_description=('Python runtime library for use with the '
+ '`Flatbuffers <https://google.github.io/flatbuffers/>`_ '
+ 'serialization format.'),
+ packages=['flatbuffers'],
+ include_package_data=True,
+ requires=[],
+ description='The FlatBuffers serialization format for Python',
+ classifiers=[
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 3',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ ],
+ project_urls={
+ 'Documentation': 'https://google.github.io/flatbuffers/',
+ 'Source': 'https://github.com/google/flatbuffers',
+ },
+)
\ No newline at end of file
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..3d5467e
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,54 @@
+ FlatBuffers
+===========
+
+[](https://gitter.im/google/flatbuffers?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](https://travis-ci.org/google/flatbuffers) [](https://ci.appveyor.com/project/gwvo/flatbuffers)
+
+**FlatBuffers** is a cross platform serialization library architected for
+maximum memory efficiency. It allows you to directly access serialized data without parsing/unpacking it first, while still having great forwards/backwards compatibility.
+
+**Go to our [landing page][] to browse our documentation.**
+
+## Supported operating systems
+* Windows
+* MacOS X
+* Linux
+* Android
+* And any others with a recent C++ compiler.
+
+## Supported programming languages
+* C++
+* C#
+* C
+* Dart
+* Go
+* Java
+* JavaScript
+* Lobster
+* Lua
+* PHP
+* Python
+* Rust
+* TypeScript
+
+*and more in progress...*
+
+## Contribution
+* [FlatBuffers Google Group][] to discuss FlatBuffers with other developers and users.
+* [FlatBuffers Issues Tracker][] to submit an issue.
+* [stackoverflow.com][] with [`flatbuffers` tag][] for any questions regarding FlatBuffers.
+
+*To contribute to this project,* see [CONTRIBUTING][].
+
+## Licensing
+*Flatbuffers* is licensed under the Apache License, Version 2.0. See [LICENSE][] for the full license text.
+
+<br>
+
+ [CONTRIBUTING]: http://github.com/google/flatbuffers/blob/master/CONTRIBUTING.md
+ [`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers
+ [FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers
+ [FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
+ [stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
+ [landing page]: https://google.github.io/flatbuffers
+ [LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt
diff --git a/reflection/generate_code.bat b/reflection/generate_code.bat
new file mode 100644
index 0000000..e299325
--- /dev/null
+++ b/reflection/generate_code.bat
@@ -0,0 +1,18 @@
+:: Copyright 2015 Google Inc. All rights reserved.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+
+set buildtype=Release
+if "%1"=="-b" set buildtype=%2
+
+..\%buildtype%\flatc.exe --cpp --no-prefix -o ../include/flatbuffers reflection.fbs || exit /b 1
diff --git a/reflection/generate_code.sh b/reflection/generate_code.sh
new file mode 100755
index 0000000..f186b73
--- /dev/null
+++ b/reflection/generate_code.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+
+../flatc -c --no-prefix -o ../include/flatbuffers reflection.fbs
diff --git a/reflection/reflection.fbs b/reflection/reflection.fbs
new file mode 100644
index 0000000..8fed025
--- /dev/null
+++ b/reflection/reflection.fbs
@@ -0,0 +1,113 @@
+// This schema defines objects that represent a parsed schema, like
+// the binary version of a .fbs file.
+// This could be used to operate on unknown FlatBuffers at runtime.
+// It can even ... represent itself (!)
+
+namespace reflection;
+
+// These must correspond to the enum in idl.h.
+enum BaseType : byte {
+ None,
+ UType,
+ Bool,
+ Byte,
+ UByte,
+ Short,
+ UShort,
+ Int,
+ UInt,
+ Long,
+ ULong,
+ Float,
+ Double,
+ String,
+ Vector,
+ Obj, // Used for tables & structs.
+ Union,
+ Array
+}
+
+table Type {
+ base_type:BaseType;
+ element:BaseType = None; // Only if base_type == Vector
+ // or base_type == Array.
+ index:int = -1; // If base_type == Object, index into "objects" below.
+ // If base_type == Union, UnionType, or integral derived
+ // from an enum, index into "enums" below.
+ fixed_length:uint16 = 0; // Only if base_type == Array.
+}
+
+table KeyValue {
+ key:string (required, key);
+ value:string;
+}
+
+table EnumVal {
+ name:string (required);
+ value:long (key);
+ object:Object; // Will be deprecated in favor of union_type in the future.
+ union_type:Type;
+ documentation:[string];
+}
+
+table Enum {
+ name:string (required, key);
+ values:[EnumVal] (required); // In order of their values.
+ is_union:bool = false;
+ underlying_type:Type (required);
+ attributes:[KeyValue];
+ documentation:[string];
+}
+
+table Field {
+ name:string (required, key);
+ type:Type (required);
+ id:ushort;
+ offset:ushort; // Offset into the vtable for tables, or into the struct.
+ default_integer:long = 0;
+ default_real:double = 0.0;
+ deprecated:bool = false;
+ required:bool = false;
+ key:bool = false;
+ attributes:[KeyValue];
+ documentation:[string];
+}
+
+table Object { // Used for both tables and structs.
+ name:string (required, key);
+ fields:[Field] (required); // Sorted.
+ is_struct:bool = false;
+ minalign:int;
+ bytesize:int; // For structs.
+ attributes:[KeyValue];
+ documentation:[string];
+}
+
+table RPCCall {
+ name:string (required, key);
+ request:Object (required); // must be a table (not a struct)
+ response:Object (required); // must be a table (not a struct)
+ attributes:[KeyValue];
+ documentation:[string];
+}
+
+table Service {
+ name:string (required, key);
+ calls:[RPCCall];
+ attributes:[KeyValue];
+ documentation:[string];
+}
+
+table Schema {
+ objects:[Object] (required); // Sorted.
+ enums:[Enum] (required); // Sorted.
+ file_ident:string;
+ file_ext:string;
+ root_table:Object;
+ services:[Service]; // Sorted.
+}
+
+root_type Schema;
+
+file_identifier "BFBS";
+file_extension "bfbs";
diff --git a/rust/flatbuffers/Cargo.toml b/rust/flatbuffers/Cargo.toml
new file mode 100644
index 0000000..32d9b1b
--- /dev/null
+++ b/rust/flatbuffers/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "flatbuffers"
+version = "0.6.0"
+authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
+license = "Apache-2.0"
+description = "Official FlatBuffers Rust runtime library."
+homepage = "https://google.github.io/flatbuffers/"
+repository = "https://github.com/google/flatbuffers"
+keywords = ["flatbuffers", "serialization", "zero-copy"]
+categories = ["encoding", "data-structures", "memory-management"]
+
+[dependencies]
+smallvec = "0.6"
diff --git a/rust/flatbuffers/src/builder.rs b/rust/flatbuffers/src/builder.rs
new file mode 100644
index 0000000..36d6c6a
--- /dev/null
+++ b/rust/flatbuffers/src/builder.rs
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern crate smallvec;
+
+use std::cmp::max;
+use std::marker::PhantomData;
+use std::ptr::write_bytes;
+use std::slice::from_raw_parts;
+
+use endian_scalar::{emplace_scalar, read_scalar_at};
+use primitives::*;
+use push::{Push, PushAlignment};
+use table::Table;
+use vector::{SafeSliceAccess, Vector};
+use vtable::{field_index_to_field_offset, VTable};
+use vtable_writer::VTableWriter;
+
+pub const N_SMALLVEC_STRING_VECTOR_CAPACITY: usize = 16;
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+struct FieldLoc {
+ off: UOffsetT,
+ id: VOffsetT,
+}
+
+/// FlatBufferBuilder builds a FlatBuffer through manipulating its internal
+/// state. It has an owned `Vec<u8>` that grows as needed (up to the hardcoded
+/// limit of 2GiB, which is set by the FlatBuffers format).
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct FlatBufferBuilder<'fbb> {
+ owned_buf: Vec<u8>,
+ head: usize,
+
+ field_locs: Vec<FieldLoc>,
+ written_vtable_revpos: Vec<UOffsetT>,
+
+ nested: bool,
+ finished: bool,
+
+ min_align: usize,
+
+ _phantom: PhantomData<&'fbb ()>,
+}
+
+impl<'fbb> FlatBufferBuilder<'fbb> {
+ /// Create a FlatBufferBuilder that is ready for writing.
+ pub fn new() -> Self {
+ Self::new_with_capacity(0)
+ }
+
+ /// Create a FlatBufferBuilder that is ready for writing, with a
+ /// ready-to-use capacity of the provided size.
+ ///
+ /// The maximum valid value is `FLATBUFFERS_MAX_BUFFER_SIZE`.
+ pub fn new_with_capacity(size: usize) -> Self {
+ // we need to check the size here because we create the backing buffer
+ // directly, bypassing the typical way of using grow_owned_buf:
+ assert!(
+ size <= FLATBUFFERS_MAX_BUFFER_SIZE,
+ "cannot initialize buffer bigger than 2 gigabytes"
+ );
+
+ FlatBufferBuilder {
+ owned_buf: vec![0u8; size],
+ head: size,
+
+ field_locs: Vec::new(),
+ written_vtable_revpos: Vec::new(),
+
+ nested: false,
+ finished: false,
+
+ min_align: 0,
+
+ _phantom: PhantomData,
+ }
+ }
+
+ /// Reset the FlatBufferBuilder internal state. Use this method after a
+ /// call to a `finish` function in order to re-use a FlatBufferBuilder.
+ ///
+ /// This function is the only way to reset the `finished` state and start
+ /// again.
+ ///
+ /// If you are using a FlatBufferBuilder repeatedly, make sure to use this
+ /// function, because it re-uses the FlatBufferBuilder's existing
+ /// heap-allocated `Vec<u8>` internal buffer. This offers significant speed
+ /// improvements as compared to creating a new FlatBufferBuilder for every
+ /// new object.
+ pub fn reset(&mut self) {
+ // memset only the part of the buffer that could be dirty:
+ {
+ let to_clear = self.owned_buf.len() - self.head;
+ let ptr = (&mut self.owned_buf[self.head..]).as_mut_ptr();
+ unsafe {
+ write_bytes(ptr, 0, to_clear);
+ }
+ }
+
+ self.head = self.owned_buf.len();
+ self.written_vtable_revpos.clear();
+
+ self.nested = false;
+ self.finished = false;
+
+ self.min_align = 0;
+ }
+
+ /// Destroy the FlatBufferBuilder, returning its internal byte vector
+ /// and the index into it that represents the start of valid data.
+ pub fn collapse(self) -> (Vec<u8>, usize) {
+ (self.owned_buf, self.head)
+ }
+
+ /// Push a Push'able value onto the front of the in-progress data.
+ ///
+ /// This function uses traits to provide a unified API for writing
+ /// scalars, tables, vectors, and WIPOffsets.
+ #[inline]
+ pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> {
+ let sz = P::size();
+ self.align(sz, P::alignment());
+ self.make_space(sz);
+ {
+ let (dst, rest) = (&mut self.owned_buf[self.head..]).split_at_mut(sz);
+ x.push(dst, rest);
+ }
+ WIPOffset::new(self.used_space() as UOffsetT)
+ }
+
+ /// Push a Push'able value onto the front of the in-progress data, and
+ /// store a reference to it in the in-progress vtable. If the value matches
+ /// the default, then this is a no-op.
+ #[inline]
+ pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) {
+ self.assert_nested("push_slot");
+ if x == default {
+ return;
+ }
+ self.push_slot_always(slotoff, x);
+ }
+
+ /// Push a Push'able value onto the front of the in-progress data, and
+ /// store a reference to it in the in-progress vtable.
+ #[inline]
+ pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) {
+ self.assert_nested("push_slot_always");
+ let off = self.push(x);
+ self.track_field(slotoff, off.value());
+ }
+
+ /// Retrieve the number of vtables that have been serialized into the
+ /// FlatBuffer. This is primarily used to check vtable deduplication.
+ #[inline]
+ pub fn num_written_vtables(&self) -> usize {
+ self.written_vtable_revpos.len()
+ }
+
+ /// Start a Table write.
+ ///
+ /// Asserts that the builder is not in a nested state.
+ ///
+ /// Users probably want to use `push_slot` to add values after calling this.
+ #[inline]
+ pub fn start_table(&mut self) -> WIPOffset<TableUnfinishedWIPOffset> {
+ self.assert_not_nested(
+ "start_table can not be called when a table or vector is under construction",
+ );
+ self.nested = true;
+
+ WIPOffset::new(self.used_space() as UOffsetT)
+ }
+
+ /// End a Table write.
+ ///
+ /// Asserts that the builder is in a nested state.
+ #[inline]
+ pub fn end_table(
+ &mut self,
+ off: WIPOffset<TableUnfinishedWIPOffset>,
+ ) -> WIPOffset<TableFinishedWIPOffset> {
+ self.assert_nested("end_table");
+
+ let o = self.write_vtable(off);
+
+ self.nested = false;
+ self.field_locs.clear();
+
+ WIPOffset::new(o.value())
+ }
+
+ /// Start a Vector write.
+ ///
+ /// Asserts that the builder is not in a nested state.
+ ///
+ /// Most users will prefer to call `create_vector`.
+ /// Speed optimizing users who choose to create vectors manually using this
+ /// function will want to use `push` to add values.
+ #[inline]
+ pub fn start_vector<T: Push>(&mut self, num_items: usize) {
+ self.assert_not_nested(
+ "start_vector can not be called when a table or vector is under construction",
+ );
+ self.nested = true;
+ self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET));
+ }
+
+ /// End a Vector write.
+ ///
+ /// Note that the `num_elems` parameter is the number of written items, not
+ /// the byte count.
+ ///
+ /// Asserts that the builder is in a nested state.
+ #[inline]
+ pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> {
+ self.assert_nested("end_vector");
+ self.nested = false;
+ let o = self.push::<UOffsetT>(num_elems as UOffsetT);
+ WIPOffset::new(o.value())
+ }
+
+ /// Create a utf8 string.
+ ///
+ /// The wire format represents this as a zero-terminated byte vector.
+ #[inline]
+ pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
+ self.assert_not_nested(
+ "create_string can not be called when a table or vector is under construction",
+ );
+ WIPOffset::new(self.create_byte_string(s.as_bytes()).value())
+ }
+
+ /// Create a zero-terminated byte vector.
+ #[inline]
+ pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> {
+ self.assert_not_nested(
+ "create_byte_string can not be called when a table or vector is under construction",
+ );
+ self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET));
+ self.push(0u8);
+ self.push_bytes_unprefixed(data);
+ self.push(data.len() as UOffsetT);
+ WIPOffset::new(self.used_space() as UOffsetT)
+ }
+
+ /// Create a vector by memcpy'ing. This is much faster than calling
+ /// `create_vector`, but the underlying type must be represented as
+ /// little-endian on the host machine. This property is encoded in the
+ /// type system through the SafeSliceAccess trait. The following types are
+ /// always safe, on any platform: bool, u8, i8, and any
+ /// FlatBuffers-generated struct.
+ #[inline]
+ pub fn create_vector_direct<'a: 'b, 'b, T: SafeSliceAccess + Push + Sized + 'b>(
+ &'a mut self,
+ items: &'b [T],
+ ) -> WIPOffset<Vector<'fbb, T>> {
+ self.assert_not_nested(
+ "create_vector_direct can not be called when a table or vector is under construction",
+ );
+ let elem_size = T::size();
+ self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
+
+ let bytes = {
+ let ptr = items.as_ptr() as *const T as *const u8;
+ unsafe { from_raw_parts(ptr, items.len() * elem_size) }
+ };
+ self.push_bytes_unprefixed(bytes);
+ self.push(items.len() as UOffsetT);
+
+ WIPOffset::new(self.used_space() as UOffsetT)
+ }
+
+ /// Create a vector of strings.
+ ///
+ /// Speed-sensitive users may wish to reduce memory usage by creating the
+ /// vector manually: use `start_vector`, `push`, and `end_vector`.
+ #[inline]
+ pub fn create_vector_of_strings<'a, 'b>(
+ &'a mut self,
+ xs: &'b [&'b str],
+ ) -> WIPOffset<Vector<'fbb, ForwardsUOffset<&'fbb str>>> {
+ self.assert_not_nested("create_vector_of_strings can not be called when a table or vector is under construction");
+ // internally, smallvec can be a stack-allocated or heap-allocated vector:
+ // if xs.len() > N_SMALLVEC_STRING_VECTOR_CAPACITY then it will overflow to the heap.
+ let mut offsets: smallvec::SmallVec<[WIPOffset<&str>; N_SMALLVEC_STRING_VECTOR_CAPACITY]> =
+ smallvec::SmallVec::with_capacity(xs.len());
+ unsafe {
+ offsets.set_len(xs.len());
+ }
+
+ // note that this happens in reverse, because the buffer is built back-to-front:
+ for (i, &s) in xs.iter().enumerate().rev() {
+ let o = self.create_string(s);
+ offsets[i] = o;
+ }
+ self.create_vector(&offsets[..])
+ }
+
+ /// Create a vector of Push-able objects.
+ ///
+ /// Speed-sensitive users may wish to reduce memory usage by creating the
+ /// vector manually: use `start_vector`, `push`, and `end_vector`.
+ #[inline]
+ pub fn create_vector<'a: 'b, 'b, T: Push + Copy + 'b>(
+ &'a mut self,
+ items: &'b [T],
+ ) -> WIPOffset<Vector<'fbb, T::Output>> {
+ let elem_size = T::size();
+ self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
+ for i in (0..items.len()).rev() {
+ self.push(items[i]);
+ }
+ WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value())
+ }
+
+ /// Get the byte slice for the data that has been written, regardless of
+ /// whether it has been finished.
+ #[inline]
+ pub fn unfinished_data(&self) -> &[u8] {
+ &self.owned_buf[self.head..]
+ }
+ /// Get the byte slice for the data that has been written after a call to
+ /// one of the `finish` functions.
+ #[inline]
+ pub fn finished_data(&self) -> &[u8] {
+ self.assert_finished("finished_bytes cannot be called when the buffer is not yet finished");
+ &self.owned_buf[self.head..]
+ }
+ /// Assert that a field is present in the just-finished Table.
+ ///
+ /// This is somewhat low-level and is mostly used by the generated code.
+ #[inline]
+ pub fn required(
+ &self,
+ tab_revloc: WIPOffset<TableFinishedWIPOffset>,
+ slot_byte_loc: VOffsetT,
+ assert_msg_name: &'static str,
+ ) {
+ let idx = self.used_space() - tab_revloc.value() as usize;
+ let tab = Table::new(&self.owned_buf[self.head..], idx);
+ let o = tab.vtable().get(slot_byte_loc) as usize;
+ assert!(o != 0, "missing required field {}", assert_msg_name);
+ }
+
+ /// Finalize the FlatBuffer by: aligning it, pushing an optional file
+ /// identifier on to it, pushing a size prefix on to it, and marking the
+ /// internal state of the FlatBufferBuilder as `finished`. Afterwards,
+ /// users can call `finished_data` to get the resulting data.
+ #[inline]
+ pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
+ self.finish_with_opts(root, file_identifier, true);
+ }
+
+ /// Finalize the FlatBuffer by: aligning it, pushing an optional file
+ /// identifier on to it, and marking the internal state of the
+ /// FlatBufferBuilder as `finished`. Afterwards, users can call
+ /// `finished_data` to get the resulting data.
+ #[inline]
+ pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
+ self.finish_with_opts(root, file_identifier, false);
+ }
+
+ /// Finalize the FlatBuffer by: aligning it and marking the internal state
+ /// of the FlatBufferBuilder as `finished`. Afterwards, users can call
+ /// `finished_data` to get the resulting data.
+ #[inline]
+ pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) {
+ self.finish_with_opts(root, None, false);
+ }
+
+ #[inline]
+ fn used_space(&self) -> usize {
+ self.owned_buf.len() - self.head as usize
+ }
+
+ #[inline]
+ fn track_field(&mut self, slot_off: VOffsetT, off: UOffsetT) {
+ let fl = FieldLoc {
+ id: slot_off,
+ off: off,
+ };
+ self.field_locs.push(fl);
+ }
+
+ /// Write the VTable, if it is new.
+ fn write_vtable(
+ &mut self,
+ table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>,
+ ) -> WIPOffset<VTableWIPOffset> {
+ self.assert_nested("write_vtable");
+
+ // Write the vtable offset, which is the start of any Table.
+ // We fill its value later.
+ let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> =
+ WIPOffset::new(self.push::<UOffsetT>(0xF0F0F0F0 as UOffsetT).value());
+
+ // Layout of the data this function will create when a new vtable is
+ // needed.
+ // --------------------------------------------------------------------
+ // vtable starts here
+ // | x, x -- vtable len (bytes) [u16]
+ // | x, x -- object inline len (bytes) [u16]
+ // | x, x -- zero, or num bytes from start of object to field #0 [u16]
+ // | ...
+ // | x, x -- zero, or num bytes from start of object to field #n-1 [u16]
+ // vtable ends here
+ // table starts here
+ // | x, x, x, x -- offset (negative direction) to the vtable [i32]
+ // | aka "vtableoffset"
+ // | -- table inline data begins here, we don't touch it --
+ // table ends here -- aka "table_start"
+ // --------------------------------------------------------------------
+ //
+ // Layout of the data this function will create when we re-use an
+ // existing vtable.
+ //
+ // We always serialize this particular vtable, then compare it to the
+ // other vtables we know about to see if there is a duplicate. If there
+ // is, then we erase the serialized vtable we just made.
+ // We serialize it first so that we are able to do byte-by-byte
+ // comparisons with already-serialized vtables. This 1) saves
+ // bookkeeping space (we only keep revlocs to existing vtables), 2)
+ // allows us to convert to little-endian once, then do
+ // fast memcmp comparisons, and 3) by ensuring we are comparing real
+ // serialized vtables, we can be more assured that we are doing the
+ // comparisons correctly.
+ //
+ // --------------------------------------------------------------------
+ // table starts here
+ // | x, x, x, x -- offset (negative direction) to an existing vtable [i32]
+ // | aka "vtableoffset"
+ // | -- table inline data begins here, we don't touch it --
+ // table starts here: aka "table_start"
+ // --------------------------------------------------------------------
+
+ // fill the WIP vtable with zeros:
+ let vtable_byte_len = get_vtable_byte_len(&self.field_locs);
+ self.make_space(vtable_byte_len);
+
+ // compute the length of the table (not vtable!) in bytes:
+ let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value();
+ debug_assert!(table_object_size < 0x10000); // vTable use 16bit offsets.
+
+ // Write the VTable (we may delete it afterwards, if it is a duplicate):
+ let vt_start_pos = self.head;
+ let vt_end_pos = self.head + vtable_byte_len;
+ {
+ // write the vtable header:
+ let vtfw = &mut VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]);
+ vtfw.write_vtable_byte_length(vtable_byte_len as VOffsetT);
+ vtfw.write_object_inline_size(table_object_size as VOffsetT);
+
+ // serialize every FieldLoc to the vtable:
+ for &fl in self.field_locs.iter() {
+ let pos: VOffsetT = (object_revloc_to_vtable.value() - fl.off) as VOffsetT;
+ debug_assert_eq!(
+ vtfw.get_field_offset(fl.id),
+ 0,
+ "tried to write a vtable field multiple times"
+ );
+ vtfw.write_field_offset(fl.id, pos);
+ }
+ }
+ let dup_vt_use = {
+ let this_vt = VTable::init(&self.owned_buf[..], self.head);
+ self.find_duplicate_stored_vtable_revloc(this_vt)
+ };
+
+ let vt_use = match dup_vt_use {
+ Some(n) => {
+ VTableWriter::init(&mut self.owned_buf[vt_start_pos..vt_end_pos]).clear();
+ self.head += vtable_byte_len;
+ n
+ }
+ None => {
+ let new_vt_use = self.used_space() as UOffsetT;
+ self.written_vtable_revpos.push(new_vt_use);
+ new_vt_use
+ }
+ };
+
+ {
+ let n = self.head + self.used_space() - object_revloc_to_vtable.value() as usize;
+ let saw = read_scalar_at::<UOffsetT>(&self.owned_buf, n);
+ debug_assert_eq!(saw, 0xF0F0F0F0);
+ emplace_scalar::<SOffsetT>(
+ &mut self.owned_buf[n..n + SIZE_SOFFSET],
+ vt_use as SOffsetT - object_revloc_to_vtable.value() as SOffsetT,
+ );
+ }
+
+ self.field_locs.clear();
+
+ object_revloc_to_vtable
+ }
+
+ #[inline]
+ fn find_duplicate_stored_vtable_revloc(&self, needle: VTable) -> Option<UOffsetT> {
+ for &revloc in self.written_vtable_revpos.iter().rev() {
+ let o = VTable::init(
+ &self.owned_buf[..],
+ self.head + self.used_space() - revloc as usize,
+ );
+ if needle == o {
+ return Some(revloc);
+ }
+ }
+ None
+ }
+
+ // Only call this when you know it is safe to double the size of the buffer.
+ #[inline]
+ fn grow_owned_buf(&mut self) {
+ let old_len = self.owned_buf.len();
+ let new_len = max(1, old_len * 2);
+
+ let starting_active_size = self.used_space();
+
+ let diff = new_len - old_len;
+ self.owned_buf.resize(new_len, 0);
+ self.head += diff;
+
+ let ending_active_size = self.used_space();
+ debug_assert_eq!(starting_active_size, ending_active_size);
+
+ if new_len == 1 {
+ return;
+ }
+
+ // calculate the midpoint, and safely copy the old end data to the new
+ // end position:
+ let middle = new_len / 2;
+ {
+ let (left, right) = &mut self.owned_buf[..].split_at_mut(middle);
+ right.copy_from_slice(left);
+ }
+ // finally, zero out the old end data.
+ {
+ let ptr = (&mut self.owned_buf[..middle]).as_mut_ptr();
+ unsafe {
+ write_bytes(ptr, 0, middle);
+ }
+ }
+ }
+
+ // with or without a size prefix changes how we load the data, so finish*
+ // functions are split along those lines.
+ fn finish_with_opts<T>(
+ &mut self,
+ root: WIPOffset<T>,
+ file_identifier: Option<&str>,
+ size_prefixed: bool,
+ ) {
+ self.assert_not_finished("buffer cannot be finished when it is already finished");
+ self.assert_not_nested(
+ "buffer cannot be finished when a table or vector is under construction",
+ );
+ self.written_vtable_revpos.clear();
+
+ let to_align = {
+ // for the root offset:
+ let a = SIZE_UOFFSET;
+ // for the size prefix:
+ let b = if size_prefixed { SIZE_UOFFSET } else { 0 };
+ // for the file identifier (a string that is not zero-terminated):
+ let c = if file_identifier.is_some() {
+ FILE_IDENTIFIER_LENGTH
+ } else {
+ 0
+ };
+ a + b + c
+ };
+
+ {
+ let ma = PushAlignment::new(self.min_align);
+ self.align(to_align, ma);
+ }
+
+ if let Some(ident) = file_identifier {
+ debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
+ self.push_bytes_unprefixed(ident.as_bytes());
+ }
+
+ self.push(root);
+
+ if size_prefixed {
+ let sz = self.used_space() as UOffsetT;
+ self.push::<UOffsetT>(sz);
+ }
+ self.finished = true;
+ }
+
+ #[inline]
+ fn align(&mut self, len: usize, alignment: PushAlignment) {
+ self.track_min_align(alignment.value());
+ let s = self.used_space() as usize;
+ self.make_space(padding_bytes(s + len, alignment.value()));
+ }
+
+ #[inline]
+ fn track_min_align(&mut self, alignment: usize) {
+ self.min_align = max(self.min_align, alignment);
+ }
+
+ #[inline]
+ fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT {
+ let n = self.make_space(x.len());
+ &mut self.owned_buf[n..n + x.len()].copy_from_slice(x);
+
+ n as UOffsetT
+ }
+
+ #[inline]
+ fn make_space(&mut self, want: usize) -> usize {
+ self.ensure_capacity(want);
+ self.head -= want;
+ self.head
+ }
+
+ #[inline]
+ fn ensure_capacity(&mut self, want: usize) -> usize {
+ if self.unused_ready_space() >= want {
+ return want;
+ }
+ assert!(
+ want <= FLATBUFFERS_MAX_BUFFER_SIZE,
+ "cannot grow buffer beyond 2 gigabytes"
+ );
+
+ while self.unused_ready_space() < want {
+ self.grow_owned_buf();
+ }
+ want
+ }
+ #[inline]
+ fn unused_ready_space(&self) -> usize {
+ self.head
+ }
+ #[inline]
+ fn assert_nested(&self, fn_name: &'static str) {
+ // we don't assert that self.field_locs.len() >0 because the vtable
+ // could be empty (e.g. for empty tables, or for all-default values).
+ debug_assert!(
+ self.nested,
+ format!(
+ "incorrect FlatBufferBuilder usage: {} must be called while in a nested state",
+ fn_name
+ )
+ );
+ }
+ #[inline]
+ fn assert_not_nested(&self, msg: &'static str) {
+ debug_assert!(!self.nested, msg);
+ }
+ #[inline]
+ fn assert_finished(&self, msg: &'static str) {
+ debug_assert!(self.finished, msg);
+ }
+ #[inline]
+ fn assert_not_finished(&self, msg: &'static str) {
+ debug_assert!(!self.finished, msg);
+ }
+}
+
+/// Compute the length of the vtable needed to represent the provided FieldLocs.
+/// If there are no FieldLocs, then provide the minimum number of bytes
+/// required: enough to write the VTable header.
+#[inline]
+fn get_vtable_byte_len(field_locs: &[FieldLoc]) -> usize {
+ let max_voffset = field_locs.iter().map(|fl| fl.id).max();
+ match max_voffset {
+ None => field_index_to_field_offset(0) as usize,
+ Some(mv) => mv as usize + SIZE_VOFFSET,
+ }
+}
+
+#[inline]
+fn padding_bytes(buf_size: usize, scalar_size: usize) -> usize {
+ // ((!buf_size) + 1) & (scalar_size - 1)
+ (!buf_size).wrapping_add(1) & (scalar_size.wrapping_sub(1))
+}
+
+impl<'fbb> Default for FlatBufferBuilder<'fbb> {
+ fn default() -> Self {
+ Self::new_with_capacity(0)
+ }
+}
diff --git a/rust/flatbuffers/src/endian_scalar.rs b/rust/flatbuffers/src/endian_scalar.rs
new file mode 100644
index 0000000..df0b384
--- /dev/null
+++ b/rust/flatbuffers/src/endian_scalar.rs
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::mem::size_of;
+
+/// Trait for values that must be stored in little-endian byte order, but
+/// might be represented in memory as big-endian. Every type that implements
+/// EndianScalar is a valid FlatBuffers scalar value.
+///
+/// The Rust stdlib does not provide a trait to represent scalars, so this trait
+/// serves that purpose, too.
+///
+/// Note that we do not use the num-traits crate for this, because it provides
+/// "too much". For example, num-traits provides i128 support, but that is an
+/// invalid FlatBuffers type.
+pub trait EndianScalar: Sized + PartialEq + Copy + Clone {
+ fn to_little_endian(self) -> Self;
+ fn from_little_endian(self) -> Self;
+}
+
+/// Macro for implementing a no-op endian conversion. This is used for types
+/// that are one byte wide.
+macro_rules! impl_endian_scalar_noop {
+ ($ty:ident) => {
+ impl EndianScalar for $ty {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ self
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ self
+ }
+ }
+ };
+}
+
+/// Macro for implementing an endian conversion using the stdlib `to_le` and
+/// `from_le` functions. This is used for integer types. It is not used for
+/// floats, because the `to_le` and `from_le` are not implemented for them in
+/// the stdlib.
+macro_rules! impl_endian_scalar_stdlib_le_conversion {
+ ($ty:ident) => {
+ impl EndianScalar for $ty {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ Self::to_le(self)
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ Self::from_le(self)
+ }
+ }
+ };
+}
+
+impl_endian_scalar_noop!(bool);
+impl_endian_scalar_noop!(u8);
+impl_endian_scalar_noop!(i8);
+
+impl_endian_scalar_stdlib_le_conversion!(u16);
+impl_endian_scalar_stdlib_le_conversion!(u32);
+impl_endian_scalar_stdlib_le_conversion!(u64);
+impl_endian_scalar_stdlib_le_conversion!(i16);
+impl_endian_scalar_stdlib_le_conversion!(i32);
+impl_endian_scalar_stdlib_le_conversion!(i64);
+
+impl EndianScalar for f32 {
+ /// Convert f32 from host endian-ness to little-endian.
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ byte_swap_f32(self)
+ }
+ }
+ /// Convert f32 from little-endian to host endian-ness.
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ byte_swap_f32(self)
+ }
+ }
+}
+
+impl EndianScalar for f64 {
+ /// Convert f64 from host endian-ness to little-endian.
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ byte_swap_f64(self)
+ }
+ }
+ /// Convert f64 from little-endian to host endian-ness.
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ #[cfg(target_endian = "little")]
+ {
+ self
+ }
+ #[cfg(not(target_endian = "little"))]
+ {
+ byte_swap_f64(self)
+ }
+ }
+}
+
+/// Swaps the bytes of an f32.
+#[allow(dead_code)]
+#[inline]
+pub fn byte_swap_f32(x: f32) -> f32 {
+ f32::from_bits(x.to_bits().swap_bytes())
+}
+
+/// Swaps the bytes of an f64.
+#[allow(dead_code)]
+#[inline]
+pub fn byte_swap_f64(x: f64) -> f64 {
+ f64::from_bits(x.to_bits().swap_bytes())
+}
+
+/// Place an EndianScalar into the provided mutable byte slice. Performs
+/// endian conversion, if necessary.
+#[inline]
+pub fn emplace_scalar<T: EndianScalar>(s: &mut [u8], x: T) {
+ let sz = size_of::<T>();
+ let mut_ptr = (&mut s[..sz]).as_mut_ptr() as *mut T;
+ let val = x.to_little_endian();
+ unsafe {
+ *mut_ptr = val;
+ }
+}
+
+/// Read an EndianScalar from the provided byte slice at the specified location.
+/// Performs endian conversion, if necessary.
+#[inline]
+pub fn read_scalar_at<T: EndianScalar>(s: &[u8], loc: usize) -> T {
+ let buf = &s[loc..loc + size_of::<T>()];
+ read_scalar(buf)
+}
+
+/// Read an EndianScalar from the provided byte slice. Performs endian
+/// conversion, if necessary.
+#[inline]
+pub fn read_scalar<T: EndianScalar>(s: &[u8]) -> T {
+ let sz = size_of::<T>();
+
+ let p = (&s[..sz]).as_ptr() as *const T;
+ let x = unsafe { *p };
+
+ x.from_little_endian()
+}
diff --git a/rust/flatbuffers/src/follow.rs b/rust/flatbuffers/src/follow.rs
new file mode 100644
index 0000000..4d3eff7
--- /dev/null
+++ b/rust/flatbuffers/src/follow.rs
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::marker::PhantomData;
+
+/// Follow is a trait that allows us to access FlatBuffers in a declarative,
+/// type safe, and fast way. They compile down to almost no code (after
+/// optimizations). Conceptually, Follow lifts the offset-based access
+/// patterns of FlatBuffers data into the type system. This trait is used
+/// pervasively at read time, to access tables, vtables, vectors, strings, and
+/// all other data. At this time, Follow is not utilized much on the write
+/// path.
+///
+/// Writing a new Follow implementation primarily involves deciding whether
+/// you want to return data (of the type Self::Inner) or do you want to
+/// continue traversing the FlatBuffer.
+pub trait Follow<'a> {
+ type Inner;
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner;
+}
+
+/// Execute a follow as a top-level function.
+#[allow(dead_code)]
+#[inline]
+pub fn lifted_follow<'a, T: Follow<'a>>(buf: &'a [u8], loc: usize) -> T::Inner {
+ T::follow(buf, loc)
+}
+
+/// FollowStart wraps a Follow impl in a struct type. This can make certain
+/// programming patterns more ergonomic.
+#[derive(Debug)]
+pub struct FollowStart<T>(PhantomData<T>);
+impl<'a, T: Follow<'a> + 'a> FollowStart<T> {
+ #[inline]
+ pub fn new() -> Self {
+ Self { 0: PhantomData }
+ }
+ #[inline]
+ pub fn self_follow(&'a self, buf: &'a [u8], loc: usize) -> T::Inner {
+ T::follow(buf, loc)
+ }
+}
+impl<'a, T: Follow<'a>> Follow<'a> for FollowStart<T> {
+ type Inner = T::Inner;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ T::follow(buf, loc)
+ }
+}
diff --git a/rust/flatbuffers/src/lib.rs b/rust/flatbuffers/src/lib.rs
new file mode 100644
index 0000000..ef54132
--- /dev/null
+++ b/rust/flatbuffers/src/lib.rs
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! # FlatBuffers
+//!
+//! A library for memory-efficient serialization of data.
+//!
+//! This crate provides runtime support for the FlatBuffers format in the Rust programming language.
+//! To use this crate, first generate code with the `flatc` compiler, as described here: https://google.github.io/flatbuffers/
+//! Then, include that code into your project.
+//! Finally, add this crate to your `Cargo.toml`.
+//!
+//! At this time, Rust support is experimental, and APIs may change between minor versions.
+//!
+//! At this time, to generate Rust code, you will need the latest `master` version of `flatc`, available from here: https://github.com/google/flatbuffers
+//! (On OSX, you can install FlatBuffers from `HEAD` with the Homebrew package manager.)
+
+mod builder;
+mod endian_scalar;
+mod follow;
+mod primitives;
+mod push;
+mod table;
+mod vector;
+mod vtable;
+mod vtable_writer;
+
+pub use builder::FlatBufferBuilder;
+pub use endian_scalar::{
+ byte_swap_f32, byte_swap_f64, emplace_scalar, read_scalar, read_scalar_at, EndianScalar,
+};
+pub use follow::{Follow, FollowStart};
+pub use primitives::*;
+pub use push::Push;
+pub use table::{buffer_has_identifier, get_root, get_size_prefixed_root, Table};
+pub use vector::{follow_cast_ref, SafeSliceAccess, Vector};
+pub use vtable::field_index_to_field_offset;
+
+// TODO(rw): Unify `create_vector` and `create_vector_direct` by using
+// `Into<Vector<...>>`.
+// TODO(rw): Split fill ops in builder into fill_small, fill_big like in C++.
diff --git a/rust/flatbuffers/src/primitives.rs b/rust/flatbuffers/src/primitives.rs
new file mode 100644
index 0000000..cfd4140
--- /dev/null
+++ b/rust/flatbuffers/src/primitives.rs
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::marker::PhantomData;
+use std::mem::size_of;
+use std::ops::Deref;
+
+use endian_scalar::{emplace_scalar, read_scalar, read_scalar_at};
+use follow::Follow;
+use push::Push;
+
+pub const FLATBUFFERS_MAX_BUFFER_SIZE: usize = (1u64 << 31) as usize;
+
+pub const FILE_IDENTIFIER_LENGTH: usize = 4;
+
+pub const VTABLE_METADATA_FIELDS: usize = 2;
+
+pub const SIZE_U8: usize = size_of::<u8>();
+pub const SIZE_I8: usize = size_of::<i8>();
+
+pub const SIZE_U16: usize = size_of::<u16>();
+pub const SIZE_I16: usize = size_of::<i16>();
+
+pub const SIZE_U32: usize = size_of::<u32>();
+pub const SIZE_I32: usize = size_of::<i32>();
+
+pub const SIZE_U64: usize = size_of::<u64>();
+pub const SIZE_I64: usize = size_of::<i64>();
+
+pub const SIZE_F32: usize = size_of::<f32>();
+pub const SIZE_F64: usize = size_of::<f64>();
+
+pub const SIZE_SOFFSET: usize = SIZE_I32;
+pub const SIZE_UOFFSET: usize = SIZE_U32;
+pub const SIZE_VOFFSET: usize = SIZE_I16;
+
+pub const SIZE_SIZEPREFIX: usize = SIZE_UOFFSET;
+
+/// SOffsetT is an i32 that is used by tables to reference their vtables.
+pub type SOffsetT = i32;
+
+/// UOffsetT is a u32 that is used by pervasively to represent both pointers
+/// and lengths of vectors.
+pub type UOffsetT = u32;
+
+/// VOffsetT is a i32 that is used by vtables to store field data.
+pub type VOffsetT = i16;
+
+/// TableFinishedWIPOffset marks a WIPOffset as being for a finished table.
+pub struct TableFinishedWIPOffset {}
+
+/// TableUnfinishedWIPOffset marks a WIPOffset as being for an unfinished table.
+pub struct TableUnfinishedWIPOffset {}
+
+/// UnionWIPOffset marks a WIPOffset as being for a union value.
+pub struct UnionWIPOffset {}
+
+/// VTableWIPOffset marks a WIPOffset as being for a vtable.
+pub struct VTableWIPOffset {}
+
+/// WIPOffset contains an UOffsetT with a special meaning: it is the location of
+/// data relative to the *end* of an in-progress FlatBuffer. The
+/// FlatBufferBuilder uses this to track the location of objects in an absolute
+/// way. The impl of Push converts a WIPOffset into a ForwardsUOffset.
+#[derive(Debug)]
+pub struct WIPOffset<T>(UOffsetT, PhantomData<T>);
+
+// TODO(rw): why do we need to reimplement (with a default impl) Copy to
+// avoid ownership errors?
+impl<T> Copy for WIPOffset<T> {}
+impl<T> Clone for WIPOffset<T> {
+ #[inline]
+ fn clone(&self) -> WIPOffset<T> {
+ WIPOffset::new(self.0.clone())
+ }
+}
+impl<T> PartialEq for WIPOffset<T> {
+ fn eq(&self, o: &WIPOffset<T>) -> bool {
+ self.value() == o.value()
+ }
+}
+
+impl<T> Deref for WIPOffset<T> {
+ type Target = UOffsetT;
+ #[inline]
+ fn deref(&self) -> &UOffsetT {
+ &self.0
+ }
+}
+impl<'a, T: 'a> WIPOffset<T> {
+ /// Create a new WIPOffset.
+ #[inline]
+ pub fn new(o: UOffsetT) -> WIPOffset<T> {
+ WIPOffset {
+ 0: o,
+ 1: PhantomData,
+ }
+ }
+
+ /// Return a wrapped value that brings its meaning as a union WIPOffset
+ /// into the type system.
+ #[inline(always)]
+ pub fn as_union_value(&self) -> WIPOffset<UnionWIPOffset> {
+ WIPOffset::new(self.0)
+ }
+ /// Get the underlying value.
+ #[inline(always)]
+ pub fn value(&self) -> UOffsetT {
+ self.0
+ }
+}
+
+impl<T> Push for WIPOffset<T> {
+ type Output = ForwardsUOffset<T>;
+
+ #[inline(always)]
+ fn push(&self, dst: &mut [u8], rest: &[u8]) {
+ let n = (SIZE_UOFFSET + rest.len() - self.value() as usize) as UOffsetT;
+ emplace_scalar::<UOffsetT>(dst, n);
+ }
+}
+
+impl<T> Push for ForwardsUOffset<T> {
+ type Output = Self;
+
+ #[inline(always)]
+ fn push(&self, dst: &mut [u8], rest: &[u8]) {
+ self.value().push(dst, rest);
+ }
+}
+
+/// ForwardsUOffset is used by Follow to traverse a FlatBuffer: the pointer
+/// is incremented by the value contained in this type.
+#[derive(Debug)]
+pub struct ForwardsUOffset<T>(UOffsetT, PhantomData<T>);
+impl<T> ForwardsUOffset<T> {
+ #[inline(always)]
+ pub fn value(&self) -> UOffsetT {
+ self.0
+ }
+}
+
+impl<'a, T: Follow<'a>> Follow<'a> for ForwardsUOffset<T> {
+ type Inner = T::Inner;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let slice = &buf[loc..loc + SIZE_UOFFSET];
+ let off = read_scalar::<u32>(slice) as usize;
+ T::follow(buf, loc + off)
+ }
+}
+
+/// ForwardsVOffset is used by Follow to traverse a FlatBuffer: the pointer
+/// is incremented by the value contained in this type.
+#[derive(Debug)]
+pub struct ForwardsVOffset<T>(VOffsetT, PhantomData<T>);
+impl<T> ForwardsVOffset<T> {
+ #[inline(always)]
+ pub fn value(&self) -> VOffsetT {
+ self.0
+ }
+}
+
+impl<'a, T: Follow<'a>> Follow<'a> for ForwardsVOffset<T> {
+ type Inner = T::Inner;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let slice = &buf[loc..loc + SIZE_VOFFSET];
+ let off = read_scalar::<VOffsetT>(slice) as usize;
+ T::follow(buf, loc + off)
+ }
+}
+
+impl<T> Push for ForwardsVOffset<T> {
+ type Output = Self;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], rest: &[u8]) {
+ self.value().push(dst, rest);
+ }
+}
+
+/// ForwardsSOffset is used by Follow to traverse a FlatBuffer: the pointer
+/// is incremented by the *negative* of the value contained in this type.
+#[derive(Debug)]
+pub struct BackwardsSOffset<T>(SOffsetT, PhantomData<T>);
+impl<T> BackwardsSOffset<T> {
+ #[inline(always)]
+ pub fn value(&self) -> SOffsetT {
+ self.0
+ }
+}
+
+impl<'a, T: Follow<'a>> Follow<'a> for BackwardsSOffset<T> {
+ type Inner = T::Inner;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let slice = &buf[loc..loc + SIZE_SOFFSET];
+ let off = read_scalar::<SOffsetT>(slice);
+ T::follow(buf, (loc as SOffsetT - off) as usize)
+ }
+}
+
+impl<T> Push for BackwardsSOffset<T> {
+ type Output = Self;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], rest: &[u8]) {
+ self.value().push(dst, rest);
+ }
+}
+
+/// SkipSizePrefix is used by Follow to traverse a FlatBuffer: the pointer is
+/// incremented by a fixed constant in order to skip over the size prefix value.
+pub struct SkipSizePrefix<T>(PhantomData<T>);
+impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipSizePrefix<T> {
+ type Inner = T::Inner;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ T::follow(buf, loc + SIZE_SIZEPREFIX)
+ }
+}
+
+/// SkipRootOffset is used by Follow to traverse a FlatBuffer: the pointer is
+/// incremented by a fixed constant in order to skip over the root offset value.
+pub struct SkipRootOffset<T>(PhantomData<T>);
+impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipRootOffset<T> {
+ type Inner = T::Inner;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ T::follow(buf, loc + SIZE_UOFFSET)
+ }
+}
+
+/// FileIdentifier is used by Follow to traverse a FlatBuffer: the pointer is
+/// dereferenced into a byte slice, whose bytes are the file identifer value.
+pub struct FileIdentifier;
+impl<'a> Follow<'a> for FileIdentifier {
+ type Inner = &'a [u8];
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ &buf[loc..loc + FILE_IDENTIFIER_LENGTH]
+ }
+}
+
+/// SkipFileIdentifier is used by Follow to traverse a FlatBuffer: the pointer
+/// is incremented by a fixed constant in order to skip over the file
+/// identifier value.
+pub struct SkipFileIdentifier<T>(PhantomData<T>);
+impl<'a, T: Follow<'a> + 'a> Follow<'a> for SkipFileIdentifier<T> {
+ type Inner = T::Inner;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ T::follow(buf, loc + FILE_IDENTIFIER_LENGTH)
+ }
+}
+
+/// Follow trait impls for primitive types.
+///
+/// Ideally, these would be implemented as a single impl using trait bounds on
+/// EndianScalar, but implementing Follow that way causes a conflict with
+/// other impls.
+macro_rules! impl_follow_for_endian_scalar {
+ ($ty:ident) => {
+ impl<'a> Follow<'a> for $ty {
+ type Inner = $ty;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ read_scalar_at::<$ty>(buf, loc)
+ }
+ }
+ };
+}
+
+impl_follow_for_endian_scalar!(bool);
+impl_follow_for_endian_scalar!(u8);
+impl_follow_for_endian_scalar!(u16);
+impl_follow_for_endian_scalar!(u32);
+impl_follow_for_endian_scalar!(u64);
+impl_follow_for_endian_scalar!(i8);
+impl_follow_for_endian_scalar!(i16);
+impl_follow_for_endian_scalar!(i32);
+impl_follow_for_endian_scalar!(i64);
+impl_follow_for_endian_scalar!(f32);
+impl_follow_for_endian_scalar!(f64);
diff --git a/rust/flatbuffers/src/push.rs b/rust/flatbuffers/src/push.rs
new file mode 100644
index 0000000..1863058
--- /dev/null
+++ b/rust/flatbuffers/src/push.rs
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::cmp::max;
+use std::mem::{align_of, size_of};
+
+use endian_scalar::emplace_scalar;
+
+/// Trait to abstract over functionality needed to write values (either owned
+/// or referenced). Used in FlatBufferBuilder and implemented for generated
+/// types.
+pub trait Push: Sized {
+ type Output;
+ fn push(&self, dst: &mut [u8], _rest: &[u8]);
+ #[inline]
+ fn size() -> usize {
+ size_of::<Self::Output>()
+ }
+ #[inline]
+ fn alignment() -> PushAlignment {
+ PushAlignment::new(align_of::<Self::Output>())
+ }
+}
+
+/// Ensure Push alignment calculations are typesafe (because this helps reduce
+/// implementation issues when using FlatBufferBuilder::align).
+pub struct PushAlignment(usize);
+impl PushAlignment {
+ #[inline]
+ pub fn new(x: usize) -> Self {
+ PushAlignment { 0: x }
+ }
+ #[inline]
+ pub fn value(&self) -> usize {
+ self.0
+ }
+ #[inline]
+ pub fn max_of(&self, o: usize) -> Self {
+ PushAlignment::new(max(self.0, o))
+ }
+}
+
+/// Macro to implement Push for EndianScalar types.
+macro_rules! impl_push_for_endian_scalar {
+ ($ty:ident) => {
+ impl Push for $ty {
+ type Output = $ty;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ emplace_scalar::<$ty>(dst, *self);
+ }
+ }
+ };
+}
+
+impl_push_for_endian_scalar!(bool);
+impl_push_for_endian_scalar!(u8);
+impl_push_for_endian_scalar!(i8);
+impl_push_for_endian_scalar!(u16);
+impl_push_for_endian_scalar!(i16);
+impl_push_for_endian_scalar!(u32);
+impl_push_for_endian_scalar!(i32);
+impl_push_for_endian_scalar!(u64);
+impl_push_for_endian_scalar!(i64);
+impl_push_for_endian_scalar!(f32);
+impl_push_for_endian_scalar!(f64);
diff --git a/rust/flatbuffers/src/table.rs b/rust/flatbuffers/src/table.rs
new file mode 100644
index 0000000..7b1c4a5
--- /dev/null
+++ b/rust/flatbuffers/src/table.rs
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use follow::Follow;
+use primitives::*;
+use vtable::VTable;
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Table<'a> {
+ pub buf: &'a [u8],
+ pub loc: usize,
+}
+
+impl<'a> Table<'a> {
+ #[inline]
+ pub fn new(buf: &'a [u8], loc: usize) -> Self {
+ Table { buf: buf, loc: loc }
+ }
+ #[inline]
+ pub fn vtable(&self) -> VTable<'a> {
+ <BackwardsSOffset<VTable<'a>>>::follow(self.buf, self.loc)
+ }
+ #[inline]
+ pub fn get<T: Follow<'a> + 'a>(
+ &self,
+ slot_byte_loc: VOffsetT,
+ default: Option<T::Inner>,
+ ) -> Option<T::Inner> {
+ let o = self.vtable().get(slot_byte_loc) as usize;
+ if o == 0 {
+ return default;
+ }
+ Some(<T>::follow(self.buf, self.loc + o))
+ }
+}
+
+impl<'a> Follow<'a> for Table<'a> {
+ type Inner = Table<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Table { buf: buf, loc: loc }
+ }
+}
+
+#[inline]
+pub fn get_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
+ <ForwardsUOffset<T>>::follow(data, 0)
+}
+#[inline]
+pub fn get_size_prefixed_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner {
+ <SkipSizePrefix<ForwardsUOffset<T>>>::follow(data, 0)
+}
+#[inline]
+pub fn buffer_has_identifier(data: &[u8], ident: &str, size_prefixed: bool) -> bool {
+ assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
+
+ let got = if size_prefixed {
+ <SkipSizePrefix<SkipRootOffset<FileIdentifier>>>::follow(data, 0)
+ } else {
+ <SkipRootOffset<FileIdentifier>>::follow(data, 0)
+ };
+
+ ident.as_bytes() == got
+}
diff --git a/rust/flatbuffers/src/vector.rs b/rust/flatbuffers/src/vector.rs
new file mode 100644
index 0000000..66653eb
--- /dev/null
+++ b/rust/flatbuffers/src/vector.rs
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::marker::PhantomData;
+use std::mem::size_of;
+use std::slice::from_raw_parts;
+use std::str::from_utf8_unchecked;
+
+#[cfg(target_endian = "little")]
+use endian_scalar::EndianScalar;
+use endian_scalar::{read_scalar, read_scalar_at};
+use follow::Follow;
+use primitives::*;
+
+#[derive(Debug)]
+pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
+
+impl<'a, T: 'a> Vector<'a, T> {
+ #[inline(always)]
+ pub fn new(buf: &'a [u8], loc: usize) -> Self {
+ Vector {
+ 0: buf,
+ 1: loc,
+ 2: PhantomData,
+ }
+ }
+
+ #[inline(always)]
+ pub fn len(&self) -> usize {
+ read_scalar::<UOffsetT>(&self.0[self.1 as usize..]) as usize
+ }
+}
+
+impl<'a, T: Follow<'a> + 'a> Vector<'a, T> {
+ #[inline(always)]
+ pub fn get(&self, idx: usize) -> T::Inner {
+ debug_assert!(idx < read_scalar::<u32>(&self.0[self.1 as usize..]) as usize);
+ let sz = size_of::<T>();
+ debug_assert!(sz > 0);
+ T::follow(self.0, self.1 as usize + SIZE_UOFFSET + sz * idx)
+ }
+}
+
+pub trait SafeSliceAccess {}
+impl<'a, T: SafeSliceAccess + 'a> Vector<'a, T> {
+ pub fn safe_slice(self) -> &'a [T] {
+ let buf = self.0;
+ let loc = self.1;
+ let sz = size_of::<T>();
+ debug_assert!(sz > 0);
+ let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
+ let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz];
+ let ptr = data_buf.as_ptr() as *const T;
+ let s: &'a [T] = unsafe { from_raw_parts(ptr, len) };
+ s
+ }
+}
+
+impl SafeSliceAccess for u8 {}
+impl SafeSliceAccess for i8 {}
+impl SafeSliceAccess for bool {}
+
+#[cfg(target_endian = "little")]
+mod le_safe_slice_impls {
+ impl super::SafeSliceAccess for u16 {}
+ impl super::SafeSliceAccess for u32 {}
+ impl super::SafeSliceAccess for u64 {}
+
+ impl super::SafeSliceAccess for i16 {}
+ impl super::SafeSliceAccess for i32 {}
+ impl super::SafeSliceAccess for i64 {}
+
+ impl super::SafeSliceAccess for f32 {}
+ impl super::SafeSliceAccess for f64 {}
+}
+
+#[cfg(target_endian = "little")]
+pub use self::le_safe_slice_impls::*;
+
+pub fn follow_cast_ref<'a, T: Sized + 'a>(buf: &'a [u8], loc: usize) -> &'a T {
+ let sz = size_of::<T>();
+ let buf = &buf[loc..loc + sz];
+ let ptr = buf.as_ptr() as *const T;
+ unsafe { &*ptr }
+}
+
+impl<'a> Follow<'a> for &'a str {
+ type Inner = &'a str;
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
+ let slice = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len];
+ let s = unsafe { from_utf8_unchecked(slice) };
+ s
+ }
+}
+
+#[cfg(target_endian = "little")]
+fn follow_slice_helper<T>(buf: &[u8], loc: usize) -> &[T] {
+ let sz = size_of::<T>();
+ debug_assert!(sz > 0);
+ let len = read_scalar_at::<UOffsetT>(&buf, loc) as usize;
+ let data_buf = &buf[loc + SIZE_UOFFSET..loc + SIZE_UOFFSET + len * sz];
+ let ptr = data_buf.as_ptr() as *const T;
+ let s: &[T] = unsafe { from_raw_parts(ptr, len) };
+ s
+}
+
+/// Implement direct slice access if the host is little-endian.
+#[cfg(target_endian = "little")]
+impl<'a, T: EndianScalar> Follow<'a> for &'a [T] {
+ type Inner = &'a [T];
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ follow_slice_helper::<T>(buf, loc)
+ }
+}
+
+/// Implement Follow for all possible Vectors that have Follow-able elements.
+impl<'a, T: Follow<'a> + 'a> Follow<'a> for Vector<'a, T> {
+ type Inner = Vector<'a, T>;
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Vector::new(buf, loc)
+ }
+}
diff --git a/rust/flatbuffers/src/vtable.rs b/rust/flatbuffers/src/vtable.rs
new file mode 100644
index 0000000..5808670
--- /dev/null
+++ b/rust/flatbuffers/src/vtable.rs
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use endian_scalar::read_scalar_at;
+use follow::Follow;
+use primitives::*;
+
+/// VTable encapsulates read-only usage of a vtable. It is only to be used
+/// by generated code.
+#[derive(Debug)]
+pub struct VTable<'a> {
+ buf: &'a [u8],
+ loc: usize,
+}
+
+impl<'a> PartialEq for VTable<'a> {
+ fn eq(&self, other: &VTable) -> bool {
+ self.as_bytes().eq(other.as_bytes())
+ }
+}
+
+impl<'a> VTable<'a> {
+ pub fn init(buf: &'a [u8], loc: usize) -> Self {
+ VTable { buf: buf, loc: loc }
+ }
+ pub fn num_fields(&self) -> usize {
+ (self.num_bytes() / SIZE_VOFFSET) - 2
+ }
+ pub fn num_bytes(&self) -> usize {
+ read_scalar_at::<VOffsetT>(self.buf, self.loc) as usize
+ }
+ pub fn object_inline_num_bytes(&self) -> usize {
+ let n = read_scalar_at::<VOffsetT>(self.buf, self.loc + SIZE_VOFFSET);
+ n as usize
+ }
+ pub fn get_field(&self, idx: usize) -> VOffsetT {
+ // TODO(rw): distinguish between None and 0?
+ if idx > self.num_fields() {
+ return 0;
+ }
+ read_scalar_at::<VOffsetT>(
+ self.buf,
+ self.loc + SIZE_VOFFSET + SIZE_VOFFSET + SIZE_VOFFSET * idx,
+ )
+ }
+ pub fn get(&self, byte_loc: VOffsetT) -> VOffsetT {
+ // TODO(rw): distinguish between None and 0?
+ if byte_loc as usize >= self.num_bytes() {
+ return 0;
+ }
+ read_scalar_at::<VOffsetT>(self.buf, self.loc + byte_loc as usize)
+ }
+ pub fn as_bytes(&self) -> &[u8] {
+ let len = self.num_bytes();
+ &self.buf[self.loc..self.loc + len]
+ }
+}
+
+#[allow(dead_code)]
+pub fn field_index_to_field_offset(field_id: VOffsetT) -> VOffsetT {
+ // Should correspond to what end_table() below builds up.
+ let fixed_fields = 2; // Vtable size and Object Size.
+ ((field_id + fixed_fields) * (SIZE_VOFFSET as VOffsetT)) as VOffsetT
+}
+
+#[allow(dead_code)]
+pub fn field_offset_to_field_index(field_o: VOffsetT) -> VOffsetT {
+ debug_assert!(field_o >= 2);
+ let fixed_fields = 2; // VTable size and Object Size.
+ (field_o / (SIZE_VOFFSET as VOffsetT)) - fixed_fields
+}
+
+impl<'a> Follow<'a> for VTable<'a> {
+ type Inner = VTable<'a>;
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ VTable::init(buf, loc)
+ }
+}
diff --git a/rust/flatbuffers/src/vtable_writer.rs b/rust/flatbuffers/src/vtable_writer.rs
new file mode 100644
index 0000000..d1e87dd
--- /dev/null
+++ b/rust/flatbuffers/src/vtable_writer.rs
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::ptr::write_bytes;
+
+use endian_scalar::{emplace_scalar, read_scalar_at};
+use primitives::*;
+
+/// VTableWriter compartmentalizes actions needed to create a vtable.
+#[derive(Debug)]
+pub struct VTableWriter<'a> {
+ buf: &'a mut [u8],
+}
+
+impl<'a> VTableWriter<'a> {
+ #[inline(always)]
+ pub fn init(buf: &'a mut [u8]) -> Self {
+ VTableWriter { buf: buf }
+ }
+
+ /// Writes the vtable length (in bytes) into the vtable.
+ ///
+ /// Note that callers already need to have computed this to initialize
+ /// a VTableWriter.
+ ///
+ /// In debug mode, asserts that the length of the underlying data is equal
+ /// to the provided value.
+ #[inline(always)]
+ pub fn write_vtable_byte_length(&mut self, n: VOffsetT) {
+ emplace_scalar::<VOffsetT>(&mut self.buf[..SIZE_VOFFSET], n);
+ debug_assert_eq!(n as usize, self.buf.len());
+ }
+
+ /// Writes an object length (in bytes) into the vtable.
+ #[inline(always)]
+ pub fn write_object_inline_size(&mut self, n: VOffsetT) {
+ emplace_scalar::<VOffsetT>(&mut self.buf[SIZE_VOFFSET..2 * SIZE_VOFFSET], n);
+ }
+
+ /// Gets an object field offset from the vtable. Only used for debugging.
+ ///
+ /// Note that this expects field offsets (which are like pointers), not
+ /// field ids (which are like array indices).
+ #[inline(always)]
+ pub fn get_field_offset(&self, vtable_offset: VOffsetT) -> VOffsetT {
+ let idx = vtable_offset as usize;
+ read_scalar_at::<VOffsetT>(&self.buf, idx)
+ }
+
+ /// Writes an object field offset into the vtable.
+ ///
+ /// Note that this expects field offsets (which are like pointers), not
+ /// field ids (which are like array indices).
+ #[inline(always)]
+ pub fn write_field_offset(&mut self, vtable_offset: VOffsetT, object_data_offset: VOffsetT) {
+ let idx = vtable_offset as usize;
+ emplace_scalar::<VOffsetT>(&mut self.buf[idx..idx + SIZE_VOFFSET], object_data_offset);
+ }
+
+ /// Clears all data in this VTableWriter. Used to cleanly undo a
+ /// vtable write.
+ #[inline(always)]
+ pub fn clear(&mut self) {
+ // This is the closest thing to memset in Rust right now.
+ let len = self.buf.len();
+ let p = self.buf.as_mut_ptr() as *mut u8;
+ unsafe {
+ write_bytes(p, 0, len);
+ }
+ }
+}
diff --git a/samples/SampleBinary.cs b/samples/SampleBinary.cs
new file mode 100644
index 0000000..d07caf7
--- /dev/null
+++ b/samples/SampleBinary.cs
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `csharp_sample.sh` script.
+
+using System;
+using FlatBuffers;
+using MyGame.Sample;
+
+class SampleBinary
+{
+ // Example how to use FlatBuffers to create and read binary buffers.
+ static void Main()
+ {
+ var builder = new FlatBufferBuilder(1);
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ var weapon1Name = builder.CreateString("Sword");
+ var weapon1Damage = 3;
+ var weapon2Name = builder.CreateString("Axe");
+ var weapon2Damage = 5;
+
+ // Use the `CreateWeapon()` helper function to create the weapons, since we set every field.
+ var weaps = new Offset<Weapon>[2];
+ weaps[0] = Weapon.CreateWeapon(builder, weapon1Name, (short)weapon1Damage);
+ weaps[1] = Weapon.CreateWeapon(builder, weapon2Name, (short)weapon2Damage);
+
+ // Serialize the FlatBuffer data.
+ var name = builder.CreateString("Orc");
+ var treasure = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ var inv = Monster.CreateInventoryVector(builder, treasure);
+ var weapons = Monster.CreateWeaponsVector(builder, weaps);
+ var pos = Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
+
+ Monster.StartMonster(builder);
+ Monster.AddPos(builder, pos);
+ Monster.AddHp(builder, (short)300);
+ Monster.AddName(builder, name);
+ Monster.AddInventory(builder, inv);
+ Monster.AddColor(builder, Color.Red);
+ Monster.AddWeapons(builder, weapons);
+ Monster.AddEquippedType(builder, Equipment.Weapon);
+ Monster.AddEquipped(builder, weaps[1].Value);
+ var orc = Monster.EndMonster(builder);
+
+ builder.Finish(orc.Value); // You could also call `Monster.FinishMonsterBuffer(builder, orc);`.
+
+ // We now have a FlatBuffer that we could store on disk or send over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ var buf = builder.DataBuffer;
+
+ // Get access to the root:
+ var monster = Monster.GetRootAsMonster(buf);
+
+ // For C#, unlike other languages, most values (except for vectors and unions) are available as
+ // properties instead of accessor methods.
+
+ // Note: We did not set the `Mana` field explicitly, so we get back the default value.
+ Assert(monster.Mana == 150, "monster.Mana", Convert.ToString(monster.Mana),
+ Convert.ToString(150));
+ Assert(monster.Hp == 300, "monster.Hp", Convert.ToString(monster.Hp), Convert.ToString(30));
+ Assert(monster.Name.Equals("Orc", StringComparison.Ordinal), "monster.Name", monster.Name,
+ "Orc");
+ Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color),
+ Convert.ToString(Color.Red));
+
+ var vec = monster.Pos.Value;
+ Assert(vec.X == 1.0f, "vec.X",
+ Convert.ToString(vec.X), Convert.ToString(1.0f));
+ Assert(vec.Y == 2.0f, "vec.Y",
+ Convert.ToString(vec.Y), Convert.ToString(2.0f));
+ Assert(vec.Z == 3.0f, "vec.Z",
+ Convert.ToString(vec.Z), Convert.ToString(3.0f));
+
+ // Get and test the `Inventory` FlatBuffer `vector`.
+ for (int i = 0; i < monster.InventoryLength; i++)
+ {
+ Assert(monster.Inventory(i) == i, "monster.Inventory",
+ Convert.ToString(monster.Inventory(i)), Convert.ToString(i));
+ }
+
+ // Get and test the `Weapons` FlatBuffer `vector` of `table`s.
+ var expectedWeaponNames = new string[] {"Sword", "Axe"};
+ var expectedWeaponDamages = new short[] {3, 5};
+ for (int i = 0; i < monster.WeaponsLength; i++)
+ {
+ Assert(monster.Weapons(i).Value.Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
+ "monster.Weapons", monster.Weapons(i).Value.Name, expectedWeaponNames[i]);
+ Assert(monster.Weapons(i).Value.Damage == expectedWeaponDamages[i], "monster.GetWeapons",
+ Convert.ToString(monster.Weapons(i).Value.Damage),
+ Convert.ToString(expectedWeaponDamages[i]));
+ }
+
+ // Get and test the `Equipped` FlatBuffer `union`.
+ Assert(monster.EquippedType == Equipment.Weapon, "monster.EquippedType",
+ Convert.ToString(monster.EquippedType), Convert.ToString(Equipment.Weapon));
+ var equipped = monster.Equipped<Weapon>().Value;
+ Assert(equipped.Name.Equals("Axe", StringComparison.Ordinal), "equipped.Name", equipped.Name,
+ "Axe");
+ Assert(equipped.Damage == 5, "equipped.Damage", Convert.ToString(equipped.Damage),
+ Convert.ToString(5));
+
+ Console.WriteLine("The FlatBuffer was successfully created and verified!");
+ }
+
+ // A helper function to handle assertions.
+ static void Assert(bool assertPassed, string codeExecuted, string actualValue,
+ string expectedValue)
+ {
+ if (assertPassed == false)
+ {
+ Console.WriteLine("Assert failed! " + codeExecuted + " (" + actualValue +
+ ") was not equal to " + expectedValue + ".");
+ System.Environment.Exit(1);
+ }
+ }
+}
diff --git a/samples/SampleBinary.java b/samples/SampleBinary.java
new file mode 100644
index 0000000..555194f
--- /dev/null
+++ b/samples/SampleBinary.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Run this file with the `java_sample.sh` script.
+
+import MyGame.Sample.Color;
+import MyGame.Sample.Equipment;
+import MyGame.Sample.Monster;
+import MyGame.Sample.Vec3;
+import MyGame.Sample.Weapon;
+
+import com.google.flatbuffers.FlatBufferBuilder;
+
+import java.nio.ByteBuffer;
+
+class SampleBinary {
+ // Example how to use FlatBuffers to create and read binary buffers.
+ public static void main(String[] args) {
+ FlatBufferBuilder builder = new FlatBufferBuilder(0);
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ int weaponOneName = builder.createString("Sword");
+ short weaponOneDamage = 3;
+ int weaponTwoName = builder.createString("Axe");
+ short weaponTwoDamage = 5;
+
+ // Use the `createWeapon()` helper function to create the weapons, since we set every field.
+ int[] weaps = new int[2];
+ weaps[0] = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage);
+ weaps[1] = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage);
+
+ // Serialize the FlatBuffer data.
+ int name = builder.createString("Orc");
+ byte[] treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ int inv = Monster.createInventoryVector(builder, treasure);
+ int weapons = Monster.createWeaponsVector(builder, weaps);
+ int pos = Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
+
+ Monster.startMonster(builder);
+ Monster.addPos(builder, pos);
+ Monster.addName(builder, name);
+ Monster.addColor(builder, Color.Red);
+ Monster.addHp(builder, (short)300);
+ Monster.addInventory(builder, inv);
+ Monster.addWeapons(builder, weapons);
+ Monster.addEquippedType(builder, Equipment.Weapon);
+ Monster.addEquipped(builder, weaps[1]);
+ int orc = Monster.endMonster(builder);
+
+ builder.finish(orc); // You could also call `Monster.finishMonsterBuffer(builder, orc);`.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ ByteBuffer buf = builder.dataBuffer();
+
+ // Get access to the root:
+ Monster monster = Monster.getRootAsMonster(buf);
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ assert monster.mana() == (short)150;
+ assert monster.hp() == (short)300;
+ assert monster.name().equals("Orc");
+ assert monster.color() == Color.Red;
+ assert monster.pos().x() == 1.0f;
+ assert monster.pos().y() == 2.0f;
+ assert monster.pos().z() == 3.0f;
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for (int i = 0; i < monster.inventoryLength(); i++) {
+ assert monster.inventory(i) == (byte)i;
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ String[] expectedWeaponNames = {"Sword", "Axe"};
+ int[] expectedWeaponDamages = {3, 5};
+ for (int i = 0; i < monster.weaponsLength(); i++) {
+ assert monster.weapons(i).name().equals(expectedWeaponNames[i]);
+ assert monster.weapons(i).damage() == expectedWeaponDamages[i];
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ assert monster.equippedType() == Equipment.Weapon;
+ Weapon equipped = (Weapon)monster.equipped(new Weapon());
+ assert equipped.name().equals("Axe");
+ assert equipped.damage() == 5;
+
+ System.out.println("The FlatBuffer was successfully created and verified!");
+ }
+}
diff --git a/samples/SampleBinary.kt b/samples/SampleBinary.kt
new file mode 100644
index 0000000..2974f36
--- /dev/null
+++ b/samples/SampleBinary.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Run this file with the `java_sample.sh` script.
+
+import MyGame.Sample.Color
+import MyGame.Sample.Equipment
+import MyGame.Sample.Monster
+import MyGame.Sample.Vec3
+import MyGame.Sample.Weapon
+
+import com.google.flatbuffers.FlatBufferBuilder
+
+class SampleBinary {
+
+ companion object {
+ // Example how to use FlatBuffers to create and read binary buffers.
+ @JvmStatic
+ fun main(args: Array<String>) {
+ val builder = FlatBufferBuilder(0)
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ val weaponOneName = builder.createString("Sword")
+ val weaponOneDamage: Short = 3
+ val weaponTwoName = builder.createString("Axe")
+ val weaponTwoDamage: Short = 5
+
+ // Use the `createWeapon()` helper function to create the weapons, since we set every field.
+ val weaps = IntArray(2)
+ weaps[0] = Weapon.createWeapon(builder, weaponOneName, weaponOneDamage)
+ weaps[1] = Weapon.createWeapon(builder, weaponTwoName, weaponTwoDamage)
+
+ // Serialize the FlatBuffer data.
+ val name = builder.createString("Orc")
+ val treasure = byteArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+ val inv = Monster.createInventoryVector(builder, treasure)
+ val weapons = Monster.createWeaponsVector(builder, weaps)
+ val pos = Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f)
+
+ Monster.startMonster(builder)
+ Monster.addPos(builder, pos)
+ Monster.addName(builder, name)
+ Monster.addColor(builder, Color.Red)
+ Monster.addHp(builder, 300.toShort())
+ Monster.addInventory(builder, inv)
+ Monster.addWeapons(builder, weapons)
+ Monster.addEquippedType(builder, Equipment.Weapon)
+ Monster.addEquipped(builder, weaps[1])
+ val orc = Monster.endMonster(builder)
+
+ builder.finish(orc) // You could also call `Monster.finishMonsterBuffer(builder, orc);`.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ val buf = builder.dataBuffer()
+
+ // Get access to the root:
+ val monster = Monster.getRootAsMonster(buf)
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ assert(monster.mana == 150.toShort())
+ assert(monster.hp == 300.toShort())
+ assert(monster.name.equals("Orc"))
+ assert(monster.color == Color.Red)
+ assert(monster.pos!!.x == 1.0f)
+ assert(monster.pos!!.y == 2.0f)
+ assert(monster.pos!!.z == 3.0f)
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for (i in 0 until monster.inventoryLength) {
+ assert(monster.inventory(i) == i.toByte().toInt())
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ val expectedWeaponNames = arrayOf("Sword", "Axe")
+ val expectedWeaponDamages = intArrayOf(3, 5)
+ for (i in 0 until monster.weaponsLength) {
+ assert(monster.weapons(i)!!.name.equals(expectedWeaponNames[i]))
+ assert(monster.weapons(i)!!.damage.toInt() == expectedWeaponDamages[i])
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ assert(monster.equippedType == Equipment.Weapon)
+ val equipped = monster.equipped(Weapon()) as Weapon?
+ assert(equipped!!.name.equals("Axe"))
+ assert(equipped.damage == 5.toShort())
+
+ println("The FlatBuffer was successfully created and verified!")
+ }
+ }
+}
diff --git a/samples/SampleBinary.php b/samples/SampleBinary.php
new file mode 100644
index 0000000..d28ffa3
--- /dev/null
+++ b/samples/SampleBinary.php
@@ -0,0 +1,115 @@
+<?php
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `php_sample.sh` script.
+
+// It is recommended that you use PSR autoload when using FlatBuffers.
+function __autoload($class_name) {
+ $class = substr($class_name, strrpos($class_name, "\\") + 1);
+ $root_dir = join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)))); // `flatbuffers` root.
+ $paths = array(join(DIRECTORY_SEPARATOR, array($root_dir, "php")),
+ join(DIRECTORY_SEPARATOR, array($root_dir, "samples", "MyGame", "Sample")));
+ foreach ($paths as $path) {
+ $file = join(DIRECTORY_SEPARATOR, array($path, $class . ".php"));
+ if (file_exists($file)) {
+ require($file);
+ break;
+ }
+ }
+}
+
+// Example how to use FlatBuffers to create and read binary buffers.
+function main() {
+ $builder = new Google\FlatBuffers\FlatbufferBuilder(0);
+
+ // Create some weapons for our Monster using the `createWeapon()` helper function.
+ $weapon_one = $builder->createString("Sword");
+ $sword = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_one, 3);
+ $weapon_two = $builder->createString("Axe");
+ $axe = \MyGame\Sample\Weapon::CreateWeapon($builder, $weapon_two, 5);
+
+ // Serialize the FlatBuffer data.
+ $name = $builder->createString("Orc");
+
+ $treasure = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ $inv = \MyGame\Sample\Monster::CreateInventoryVector($builder, $treasure);
+
+ $weaps = array($sword, $axe);
+ $weapons = \MyGame\Sample\Monster::CreateWeaponsVector($builder, $weaps);
+
+ $pos = \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
+
+ \MyGame\Sample\Monster::StartMonster($builder);
+ \MyGame\Sample\Monster::AddPos($builder, $pos);
+ \MyGame\Sample\Monster::AddHp($builder, 300);
+ \MyGame\Sample\Monster::AddName($builder, $name);
+ \MyGame\Sample\Monster::AddInventory($builder, $inv);
+ \MyGame\Sample\Monster::AddColor($builder, \MyGame\Sample\Color::Red);
+ \MyGame\Sample\Monster::AddWeapons($builder, $weapons);
+ \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon);
+ \MyGame\Sample\Monster::AddEquipped($builder, $weaps[1]);
+ $orc = \MyGame\Sample\Monster::EndMonster($builder);
+
+ $builder->finish($orc); // You may also call `\MyGame\Sample\Monster::FinishMonsterBuffer($builder, $orc);`.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ $buf = $builder->dataBuffer();
+
+ // Get access to the root:
+ $monster = \MyGame\Sample\Monster::GetRootAsMonster($buf);
+
+ $success = true; // Tracks if an assert occurred.
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ $success &= assert($monster->getMana() == 150);
+ $success &= assert($monster->getHp() == 300);
+ $success &= assert($monster->getName() == "Orc");
+ $success &= assert($monster->getColor() == \MyGame\Sample\Color::Red);
+ $success &= assert($monster->getPos()->getX() == 1.0);
+ $success &= assert($monster->getPos()->getY() == 2.0);
+ $success &= assert($monster->getPos()->getZ() == 3.0);
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for ($i = 0; $i < $monster->getInventoryLength(); $i++) {
+ $success &= assert($monster->getInventory($i) == $i);
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ $expected_weapon_names = array("Sword", "Axe");
+ $expected_weapon_damages = array(3, 5);
+ for ($i = 0; $i < $monster->getWeaponsLength(); $i++) {
+ $success &= assert($monster->getWeapons($i)->getName() == $expected_weapon_names[$i]);
+ $success &= assert($monster->getWeapons($i)->getDamage() == $expected_weapon_damages[$i]);
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ $success &= assert($monster->getEquippedType() == \MyGame\Sample\Equipment::Weapon);
+ $success &= assert($monster->getEquipped(new \MyGame\Sample\Weapon())->getName() == "Axe");
+ $success &= assert($monster->getEquipped(new \MyGame\Sample\Weapon())->getDamage() == 5);
+
+ if ($success) {
+ print("The FlatBuffer was successfully created and verified!\n");
+ }
+}
+
+main();
+?>
diff --git a/samples/android/AndroidManifest.xml b/samples/android/AndroidManifest.xml
new file mode 100644
index 0000000..352e0fa
--- /dev/null
+++ b/samples/android/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015 Google, Inc.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ -->
+<!-- BEGIN_INCLUDE(manifest) -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.samples.FlatBufferSample">
+
+ <uses-feature android:glEsVersion="0x00020000"></uses-feature>
+
+ <!-- This .apk has no Java code itself, so set hasCode to false. -->
+ <application android:label="@string/app_name"
+ android:hasCode="false"
+ android:allowBackup="false">
+ <!-- Our activity is the built-in NativeActivity framework class.
+ This will take care of integrating with our NDK code. -->
+ <activity android:name="android.app.NativeActivity"
+ android:label="@string/app_name"
+ android:configChanges="orientation|keyboardHidden"
+ android:screenOrientation="landscape">
+ <!-- Tell NativeActivity the name of or .so -->
+ <meta-data android:name="android.app.lib_name"
+ android:value="FlatBufferSample" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
+<!-- END_INCLUDE(manifest) -->
diff --git a/samples/android/build.gradle b/samples/android/build.gradle
new file mode 100644
index 0000000..81c1af0
--- /dev/null
+++ b/samples/android/build.gradle
@@ -0,0 +1,108 @@
+// Copyright (c) 2017 Google, Inc.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.0'
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion '25.0.2'
+
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ res.srcDirs = ['res']
+ }
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ path "jni/Android.mk"
+ }
+ }
+
+ defaultConfig {
+ applicationId 'com.samples.FlatBufferSample'
+ // This is the platform API where NativeActivity was introduced.
+ minSdkVersion 9
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ }
+ }
+
+ externalNativeBuild {
+ ndkBuild {
+ targets "FlatBufferSample"
+ arguments "-j" + Runtime.getRuntime().availableProcessors()
+ abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+ }
+ }
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ // Build with each STL variant.
+ productFlavors {
+ stlport {
+ applicationIdSuffix ".stlport"
+ versionNameSuffix "-stlport"
+ externalNativeBuild {
+ ndkBuild {
+ arguments "APP_STL=stlport_static"
+ }
+ }
+ }
+ gnustl {
+ applicationIdSuffix ".gnustl"
+ versionNameSuffix "-gnustl"
+ externalNativeBuild {
+ ndkBuild {
+ arguments "APP_STL=gnustl_static"
+ }
+ }
+ }
+ libcpp {
+ applicationIdSuffix ".libcpp"
+ versionNameSuffix "-libcpp"
+ externalNativeBuild {
+ ndkBuild {
+ arguments "APP_STL=c++_static"
+ }
+ }
+ }
+ }
+}
diff --git a/samples/android/gradle/wrapper/gradle-wrapper.jar b/samples/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..b4163b8
--- /dev/null
+++ b/samples/android/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/samples/android/gradle/wrapper/gradle-wrapper.properties b/samples/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1e1168c
--- /dev/null
+++ b/samples/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 19 11:54:59 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
diff --git a/samples/android/gradlew b/samples/android/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/samples/android/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/samples/android/gradlew.bat b/samples/android/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/samples/android/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/android/jni/Android.mk b/samples/android/jni/Android.mk
new file mode 100644
index 0000000..917c2f9
--- /dev/null
+++ b/samples/android/jni/Android.mk
@@ -0,0 +1,56 @@
+# Copyright (c) 2013 Google, Inc.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+LOCAL_PATH := $(call my-dir)
+FLATBUFFERS_ROOT_DIR := $(LOCAL_PATH)/../../..
+
+# FlatBuffers test
+include $(CLEAR_VARS)
+
+# Include the FlatBuffer utility function to generate header files from schemas.
+include $(FLATBUFFERS_ROOT_DIR)/android/jni/include.mk
+
+LOCAL_MODULE := FlatBufferSample
+
+# Set up some useful variables to identify schema and output directories and
+# schema files.
+ANDROID_SAMPLE_GENERATED_OUTPUT_DIR := $(LOCAL_PATH)/gen/include
+ANDROID_SAMPLE_SCHEMA_DIR := $(LOCAL_PATH)/schemas
+ANDROID_SAMPLE_SCHEMA_FILES := $(ANDROID_SAMPLE_SCHEMA_DIR)/animal.fbs
+
+LOCAL_C_INCLUDES := $(ANDROID_SAMPLE_GENERATED_OUTPUT_DIR)
+
+$(info $(LOCAL_C_INCLUDES))
+
+LOCAL_SRC_FILES := main.cpp
+
+LOCAL_CPPFLAGS := -std=c++11 -fexceptions -Wall -Wno-literal-suffix
+LOCAL_LDLIBS := -llog -landroid -latomic
+LOCAL_ARM_MODE := arm
+LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
+
+ifeq (,$(ANDROID_SAMPLE_RUN_ONCE))
+ANDROID_SAMPLE_RUN_ONCE := 1
+$(call flatbuffers_header_build_rules,$(ANDROID_SAMPLE_SCHEMA_FILES),$(ANDROID_SAMPLE_SCHEMA_DIR),$(ANDROID_SAMPLE_GENERATED_OUTPUT_DIR),,$(LOCAL_SRC_FILES))
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Path to Flatbuffers root directory.
+$(call import-add-path,$(FLATBUFFERS_ROOT_DIR)/..)
+
+$(call import-module,flatbuffers/android/jni)
+$(call import-module,android/native_app_glue)
diff --git a/samples/android/jni/Application.mk b/samples/android/jni/Application.mk
new file mode 100644
index 0000000..ca9e800
--- /dev/null
+++ b/samples/android/jni/Application.mk
@@ -0,0 +1,20 @@
+# Copyright (c) 2014 Google, Inc.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+APP_PLATFORM := android-9
+APP_PROJECT_PATH := $(call my-dir)/..
+APP_STL ?= stlport_static
+APP_ABI := armeabi-v7a
+APP_CPPFLAGS += -std=c++11
diff --git a/samples/android/jni/main.cpp b/samples/android/jni/main.cpp
new file mode 100644
index 0000000..8758027
--- /dev/null
+++ b/samples/android/jni/main.cpp
@@ -0,0 +1,43 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android/log.h>
+
+#include "android_native_app_glue.h"
+#include "animal_generated.h" // Includes "flatbuffers/flatbuffers.h".
+
+void android_main(android_app *app) {
+ app_dummy();
+
+ flatbuffers::FlatBufferBuilder builder;
+ auto name = builder.CreateString("Dog");
+ auto sound = builder.CreateString("Bark");
+ auto animal_buffer = sample::CreateAnimal(builder, name, sound);
+ builder.Finish(animal_buffer);
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store on disk or send over a network goes here...
+
+ // Instead, we're going to access it immediately, as if we just recieved this.
+
+ auto animal = sample::GetAnimal(builder.GetBufferPointer());
+
+ assert(animal->name()->str() == "Dog");
+ assert(animal->sound()->str() == "Bark");
+ (void)animal; // To silence "Unused Variable" warnings.
+
+ __android_log_print(ANDROID_LOG_INFO, "FlatBufferSample",
+ "FlatBuffer successfully created and verified.");
+}
diff --git a/samples/android/jni/schemas/animal.fbs b/samples/android/jni/schemas/animal.fbs
new file mode 100644
index 0000000..d1bd38d
--- /dev/null
+++ b/samples/android/jni/schemas/animal.fbs
@@ -0,0 +1,22 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace sample;
+
+table Animal {
+ name:string;
+ sound:string;
+}
+
+root_type Animal;
diff --git a/samples/android/res/values/strings.xml b/samples/android/res/values/strings.xml
new file mode 100644
index 0000000..57ddaf4
--- /dev/null
+++ b/samples/android/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015 Google, Inc.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ -->
+<resources>
+ <string name="app_name">FlatBufferSample</string>
+</resources>
diff --git a/samples/android_sample.sh b/samples/android_sample.sh
new file mode 100755
index 0000000..53633ac
--- /dev/null
+++ b/samples/android_sample.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script requires the Android NDK and Android SDK to be installed.
+# It also requires an Android device to be connected for installing and
+# running the applicaton.
+
+sampledir=$(readlink -fn `dirname $0`)
+currentdir=$(readlink -fn `pwd`)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Execute `build_apk.sh` to build and run the android app.
+cd android
+./gradlew build
+
+
+
diff --git a/samples/csharp_sample.sh b/samples/csharp_sample.sh
new file mode 100755
index 0000000..ea472ed
--- /dev/null
+++ b/samples/csharp_sample.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `mono` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootidr=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --csharp --gen-mutable monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --csharp --gen-mutable monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the C# sample.
+
+# Compile and execute the sample.
+mcs SampleBinary.cs MyGame/Sample/*.cs ../net/FlatBuffers/*.cs
+mono SampleBinary.exe
+
+# Cleanup temporary files.
+rm SampleBinary.exe
+rm -rf MyGame/
diff --git a/samples/dart_sample.sh b/samples/dart_sample.sh
new file mode 100755
index 0000000..5616066
--- /dev/null
+++ b/samples/dart_sample.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# Copyright 2018 Dan Field. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `Node.js` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+cd ../dart/example
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../../flatc ]; then
+ ../../flatc --dart ../../samples/monster.fbs
+elif [ -e ../../Debug/flatc ]; then
+ ../../Debug/flatc --dart ../../samples/monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the Dart sample.
+
+# Execute the sample.
+dart example.dart
+
+# Cleanup temporary files.
+git checkout monster_my_game.sample_generated.dart
+
+cd ../../samples
diff --git a/samples/go_sample.sh b/samples/go_sample.sh
new file mode 100755
index 0000000..13a96c1
--- /dev/null
+++ b/samples/go_sample.sh
@@ -0,0 +1,63 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `go` to be installed
+# and 'flatc' to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --go monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --go monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the Go sample.
+
+# Go requires a particular layout of files in order to link the necessary
+# packages. Copy these files to the respective directores to compile the
+# sample.
+mkdir -p ${sampledir}/go_gen/src/MyGame/Sample
+mkdir -p ${sampledir}/go_gen/src/github.com/google/flatbuffers/go
+cp MyGame/Sample/*.go ${sampledir}/go_gen/src/MyGame/Sample/
+cp ${sampledir}/../go/* ${sampledir}/go_gen/src/github.com/google/flatbuffers/go
+
+# Export the `GOPATH`, so that `go` will know which directories to search for
+# the libraries.
+export GOPATH=${sampledir}/go_gen/
+
+# Compile and execute the sample.
+go build -o go_sample sample_binary.go
+./go_sample
+
+# Clean up the temporary files.
+rm -rf MyGame/
+rm -rf ${sampledir}/go_gen/
+rm go_sample
diff --git a/samples/java_sample.sh b/samples/java_sample.sh
new file mode 100755
index 0000000..bd1315f
--- /dev/null
+++ b/samples/java_sample.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `java` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --java --gen-mutable monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --java --gen-mutable monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the Java sample.
+
+# Compile and execute the sample.
+javac -classpath ${sampledir}/../java:${sampledir} SampleBinary.java
+java -classpath ${sampledir}/../java:${sampledir} SampleBinary
+
+# Cleanup temporary files.
+rm -rf MyGame/
+rm ${sampledir}/../java/com/google/flatbuffers/*.class
+rm *.class
diff --git a/samples/javascript_sample.sh b/samples/javascript_sample.sh
new file mode 100755
index 0000000..4bbc478
--- /dev/null
+++ b/samples/javascript_sample.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `Node.js` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --js monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --js monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the JavaScript sample.
+
+# Execute the sample.
+node samplebinary.js
+
+# Cleanup temporary files.
+rm monster_generated.js
diff --git a/samples/kotlin_sample.sh b/samples/kotlin_sample.sh
new file mode 100755
index 0000000..30ca00a
--- /dev/null
+++ b/samples/kotlin_sample.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `kotlin` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ echo "compiling now"
+ ../flatc --kotlin --gen-mutable monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --kotlin --gen-mutable monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Compiling and running the Kotlin sample
+
+all_kt_files=`find $sampledir -name "*.kt" -print`
+# Run test
+mkdir -v "${sampledir}/kotlin"
+echo Compiling Java Runtime
+javac ${rootdir}/java/com/google/flatbuffers/*.java -d ${sampledir}/kotlin
+echo Compiling Kotlin source
+kotlinc -classpath ${sampledir}/../java:${sampledir}/kotlin $all_kt_files SampleBinary.kt -include-runtime -d ${sampledir}/kotlin
+# Make jar
+echo Making jar
+jar cvf ${sampledir}/kotlin/kotlin_sample.jar -C ${sampledir}/kotlin . > /dev/null
+echo Running test
+kotlin -cp ${sampledir}/kotlin/kotlin_sample.jar SampleBinary
+
+# Cleanup temporary files.
+# rm -rf MyGame/
+# rm -rf ${sampledir}/kotlin
diff --git a/samples/lua/MyGame/Sample/Color.lua b/samples/lua/MyGame/Sample/Color.lua
new file mode 100644
index 0000000..8bf62e1
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Color.lua
@@ -0,0 +1,11 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local Color = {
+ Red = 0,
+ Green = 1,
+ Blue = 2,
+}
+
+return Color -- return the module
\ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Equipment.lua b/samples/lua/MyGame/Sample/Equipment.lua
new file mode 100644
index 0000000..0a20b36
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Equipment.lua
@@ -0,0 +1,10 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local Equipment = {
+ NONE = 0,
+ Weapon = 1,
+}
+
+return Equipment -- return the module
\ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Monster.lua b/samples/lua/MyGame/Sample/Monster.lua
new file mode 100644
index 0000000..b55c27e
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Monster.lua
@@ -0,0 +1,122 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local flatbuffers = require('flatbuffers')
+
+local Monster = {} -- the module
+local Monster_mt = {} -- the class metatable
+
+function Monster.New()
+ local o = {}
+ setmetatable(o, {__index = Monster_mt})
+ return o
+end
+function Monster.GetRootAsMonster(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Monster.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Monster_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Monster_mt:Pos()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = o + self.view.pos
+ local obj = require('MyGame.Sample.Vec3').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Mana()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 150
+end
+function Monster_mt:Hp()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 100
+end
+function Monster_mt:Name()
+ local o = self.view:Offset(10)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Monster_mt:Inventory(j)
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:InventoryLength()
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Color()
+ local o = self.view:Offset(16)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 2
+end
+function Monster_mt:Weapons(j)
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Sample.Weapon').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:WeaponsLength()
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:EquippedType()
+ local o = self.view:Offset(20)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Equipped()
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
+ self.view:Union(obj, o)
+ return obj
+ end
+end
+function Monster.Start(builder) builder:StartObject(10) end
+function Monster.AddPos(builder, pos) builder:PrependStructSlot(0, pos, 0) end
+function Monster.AddMana(builder, mana) builder:PrependInt16Slot(1, mana, 150) end
+function Monster.AddHp(builder, hp) builder:PrependInt16Slot(2, hp, 100) end
+function Monster.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(3, name, 0) end
+function Monster.AddInventory(builder, inventory) builder:PrependUOffsetTRelativeSlot(5, inventory, 0) end
+function Monster.StartInventoryVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddColor(builder, color) builder:PrependInt8Slot(6, color, 2) end
+function Monster.AddWeapons(builder, weapons) builder:PrependUOffsetTRelativeSlot(7, weapons, 0) end
+function Monster.StartWeaponsVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddEquippedType(builder, equippedType) builder:PrependUint8Slot(8, equippedType, 0) end
+function Monster.AddEquipped(builder, equipped) builder:PrependUOffsetTRelativeSlot(9, equipped, 0) end
+function Monster.End(builder) return builder:EndObject() end
+
+return Monster -- return the module
\ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Vec3.lua b/samples/lua/MyGame/Sample/Vec3.lua
new file mode 100644
index 0000000..d42b055
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Vec3.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local flatbuffers = require('flatbuffers')
+
+local Vec3 = {} -- the module
+local Vec3_mt = {} -- the class metatable
+
+function Vec3.New()
+ local o = {}
+ setmetatable(o, {__index = Vec3_mt})
+ return o
+end
+function Vec3_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Vec3_mt:X()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 0)
+end
+function Vec3_mt:Y()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 4)
+end
+function Vec3_mt:Z()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 8)
+end
+function Vec3.CreateVec3(builder, x, y, z)
+ builder:Prep(4, 12)
+ builder:PrependFloat32(z)
+ builder:PrependFloat32(y)
+ builder:PrependFloat32(x)
+ return builder:Offset()
+end
+
+return Vec3 -- return the module
\ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Weapon.lua b/samples/lua/MyGame/Sample/Weapon.lua
new file mode 100644
index 0000000..60442b9
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Weapon.lua
@@ -0,0 +1,42 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local flatbuffers = require('flatbuffers')
+
+local Weapon = {} -- the module
+local Weapon_mt = {} -- the class metatable
+
+function Weapon.New()
+ local o = {}
+ setmetatable(o, {__index = Weapon_mt})
+ return o
+end
+function Weapon.GetRootAsWeapon(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Weapon.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Weapon_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Weapon_mt:Name()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Weapon_mt:Damage()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 0
+end
+function Weapon.Start(builder) builder:StartObject(2) end
+function Weapon.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(0, name, 0) end
+function Weapon.AddDamage(builder, damage) builder:PrependInt16Slot(1, damage, 0) end
+function Weapon.End(builder) return builder:EndObject() end
+
+return Weapon -- return the module
\ No newline at end of file
diff --git a/samples/monster.bfbs b/samples/monster.bfbs
new file mode 100644
index 0000000..061a17b
--- /dev/null
+++ b/samples/monster.bfbs
Binary files differ
diff --git a/samples/monster.fbs b/samples/monster.fbs
new file mode 100644
index 0000000..af22451
--- /dev/null
+++ b/samples/monster.fbs
@@ -0,0 +1,33 @@
+// Example IDL file for our monster's schema.
+
+namespace MyGame.Sample;
+
+enum Color:byte { Red = 0, Green, Blue = 2 }
+
+union Equipment { Weapon } // Optionally add more tables.
+
+struct Vec3 {
+ x:float;
+ y:float;
+ z:float;
+}
+
+table Monster {
+ pos:Vec3;
+ mana:short = 150;
+ hp:short = 100;
+ name:string;
+ friendly:bool = false (deprecated);
+ inventory:[ubyte];
+ color:Color = Blue;
+ weapons:[Weapon];
+ equipped:Equipment;
+ path:[Vec3];
+}
+
+table Weapon {
+ name:string;
+ damage:short;
+}
+
+root_type Monster;
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
new file mode 100644
index 0000000..30115da
--- /dev/null
+++ b/samples/monster_generated.h
@@ -0,0 +1,877 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
+#define FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace MyGame {
+namespace Sample {
+
+struct Vec3;
+
+struct Monster;
+struct MonsterT;
+
+struct Weapon;
+struct WeaponT;
+
+bool operator==(const Vec3 &lhs, const Vec3 &rhs);
+bool operator!=(const Vec3 &lhs, const Vec3 &rhs);
+bool operator==(const MonsterT &lhs, const MonsterT &rhs);
+bool operator!=(const MonsterT &lhs, const MonsterT &rhs);
+bool operator==(const WeaponT &lhs, const WeaponT &rhs);
+bool operator!=(const WeaponT &lhs, const WeaponT &rhs);
+
+inline const flatbuffers::TypeTable *Vec3TypeTable();
+
+inline const flatbuffers::TypeTable *MonsterTypeTable();
+
+inline const flatbuffers::TypeTable *WeaponTypeTable();
+
+enum Color {
+ Color_Red = 0,
+ Color_Green = 1,
+ Color_Blue = 2,
+ Color_MIN = Color_Red,
+ Color_MAX = Color_Blue
+};
+
+inline const Color (&EnumValuesColor())[3] {
+ static const Color values[] = {
+ Color_Red,
+ Color_Green,
+ Color_Blue
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesColor() {
+ static const char * const names[4] = {
+ "Red",
+ "Green",
+ "Blue",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameColor(Color e) {
+ if (e < Color_Red || e > Color_Blue) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesColor()[index];
+}
+
+enum Equipment {
+ Equipment_NONE = 0,
+ Equipment_Weapon = 1,
+ Equipment_MIN = Equipment_NONE,
+ Equipment_MAX = Equipment_Weapon
+};
+
+inline const Equipment (&EnumValuesEquipment())[2] {
+ static const Equipment values[] = {
+ Equipment_NONE,
+ Equipment_Weapon
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesEquipment() {
+ static const char * const names[3] = {
+ "NONE",
+ "Weapon",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameEquipment(Equipment e) {
+ if (e < Equipment_NONE || e > Equipment_Weapon) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesEquipment()[index];
+}
+
+template<typename T> struct EquipmentTraits {
+ static const Equipment enum_value = Equipment_NONE;
+};
+
+template<> struct EquipmentTraits<MyGame::Sample::Weapon> {
+ static const Equipment enum_value = Equipment_Weapon;
+};
+
+struct EquipmentUnion {
+ Equipment type;
+ void *value;
+
+ EquipmentUnion() : type(Equipment_NONE), value(nullptr) {}
+ EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(Equipment_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ EquipmentUnion(const EquipmentUnion &) FLATBUFFERS_NOEXCEPT;
+ EquipmentUnion &operator=(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT
+ { EquipmentUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+ EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~EquipmentUnion() { Reset(); }
+
+ void Reset();
+
+#ifndef FLATBUFFERS_CPP98_STL
+ template <typename T>
+ void Set(T&& val) {
+ using RT = typename std::remove_reference<T>::type;
+ Reset();
+ type = EquipmentTraits<typename RT::TableType>::enum_value;
+ if (type != Equipment_NONE) {
+ value = new RT(std::forward<T>(val));
+ }
+ }
+#endif // FLATBUFFERS_CPP98_STL
+
+ static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+ MyGame::Sample::WeaponT *AsWeapon() {
+ return type == Equipment_Weapon ?
+ reinterpret_cast<MyGame::Sample::WeaponT *>(value) : nullptr;
+ }
+ const MyGame::Sample::WeaponT *AsWeapon() const {
+ return type == Equipment_Weapon ?
+ reinterpret_cast<const MyGame::Sample::WeaponT *>(value) : nullptr;
+ }
+};
+
+
+inline bool operator==(const EquipmentUnion &lhs, const EquipmentUnion &rhs) {
+ if (lhs.type != rhs.type) return false;
+ switch (lhs.type) {
+ case Equipment_NONE: {
+ return true;
+ }
+ case Equipment_Weapon: {
+ return *(reinterpret_cast<const MyGame::Sample::WeaponT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Sample::WeaponT *>(rhs.value));
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+inline bool operator!=(const EquipmentUnion &lhs, const EquipmentUnion &rhs) {
+ return !(lhs == rhs);
+}
+
+bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type);
+bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
+ private:
+ float x_;
+ float y_;
+ float z_;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return Vec3TypeTable();
+ }
+ Vec3() {
+ memset(static_cast<void *>(this), 0, sizeof(Vec3));
+ }
+ Vec3(float _x, float _y, float _z)
+ : x_(flatbuffers::EndianScalar(_x)),
+ y_(flatbuffers::EndianScalar(_y)),
+ z_(flatbuffers::EndianScalar(_z)) {
+ }
+ float x() const {
+ return flatbuffers::EndianScalar(x_);
+ }
+ void mutate_x(float _x) {
+ flatbuffers::WriteScalar(&x_, _x);
+ }
+ float y() const {
+ return flatbuffers::EndianScalar(y_);
+ }
+ void mutate_y(float _y) {
+ flatbuffers::WriteScalar(&y_, _y);
+ }
+ float z() const {
+ return flatbuffers::EndianScalar(z_);
+ }
+ void mutate_z(float _z) {
+ flatbuffers::WriteScalar(&z_, _z);
+ }
+};
+FLATBUFFERS_STRUCT_END(Vec3, 12);
+
+inline bool operator==(const Vec3 &lhs, const Vec3 &rhs) {
+ return
+ (lhs.x() == rhs.x()) &&
+ (lhs.y() == rhs.y()) &&
+ (lhs.z() == rhs.z());
+}
+
+inline bool operator!=(const Vec3 &lhs, const Vec3 &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct MonsterT : public flatbuffers::NativeTable {
+ typedef Monster TableType;
+ flatbuffers::unique_ptr<MyGame::Sample::Vec3> pos;
+ int16_t mana;
+ int16_t hp;
+ std::string name;
+ std::vector<uint8_t> inventory;
+ MyGame::Sample::Color color;
+ std::vector<flatbuffers::unique_ptr<MyGame::Sample::WeaponT>> weapons;
+ EquipmentUnion equipped;
+ std::vector<MyGame::Sample::Vec3> path;
+ MonsterT()
+ : mana(150),
+ hp(100),
+ color(MyGame::Sample::Color_Blue) {
+ }
+};
+
+inline bool operator==(const MonsterT &lhs, const MonsterT &rhs) {
+ return
+ (lhs.pos == rhs.pos) &&
+ (lhs.mana == rhs.mana) &&
+ (lhs.hp == rhs.hp) &&
+ (lhs.name == rhs.name) &&
+ (lhs.inventory == rhs.inventory) &&
+ (lhs.color == rhs.color) &&
+ (lhs.weapons == rhs.weapons) &&
+ (lhs.equipped == rhs.equipped) &&
+ (lhs.path == rhs.path);
+}
+
+inline bool operator!=(const MonsterT &lhs, const MonsterT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return MonsterTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_POS = 4,
+ VT_MANA = 6,
+ VT_HP = 8,
+ VT_NAME = 10,
+ VT_INVENTORY = 14,
+ VT_COLOR = 16,
+ VT_WEAPONS = 18,
+ VT_EQUIPPED_TYPE = 20,
+ VT_EQUIPPED = 22,
+ VT_PATH = 24
+ };
+ const MyGame::Sample::Vec3 *pos() const {
+ return GetStruct<const MyGame::Sample::Vec3 *>(VT_POS);
+ }
+ MyGame::Sample::Vec3 *mutable_pos() {
+ return GetStruct<MyGame::Sample::Vec3 *>(VT_POS);
+ }
+ int16_t mana() const {
+ return GetField<int16_t>(VT_MANA, 150);
+ }
+ bool mutate_mana(int16_t _mana) {
+ return SetField<int16_t>(VT_MANA, _mana, 150);
+ }
+ int16_t hp() const {
+ return GetField<int16_t>(VT_HP, 100);
+ }
+ bool mutate_hp(int16_t _hp) {
+ return SetField<int16_t>(VT_HP, _hp, 100);
+ }
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ flatbuffers::String *mutable_name() {
+ return GetPointer<flatbuffers::String *>(VT_NAME);
+ }
+ const flatbuffers::Vector<uint8_t> *inventory() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_INVENTORY);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_inventory() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_INVENTORY);
+ }
+ MyGame::Sample::Color color() const {
+ return static_cast<MyGame::Sample::Color>(GetField<int8_t>(VT_COLOR, 2));
+ }
+ bool mutate_color(MyGame::Sample::Color _color) {
+ return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<MyGame::Sample::Weapon>> *weapons() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<MyGame::Sample::Weapon>> *>(VT_WEAPONS);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<MyGame::Sample::Weapon>> *mutable_weapons() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<MyGame::Sample::Weapon>> *>(VT_WEAPONS);
+ }
+ MyGame::Sample::Equipment equipped_type() const {
+ return static_cast<MyGame::Sample::Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0));
+ }
+ bool mutate_equipped_type(MyGame::Sample::Equipment _equipped_type) {
+ return SetField<uint8_t>(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type), 0);
+ }
+ const void *equipped() const {
+ return GetPointer<const void *>(VT_EQUIPPED);
+ }
+ template<typename T> const T *equipped_as() const;
+ const MyGame::Sample::Weapon *equipped_as_Weapon() const {
+ return equipped_type() == MyGame::Sample::Equipment_Weapon ? static_cast<const MyGame::Sample::Weapon *>(equipped()) : nullptr;
+ }
+ void *mutable_equipped() {
+ return GetPointer<void *>(VT_EQUIPPED);
+ }
+ const flatbuffers::Vector<const MyGame::Sample::Vec3 *> *path() const {
+ return GetPointer<const flatbuffers::Vector<const MyGame::Sample::Vec3 *> *>(VT_PATH);
+ }
+ flatbuffers::Vector<const MyGame::Sample::Vec3 *> *mutable_path() {
+ return GetPointer<flatbuffers::Vector<const MyGame::Sample::Vec3 *> *>(VT_PATH);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<MyGame::Sample::Vec3>(verifier, VT_POS) &&
+ VerifyField<int16_t>(verifier, VT_MANA) &&
+ VerifyField<int16_t>(verifier, VT_HP) &&
+ VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffset(verifier, VT_INVENTORY) &&
+ verifier.VerifyVector(inventory()) &&
+ VerifyField<int8_t>(verifier, VT_COLOR) &&
+ VerifyOffset(verifier, VT_WEAPONS) &&
+ verifier.VerifyVector(weapons()) &&
+ verifier.VerifyVectorOfTables(weapons()) &&
+ VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) &&
+ VerifyOffset(verifier, VT_EQUIPPED) &&
+ VerifyEquipment(verifier, equipped(), equipped_type()) &&
+ VerifyOffset(verifier, VT_PATH) &&
+ verifier.VerifyVector(path()) &&
+ verifier.EndTable();
+ }
+ MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+template<> inline const MyGame::Sample::Weapon *Monster::equipped_as<MyGame::Sample::Weapon>() const {
+ return equipped_as_Weapon();
+}
+
+struct MonsterBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_pos(const MyGame::Sample::Vec3 *pos) {
+ fbb_.AddStruct(Monster::VT_POS, pos);
+ }
+ void add_mana(int16_t mana) {
+ fbb_.AddElement<int16_t>(Monster::VT_MANA, mana, 150);
+ }
+ void add_hp(int16_t hp) {
+ fbb_.AddElement<int16_t>(Monster::VT_HP, hp, 100);
+ }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Monster::VT_NAME, name);
+ }
+ void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) {
+ fbb_.AddOffset(Monster::VT_INVENTORY, inventory);
+ }
+ void add_color(MyGame::Sample::Color color) {
+ fbb_.AddElement<int8_t>(Monster::VT_COLOR, static_cast<int8_t>(color), 2);
+ }
+ void add_weapons(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Sample::Weapon>>> weapons) {
+ fbb_.AddOffset(Monster::VT_WEAPONS, weapons);
+ }
+ void add_equipped_type(MyGame::Sample::Equipment equipped_type) {
+ fbb_.AddElement<uint8_t>(Monster::VT_EQUIPPED_TYPE, static_cast<uint8_t>(equipped_type), 0);
+ }
+ void add_equipped(flatbuffers::Offset<void> equipped) {
+ fbb_.AddOffset(Monster::VT_EQUIPPED, equipped);
+ }
+ void add_path(flatbuffers::Offset<flatbuffers::Vector<const MyGame::Sample::Vec3 *>> path) {
+ fbb_.AddOffset(Monster::VT_PATH, path);
+ }
+ explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ MonsterBuilder &operator=(const MonsterBuilder &);
+ flatbuffers::Offset<Monster> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Monster>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Monster> CreateMonster(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const MyGame::Sample::Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
+ MyGame::Sample::Color color = MyGame::Sample::Color_Blue,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Sample::Weapon>>> weapons = 0,
+ MyGame::Sample::Equipment equipped_type = MyGame::Sample::Equipment_NONE,
+ flatbuffers::Offset<void> equipped = 0,
+ flatbuffers::Offset<flatbuffers::Vector<const MyGame::Sample::Vec3 *>> path = 0) {
+ MonsterBuilder builder_(_fbb);
+ builder_.add_path(path);
+ builder_.add_equipped(equipped);
+ builder_.add_weapons(weapons);
+ builder_.add_inventory(inventory);
+ builder_.add_name(name);
+ builder_.add_pos(pos);
+ builder_.add_hp(hp);
+ builder_.add_mana(mana);
+ builder_.add_equipped_type(equipped_type);
+ builder_.add_color(color);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Monster> CreateMonsterDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const MyGame::Sample::Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ const char *name = nullptr,
+ const std::vector<uint8_t> *inventory = nullptr,
+ MyGame::Sample::Color color = MyGame::Sample::Color_Blue,
+ const std::vector<flatbuffers::Offset<MyGame::Sample::Weapon>> *weapons = nullptr,
+ MyGame::Sample::Equipment equipped_type = MyGame::Sample::Equipment_NONE,
+ flatbuffers::Offset<void> equipped = 0,
+ const std::vector<MyGame::Sample::Vec3> *path = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto inventory__ = inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0;
+ auto weapons__ = weapons ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Sample::Weapon>>(*weapons) : 0;
+ auto path__ = path ? _fbb.CreateVectorOfStructs<MyGame::Sample::Vec3>(*path) : 0;
+ return MyGame::Sample::CreateMonster(
+ _fbb,
+ pos,
+ mana,
+ hp,
+ name__,
+ inventory__,
+ color,
+ weapons__,
+ equipped_type,
+ equipped,
+ path__);
+}
+
+flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct WeaponT : public flatbuffers::NativeTable {
+ typedef Weapon TableType;
+ std::string name;
+ int16_t damage;
+ WeaponT()
+ : damage(0) {
+ }
+};
+
+inline bool operator==(const WeaponT &lhs, const WeaponT &rhs) {
+ return
+ (lhs.name == rhs.name) &&
+ (lhs.damage == rhs.damage);
+}
+
+inline bool operator!=(const WeaponT &lhs, const WeaponT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef WeaponT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return WeaponTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_NAME = 4,
+ VT_DAMAGE = 6
+ };
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ flatbuffers::String *mutable_name() {
+ return GetPointer<flatbuffers::String *>(VT_NAME);
+ }
+ int16_t damage() const {
+ return GetField<int16_t>(VT_DAMAGE, 0);
+ }
+ bool mutate_damage(int16_t _damage) {
+ return SetField<int16_t>(VT_DAMAGE, _damage, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyField<int16_t>(verifier, VT_DAMAGE) &&
+ verifier.EndTable();
+ }
+ WeaponT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(WeaponT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Weapon> Pack(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct WeaponBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Weapon::VT_NAME, name);
+ }
+ void add_damage(int16_t damage) {
+ fbb_.AddElement<int16_t>(Weapon::VT_DAMAGE, damage, 0);
+ }
+ explicit WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ WeaponBuilder &operator=(const WeaponBuilder &);
+ flatbuffers::Offset<Weapon> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Weapon>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Weapon> CreateWeapon(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ int16_t damage = 0) {
+ WeaponBuilder builder_(_fbb);
+ builder_.add_name(name);
+ builder_.add_damage(damage);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Weapon> CreateWeaponDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *name = nullptr,
+ int16_t damage = 0) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ return MyGame::Sample::CreateWeapon(
+ _fbb,
+ name__,
+ damage);
+}
+
+flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new MonsterT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = pos(); if (_e) _o->pos = flatbuffers::unique_ptr<MyGame::Sample::Vec3>(new MyGame::Sample::Vec3(*_e)); };
+ { auto _e = mana(); _o->mana = _e; };
+ { auto _e = hp(); _o->hp = _e; };
+ { auto _e = name(); if (_e) _o->name = _e->str(); };
+ { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
+ { auto _e = color(); _o->color = _e; };
+ { auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = flatbuffers::unique_ptr<MyGame::Sample::WeaponT>(_e->Get(_i)->UnPack(_resolver)); } } };
+ { auto _e = equipped_type(); _o->equipped.type = _e; };
+ { auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
+ { auto _e = path(); if (_e) { _o->path.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->path[_i] = *_e->Get(_i); } } };
+}
+
+inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonster(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _pos = _o->pos ? _o->pos.get() : 0;
+ auto _mana = _o->mana;
+ auto _hp = _o->hp;
+ auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
+ auto _inventory = _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0;
+ auto _color = _o->color;
+ auto _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Sample::Weapon>> (_o->weapons.size(), [](size_t i, _VectorArgs *__va) { return CreateWeapon(*__va->__fbb, __va->__o->weapons[i].get(), __va->__rehasher); }, &_va ) : 0;
+ auto _equipped_type = _o->equipped.type;
+ auto _equipped = _o->equipped.Pack(_fbb);
+ auto _path = _o->path.size() ? _fbb.CreateVectorOfStructs(_o->path) : 0;
+ return MyGame::Sample::CreateMonster(
+ _fbb,
+ _pos,
+ _mana,
+ _hp,
+ _name,
+ _inventory,
+ _color,
+ _weapons,
+ _equipped_type,
+ _equipped,
+ _path);
+}
+
+inline WeaponT *Weapon::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new WeaponT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Weapon::UnPackTo(WeaponT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = name(); if (_e) _o->name = _e->str(); };
+ { auto _e = damage(); _o->damage = _e; };
+}
+
+inline flatbuffers::Offset<Weapon> Weapon::Pack(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateWeapon(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const WeaponT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
+ auto _damage = _o->damage;
+ return MyGame::Sample::CreateWeapon(
+ _fbb,
+ _name,
+ _damage);
+}
+
+inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type) {
+ switch (type) {
+ case Equipment_NONE: {
+ return true;
+ }
+ case Equipment_Weapon: {
+ auto ptr = reinterpret_cast<const MyGame::Sample::Weapon *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default: return false;
+ }
+}
+
+inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
+ if (!values || !types) return !values && !types;
+ if (values->size() != types->size()) return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
+ if (!VerifyEquipment(
+ verifier, values->Get(i), types->GetEnum<Equipment>(i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
+ switch (type) {
+ case Equipment_Weapon: {
+ auto ptr = reinterpret_cast<const MyGame::Sample::Weapon *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+ switch (type) {
+ case Equipment_Weapon: {
+ auto ptr = reinterpret_cast<const MyGame::Sample::WeaponT *>(value);
+ return CreateWeapon(_fbb, ptr, _rehasher).Union();
+ }
+ default: return 0;
+ }
+}
+
+inline EquipmentUnion::EquipmentUnion(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+ switch (type) {
+ case Equipment_Weapon: {
+ value = new MyGame::Sample::WeaponT(*reinterpret_cast<MyGame::Sample::WeaponT *>(u.value));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+inline void EquipmentUnion::Reset() {
+ switch (type) {
+ case Equipment_Weapon: {
+ auto ptr = reinterpret_cast<MyGame::Sample::WeaponT *>(value);
+ delete ptr;
+ break;
+ }
+ default: break;
+ }
+ value = nullptr;
+ type = Equipment_NONE;
+}
+
+inline const flatbuffers::TypeTable *ColorTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Sample::ColorTypeTable
+ };
+ static const char * const names[] = {
+ "Red",
+ "Green",
+ "Blue"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *EquipmentTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Sample::WeaponTypeTable
+ };
+ static const char * const names[] = {
+ "NONE",
+ "Weapon"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_UNION, 2, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *Vec3TypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 4, 8, 12 };
+ static const char * const names[] = {
+ "x",
+ "y",
+ "z"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 3, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *MonsterTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SHORT, 0, -1 },
+ { flatbuffers::ET_SHORT, 0, -1 },
+ { flatbuffers::ET_STRING, 0, -1 },
+ { flatbuffers::ET_BOOL, 0, -1 },
+ { flatbuffers::ET_UCHAR, 1, -1 },
+ { flatbuffers::ET_CHAR, 0, 1 },
+ { flatbuffers::ET_SEQUENCE, 1, 2 },
+ { flatbuffers::ET_UTYPE, 0, 3 },
+ { flatbuffers::ET_SEQUENCE, 0, 3 },
+ { flatbuffers::ET_SEQUENCE, 1, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Sample::Vec3TypeTable,
+ MyGame::Sample::ColorTypeTable,
+ MyGame::Sample::WeaponTypeTable,
+ MyGame::Sample::EquipmentTypeTable
+ };
+ static const char * const names[] = {
+ "pos",
+ "mana",
+ "hp",
+ "name",
+ "friendly",
+ "inventory",
+ "color",
+ "weapons",
+ "equipped_type",
+ "equipped",
+ "path"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 11, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *WeaponTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_STRING, 0, -1 },
+ { flatbuffers::ET_SHORT, 0, -1 }
+ };
+ static const char * const names[] = {
+ "name",
+ "damage"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 2, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const MyGame::Sample::Monster *GetMonster(const void *buf) {
+ return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf);
+}
+
+inline const MyGame::Sample::Monster *GetSizePrefixedMonster(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<MyGame::Sample::Monster>(buf);
+}
+
+inline Monster *GetMutableMonster(void *buf) {
+ return flatbuffers::GetMutableRoot<Monster>(buf);
+}
+
+inline bool VerifyMonsterBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr);
+}
+
+inline bool VerifySizePrefixedMonsterBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<MyGame::Sample::Monster>(nullptr);
+}
+
+inline void FinishMonsterBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::Sample::Monster> root) {
+ fbb.Finish(root);
+}
+
+inline void FinishSizePrefixedMonsterBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::Sample::Monster> root) {
+ fbb.FinishSizePrefixed(root);
+}
+
+inline flatbuffers::unique_ptr<MyGame::Sample::MonsterT> UnPackMonster(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MyGame::Sample::MonsterT>(GetMonster(buf)->UnPack(res));
+}
+
+inline flatbuffers::unique_ptr<MyGame::Sample::MonsterT> UnPackSizePrefixedMonster(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MyGame::Sample::MonsterT>(GetSizePrefixedMonster(buf)->UnPack(res));
+}
+
+} // namespace Sample
+} // namespace MyGame
+
+#endif // FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
diff --git a/samples/monster_generated.lobster b/samples/monster_generated.lobster
new file mode 100644
index 0000000..702cdd4
--- /dev/null
+++ b/samples/monster_generated.lobster
@@ -0,0 +1,143 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+import flatbuffers
+
+namespace MyGame_Sample
+
+enum Color:
+ Color_Red = 0
+ Color_Green = 1
+ Color_Blue = 2
+
+enum Equipment:
+ Equipment_NONE = 0
+ Equipment_Weapon = 1
+
+class Vec3
+
+class Monster
+
+class Weapon
+
+class Vec3 : flatbuffers_handle
+ def x():
+ return buf_.read_float32_le(pos_ + 0)
+ def y():
+ return buf_.read_float32_le(pos_ + 4)
+ def z():
+ return buf_.read_float32_le(pos_ + 8)
+
+def CreateVec3(b_:flatbuffers_builder, x:float, y:float, z:float):
+ b_.Prep(4, 12)
+ b_.PrependFloat32(z)
+ b_.PrependFloat32(y)
+ b_.PrependFloat32(x)
+ return b_.Offset()
+
+class Monster : flatbuffers_handle
+ def pos():
+ let o = buf_.flatbuffers_field_struct(pos_, 4)
+ return if o: MyGame_Sample_Vec3 { buf_, o } else: nil
+ def mana():
+ return buf_.flatbuffers_field_int16(pos_, 6, 150)
+ def hp():
+ return buf_.flatbuffers_field_int16(pos_, 8, 100)
+ def name():
+ return buf_.flatbuffers_field_string(pos_, 10)
+ def inventory(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 14) + i * 1)
+ def inventory_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 14)
+ def color():
+ return Color(buf_.flatbuffers_field_int8(pos_, 16, 2))
+ def weapons(i:int):
+ return MyGame_Sample_Weapon { buf_, buf_.flatbuffers_indirect(buf_.flatbuffers_field_vector(pos_, 18) + i * 4) }
+ def weapons_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 18)
+ def equipped_type():
+ return Equipment(buf_.flatbuffers_field_int8(pos_, 20, 0))
+ def equipped_as_Weapon():
+ return MyGame_Sample_Weapon { buf_, buf_.flatbuffers_field_table(pos_, 22) }
+ def path(i:int):
+ return MyGame_Sample_Vec3 { buf_, buf_.flatbuffers_field_vector(pos_, 24) + i * 12 }
+ def path_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 24)
+
+def GetRootAsMonster(buf:string): return Monster { buf, buf.flatbuffers_indirect(0) }
+
+struct MonsterBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(11)
+ return this
+ def add_pos(pos:flatbuffers_offset):
+ b_.PrependStructSlot(0, pos)
+ return this
+ def add_mana(mana:int):
+ b_.PrependInt16Slot(1, mana, 150)
+ return this
+ def add_hp(hp:int):
+ b_.PrependInt16Slot(2, hp, 100)
+ return this
+ def add_name(name:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(3, name)
+ return this
+ def add_inventory(inventory:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(5, inventory)
+ return this
+ def add_color(color:Color):
+ b_.PrependInt8Slot(6, color, 2)
+ return this
+ def add_weapons(weapons:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(7, weapons)
+ return this
+ def add_equipped_type(equipped_type:Equipment):
+ b_.PrependUint8Slot(8, equipped_type, 0)
+ return this
+ def add_equipped(equipped:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(9, equipped)
+ return this
+ def add_path(path:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(10, path)
+ return this
+ def end():
+ return b_.EndObject()
+
+def MonsterStartInventoryVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def MonsterCreateInventoryVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependUint8(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartWeaponsVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 4)
+def MonsterCreateWeaponsVector(b_:flatbuffers_builder, v_:[flatbuffers_offset]):
+ b_.StartVector(4, v_.length, 4)
+ reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartPathVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(12, n_, 4)
+
+class Weapon : flatbuffers_handle
+ def name():
+ return buf_.flatbuffers_field_string(pos_, 4)
+ def damage():
+ return buf_.flatbuffers_field_int16(pos_, 6, 0)
+
+def GetRootAsWeapon(buf:string): return Weapon { buf, buf.flatbuffers_indirect(0) }
+
+struct WeaponBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(2)
+ return this
+ def add_name(name:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(0, name)
+ return this
+ def add_damage(damage:int):
+ b_.PrependInt16Slot(1, damage, 0)
+ return this
+ def end():
+ return b_.EndObject()
+
diff --git a/samples/monster_generated.rs b/samples/monster_generated.rs
new file mode 100644
index 0000000..9ec573c
--- /dev/null
+++ b/samples/monster_generated.rs
@@ -0,0 +1,507 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+pub mod my_game {
+ #![allow(dead_code)]
+ #![allow(unused_imports)]
+
+ use std::mem;
+ use std::marker::PhantomData;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+pub mod sample {
+ #![allow(dead_code)]
+ #![allow(unused_imports)]
+
+ use std::mem;
+ use std::marker::PhantomData;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+
+#[allow(non_camel_case_types)]
+#[repr(i8)]
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum Color {
+ Red = 0,
+ Green = 1,
+ Blue = 2
+}
+
+const ENUM_MIN_COLOR: i8 = 0;
+const ENUM_MAX_COLOR: i8 = 2;
+
+impl<'a> flatbuffers::Follow<'a> for Color {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for Color {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = i8::to_le(self as i8);
+ let p = &n as *const i8 as *const Color;
+ 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 Color;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for Color {
+ type Output = Color;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<Color>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_COLOR:[Color; 3] = [
+ Color::Red,
+ Color::Green,
+ Color::Blue
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_COLOR:[&'static str; 3] = [
+ "Red",
+ "Green",
+ "Blue"
+];
+
+pub fn enum_name_color(e: Color) -> &'static str {
+ let index: usize = e as usize;
+ ENUM_NAMES_COLOR[index]
+}
+
+#[allow(non_camel_case_types)]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum Equipment {
+ NONE = 0,
+ Weapon = 1
+}
+
+const ENUM_MIN_EQUIPMENT: u8 = 0;
+const ENUM_MAX_EQUIPMENT: u8 = 1;
+
+impl<'a> flatbuffers::Follow<'a> for Equipment {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for Equipment {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = u8::to_le(self as u8);
+ let p = &n as *const u8 as *const Equipment;
+ unsafe { *p }
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ let n = u8::from_le(self as u8);
+ let p = &n as *const u8 as *const Equipment;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for Equipment {
+ type Output = Equipment;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<Equipment>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_EQUIPMENT:[Equipment; 2] = [
+ Equipment::NONE,
+ Equipment::Weapon
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_EQUIPMENT:[&'static str; 2] = [
+ "NONE",
+ "Weapon"
+];
+
+pub fn enum_name_equipment(e: Equipment) -> &'static str {
+ let index: usize = e as usize;
+ ENUM_NAMES_EQUIPMENT[index]
+}
+
+pub struct EquipmentUnionTableOffset {}
+// struct Vec3, aligned to 4
+#[repr(C, align(4))]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Vec3 {
+ x_: f32,
+ y_: f32,
+ z_: f32,
+} // pub struct Vec3
+impl flatbuffers::SafeSliceAccess for Vec3 {}
+impl<'a> flatbuffers::Follow<'a> for Vec3 {
+ type Inner = &'a Vec3;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ <&'a Vec3>::follow(buf, loc)
+ //flatbuffers::follow_cast_ref::<Vec3>(buf, loc)
+ }
+}
+impl<'a> flatbuffers::Follow<'a> for &'a Vec3 {
+ type Inner = &'a Vec3;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::follow_cast_ref::<Vec3>(buf, loc)
+ }
+}
+impl<'b> flatbuffers::Push for Vec3 {
+ type Output = Vec3;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(self as *const Vec3 as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+impl<'b> flatbuffers::Push for &'b Vec3 {
+ type Output = Vec3;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(*self as *const Vec3 as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+
+
+impl Vec3 {
+ pub fn new<'a>(_x: f32, _y: f32, _z: f32) -> Self {
+ Vec3 {
+ x_: _x.to_little_endian(),
+ y_: _y.to_little_endian(),
+ z_: _z.to_little_endian(),
+
+ }
+ }
+ pub fn x<'a>(&'a self) -> f32 {
+ self.x_.from_little_endian()
+ }
+ pub fn y<'a>(&'a self) -> f32 {
+ self.y_.from_little_endian()
+ }
+ pub fn z<'a>(&'a self) -> f32 {
+ self.z_.from_little_endian()
+ }
+}
+
+pub enum MonsterOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct Monster<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for Monster<'a> {
+ type Inner = Monster<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> Monster<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ Monster {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args MonsterArgs<'args>) -> flatbuffers::WIPOffset<Monster<'bldr>> {
+ let mut builder = MonsterBuilder::new(_fbb);
+ if let Some(x) = args.equipped { builder.add_equipped(x); }
+ if let Some(x) = args.weapons { builder.add_weapons(x); }
+ if let Some(x) = args.inventory { builder.add_inventory(x); }
+ if let Some(x) = args.name { builder.add_name(x); }
+ if let Some(x) = args.pos { builder.add_pos(x); }
+ builder.add_hp(args.hp);
+ builder.add_mana(args.mana);
+ builder.add_equipped_type(args.equipped_type);
+ builder.add_color(args.color);
+ builder.finish()
+ }
+
+ pub const VT_POS: flatbuffers::VOffsetT = 4;
+ pub const VT_MANA: flatbuffers::VOffsetT = 6;
+ pub const VT_HP: flatbuffers::VOffsetT = 8;
+ pub const VT_NAME: flatbuffers::VOffsetT = 10;
+ pub const VT_INVENTORY: flatbuffers::VOffsetT = 14;
+ pub const VT_COLOR: flatbuffers::VOffsetT = 16;
+ pub const VT_WEAPONS: flatbuffers::VOffsetT = 18;
+ pub const VT_EQUIPPED_TYPE: flatbuffers::VOffsetT = 20;
+ pub const VT_EQUIPPED: flatbuffers::VOffsetT = 22;
+
+ #[inline]
+ pub fn pos(&'a self) -> Option<&'a Vec3> {
+ self._tab.get::<Vec3>(Monster::VT_POS, None)
+ }
+ #[inline]
+ pub fn mana(&'a self) -> i16 {
+ self._tab.get::<i16>(Monster::VT_MANA, Some(150)).unwrap()
+ }
+ #[inline]
+ pub fn hp(&'a self) -> i16 {
+ self._tab.get::<i16>(Monster::VT_HP, Some(100)).unwrap()
+ }
+ #[inline]
+ pub fn name(&'a self) -> Option<&'a str> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Monster::VT_NAME, None)
+ }
+ #[inline]
+ pub fn inventory(&'a self) -> Option<&'a [u8]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u8>>>(Monster::VT_INVENTORY, None).map(|v| v.safe_slice())
+ }
+ #[inline]
+ pub fn color(&'a self) -> Color {
+ self._tab.get::<Color>(Monster::VT_COLOR, Some(Color::Blue)).unwrap()
+ }
+ #[inline]
+ pub fn weapons(&'a self) -> Option<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Weapon<'a>>>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Weapon<'a>>>>>(Monster::VT_WEAPONS, None)
+ }
+ #[inline]
+ pub fn equipped_type(&'a self) -> Equipment {
+ self._tab.get::<Equipment>(Monster::VT_EQUIPPED_TYPE, Some(Equipment::NONE)).unwrap()
+ }
+ #[inline]
+ pub fn equipped(&'a self) -> Option<flatbuffers::Table<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Table<'a>>>(Monster::VT_EQUIPPED, None)
+ }
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn equipped_as_weapon(&'a self) -> Option<Weapon> {
+ if self.equipped_type() == Equipment::Weapon {
+ self.equipped().map(|u| Weapon::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+}
+
+pub struct MonsterArgs<'a> {
+ pub pos: Option<&'a Vec3>,
+ pub mana: i16,
+ pub hp: i16,
+ pub name: Option<flatbuffers::WIPOffset<&'a str>>,
+ pub inventory: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u8>>>,
+ pub color: Color,
+ pub weapons: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<Weapon<'a >>>>>,
+ pub equipped_type: Equipment,
+ pub equipped: Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
+}
+impl<'a> Default for MonsterArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ MonsterArgs {
+ pos: None,
+ mana: 150,
+ hp: 100,
+ name: None,
+ inventory: None,
+ color: Color::Blue,
+ weapons: None,
+ equipped_type: Equipment::NONE,
+ equipped: None,
+ }
+ }
+}
+pub struct MonsterBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> MonsterBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_pos(&mut self, pos: &'b Vec3) {
+ self.fbb_.push_slot_always::<&Vec3>(Monster::VT_POS, pos);
+ }
+ #[inline]
+ pub fn add_mana(&mut self, mana: i16) {
+ self.fbb_.push_slot::<i16>(Monster::VT_MANA, mana, 150);
+ }
+ #[inline]
+ pub fn add_hp(&mut self, hp: i16) {
+ self.fbb_.push_slot::<i16>(Monster::VT_HP, hp, 100);
+ }
+ #[inline]
+ pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_NAME, name);
+ }
+ #[inline]
+ pub fn add_inventory(&mut self, inventory: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u8>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_INVENTORY, inventory);
+ }
+ #[inline]
+ pub fn add_color(&mut self, color: Color) {
+ self.fbb_.push_slot::<Color>(Monster::VT_COLOR, color, Color::Blue);
+ }
+ #[inline]
+ pub fn add_weapons(&mut self, weapons: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<Weapon<'b >>>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_WEAPONS, weapons);
+ }
+ #[inline]
+ pub fn add_equipped_type(&mut self, equipped_type: Equipment) {
+ self.fbb_.push_slot::<Equipment>(Monster::VT_EQUIPPED_TYPE, equipped_type, Equipment::NONE);
+ }
+ #[inline]
+ pub fn add_equipped(&mut self, equipped: flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_EQUIPPED, equipped);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> MonsterBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ MonsterBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<Monster<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+pub enum WeaponOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct Weapon<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for Weapon<'a> {
+ type Inner = Weapon<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> Weapon<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ Weapon {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args WeaponArgs<'args>) -> flatbuffers::WIPOffset<Weapon<'bldr>> {
+ let mut builder = WeaponBuilder::new(_fbb);
+ if let Some(x) = args.name { builder.add_name(x); }
+ builder.add_damage(args.damage);
+ builder.finish()
+ }
+
+ pub const VT_NAME: flatbuffers::VOffsetT = 4;
+ pub const VT_DAMAGE: flatbuffers::VOffsetT = 6;
+
+ #[inline]
+ pub fn name(&'a self) -> Option<&'a str> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Weapon::VT_NAME, None)
+ }
+ #[inline]
+ pub fn damage(&'a self) -> i16 {
+ self._tab.get::<i16>(Weapon::VT_DAMAGE, Some(0)).unwrap()
+ }
+}
+
+pub struct WeaponArgs<'a> {
+ pub name: Option<flatbuffers::WIPOffset<&'a str>>,
+ pub damage: i16,
+}
+impl<'a> Default for WeaponArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ WeaponArgs {
+ name: None,
+ damage: 0,
+ }
+ }
+}
+pub struct WeaponBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> WeaponBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Weapon::VT_NAME, name);
+ }
+ #[inline]
+ pub fn add_damage(&mut self, damage: i16) {
+ self.fbb_.push_slot::<i16>(Weapon::VT_DAMAGE, damage, 0);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> WeaponBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ WeaponBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<Weapon<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+#[inline]
+pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
+ flatbuffers::get_root::<Monster<'a>>(buf)
+}
+
+#[inline]
+pub fn get_size_prefixed_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
+ flatbuffers::get_size_prefixed_root::<Monster<'a>>(buf)
+}
+
+#[inline]
+pub fn finish_monster_buffer<'a, 'b>(
+ fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ root: flatbuffers::WIPOffset<Monster<'a>>) {
+ fbb.finish(root, None);
+}
+
+#[inline]
+pub fn finish_size_prefixed_monster_buffer<'a, 'b>(fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, root: flatbuffers::WIPOffset<Monster<'a>>) {
+ fbb.finish_size_prefixed(root, None);
+}
+} // pub mod Sample
+} // pub mod MyGame
+
diff --git a/samples/monsterdata.json b/samples/monsterdata.json
new file mode 100644
index 0000000..fa60b35
--- /dev/null
+++ b/samples/monsterdata.json
@@ -0,0 +1,24 @@
+{
+ pos: {
+ x: 1.0,
+ y: 2.0,
+ z: 3.0
+ },
+ hp: 300,
+ name: "Orc",
+ weapons: [
+ {
+ name: "axe",
+ damage: 100
+ },
+ {
+ name: "bow",
+ damage: 90
+ }
+ ],
+ equipped_type: "Weapon",
+ equipped: {
+ name: "bow",
+ damage: 90
+ }
+}
diff --git a/samples/php_sample.sh b/samples/php_sample.sh
new file mode 100755
index 0000000..c23edc3
--- /dev/null
+++ b/samples/php_sample.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `php` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --php monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --php monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the PHP sample.
+
+# Execute the sample.
+php SampleBinary.php
+
+# Clean up temporary files.
+rm -rf MyGame/
diff --git a/samples/python_sample.sh b/samples/python_sample.sh
new file mode 100755
index 0000000..ca5de2b
--- /dev/null
+++ b/samples/python_sample.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Note: This script runs on Mac and Linux. It requires `python` to be installed
+# and `flatc` to be built (using `cmake` in the root directory).
+
+sampledir=$(cd $(dirname $BASH_SOURCE) && pwd)
+rootdir=$(cd $sampledir/.. && pwd)
+currentdir=$(pwd)
+
+if [[ "$sampledir" != "$currentdir" ]]; then
+ echo Error: This script must be run from inside the $sampledir directory.
+ echo You executed it from the $currentdir directory.
+ exit 1
+fi
+
+# Run `flatc`. Note: This requires you to compile using `cmake` from the
+# root `/flatbuffers` directory.
+if [ -e ../flatc ]; then
+ ../flatc --python monster.fbs
+elif [ -e ../Debug/flatc ]; then
+ ../Debug/flatc --python monster.fbs
+else
+ echo 'flatc' could not be found. Make sure to build FlatBuffers from the \
+ $rootdir directory.
+ exit 1
+fi
+
+echo Running the Python sample.
+
+# Execute the sample.
+python sample_binary.py
+
+# Clean up the temporary files.
+rm -rf MyGame
diff --git a/samples/sample_bfbs.cpp b/samples/sample_bfbs.cpp
new file mode 100644
index 0000000..9512e24
--- /dev/null
+++ b/samples/sample_bfbs.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include "monster_test_generated.h"
+#include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h".
+
+using namespace MyGame::Sample;
+
+// This is an example of parsing text straight into a buffer and then
+// generating flatbuffer (JSON) text from the buffer.
+int main(int /*argc*/, const char * /*argv*/[]) {
+ // load FlatBuffer schema (.fbs) and JSON from disk
+ std::string schema_file;
+ std::string json_file;
+ std::string bfbs_file;
+ bool ok =
+ flatbuffers::LoadFile("tests/monster_test.fbs", false, &schema_file) &&
+ flatbuffers::LoadFile("tests/monsterdata_test.golden", false, &json_file) &&
+ flatbuffers::LoadFile("tests/monster_test.bfbs", true, &bfbs_file);
+ if (!ok) {
+ printf("couldn't load files!\n");
+ return 1;
+ }
+
+ const char *include_directories[] = { "samples", "tests",
+ "tests/include_test", nullptr };
+ // parse fbs schema
+ flatbuffers::Parser parser1;
+ ok = parser1.Parse(schema_file.c_str(), include_directories);
+ assert(ok);
+
+ // inizialize parser by deserializing bfbs schema
+ flatbuffers::Parser parser2;
+ ok = parser2.Deserialize((uint8_t *)bfbs_file.c_str(), bfbs_file.length());
+ assert(ok);
+
+ // parse json in parser from fbs and bfbs
+ ok = parser1.Parse(json_file.c_str(), include_directories);
+ assert(ok);
+ ok = parser2.Parse(json_file.c_str(), include_directories);
+ assert(ok);
+
+ // to ensure it is correct, we now generate text back from the binary,
+ // and compare the two:
+ std::string jsongen1;
+ if (!GenerateText(parser1, parser1.builder_.GetBufferPointer(), &jsongen1)) {
+ printf("Couldn't serialize parsed data to JSON!\n");
+ return 1;
+ }
+
+ std::string jsongen2;
+ if (!GenerateText(parser2, parser2.builder_.GetBufferPointer(), &jsongen2)) {
+ printf("Couldn't serialize parsed data to JSON!\n");
+ return 1;
+ }
+
+ if (jsongen1 != jsongen2) {
+ printf("%s----------------\n%s", jsongen1.c_str(), jsongen2.c_str());
+ }
+
+ printf("The FlatBuffer has been parsed from JSON successfully.\n");
+}
diff --git a/samples/sample_binary.cpp b/samples/sample_binary.cpp
new file mode 100644
index 0000000..46f08bb
--- /dev/null
+++ b/samples/sample_binary.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h".
+
+using namespace MyGame::Sample;
+
+// Example how to use FlatBuffers to create and read binary buffers.
+
+int main(int /*argc*/, const char * /*argv*/ []) {
+ // Build up a serialized buffer algorithmically:
+ flatbuffers::FlatBufferBuilder builder;
+
+ // First, lets serialize some weapons for the Monster: A 'sword' and an 'axe'.
+ auto weapon_one_name = builder.CreateString("Sword");
+ short weapon_one_damage = 3;
+
+ auto weapon_two_name = builder.CreateString("Axe");
+ short weapon_two_damage = 5;
+
+ // Use the `CreateWeapon` shortcut to create Weapons with all fields set.
+ auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage);
+ auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage);
+
+ // Create a FlatBuffer's `vector` from the `std::vector`.
+ std::vector<flatbuffers::Offset<Weapon>> weapons_vector;
+ weapons_vector.push_back(sword);
+ weapons_vector.push_back(axe);
+ auto weapons = builder.CreateVector(weapons_vector);
+
+ // Second, serialize the rest of the objects needed by the Monster.
+ auto position = Vec3(1.0f, 2.0f, 3.0f);
+
+ auto name = builder.CreateString("MyMonster");
+
+ unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ auto inventory = builder.CreateVector(inv_data, 10);
+
+ // Shortcut for creating monster with all fields set:
+ auto orc = CreateMonster(builder, &position, 150, 80, name, inventory,
+ Color_Red, weapons, Equipment_Weapon, axe.Union());
+
+ builder.Finish(orc); // Serialize the root of the object.
+
+ // We now have a FlatBuffer we can store on disk or send over a network.
+
+ // ** file/network code goes here :) **
+ // access builder.GetBufferPointer() for builder.GetSize() bytes
+
+ // Instead, we're going to access it right away (as if we just received it).
+
+ // Get access to the root:
+ auto monster = GetMonster(builder.GetBufferPointer());
+
+ // Get and test some scalar types from the FlatBuffer.
+ assert(monster->hp() == 80);
+ assert(monster->mana() == 150); // default
+ assert(monster->name()->str() == "MyMonster");
+
+ // Get and test a field of the FlatBuffer's `struct`.
+ auto pos = monster->pos();
+ assert(pos);
+ assert(pos->z() == 3.0f);
+ (void)pos;
+
+ // Get a test an element from the `inventory` FlatBuffer's `vector`.
+ auto inv = monster->inventory();
+ assert(inv);
+ assert(inv->Get(9) == 9);
+ (void)inv;
+
+ // Get and test the `weapons` FlatBuffers's `vector`.
+ std::string expected_weapon_names[] = { "Sword", "Axe" };
+ short expected_weapon_damages[] = { 3, 5 };
+ auto weps = monster->weapons();
+ for (unsigned int i = 0; i < weps->size(); i++) {
+ assert(weps->Get(i)->name()->str() == expected_weapon_names[i]);
+ assert(weps->Get(i)->damage() == expected_weapon_damages[i]);
+ }
+ (void)expected_weapon_names;
+ (void)expected_weapon_damages;
+
+ // Get and test the `Equipment` union (`equipped` field).
+ assert(monster->equipped_type() == Equipment_Weapon);
+ auto equipped = static_cast<const Weapon *>(monster->equipped());
+ assert(equipped->name()->str() == "Axe");
+ assert(equipped->damage() == 5);
+ (void)equipped;
+
+ printf("The FlatBuffer was successfully created and verified!\n");
+}
diff --git a/samples/sample_binary.go b/samples/sample_binary.go
new file mode 100644
index 0000000..e04650b
--- /dev/null
+++ b/samples/sample_binary.go
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `go_sample.sh` script.
+
+package main
+
+import (
+ sample "MyGame/Sample"
+ "fmt"
+ flatbuffers "github.com/google/flatbuffers/go"
+ "strconv"
+)
+
+// Example how to use Flatbuffers to create and read binary buffers.
+func main() {
+ builder := flatbuffers.NewBuilder(0)
+
+ // Create some weapons for our Monster ("Sword" and "Axe").
+ weaponOne := builder.CreateString("Sword")
+ weaponTwo := builder.CreateString("Axe")
+
+ sample.WeaponStart(builder)
+ sample.WeaponAddName(builder, weaponOne)
+ sample.WeaponAddDamage(builder, 3)
+ sword := sample.WeaponEnd(builder)
+
+ sample.WeaponStart(builder)
+ sample.WeaponAddName(builder, weaponTwo)
+ sample.WeaponAddDamage(builder, 5)
+ axe := sample.WeaponEnd(builder)
+
+ // Serialize the FlatBuffer data.
+ name := builder.CreateString("Orc")
+
+ sample.MonsterStartInventoryVector(builder, 10)
+ // Note: Since we prepend the bytes, this loop iterates in reverse.
+ for i := 9; i >= 0; i-- {
+ builder.PrependByte(byte(i))
+ }
+ inv := builder.EndVector(10)
+
+ sample.MonsterStartWeaponsVector(builder, 2)
+ // Note: Since we prepend the weapons, prepend in reverse order.
+ builder.PrependUOffsetT(axe)
+ builder.PrependUOffsetT(sword)
+ weapons := builder.EndVector(2)
+
+ pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
+
+ sample.MonsterStart(builder)
+ sample.MonsterAddPos(builder, pos)
+ sample.MonsterAddHp(builder, 300)
+ sample.MonsterAddName(builder, name)
+ sample.MonsterAddInventory(builder, inv)
+ sample.MonsterAddColor(builder, sample.ColorRed)
+ sample.MonsterAddWeapons(builder, weapons)
+ sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
+ sample.MonsterAddEquipped(builder, axe)
+ orc := sample.MonsterEnd(builder)
+
+ builder.Finish(orc)
+
+ // We now have a FlatBuffer that we could store on disk or send over a network.
+
+ // ...Saving to file or sending over a network code goes here...
+
+ // Instead, we are going to access this buffer right away (as if we just received it).
+
+ buf := builder.FinishedBytes()
+
+ // Note: We use `0` for the offset here, since we got the data using the
+ // `builder.FinishedBytes()` method. This simulates the data you would store/receive in your
+ // FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to
+ // pass in the offset of `builder.Head()`, as the builder actually constructs the buffer
+ // backwards.
+ monster := sample.GetRootAsMonster(buf, 0)
+
+ // Note: We did not set the `mana` field explicitly, so we get the
+ // default value.
+ assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150")
+ assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300")
+ assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()),
+ "\"Orc\"")
+ assert(monster.Color() == sample.ColorRed, "`monster.Color()`",
+ strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed)))
+
+ // Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object
+ // gets created. If your code is very performance sensitive, you can pass in a pointer to an
+ // existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce
+ // the amount of object allocation/garbage collection.
+ assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`",
+ strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0")
+ assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`",
+ strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0")
+ assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`",
+ strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0")
+
+ // For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used
+ // to query the length of the vector. You can index the vector by passing an index value
+ // into the accessor.
+ for i := 0; i < monster.InventoryLength(); i++ {
+ assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`",
+ strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i))))
+ }
+
+ expectedWeaponNames := []string{"Sword", "Axe"}
+ expectedWeaponDamages := []int{3, 5}
+ weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
+ // to capture the output of that function.
+ for i := 0; i < monster.WeaponsLength(); i++ {
+ if monster.Weapons(weapon, i) {
+ assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`",
+ string(weapon.Name()), expectedWeaponNames[i])
+ assert(int(weapon.Damage()) == expectedWeaponDamages[i],
+ "`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())),
+ strconv.Itoa(expectedWeaponDamages[i]))
+ }
+ }
+
+ // For FlatBuffer `union`s, you can get the type of the union, as well as the union
+ // data itself.
+ assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`",
+ strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon)))
+
+ unionTable := new(flatbuffers.Table)
+ if monster.Equipped(unionTable) {
+ // An example of how you can appropriately convert the table depending on the
+ // FlatBuffer `union` type. You could add `else if` and `else` clauses to handle
+ // other FlatBuffer `union` types for this field. (Similarly, this could be
+ // done in a switch statement.)
+ if monster.EquippedType() == sample.EquipmentWeapon {
+ unionWeapon := new(sample.Weapon)
+ unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
+
+ assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`",
+ string(unionWeapon.Name()), "Axe")
+ assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`",
+ strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5))
+ }
+ }
+
+ fmt.Printf("The FlatBuffer was successfully created and verified!\n")
+}
+
+// A helper function to print out if an assertion failed.
+func assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) {
+ if assertPassed == false {
+ panic("Assert failed! " + codeExecuted + " (" + actualValue +
+ ") was not equal to " + expectedValue + ".")
+ }
+}
diff --git a/samples/sample_binary.lobster b/samples/sample_binary.lobster
new file mode 100644
index 0000000..cd7adab
--- /dev/null
+++ b/samples/sample_binary.lobster
@@ -0,0 +1,100 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import from "../lobster/"
+import monster_generated
+
+// Example of how to use FlatBuffers to create and read binary buffers.
+
+// Create a builder.
+let b = flatbuffers_builder {}
+
+// Create some weapons for our monster.
+let weapon_names = [ "Sword", "Axe" ]
+let weapon_damages = [ 3, 5 ]
+
+let weapon_offsets = map(weapon_names) name, i:
+ let ns = b.CreateString(name)
+ MyGame_Sample_WeaponBuilder { b }
+ .start()
+ .add_name(ns)
+ .add_damage(weapon_damages[i])
+ .end()
+
+let weapons = b.MyGame_Sample_MonsterCreateWeaponsVector(weapon_offsets)
+
+// Name of the monster.
+let name = b.CreateString("Orc")
+
+// Inventory.
+let inv = b.MyGame_Sample_MonsterCreateInventoryVector(map(10): _)
+
+// Now pack it all together in our root monster object.
+let orc = MyGame_Sample_MonsterBuilder { b }
+ .start()
+ .add_pos(b.MyGame_Sample_CreateVec3(1.0, 2.0, 3.0))
+ .add_hp(300)
+ .add_name(name)
+ .add_inventory(inv)
+ .add_color(MyGame_Sample_Color_Red)
+ .add_weapons(weapons)
+ .add_equipped_type(MyGame_Sample_Equipment_Weapon)
+ .add_equipped(weapon_offsets[1])
+ .end()
+
+// Finish the buffer!
+b.Finish(orc)
+
+// We now have a FlatBuffer that we could store on disk or send over a network.
+
+let buf = b.SizedCopy()
+
+// ...Saving to file or sending over a network code goes here...
+
+// Instead, we are going to access this buffer right away (as if we just
+// received it).
+
+// Get the root object accessor.
+let monster = MyGame_Sample_GetRootAsMonster(buf)
+
+// Note: We did not set the `mana` field explicitly, so we get a default value.
+assert monster.mana == 150
+assert monster.hp == 300
+assert monster.name == "Orc"
+assert monster.color == MyGame_Sample_Color_Red
+let pos = monster.pos
+assert pos
+assert pos.x == 1.0
+assert pos.y == 2.0
+assert pos.z == 3.0
+
+// Get and test the `inventory` FlatBuffer vector.
+for(monster.inventory_length) e, i:
+ assert monster.inventory(i) == e
+
+// Get and test the `weapons` FlatBuffer vector of tables.
+for(monster.weapons_length) i:
+ assert monster.weapons(i).name == weapon_names[i]
+ assert monster.weapons(i).damage == weapon_damages[i]
+
+// Get and test the `equipped` FlatBuffer union.
+assert monster.equipped_type() == MyGame_Sample_Equipment_Weapon
+
+// Now that we know the union value is a weapon, we can safely call as_Weapon:
+let union_weapon = monster.equipped_as_Weapon
+
+assert union_weapon.name == "Axe"
+assert union_weapon.damage == 5
+
+print "The FlatBuffer was successfully created and verified!"
diff --git a/samples/sample_binary.lua b/samples/sample_binary.lua
new file mode 100644
index 0000000..da96539
--- /dev/null
+++ b/samples/sample_binary.lua
@@ -0,0 +1,107 @@
+-- need to update the Lua path to point to the local flatbuffers implementation
+package.path = string.format("../lua/?.lua;%s",package.path)
+package.path = string.format("./lua/?.lua;%s",package.path)
+
+-- require the library
+local flatbuffers = require("flatbuffers")
+
+local binaryArray = flatbuffers.binaryArray-- for hex dump utility
+
+-- require the files generated from the schema
+local weapon = require("MyGame.Sample.Weapon")
+local monster = require("MyGame.Sample.Monster")
+local vec3 = require("MyGame.Sample.Vec3")
+local color = require("MyGame.Sample.Color")
+local equipment = require("MyGame.Sample.Equipment")
+
+-- get access to the builder, providing an array of size 1024
+local builder = flatbuffers.Builder(1024)
+
+local weaponOne = builder:CreateString("Sword")
+local weaponTwo = builder:CreateString("Axe")
+
+-- Create the first 'Weapon'
+weapon.Start(builder)
+weapon.AddName(builder, weaponOne)
+weapon.AddDamage(builder, 3)
+local sword = weapon.End(builder)
+
+-- Create the second 'Weapon'
+weapon.Start(builder)
+weapon.AddName(builder, weaponTwo)
+weapon.AddDamage(builder, 5)
+local axe = weapon.End(builder)
+
+-- Serialize a name for our mosnter, called 'orc'
+local name = builder:CreateString("Orc")
+
+-- Create a `vector` representing the inventory of the Orc. Each number
+-- could correspond to an item that can be claimed after he is slain.
+-- Note: Since we prepend the bytes, this loop iterates in reverse.
+monster.StartInventoryVector(builder, 10)
+for i=10,1,-1 do
+ builder:PrependByte(i)
+end
+local inv = builder:EndVector(10)
+
+-- Create a FlatBuffer vector and prepend the weapons.
+-- Note: Since we prepend the data, prepend them in reverse order.
+monster.StartWeaponsVector(builder, 2)
+builder:PrependUOffsetTRelative(axe)
+builder:PrependUOffsetTRelative(sword)
+local weapons = builder:EndVector(2)
+
+-- Create our monster by using Start() andEnd()
+monster.Start(builder)
+monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
+monster.AddHp(builder, 300)
+monster.AddName(builder, name)
+monster.AddInventory(builder, inv)
+monster.AddColor(builder, color.Red)
+monster.AddWeapons(builder, weapons)
+monster.AddEquippedType(builder, equipment.Weapon)
+monster.AddEquipped(builder, axe)
+local orc = monster.End(builder)
+
+-- Call 'Finish()' to instruct the builder that this monster is complete.
+builder:Finish(orc)
+
+-- Get the flatbuffer as a string containing the binary data
+local bufAsString = builder:Output()
+
+-- Convert the string representation into binary array Lua structure
+local buf = flatbuffers.binaryArray.New(bufAsString)
+
+-- Get an accessor to the root object insert the buffer
+local mon = monster.GetRootAsMonster(buf, 0)
+
+assert(mon:Mana() == 150)
+assert(mon:Hp() == 300)
+assert(mon:Name() == "Orc")
+assert(mon:Color() == color.Red)
+assert(mon:Pos():X() == 1.0)
+assert(mon:Pos():Y() == 2.0)
+assert(mon:Pos():Z() == 3.0)
+
+for i=1,mon:InventoryLength() do
+ assert(mon:Inventory(i) == i)
+end
+
+local expected = {
+ {w = 'Sword', d = 3},
+ {w = 'Axe', d = 5}
+}
+
+for i=1,mon:WeaponsLength() do
+ assert(mon:Weapons(i):Name() == expected[i].w)
+ assert(mon:Weapons(i):Damage() == expected[i].d)
+end
+
+assert(mon:EquippedType() == equipment.Weapon)
+
+local unionWeapon = weapon.New()
+unionWeapon:Init(mon:Equipped().bytes,mon:Equipped().pos)
+assert(unionWeapon:Name() == "Axe")
+assert(unionWeapon:Damage() == 5)
+
+print("The Lua FlatBuffer example was successfully created and verified!")
\ No newline at end of file
diff --git a/samples/sample_binary.py b/samples/sample_binary.py
new file mode 100644
index 0000000..96711fb
--- /dev/null
+++ b/samples/sample_binary.py
@@ -0,0 +1,137 @@
+#!/usr/bin/python
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# To run this file, use `python_sample.sh`.
+
+# Append paths to the `flatbuffers` and `MyGame` modules. This is necessary
+# to facilitate executing this script in the `samples` folder, and to root
+# folder (where it gets placed when using `cmake`).
+import os
+import sys
+sys.path.append(os.path.join(os.path.dirname(__file__), '../python'))
+
+import flatbuffers
+import MyGame.Sample.Color
+import MyGame.Sample.Equipment
+import MyGame.Sample.Monster
+import MyGame.Sample.Vec3
+import MyGame.Sample.Weapon
+
+# Example of how to use FlatBuffers to create and read binary buffers.
+
+def main():
+ builder = flatbuffers.Builder(0)
+
+ # Create some weapons for our Monster ('Sword' and 'Axe').
+ weapon_one = builder.CreateString('Sword')
+ weapon_two = builder.CreateString('Axe')
+
+ MyGame.Sample.Weapon.WeaponStart(builder)
+ MyGame.Sample.Weapon.WeaponAddName(builder, weapon_one)
+ MyGame.Sample.Weapon.WeaponAddDamage(builder, 3)
+ sword = MyGame.Sample.Weapon.WeaponEnd(builder)
+
+ MyGame.Sample.Weapon.WeaponStart(builder)
+ MyGame.Sample.Weapon.WeaponAddName(builder, weapon_two)
+ MyGame.Sample.Weapon.WeaponAddDamage(builder, 5)
+ axe = MyGame.Sample.Weapon.WeaponEnd(builder)
+
+ # Serialize the FlatBuffer data.
+ name = builder.CreateString('Orc')
+
+ MyGame.Sample.Monster.MonsterStartInventoryVector(builder, 10)
+ # Note: Since we prepend the bytes, this loop iterates in reverse order.
+ for i in reversed(range(0, 10)):
+ builder.PrependByte(i)
+ inv = builder.EndVector(10)
+
+ MyGame.Sample.Monster.MonsterStartWeaponsVector(builder, 2)
+ # Note: Since we prepend the data, prepend the weapons in reverse order.
+ builder.PrependUOffsetTRelative(axe)
+ builder.PrependUOffsetTRelative(sword)
+ weapons = builder.EndVector(2)
+
+ pos = MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
+
+ MyGame.Sample.Monster.MonsterStart(builder)
+ MyGame.Sample.Monster.MonsterAddPos(builder, pos)
+ MyGame.Sample.Monster.MonsterAddHp(builder, 300)
+ MyGame.Sample.Monster.MonsterAddName(builder, name)
+ MyGame.Sample.Monster.MonsterAddInventory(builder, inv)
+ MyGame.Sample.Monster.MonsterAddColor(builder,
+ MyGame.Sample.Color.Color().Red)
+ MyGame.Sample.Monster.MonsterAddWeapons(builder, weapons)
+ MyGame.Sample.Monster.MonsterAddEquippedType(
+ builder, MyGame.Sample.Equipment.Equipment().Weapon)
+ MyGame.Sample.Monster.MonsterAddEquipped(builder, axe)
+ orc = MyGame.Sample.Monster.MonsterEnd(builder)
+
+ builder.Finish(orc)
+
+ # We now have a FlatBuffer that we could store on disk or send over a network.
+
+ # ...Saving to file or sending over a network code goes here...
+
+ # Instead, we are going to access this buffer right away (as if we just
+ # received it).
+
+ buf = builder.Output()
+
+ # Note: We use `0` for the offset here, since we got the data using the
+ # `builder.Output()` method. This simulates the data you would store/receive
+ # in your FlatBuffer. If you wanted to read from the `builder.Bytes` directly,
+ # you would need to pass in the offset of `builder.Head()`, as the builder
+ # actually constructs the buffer backwards.
+ monster = MyGame.Sample.Monster.Monster.GetRootAsMonster(buf, 0)
+
+ # Note: We did not set the `Mana` field explicitly, so we get a default value.
+ assert monster.Mana() == 150
+ assert monster.Hp() == 300
+ assert monster.Name() == 'Orc'
+ assert monster.Color() == MyGame.Sample.Color.Color().Red
+ assert monster.Pos().X() == 1.0
+ assert monster.Pos().Y() == 2.0
+ assert monster.Pos().Z() == 3.0
+
+ # Get and test the `inventory` FlatBuffer `vector`.
+ for i in xrange(monster.InventoryLength()):
+ assert monster.Inventory(i) == i
+
+ # Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ expected_weapon_names = ['Sword', 'Axe']
+ expected_weapon_damages = [3, 5]
+ for i in xrange(monster.WeaponsLength()):
+ assert monster.Weapons(i).Name() == expected_weapon_names[i]
+ assert monster.Weapons(i).Damage() == expected_weapon_damages[i]
+
+ # Get and test the `equipped` FlatBuffer `union`.
+ assert monster.EquippedType() == MyGame.Sample.Equipment.Equipment().Weapon
+
+ # An example of how you can appropriately convert the table depending on the
+ # FlatBuffer `union` type. You could add `elif` and `else` clauses to handle
+ # the other FlatBuffer `union` types for this field.
+ if monster.EquippedType() == MyGame.Sample.Equipment.Equipment().Weapon:
+ # `monster.Equipped()` returns a `flatbuffers.Table`, which can be used
+ # to initialize a `MyGame.Sample.Weapon.Weapon()`, in this case.
+ union_weapon = MyGame.Sample.Weapon.Weapon()
+ union_weapon.Init(monster.Equipped().Bytes, monster.Equipped().Pos)
+
+ assert union_weapon.Name() == "Axe"
+ assert union_weapon.Damage() == 5
+
+ print 'The FlatBuffer was successfully created and verified!'
+
+if __name__ == '__main__':
+ main()
diff --git a/samples/sample_binary.rs b/samples/sample_binary.rs
new file mode 100644
index 0000000..7a4c2ae
--- /dev/null
+++ b/samples/sample_binary.rs
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// import the flatbuffers runtime library
+extern crate flatbuffers;
+
+// import the generated code
+#[path = "./monster_generated.rs"]
+mod monster_generated;
+pub use monster_generated::my_game::sample::{get_root_as_monster,
+ Color, Equipment,
+ Monster, MonsterArgs,
+ Vec3,
+ Weapon, WeaponArgs};
+
+
+// Example how to use FlatBuffers to create and read binary buffers.
+
+fn main() {
+ // Build up a serialized buffer algorithmically.
+ // Initialize it with a capacity of 1024 bytes.
+ let mut builder = flatbuffers::FlatBufferBuilder::new_with_capacity(1024);
+
+ // Serialize some weapons for the Monster: A 'sword' and an 'axe'.
+ let weapon_one_name = builder.create_string("Sword");
+ let weapon_two_name = builder.create_string("Axe");
+
+ // Use the `Weapon::create` shortcut to create Weapons with named field
+ // arguments.
+ let sword = Weapon::create(&mut builder, &WeaponArgs{
+ name: Some(weapon_one_name),
+ damage: 3,
+ });
+ let axe = Weapon::create(&mut builder, &WeaponArgs{
+ name: Some(weapon_two_name),
+ damage: 5,
+ });
+
+ // Name of the Monster.
+ let name = builder.create_string("Orc");
+
+ // Inventory.
+ let inventory = builder.create_vector(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+ // Create a FlatBuffer `vector` that contains offsets to the sword and axe
+ // we created above.
+ let weapons = builder.create_vector(&[sword, axe]);
+
+ // Create the path vector of Vec3 objects:
+ //let x = Vec3::new(1.0, 2.0, 3.0);
+ //let y = Vec3::new(4.0, 5.0, 6.0);
+ //let path = builder.create_vector(&[x, y]);
+
+ // Note that, for convenience, it is also valid to create a vector of
+ // references to structs, like this:
+ // let path = builder.create_vector(&[&x, &y]);
+
+ // Create the monster using the `Monster::create` helper function. This
+ // function accepts a `MonsterArgs` struct, which supplies all of the data
+ // needed to build a `Monster`. To supply empty/default fields, just use the
+ // Rust built-in `Default::default()` function, as demononstrated below.
+ let orc = Monster::create(&mut builder, &MonsterArgs{
+ pos: Some(&Vec3::new(1.0f32, 2.0f32, 3.0f32)),
+ mana: 150,
+ hp: 80,
+ name: Some(name),
+ inventory: Some(inventory),
+ color: Color::Red,
+ weapons: Some(weapons),
+ equipped_type: Equipment::Weapon,
+ equipped: Some(axe.as_union_value()),
+ //path: Some(path),
+ ..Default::default()
+ });
+
+ // Serialize the root of the object, without providing a file identifier.
+ builder.finish(orc, None);
+
+ // We now have a FlatBuffer we can store on disk or send over a network.
+
+ // ** file/network code goes here :) **
+
+ // Instead, we're going to access it right away (as if we just received it).
+ // This must be called after `finish()`.
+ let buf = builder.finished_data(); // Of type `&[u8]`
+
+ // Get access to the root:
+ let monster = get_root_as_monster(buf);
+
+ // Get and test some scalar types from the FlatBuffer.
+ let hp = monster.hp();
+ let mana = monster.mana();
+ let name = monster.name();
+
+ assert_eq!(hp, 80);
+ assert_eq!(mana, 150); // default
+ assert_eq!(name, Some("Orc"));
+
+ // Get and test a field of the FlatBuffer's `struct`.
+ assert!(monster.pos().is_some());
+ let pos = monster.pos().unwrap();
+ let x = pos.x();
+ let y = pos.y();
+ let z = pos.z();
+ assert_eq!(x, 1.0f32);
+ assert_eq!(y, 2.0f32);
+ assert_eq!(z, 3.0f32);
+
+ // Get an element from the `inventory` FlatBuffer's `vector`.
+ assert!(monster.inventory().is_some());
+ let inv = monster.inventory().unwrap();
+
+ // Note that this vector is returned as a slice, because direct access for
+ // this type, a u8 vector, is safe on all platforms:
+ let third_item = inv[2];
+ assert_eq!(third_item, 2);
+
+ // Get and test the `weapons` FlatBuffers's `vector`.
+ assert!(monster.weapons().is_some());
+ let weps = monster.weapons().unwrap();
+ //let weps_len = weps.len();
+ let wep2 = weps.get(1);
+ let second_weapon_name = wep2.name();
+ let second_weapon_damage = wep2.damage();
+ assert_eq!(second_weapon_name, Some("Axe"));
+ assert_eq!(second_weapon_damage, 5);
+
+ // Get and test the `Equipment` union (`equipped` field).
+ assert_eq!(monster.equipped_type(), Equipment::Weapon);
+ let equipped = monster.equipped_as_weapon().unwrap();
+ let weapon_name = equipped.name();
+ let weapon_damage = equipped.damage();
+ assert_eq!(weapon_name, Some("Axe"));
+ assert_eq!(weapon_damage, 5);
+
+ // Get and test the `path` FlatBuffers's `vector`.
+ //assert_eq!(monster.path().unwrap().len(), 2);
+ //assert_eq!(monster.path().unwrap()[0].x(), 1.0);
+ //assert_eq!(monster.path().unwrap()[1].x(), 4.0);
+
+ println!("The FlatBuffer was successfully created and accessed!");
+}
diff --git a/samples/sample_text.cpp b/samples/sample_text.cpp
new file mode 100644
index 0000000..aca0189
--- /dev/null
+++ b/samples/sample_text.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include "monster_generated.h" // Already includes "flatbuffers/flatbuffers.h".
+
+using namespace MyGame::Sample;
+
+// This is an example of parsing text straight into a buffer and then
+// generating flatbuffer (JSON) text from the buffer.
+int main(int /*argc*/, const char * /*argv*/ []) {
+ // load FlatBuffer schema (.fbs) and JSON from disk
+ std::string schemafile;
+ std::string jsonfile;
+ bool ok = flatbuffers::LoadFile("samples/monster.fbs", false, &schemafile) &&
+ flatbuffers::LoadFile("samples/monsterdata.json", false, &jsonfile);
+ if (!ok) {
+ printf("couldn't load files!\n");
+ return 1;
+ }
+
+ // parse schema first, so we can use it to parse the data after
+ flatbuffers::Parser parser;
+ const char *include_directories[] = { "samples", nullptr };
+ ok = parser.Parse(schemafile.c_str(), include_directories) &&
+ parser.Parse(jsonfile.c_str(), include_directories);
+ assert(ok);
+
+ // here, parser.builder_ contains a binary buffer that is the parsed data.
+
+ // to ensure it is correct, we now generate text back from the binary,
+ // and compare the two:
+ std::string jsongen;
+ if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)) {
+ printf("Couldn't serialize parsed data to JSON!\n");
+ return 1;
+ }
+
+ if (jsongen != jsonfile) {
+ printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
+ }
+
+ printf("The FlatBuffer has been parsed from JSON successfully.\n");
+}
diff --git a/samples/sample_text.lobster b/samples/sample_text.lobster
new file mode 100644
index 0000000..26b3eaf
--- /dev/null
+++ b/samples/sample_text.lobster
@@ -0,0 +1,43 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import from "../lobster/"
+import monster_generated
+
+// Example how to interop with JSON.
+
+// Test loading some JSON, converting it to a binary FlatBuffer and back again.
+
+// First read the schema and JSON data.
+let schema = read_file("monster.fbs", true)
+let json = read_file("monsterdata.json", true)
+assert schema and json
+
+// Parse JSON to binary:
+let fb, err1 = flatbuffers_json_to_binary(schema, json, [])
+assert not err1
+
+// Access one field in it, just to check:
+let monster = MyGame_Sample_GetRootAsMonster(fb)
+assert monster.name == "Orc"
+
+// Convert binary back to JSON:
+let json2, err2 = flatbuffers_binary_to_json(schema, fb, [])
+assert not err2
+
+// The generated JSON should be exactly equal to the original!
+assert json == json2
+
+// Print what we've been converting for good measure:
+print json
diff --git a/samples/samplebinary.js b/samples/samplebinary.js
new file mode 100644
index 0000000..9c8c908
--- /dev/null
+++ b/samples/samplebinary.js
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// To run, use the `javascript_sample.sh` script.
+
+var assert = require('assert');
+var flatbuffers = require('../js/flatbuffers').flatbuffers;
+var MyGame = require('./monster_generated').MyGame;
+
+// Example how to use FlatBuffers to create and read binary buffers.
+function main() {
+ var builder = new flatbuffers.Builder(0);
+
+ // Create some weapons for our Monster ('Sword' and 'Axe').
+ var weaponOne = builder.createString('Sword');
+ var weaponTwo = builder.createString('Axe');
+
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponOne);
+ MyGame.Sample.Weapon.addDamage(builder, 3);
+ var sword = MyGame.Sample.Weapon.endWeapon(builder);
+
+ MyGame.Sample.Weapon.startWeapon(builder);
+ MyGame.Sample.Weapon.addName(builder, weaponTwo);
+ MyGame.Sample.Weapon.addDamage(builder, 5);
+ var axe = MyGame.Sample.Weapon.endWeapon(builder);
+
+ // Serialize the FlatBuffer data.
+ var name = builder.createString('Orc');
+
+ var treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ var inv = MyGame.Sample.Monster.createInventoryVector(builder, treasure);
+
+ var weaps = [sword, axe];
+ var weapons = MyGame.Sample.Monster.createWeaponsVector(builder, weaps);
+
+ var pos = MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
+
+ MyGame.Sample.Monster.startMonster(builder);
+ MyGame.Sample.Monster.addPos(builder, pos);
+ MyGame.Sample.Monster.addHp(builder, 300);
+ MyGame.Sample.Monster.addColor(builder, MyGame.Sample.Color.Red)
+ MyGame.Sample.Monster.addName(builder, name);
+ MyGame.Sample.Monster.addInventory(builder, inv);
+ MyGame.Sample.Monster.addWeapons(builder, weapons);
+ MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
+ MyGame.Sample.Monster.addEquipped(builder, weaps[1]);
+ var orc = MyGame.Sample.Monster.endMonster(builder);
+
+ builder.finish(orc); // You may also call 'MyGame.Example.Monster.finishMonsterBuffer(builder, orc);'.
+
+ // We now have a FlatBuffer that can be stored on disk or sent over a network.
+
+ // ...Code to store to disk or send over a network goes here...
+
+ // Instead, we are going to access it right away, as if we just received it.
+
+ var buf = builder.dataBuffer();
+
+ // Get access to the root:
+ var monster = MyGame.Sample.Monster.getRootAsMonster(buf);
+
+ // Note: We did not set the `mana` field explicitly, so we get back the default value.
+ assert.equal(monster.mana(), 150);
+ assert.equal(monster.hp(), 300);
+ assert.equal(monster.name(), 'Orc');
+ assert.equal(monster.color(), MyGame.Sample.Color.Red);
+ assert.equal(monster.pos().x(), 1.0);
+ assert.equal(monster.pos().y(), 2.0);
+ assert.equal(monster.pos().z(), 3.0);
+
+ // Get and test the `inventory` FlatBuffer `vector`.
+ for (var i = 0; i < monster.inventoryLength(); i++) {
+ assert.equal(monster.inventory(i), i);
+ }
+
+ // Get and test the `weapons` FlatBuffer `vector` of `table`s.
+ var expectedWeaponNames = ['Sword', 'Axe'];
+ var expectedWeaponDamages = [3, 5];
+ for (var i = 0; i < monster.weaponsLength(); i++) {
+ assert.equal(monster.weapons(i).name(), expectedWeaponNames[i]);
+ assert.equal(monster.weapons(i).damage(), expectedWeaponDamages[i]);
+ }
+
+ // Get and test the `equipped` FlatBuffer `union`.
+ assert.equal(monster.equippedType(), MyGame.Sample.Equipment.Weapon);
+ assert.equal(monster.equipped(new MyGame.Sample.Weapon()).name(), 'Axe');
+ assert.equal(monster.equipped(new MyGame.Sample.Weapon()).damage(), 5);
+
+ console.log('The FlatBuffer was successfully created and verified!');
+}
+
+main();
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
new file mode 100644
index 0000000..1713896
--- /dev/null
+++ b/snap/snapcraft.yaml
@@ -0,0 +1,37 @@
+name: flatbuffers
+base: core18
+version: latest
+version-script: git describe --always | sed -e 's/-/+git/;y/-/./' | tail -c +2
+summary: FlatBuffers compiler
+description: |
+ FlatBuffers compiler
+
+ NOTE: This snap also ships the necessary header files required to compile
+ projects using flatbuffers, however, for the compilation to work, you have
+ to manually add the following path in your project's configuration:
+
+ /snap/flatbuffers/current/include
+
+ If you need to use flatbuffers headers from a location other than the above
+ path, it is recommended to not use this snap as that could cause a mismatch.
+
+grade: stable
+confinement: strict
+
+parts:
+ flatc:
+ plugin: cmake
+ source: .
+ configflags:
+ - -GUnix Makefiles
+ - -DCMAKE_BUILD_TYPE=Release
+ build-packages:
+ - g++
+ # used to set version number
+ - git
+
+apps:
+ flatc:
+ command: flatc
+ plugs:
+ - home
diff --git a/src/clang-format.sh b/src/clang-format.sh
new file mode 100644
index 0000000..fbce6b9
--- /dev/null
+++ b/src/clang-format.sh
@@ -0,0 +1,2 @@
+clang-format -i -style=file include/flatbuffers/* src/*.cpp tests/test.cpp samples/*.cpp grpc/src/compiler/schema_interface.h grpc/tests/*.cpp
+git checkout include/flatbuffers/reflection_generated.h
diff --git a/src/code_generators.cpp b/src/code_generators.cpp
new file mode 100644
index 0000000..52ca305
--- /dev/null
+++ b/src/code_generators.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "flatbuffers/code_generators.h"
+#include <assert.h>
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+#include <cmath>
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4127) // C4127: conditional expression is constant
+#endif
+
+namespace flatbuffers {
+
+void CodeWriter::operator+=(std::string text) {
+ if (!ignore_ident_ && !text.empty()) AppendIdent(stream_);
+
+ while (true) {
+ auto begin = text.find("{{");
+ if (begin == std::string::npos) { break; }
+
+ auto end = text.find("}}");
+ if (end == std::string::npos || end < begin) { break; }
+
+ // Write all the text before the first {{ into the stream.
+ stream_.write(text.c_str(), begin);
+
+ // The key is between the {{ and }}.
+ const std::string key = text.substr(begin + 2, end - begin - 2);
+
+ // Find the value associated with the key. If it exists, write the
+ // value into the stream, otherwise write the key itself into the stream.
+ auto iter = value_map_.find(key);
+ if (iter != value_map_.end()) {
+ const std::string &value = iter->second;
+ stream_ << value;
+ } else {
+ FLATBUFFERS_ASSERT(false && "could not find key");
+ stream_ << key;
+ }
+
+ // Update the text to everything after the }}.
+ text = text.substr(end + 2);
+ }
+ if (!text.empty() && string_back(text) == '\\') {
+ text.pop_back();
+ ignore_ident_ = true;
+ stream_ << text;
+ } else {
+ ignore_ident_ = false;
+ stream_ << text << std::endl;
+ }
+}
+
+void CodeWriter::AppendIdent(std::stringstream &stream) {
+ int lvl = cur_ident_lvl_;
+ while (lvl--) {
+ stream.write(pad_.c_str(), static_cast<std::streamsize>(pad_.size()));
+ }
+}
+
+const char *BaseGenerator::FlatBuffersGeneratedWarning() {
+ return "automatically generated by the FlatBuffers compiler,"
+ " do not modify";
+}
+
+std::string BaseGenerator::NamespaceDir(const Parser &parser,
+ const std::string &path,
+ const Namespace &ns) {
+ EnsureDirExists(path);
+ if (parser.opts.one_file) return path;
+ std::string namespace_dir = path; // Either empty or ends in separator.
+ auto &namespaces = ns.components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ namespace_dir += *it + kPathSeparator;
+ EnsureDirExists(namespace_dir);
+ }
+ return namespace_dir;
+}
+
+std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
+ return BaseGenerator::NamespaceDir(parser_, path_, ns);
+}
+
+std::string BaseGenerator::FullNamespace(const char *separator,
+ const Namespace &ns) {
+ std::string namespace_name;
+ auto &namespaces = ns.components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (namespace_name.length()) namespace_name += separator;
+ namespace_name += *it;
+ }
+ return namespace_name;
+}
+
+std::string BaseGenerator::LastNamespacePart(const Namespace &ns) {
+ if (!ns.components.empty())
+ return ns.components.back();
+ else
+ return std::string("");
+}
+
+// Ensure that a type is prefixed with its namespace.
+std::string BaseGenerator::WrapInNameSpace(const Namespace *ns,
+ const std::string &name) const {
+ std::string qualified_name = qualifying_start_;
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
+ qualified_name += *it + qualifying_separator_;
+ return qualified_name + name;
+}
+
+std::string BaseGenerator::WrapInNameSpace(const Definition &def) const {
+ return WrapInNameSpace(def.defined_namespace, def.name);
+}
+
+std::string BaseGenerator::GetNameSpace(const Definition &def) const {
+ const Namespace *ns = def.defined_namespace;
+ if (CurrentNameSpace() == ns) return "";
+ std::string qualified_name = qualifying_start_;
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+ qualified_name += *it;
+ if ((it + 1) != ns->components.end()) {
+ qualified_name += qualifying_separator_;
+ }
+ }
+
+ return qualified_name;
+}
+
+// Generate a documentation comment, if available.
+void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
+ const CommentConfig *config, const char *prefix) {
+ if (dc.begin() == dc.end()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ std::string &code = *code_ptr;
+ if (config != nullptr && config->first_line != nullptr) {
+ code += std::string(prefix) + std::string(config->first_line) + "\n";
+ }
+ std::string line_prefix =
+ std::string(prefix) +
+ ((config != nullptr && config->content_line_prefix != nullptr)
+ ? config->content_line_prefix
+ : "///");
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ code += line_prefix + *it + "\n";
+ }
+ if (config != nullptr && config->last_line != nullptr) {
+ code += std::string(prefix) + std::string(config->last_line) + "\n";
+ }
+}
+
+template<typename T>
+std::string FloatConstantGenerator::GenFloatConstantImpl(
+ const FieldDef &field) const {
+ const auto &constant = field.value.constant;
+ T v;
+ auto done = StringToNumber(constant.c_str(), &v);
+ FLATBUFFERS_ASSERT(done);
+ if (done) {
+#if (!defined(_MSC_VER) || (_MSC_VER >= 1800))
+ if (std::isnan(v)) return NaN(v);
+ if (std::isinf(v)) return Inf(v);
+#endif
+ return Value(v, constant);
+ }
+ return "#"; // compile time error
+}
+
+std::string FloatConstantGenerator::GenFloatConstant(
+ const FieldDef &field) const {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_FLOAT: return GenFloatConstantImpl<float>(field);
+ case BASE_TYPE_DOUBLE: return GenFloatConstantImpl<double>(field);
+ default: {
+ FLATBUFFERS_ASSERT(false);
+ return "INVALID_BASE_TYPE";
+ }
+ };
+}
+
+TypedFloatConstantGenerator::TypedFloatConstantGenerator(
+ const char *double_prefix, const char *single_prefix,
+ const char *nan_number, const char *pos_inf_number,
+ const char *neg_inf_number)
+ : double_prefix_(double_prefix),
+ single_prefix_(single_prefix),
+ nan_number_(nan_number),
+ pos_inf_number_(pos_inf_number),
+ neg_inf_number_(neg_inf_number) {}
+
+std::string TypedFloatConstantGenerator::MakeNaN(
+ const std::string &prefix) const {
+ return prefix + nan_number_;
+}
+std::string TypedFloatConstantGenerator::MakeInf(
+ bool neg, const std::string &prefix) const {
+ if (neg)
+ return !neg_inf_number_.empty() ? (prefix + neg_inf_number_)
+ : ("-" + prefix + pos_inf_number_);
+ else
+ return prefix + pos_inf_number_;
+}
+
+std::string TypedFloatConstantGenerator::Value(double v,
+ const std::string &src) const {
+ (void)v;
+ return src;
+}
+
+std::string TypedFloatConstantGenerator::Inf(double v) const {
+ return MakeInf(v < 0, double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(double v) const {
+ (void)v;
+ return MakeNaN(double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::Value(float v,
+ const std::string &src) const {
+ (void)v;
+ return src + "f";
+}
+
+std::string TypedFloatConstantGenerator::Inf(float v) const {
+ return MakeInf(v < 0, single_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(float v) const {
+ (void)v;
+ return MakeNaN(single_prefix_);
+}
+
+SimpleFloatConstantGenerator::SimpleFloatConstantGenerator(
+ const char *nan_number, const char *pos_inf_number,
+ const char *neg_inf_number)
+ : nan_number_(nan_number),
+ pos_inf_number_(pos_inf_number),
+ neg_inf_number_(neg_inf_number) {}
+
+std::string SimpleFloatConstantGenerator::Value(double v,
+ const std::string &src) const {
+ (void)v;
+ return src;
+}
+
+std::string SimpleFloatConstantGenerator::Inf(double v) const {
+ return (v < 0) ? neg_inf_number_ : pos_inf_number_;
+}
+
+std::string SimpleFloatConstantGenerator::NaN(double v) const {
+ (void)v;
+ return nan_number_;
+}
+
+std::string SimpleFloatConstantGenerator::Value(float v,
+ const std::string &src) const {
+ return this->Value(static_cast<double>(v), src);
+}
+
+std::string SimpleFloatConstantGenerator::Inf(float v) const {
+ return this->Inf(static_cast<double>(v));
+}
+
+std::string SimpleFloatConstantGenerator::NaN(float v) const {
+ return this->NaN(static_cast<double>(v));
+}
+
+} // namespace flatbuffers
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
diff --git a/src/flatc.cpp b/src/flatc.cpp
new file mode 100644
index 0000000..e1236bd
--- /dev/null
+++ b/src/flatc.cpp
@@ -0,0 +1,489 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "flatbuffers/flatc.h"
+
+#include <list>
+
+namespace flatbuffers {
+
+const char *FLATC_VERSION() { return FLATBUFFERS_VERSION(); }
+
+void FlatCompiler::ParseFile(
+ flatbuffers::Parser &parser, const std::string &filename,
+ const std::string &contents,
+ std::vector<const char *> &include_directories) const {
+ auto local_include_directory = flatbuffers::StripFileName(filename);
+ include_directories.push_back(local_include_directory.c_str());
+ include_directories.push_back(nullptr);
+ if (!parser.Parse(contents.c_str(), &include_directories[0],
+ filename.c_str())) {
+ Error(parser.error_, false, false);
+ }
+ if (!parser.error_.empty()) { Warn(parser.error_, false); }
+ include_directories.pop_back();
+ include_directories.pop_back();
+}
+
+void FlatCompiler::LoadBinarySchema(flatbuffers::Parser &parser,
+ const std::string &filename,
+ const std::string &contents) {
+ if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()),
+ contents.size())) {
+ Error("failed to load binary schema: " + filename, false, false);
+ }
+}
+
+void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const {
+ params_.warn_fn(this, warn, show_exe_name);
+}
+
+void FlatCompiler::Error(const std::string &err, bool usage,
+ bool show_exe_name) const {
+ params_.error_fn(this, err, usage, show_exe_name);
+}
+
+std::string FlatCompiler::GetUsageString(const char *program_name) const {
+ std::stringstream ss;
+ ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
+ for (size_t i = 0; i < params_.num_generators; ++i) {
+ const Generator &g = params_.generators[i];
+
+ std::stringstream full_name;
+ full_name << std::setw(12) << std::left << g.generator_opt_long;
+ const char *name = g.generator_opt_short ? g.generator_opt_short : " ";
+ const char *help = g.generator_help;
+
+ ss << " " << full_name.str() << " " << name << " " << help << ".\n";
+ }
+ // clang-format off
+ ss <<
+ " -o PATH Prefix PATH to all generated files.\n"
+ " -I PATH Search for includes in the specified path.\n"
+ " -M Print make rules for generated files.\n"
+ " --version Print the version number of flatc and exit.\n"
+ " --strict-json Strict JSON: field names must be / will be quoted,\n"
+ " no trailing commas in tables/vectors.\n"
+ " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n"
+ " \\x escapes in JSON. (Default is to raise parse error on\n"
+ " non-UTF-8 input.)\n"
+ " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n"
+ " By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
+ " --defaults-json Output fields whose value is the default when\n"
+ " writing JSON\n"
+ " --unknown-json Allow fields in JSON that are not defined in the\n"
+ " schema. These fields will be discared when generating\n"
+ " binaries.\n"
+ " --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
+ " --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
+ " also implies --no-prefix.\n"
+ " --gen-includes (deprecated), this is the default behavior.\n"
+ " If the original behavior is required (no include\n"
+ " statements) use --no-includes.\n"
+ " --no-includes Don\'t generate include statements for included\n"
+ " schemas the generated file depends on (C++).\n"
+ " --gen-mutable Generate accessors that can mutate buffers in-place.\n"
+ " --gen-onefile Generate single output file for C# and Go.\n"
+ " --gen-name-strings Generate type name functions for C++.\n"
+ " --gen-object-api Generate an additional object-based API.\n"
+ " --gen-compare Generate operator== for object-based API types.\n"
+ " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
+ " --gen-generated Add @Generated annotation for Java\n"
+ " --gen-all Generate not just code for the current schema files,\n"
+ " but for all files it includes as well.\n"
+ " If the language uses a single file for output (by default\n"
+ " the case for C++ and JS), all code will end up in this one\n"
+ " file.\n"
+ " --cpp-include Adds an #include in generated file.\n"
+ " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
+ " --cpp-str-type T Set object API string type (default std::string).\n"
+ " T::c_str(), T::length() and T::empty() must be supported.\n"
+ " The custom type also needs to be constructible from std::string\n"
+ " (see the --cpp-str-flex-ctor option to change this behavior).\n"
+ " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
+ " from Flatbuffers, but (char* + length).\n"
+ " --object-prefix Customise class prefix for C++ object-based API.\n"
+ " --object-suffix Customise class suffix for C++ object-based API.\n"
+ " Default value is \"T\".\n"
+ " --no-js-exports Removes Node.js style export lines in JS.\n"
+ " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
+ " --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
+ " --go-namespace Generate the overrided namespace in Golang.\n"
+ " --go-import Generate the overrided import for flatbuffers in Golang\n"
+ " (default is \"github.com/google/flatbuffers/go\").\n"
+ " --raw-binary Allow binaries without file_indentifier to be read.\n"
+ " This may crash flatc given a mismatched schema.\n"
+ " --size-prefixed Input binaries are size prefixed buffers.\n"
+ " --proto Input is a .proto, translate to .fbs.\n"
+ " --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
+ " --grpc Generate GRPC interfaces for the specified languages.\n"
+ " --schema Serialize schemas instead of JSON (use with -b).\n"
+ " --bfbs-comments Add doc comments to the binary schema files.\n"
+ " --bfbs-builtins Add builtin attributes to the binary schema files.\n"
+ " --conform FILE Specify a schema the following schemas should be\n"
+ " an evolution of. Gives errors if not.\n"
+ " --conform-includes Include path for the schema given with --conform PATH\n"
+ " --include-prefix Prefix this path to any generated include statements.\n"
+ " PATH\n"
+ " --keep-prefix Keep original prefix of schema include statement.\n"
+ " --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
+ " --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
+ " --short-names Use short function names for JS and TypeScript.\n"
+ " --reflect-types Add minimal type reflection to code generation.\n"
+ " --reflect-names Add minimal type/name reflection.\n"
+ " --root-type T Select or override the default root_type\n"
+ " --force-defaults Emit default values in binary output from JSON\n"
+ " --force-empty When serializing from object API representation,\n"
+ " force strings and vectors to empty rather than null.\n"
+ "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
+ "or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
+ "binary flatbuffer format files.\n"
+ "Output files are named using the base file name of the input,\n"
+ "and written to the current directory or the path given by -o.\n"
+ "example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
+ // clang-format on
+ return ss.str();
+}
+
+int FlatCompiler::Compile(int argc, const char **argv) {
+ if (params_.generators == nullptr || params_.num_generators == 0) {
+ return 0;
+ }
+
+ flatbuffers::IDLOptions opts;
+ std::string output_path;
+
+ bool any_generator = false;
+ bool print_make_rules = false;
+ bool raw_binary = false;
+ bool schema_binary = false;
+ bool grpc_enabled = false;
+ std::vector<std::string> filenames;
+ std::list<std::string> include_directories_storage;
+ std::vector<const char *> include_directories;
+ std::vector<const char *> conform_include_directories;
+ std::vector<bool> generator_enabled(params_.num_generators, false);
+ size_t binary_files_from = std::numeric_limits<size_t>::max();
+ std::string conform_to_schema;
+
+ for (int argi = 0; argi < argc; argi++) {
+ std::string arg = argv[argi];
+ if (arg[0] == '-') {
+ if (filenames.size() && arg[1] != '-')
+ Error("invalid option location: " + arg, true);
+ if (arg == "-o") {
+ if (++argi >= argc) Error("missing path following: " + arg, true);
+ output_path = flatbuffers::ConCatPathFileName(
+ flatbuffers::PosixPath(argv[argi]), "");
+ } else if (arg == "-I") {
+ if (++argi >= argc) Error("missing path following" + arg, true);
+ include_directories_storage.push_back(
+ flatbuffers::PosixPath(argv[argi]));
+ include_directories.push_back(
+ include_directories_storage.back().c_str());
+ } else if (arg == "--conform") {
+ if (++argi >= argc) Error("missing path following" + arg, true);
+ conform_to_schema = flatbuffers::PosixPath(argv[argi]);
+ } else if (arg == "--conform-includes") {
+ if (++argi >= argc) Error("missing path following" + arg, true);
+ include_directories_storage.push_back(
+ flatbuffers::PosixPath(argv[argi]));
+ conform_include_directories.push_back(
+ include_directories_storage.back().c_str());
+ } else if (arg == "--include-prefix") {
+ if (++argi >= argc) Error("missing path following" + arg, true);
+ opts.include_prefix = flatbuffers::ConCatPathFileName(
+ flatbuffers::PosixPath(argv[argi]), "");
+ } else if (arg == "--keep-prefix") {
+ opts.keep_include_path = true;
+ } else if (arg == "--strict-json") {
+ opts.strict_json = true;
+ } else if (arg == "--allow-non-utf8") {
+ opts.allow_non_utf8 = true;
+ } else if (arg == "--natural-utf8") {
+ opts.natural_utf8 = true;
+ } else if (arg == "--no-js-exports") {
+ opts.skip_js_exports = true;
+ } else if (arg == "--goog-js-export") {
+ opts.use_goog_js_export_format = true;
+ opts.use_ES6_js_export_format = false;
+ } else if (arg == "--es6-js-export") {
+ opts.use_goog_js_export_format = false;
+ opts.use_ES6_js_export_format = true;
+ } else if (arg == "--go-namespace") {
+ if (++argi >= argc) Error("missing golang namespace" + arg, true);
+ opts.go_namespace = argv[argi];
+ } else if (arg == "--go-import") {
+ if (++argi >= argc) Error("missing golang import" + arg, true);
+ opts.go_import = argv[argi];
+ } else if (arg == "--defaults-json") {
+ opts.output_default_scalars_in_json = true;
+ } else if (arg == "--unknown-json") {
+ opts.skip_unexpected_fields_in_json = true;
+ } else if (arg == "--no-prefix") {
+ opts.prefixed_enums = false;
+ } else if (arg == "--scoped-enums") {
+ opts.prefixed_enums = false;
+ opts.scoped_enums = true;
+ } else if (arg == "--no-union-value-namespacing") {
+ opts.union_value_namespacing = false;
+ } else if (arg == "--gen-mutable") {
+ opts.mutable_buffer = true;
+ } else if (arg == "--gen-name-strings") {
+ opts.generate_name_strings = true;
+ } else if (arg == "--gen-object-api") {
+ opts.generate_object_based_api = true;
+ } else if (arg == "--gen-compare") {
+ opts.gen_compare = true;
+ } else if (arg == "--cpp-include") {
+ if (++argi >= argc) Error("missing include following" + arg, true);
+ opts.cpp_includes.push_back(argv[argi]);
+ } else if (arg == "--cpp-ptr-type") {
+ if (++argi >= argc) Error("missing type following" + arg, true);
+ opts.cpp_object_api_pointer_type = argv[argi];
+ } else if (arg == "--cpp-str-type") {
+ if (++argi >= argc) Error("missing type following" + arg, true);
+ opts.cpp_object_api_string_type = argv[argi];
+ } else if (arg == "--cpp-str-flex-ctor") {
+ opts.cpp_object_api_string_flexible_constructor = true;
+ } else if (arg == "--gen-nullable") {
+ opts.gen_nullable = true;
+ } else if (arg == "--gen-generated") {
+ opts.gen_generated = true;
+ } else if (arg == "--object-prefix") {
+ if (++argi >= argc) Error("missing prefix following" + arg, true);
+ opts.object_prefix = argv[argi];
+ } else if (arg == "--object-suffix") {
+ if (++argi >= argc) Error("missing suffix following" + arg, true);
+ opts.object_suffix = argv[argi];
+ } else if (arg == "--gen-all") {
+ opts.generate_all = true;
+ opts.include_dependence_headers = false;
+ } else if (arg == "--gen-includes") {
+ // Deprecated, remove this option some time in the future.
+ printf("warning: --gen-includes is deprecated (it is now default)\n");
+ } else if (arg == "--no-includes") {
+ opts.include_dependence_headers = false;
+ } else if (arg == "--gen-onefile") {
+ opts.one_file = true;
+ } else if (arg == "--raw-binary") {
+ raw_binary = true;
+ } else if (arg == "--size-prefixed") {
+ opts.size_prefixed = true;
+ } else if (arg == "--") { // Separator between text and binary inputs.
+ binary_files_from = filenames.size();
+ } else if (arg == "--proto") {
+ opts.proto_mode = true;
+ } else if (arg == "--oneof-union") {
+ opts.proto_oneof_union = true;
+ } else if (arg == "--schema") {
+ schema_binary = true;
+ } else if (arg == "-M") {
+ print_make_rules = true;
+ } else if (arg == "--version") {
+ printf("flatc version %s\n", FLATC_VERSION());
+ exit(0);
+ } else if (arg == "--grpc") {
+ grpc_enabled = true;
+ } else if (arg == "--bfbs-comments") {
+ opts.binary_schema_comments = true;
+ } else if (arg == "--bfbs-builtins") {
+ opts.binary_schema_builtins = true;
+ } else if (arg == "--no-fb-import") {
+ opts.skip_flatbuffers_import = true;
+ } else if (arg == "--no-ts-reexport") {
+ opts.reexport_ts_modules = false;
+ } else if (arg == "--short-names") {
+ opts.js_ts_short_names = true;
+ } else if (arg == "--reflect-types") {
+ opts.mini_reflect = IDLOptions::kTypes;
+ } else if (arg == "--reflect-names") {
+ opts.mini_reflect = IDLOptions::kTypesAndNames;
+ } else if (arg == "--root-type") {
+ if (++argi >= argc) Error("missing type following" + arg, true);
+ opts.root_type = argv[argi];
+ } else if (arg == "--force-defaults") {
+ opts.force_defaults = true;
+ } else if (arg == "--force-empty") {
+ opts.set_empty_to_null = false;
+ } else {
+ for (size_t i = 0; i < params_.num_generators; ++i) {
+ if (arg == params_.generators[i].generator_opt_long ||
+ (params_.generators[i].generator_opt_short &&
+ arg == params_.generators[i].generator_opt_short)) {
+ generator_enabled[i] = true;
+ any_generator = true;
+ opts.lang_to_generate |= params_.generators[i].lang;
+ goto found;
+ }
+ }
+ Error("unknown commandline argument: " + arg, true);
+ found:;
+ }
+ } else {
+ filenames.push_back(flatbuffers::PosixPath(argv[argi]));
+ }
+ }
+
+ if (!filenames.size()) Error("missing input files", false, true);
+
+ if (opts.proto_mode) {
+ if (any_generator)
+ Error("cannot generate code directly from .proto files", true);
+ } else if (!any_generator && conform_to_schema.empty()) {
+ Error("no options: specify at least one generator.", true);
+ }
+
+ flatbuffers::Parser conform_parser;
+ if (!conform_to_schema.empty()) {
+ std::string contents;
+ if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents))
+ Error("unable to load schema: " + conform_to_schema);
+
+ if (flatbuffers::GetExtension(conform_to_schema) ==
+ reflection::SchemaExtension()) {
+ LoadBinarySchema(conform_parser, conform_to_schema, contents);
+ } else {
+ ParseFile(conform_parser, conform_to_schema, contents,
+ conform_include_directories);
+ }
+ }
+
+ std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
+
+ for (auto file_it = filenames.begin(); file_it != filenames.end();
+ ++file_it) {
+ auto &filename = *file_it;
+ std::string contents;
+ if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
+ Error("unable to load file: " + filename);
+
+ bool is_binary =
+ static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from;
+ auto ext = flatbuffers::GetExtension(filename);
+ auto is_schema = ext == "fbs" || ext == "proto";
+ auto is_binary_schema = ext == reflection::SchemaExtension();
+ if (is_binary) {
+ parser->builder_.Clear();
+ parser->builder_.PushFlatBuffer(
+ reinterpret_cast<const uint8_t *>(contents.c_str()),
+ contents.length());
+ if (!raw_binary) {
+ // Generally reading binaries that do not correspond to the schema
+ // will crash, and sadly there's no way around that when the binary
+ // does not contain a file identifier.
+ // We'd expect that typically any binary used as a file would have
+ // such an identifier, so by default we require them to match.
+ if (!parser->file_identifier_.length()) {
+ Error("current schema has no file_identifier: cannot test if \"" +
+ filename +
+ "\" matches the schema, use --raw-binary to read this file"
+ " anyway.");
+ } else if (!flatbuffers::BufferHasIdentifier(
+ contents.c_str(), parser->file_identifier_.c_str(), opts.size_prefixed)) {
+ Error("binary \"" + filename +
+ "\" does not have expected file_identifier \"" +
+ parser->file_identifier_ +
+ "\", use --raw-binary to read this file anyway.");
+ }
+ }
+ } else {
+ // Check if file contains 0 bytes.
+ if (!is_binary_schema && contents.length() != strlen(contents.c_str())) {
+ Error("input file appears to be binary: " + filename, true);
+ }
+ if (is_schema) {
+ // If we're processing multiple schemas, make sure to start each
+ // one from scratch. If it depends on previous schemas it must do
+ // so explicitly using an include.
+ parser.reset(new flatbuffers::Parser(opts));
+ }
+ if (is_binary_schema) {
+ LoadBinarySchema(*parser.get(), filename, contents);
+ } else {
+ ParseFile(*parser.get(), filename, contents, include_directories);
+ if (!is_schema && !parser->builder_.GetSize()) {
+ // If a file doesn't end in .fbs, it must be json/binary. Ensure we
+ // didn't just parse a schema with a different extension.
+ Error("input file is neither json nor a .fbs (schema) file: " +
+ filename,
+ true);
+ }
+ }
+ if ((is_schema || is_binary_schema) && !conform_to_schema.empty()) {
+ auto err = parser->ConformTo(conform_parser);
+ if (!err.empty()) Error("schemas don\'t conform: " + err);
+ }
+ if (schema_binary) {
+ parser->Serialize();
+ parser->file_extension_ = reflection::SchemaExtension();
+ }
+ }
+
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(filename));
+
+ for (size_t i = 0; i < params_.num_generators; ++i) {
+ parser->opts.lang = params_.generators[i].lang;
+ if (generator_enabled[i]) {
+ if (!print_make_rules) {
+ flatbuffers::EnsureDirExists(output_path);
+ if ((!params_.generators[i].schema_only ||
+ (is_schema || is_binary_schema)) &&
+ !params_.generators[i].generate(*parser.get(), output_path,
+ filebase)) {
+ Error(std::string("Unable to generate ") +
+ params_.generators[i].lang_name + " for " + filebase);
+ }
+ } else {
+ std::string make_rule = params_.generators[i].make_rule(
+ *parser.get(), output_path, filename);
+ if (!make_rule.empty())
+ printf("%s\n",
+ flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
+ }
+ if (grpc_enabled) {
+ if (params_.generators[i].generateGRPC != nullptr) {
+ if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
+ filebase)) {
+ Error(std::string("Unable to generate GRPC interface for") +
+ params_.generators[i].lang_name);
+ }
+ } else {
+ Warn(std::string("GRPC interface generator not implemented for ") +
+ params_.generators[i].lang_name);
+ }
+ }
+ }
+ }
+
+ if (!opts.root_type.empty()) {
+ if (!parser->SetRootType(opts.root_type.c_str()))
+ Error("unknown root type: " + opts.root_type);
+ else if (parser->root_struct_def_->fixed)
+ Error("root type must be a table");
+ }
+
+ if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
+
+ // We do not want to generate code for the definitions in this file
+ // in any files coming up next.
+ parser->MarkGenerated();
+ }
+ return 0;
+}
+
+} // namespace flatbuffers
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
new file mode 100644
index 0000000..72bb4a2
--- /dev/null
+++ b/src/flatc_main.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "flatbuffers/flatc.h"
+#include "flatbuffers/util.h"
+
+static const char *g_program_name = nullptr;
+
+static void Warn(const flatbuffers::FlatCompiler *flatc,
+ const std::string &warn, bool show_exe_name) {
+ (void)flatc;
+ if (show_exe_name) { printf("%s: ", g_program_name); }
+ printf("warning: %s\n", warn.c_str());
+}
+
+static void Error(const flatbuffers::FlatCompiler *flatc,
+ const std::string &err, bool usage, bool show_exe_name) {
+ if (show_exe_name) { printf("%s: ", g_program_name); }
+ printf("error: %s\n", err.c_str());
+ if (usage) { printf("%s", flatc->GetUsageString(g_program_name).c_str()); }
+ exit(1);
+}
+
+int main(int argc, const char *argv[]) {
+ // Prevent Appveyor-CI hangs.
+ flatbuffers::SetupDefaultCRTReportMode();
+
+ g_program_name = argv[0];
+
+ const flatbuffers::FlatCompiler::Generator generators[] = {
+ { flatbuffers::GenerateBinary, "-b", "--binary", "binary", false, nullptr,
+ flatbuffers::IDLOptions::kBinary,
+ "Generate wire format binaries for any data definitions",
+ flatbuffers::BinaryMakeRule },
+ { flatbuffers::GenerateTextFile, "-t", "--json", "text", false, nullptr,
+ flatbuffers::IDLOptions::kJson,
+ "Generate text output for any data definitions",
+ flatbuffers::TextMakeRule },
+ { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true,
+ flatbuffers::GenerateCppGRPC, flatbuffers::IDLOptions::kCpp,
+ "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule },
+ { flatbuffers::GenerateGo, "-g", "--go", "Go", true,
+ flatbuffers::GenerateGoGRPC, flatbuffers::IDLOptions::kGo,
+ "Generate Go files for tables/structs", flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateGeneral, "-j", "--java", "Java", true,
+ flatbuffers::GenerateJavaGRPC, flatbuffers::IDLOptions::kJava,
+ "Generate Java classes for tables/structs",
+ flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateJSTS, "-s", "--js", "JavaScript", true, nullptr,
+ flatbuffers::IDLOptions::kJs,
+ "Generate JavaScript code for tables/structs", flatbuffers::JSTSMakeRule },
+ { flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr,
+ flatbuffers::IDLOptions::kDart,
+ "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule },
+ { flatbuffers::GenerateJSTS, "-T", "--ts", "TypeScript", true, nullptr,
+ flatbuffers::IDLOptions::kTs,
+ "Generate TypeScript code for tables/structs", flatbuffers::JSTSMakeRule },
+ { flatbuffers::GenerateGeneral, "-n", "--csharp", "C#", true, nullptr,
+ flatbuffers::IDLOptions::kCSharp,
+ "Generate C# classes for tables/structs", flatbuffers::GeneralMakeRule },
+ { flatbuffers::GeneratePython, "-p", "--python", "Python", true, nullptr,
+ flatbuffers::IDLOptions::kPython,
+ "Generate Python files for tables/structs",
+ flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true, nullptr,
+ flatbuffers::IDLOptions::kLobster,
+ "Generate Lobster files for tables/structs",
+ flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
+ flatbuffers::IDLOptions::kLua,
+ "Generate Lua files for tables/structs",
+ flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateRust, "-r", "--rust", "Rust", true, nullptr,
+ flatbuffers::IDLOptions::kRust,
+ "Generate Rust files for tables/structs",
+ flatbuffers::RustMakeRule },
+ { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr,
+ flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs",
+ flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateKotlin, nullptr, "--kotlin", "Kotlin", true, nullptr,
+ flatbuffers::IDLOptions::kKotlin, "Generate Kotlin classes for tables/structs",
+ flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema",
+ true, nullptr, flatbuffers::IDLOptions::kJsonSchema,
+ "Generate Json schema", flatbuffers::GeneralMakeRule },
+ };
+
+ flatbuffers::FlatCompiler::InitParams params;
+ params.generators = generators;
+ params.num_generators = sizeof(generators) / sizeof(generators[0]);
+ params.warn_fn = Warn;
+ params.error_fn = Error;
+
+ flatbuffers::FlatCompiler flatc(params);
+ return flatc.Compile(argc - 1, argv + 1);
+}
diff --git a/src/flathash.cpp b/src/flathash.cpp
new file mode 100644
index 0000000..bc3d2df
--- /dev/null
+++ b/src/flathash.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include "flatbuffers/hash.h"
+
+enum OutputFormat { kDecimal, kHexadecimal, kHexadecimal0x };
+
+int main(int argc, char *argv[]) {
+ const char *name = argv[0];
+ if (argc <= 1) {
+ printf("%s HASH [OPTION]... [--] STRING...\n", name);
+ printf("Available hashing algorithms:\n");
+ printf(" 16 bit:\n");
+ size_t size = sizeof(flatbuffers::kHashFunctions16) /
+ sizeof(flatbuffers::kHashFunctions16[0]);
+ for (size_t i = 0; i < size; ++i) {
+ printf(" * %s\n", flatbuffers::kHashFunctions16[i].name);
+ }
+ printf(" 32 bit:\n");
+ size = sizeof(flatbuffers::kHashFunctions32) /
+ sizeof(flatbuffers::kHashFunctions32[0]);
+ for (size_t i = 0; i < size; ++i) {
+ printf(" * %s\n", flatbuffers::kHashFunctions32[i].name);
+ }
+ printf(" 64 bit:\n");
+ size = sizeof(flatbuffers::kHashFunctions64) /
+ sizeof(flatbuffers::kHashFunctions64[0]);
+ for (size_t i = 0; i < size; ++i) {
+ printf(" * %s\n", flatbuffers::kHashFunctions64[i].name);
+ }
+ printf(
+ " -d Output hash in decimal.\n"
+ " -x Output hash in hexadecimal.\n"
+ " -0x Output hash in hexadecimal and prefix with 0x.\n"
+ " -c Append the string to the output in a c-style comment.\n");
+ return 1;
+ }
+
+ const char *hash_algorithm = argv[1];
+
+ flatbuffers::NamedHashFunction<uint16_t>::HashFunction hash_function16 =
+ flatbuffers::FindHashFunction16(hash_algorithm);
+ flatbuffers::NamedHashFunction<uint32_t>::HashFunction hash_function32 =
+ flatbuffers::FindHashFunction32(hash_algorithm);
+ flatbuffers::NamedHashFunction<uint64_t>::HashFunction hash_function64 =
+ flatbuffers::FindHashFunction64(hash_algorithm);
+
+ if (!hash_function16 && !hash_function32 && !hash_function64) {
+ printf("\"%s\" is not a known hash algorithm.\n", hash_algorithm);
+ return 1;
+ }
+
+ OutputFormat output_format = kHexadecimal;
+ bool annotate = false;
+ bool escape_dash = false;
+ for (int i = 2; i < argc; i++) {
+ const char *arg = argv[i];
+ if (!escape_dash && arg[0] == '-') {
+ std::string opt = arg;
+ if (opt == "-d")
+ output_format = kDecimal;
+ else if (opt == "-x")
+ output_format = kHexadecimal;
+ else if (opt == "-0x")
+ output_format = kHexadecimal0x;
+ else if (opt == "-c")
+ annotate = true;
+ else if (opt == "--")
+ escape_dash = true;
+ else
+ printf("Unrecognized argument: \"%s\"\n", arg);
+ } else {
+ std::stringstream ss;
+ if (output_format == kDecimal) {
+ ss << std::dec;
+ } else if (output_format == kHexadecimal) {
+ ss << std::hex;
+ } else if (output_format == kHexadecimal0x) {
+ ss << std::hex;
+ ss << "0x";
+ }
+ if (hash_function16)
+ ss << hash_function16(arg);
+ else if (hash_function32)
+ ss << hash_function32(arg);
+ else if (hash_function64)
+ ss << hash_function64(arg);
+
+ if (annotate) ss << " /* \"" << arg << "\" */";
+
+ ss << "\n";
+
+ std::cout << ss.str();
+ }
+ }
+ return 0;
+}
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
new file mode 100644
index 0000000..b667ea4
--- /dev/null
+++ b/src/idl_gen_cpp.cpp
@@ -0,0 +1,2972 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+
+// Pedantic warning free version of toupper().
+inline char ToUpper(char c) { return static_cast<char>(::toupper(c)); }
+
+// Make numerical literal with type-suffix.
+// This function is only needed for C++! Other languages do not need it.
+static inline std::string NumToStringCpp(std::string val, BaseType type) {
+ // Avoid issues with -2147483648, -9223372036854775808.
+ switch (type) {
+ case BASE_TYPE_INT:
+ return (val != "-2147483648") ? val : ("(-2147483647 - 1)");
+ case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL");
+ case BASE_TYPE_LONG:
+ if (val == "-9223372036854775808")
+ return "(-9223372036854775807LL - 1LL)";
+ else
+ return (val == "0") ? val : (val + "LL");
+ default: return val;
+ }
+}
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.h";
+}
+
+namespace cpp {
+class CppGenerator : public BaseGenerator {
+ public:
+ CppGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "::"),
+ cur_name_space_(nullptr),
+ float_const_gen_("std::numeric_limits<double>::",
+ "std::numeric_limits<float>::", "quiet_NaN()",
+ "infinity()") {
+ static const char *const keywords[] = {
+ "alignas",
+ "alignof",
+ "and",
+ "and_eq",
+ "asm",
+ "atomic_cancel",
+ "atomic_commit",
+ "atomic_noexcept",
+ "auto",
+ "bitand",
+ "bitor",
+ "bool",
+ "break",
+ "case",
+ "catch",
+ "char",
+ "char16_t",
+ "char32_t",
+ "class",
+ "compl",
+ "concept",
+ "const",
+ "constexpr",
+ "const_cast",
+ "continue",
+ "co_await",
+ "co_return",
+ "co_yield",
+ "decltype",
+ "default",
+ "delete",
+ "do",
+ "double",
+ "dynamic_cast",
+ "else",
+ "enum",
+ "explicit",
+ "export",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "friend",
+ "goto",
+ "if",
+ "import",
+ "inline",
+ "int",
+ "long",
+ "module",
+ "mutable",
+ "namespace",
+ "new",
+ "noexcept",
+ "not",
+ "not_eq",
+ "nullptr",
+ "operator",
+ "or",
+ "or_eq",
+ "private",
+ "protected",
+ "public",
+ "register",
+ "reinterpret_cast",
+ "requires",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_assert",
+ "static_cast",
+ "struct",
+ "switch",
+ "synchronized",
+ "template",
+ "this",
+ "thread_local",
+ "throw",
+ "true",
+ "try",
+ "typedef",
+ "typeid",
+ "typename",
+ "union",
+ "unsigned",
+ "using",
+ "virtual",
+ "void",
+ "volatile",
+ "wchar_t",
+ "while",
+ "xor",
+ "xor_eq",
+ nullptr,
+ };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ std::string GenIncludeGuard() const {
+ // Generate include guard.
+ std::string guard = file_name_;
+ // Remove any non-alpha-numeric characters that may appear in a filename.
+ struct IsAlnum {
+ bool operator()(char c) const { return !is_alnum(c); }
+ };
+ guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()),
+ guard.end());
+ guard = "FLATBUFFERS_GENERATED_" + guard;
+ guard += "_";
+ // For further uniqueness, also add the namespace.
+ auto name_space = parser_.current_namespace_;
+ for (auto it = name_space->components.begin();
+ it != name_space->components.end(); ++it) {
+ guard += *it + "_";
+ }
+ guard += "H_";
+ std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
+ return guard;
+ }
+
+ void GenIncludeDependencies() {
+ int num_includes = 0;
+ for (auto it = parser_.native_included_files_.begin();
+ it != parser_.native_included_files_.end(); ++it) {
+ code_ += "#include \"" + *it + "\"";
+ num_includes++;
+ }
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+
+ code_ += "#include \"" + parser_.opts.include_prefix +
+ (parser_.opts.keep_include_path ? noext : basename) +
+ "_generated.h\"";
+ num_includes++;
+ }
+ if (num_includes) code_ += "";
+ }
+
+ void GenExtraIncludes() {
+ for(std::size_t i = 0; i < parser_.opts.cpp_includes.size(); ++i) {
+ code_ += "#include \"" + parser_.opts.cpp_includes[i] + "\"";
+ }
+ if (!parser_.opts.cpp_includes.empty()) {
+ code_ += "";
+ }
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(def.name);
+ }
+
+ std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ const auto include_guard = GenIncludeGuard();
+ code_ += "#ifndef " + include_guard;
+ code_ += "#define " + include_guard;
+ code_ += "";
+
+ if (parser_.opts.gen_nullable) {
+ code_ += "#pragma clang system_header\n\n";
+ }
+
+ code_ += "#include \"flatbuffers/flatbuffers.h\"";
+ if (parser_.uses_flexbuffers_) {
+ code_ += "#include \"flatbuffers/flexbuffers.h\"";
+ }
+ code_ += "";
+
+ if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); }
+ GenExtraIncludes();
+
+ FLATBUFFERS_ASSERT(!cur_name_space_);
+
+ // Generate forward declarations for all structs/tables, since they may
+ // have circular references.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ code_ += "struct " + Name(struct_def) + ";";
+ if (parser_.opts.generate_object_based_api) {
+ auto nativeName =
+ NativeName(Name(struct_def), &struct_def, parser_.opts);
+ if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; }
+ }
+ code_ += "";
+ }
+ }
+
+ // Generate forward declarations for all equal operators
+ if (parser_.opts.generate_object_based_api && parser_.opts.gen_compare) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ auto nativeName =
+ NativeName(Name(struct_def), &struct_def, parser_.opts);
+ code_ += "bool operator==(const " + nativeName + " &lhs, const " +
+ nativeName + " &rhs);";
+ code_ += "bool operator!=(const " + nativeName + " &lhs, const " +
+ nativeName + " &rhs);";
+ }
+ }
+ code_ += "";
+ }
+
+ // Generate preablmle code for mini reflection.
+ if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ // To break cyclic dependencies, first pre-declare all tables/structs.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenMiniReflectPre(&struct_def);
+ }
+ }
+ }
+
+ // Generate code for all the enum declarations.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenEnum(enum_def);
+ }
+ }
+
+ // Generate code for all structs, then all tables.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenStruct(struct_def);
+ }
+ }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTable(struct_def);
+ }
+ }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTablePost(struct_def);
+ }
+ }
+
+ // Generate code for union verifiers.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (enum_def.is_union && !enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenUnionPost(enum_def);
+ }
+ }
+
+ // Generate code for mini reflection.
+ if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ // Then the unions/enums that may refer to them.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (!enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenMiniReflect(nullptr, &enum_def);
+ }
+ }
+ // Then the full tables/structs.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (!struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenMiniReflect(&struct_def, nullptr);
+ }
+ }
+ }
+
+ // Generate convenient global helper functions:
+ if (parser_.root_struct_def_) {
+ auto &struct_def = *parser_.root_struct_def_;
+ SetNameSpace(struct_def.defined_namespace);
+ auto name = Name(struct_def);
+ auto qualified_name = cur_name_space_->GetFullyQualifiedName(name);
+ auto cpp_name = TranslateNameSpace(qualified_name);
+
+ code_.SetValue("STRUCT_NAME", name);
+ code_.SetValue("CPP_NAME", cpp_name);
+ code_.SetValue("NULLABLE_EXT", NullableExtension());
+
+ // The root datatype accessor:
+ code_ += "inline \\";
+ code_ +=
+ "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void "
+ "*buf) {";
+ code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline \\";
+ code_ +=
+ "const {{CPP_NAME}} "
+ "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void "
+ "*buf) {";
+ code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.opts.mutable_buffer) {
+ code_ += "inline \\";
+ code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {";
+ code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);";
+ code_ += "}";
+ code_ += "";
+ }
+
+ if (parser_.file_identifier_.length()) {
+ // Return the identifier
+ code_ += "inline const char *{{STRUCT_NAME}}Identifier() {";
+ code_ += " return \"" + parser_.file_identifier_ + "\";";
+ code_ += "}";
+ code_ += "";
+
+ // Check if a buffer has the identifier.
+ code_ += "inline \\";
+ code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {";
+ code_ += " return flatbuffers::BufferHasIdentifier(";
+ code_ += " buf, {{STRUCT_NAME}}Identifier());";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // The root verifier.
+ if (parser_.file_identifier_.length()) {
+ code_.SetValue("ID", name + "Identifier()");
+ } else {
+ code_.SetValue("ID", "nullptr");
+ }
+
+ code_ += "inline bool Verify{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::Verifier &verifier) {";
+ code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::Verifier &verifier) {";
+ code_ +=
+ " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code_ += "inline const char *{{STRUCT_NAME}}Extension() {";
+ code_ += " return \"" + parser_.file_extension_ + "\";";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Finish a buffer with a given root object:
+ code_ += "inline void Finish{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::FlatBufferBuilder &fbb,";
+ code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
+ if (parser_.file_identifier_.length())
+ code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());";
+ else
+ code_ += " fbb.Finish(root);";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer(";
+ code_ += " flatbuffers::FlatBufferBuilder &fbb,";
+ code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {";
+ if (parser_.file_identifier_.length())
+ code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());";
+ else
+ code_ += " fbb.FinishSizePrefixed(root);";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.opts.generate_object_based_api) {
+ // A convenient root unpack function.
+ auto native_name =
+ NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
+ code_.SetValue("UNPACK_RETURN",
+ GenTypeNativePtr(native_name, nullptr, false));
+ code_.SetValue("UNPACK_TYPE",
+ GenTypeNativePtr(native_name, nullptr, true));
+
+ code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}(";
+ code_ += " const void *buf,";
+ code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
+ code_ += " return {{UNPACK_TYPE}}\\";
+ code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}(";
+ code_ += " const void *buf,";
+ code_ += " const flatbuffers::resolver_function_t *res = nullptr) {";
+ code_ += " return {{UNPACK_TYPE}}\\";
+ code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ // Close the include guard.
+ code_ += "#endif // " + include_guard;
+
+ const auto file_path = GeneratedFileName(path_, file_name_);
+ const auto final_code = code_.ToString();
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+
+ private:
+ CodeWriter code_;
+
+ std::unordered_set<std::string> keywords_;
+
+ // This tracks the current namespace so we can insert namespace declarations.
+ const Namespace *cur_name_space_;
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ // Translates a qualified name in flatbuffer text format to the same name in
+ // the equivalent C++ namespace.
+ static std::string TranslateNameSpace(const std::string &qualified_name) {
+ std::string cpp_qualified_name = qualified_name;
+ size_t start_pos = 0;
+ while ((start_pos = cpp_qualified_name.find('.', start_pos)) !=
+ std::string::npos) {
+ cpp_qualified_name.replace(start_pos, 1, "::");
+ }
+ return cpp_qualified_name;
+ }
+
+ void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
+ std::string text;
+ ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
+ code_ += text + "\\";
+ }
+
+ // Return a C++ type from the table in idl.h
+ std::string GenTypeBasic(const Type &type, bool user_facing_type) const {
+ // clang-format off
+ static const char *const ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, KTYPE) \
+ #CTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+ if (user_facing_type) {
+ if (type.enum_def) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_BOOL) return "bool";
+ }
+ return ctypename[type.base_type];
+ }
+
+ // Return a C++ pointer type, specialized to the actual struct/table types,
+ // and vector element types.
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ return "flatbuffers::String";
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto type_name = GenTypeWire(type.VectorType(), "", false);
+ return "flatbuffers::Vector<" + type_name + ">";
+ }
+ case BASE_TYPE_STRUCT: {
+ return WrapInNameSpace(*type.struct_def);
+ }
+ case BASE_TYPE_UNION:
+ // fall through
+ default: { return "void"; }
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // building a flatbuffer.
+ std::string GenTypeWire(const Type &type, const char *postfix,
+ bool user_facing_type) const {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, user_facing_type) + postfix;
+ } else if (IsStruct(type)) {
+ return "const " + GenTypePointer(type) + " *";
+ } else {
+ return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix;
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) that reflects its
+ // serialized size.
+ std::string GenTypeSize(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, false);
+ } else if (IsStruct(type)) {
+ return GenTypePointer(type);
+ } else {
+ return "flatbuffers::uoffset_t";
+ }
+ }
+
+ std::string NullableExtension() {
+ return parser_.opts.gen_nullable ? " _Nullable " : "";
+ }
+
+ static std::string NativeName(const std::string &name, const StructDef *sd,
+ const IDLOptions &opts) {
+ return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix
+ : name;
+ }
+
+ const std::string &PtrType(const FieldDef *field) {
+ auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
+ return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
+ }
+
+ const std::string NativeString(const FieldDef *field) {
+ auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
+ auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type;
+ if (ret.empty()) { return "std::string"; }
+ return ret;
+ }
+
+ bool FlexibleStringConstructor(const FieldDef *field) {
+ auto attr = field
+ ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr)
+ : false;
+ auto ret =
+ attr ? attr : parser_.opts.cpp_object_api_string_flexible_constructor;
+ return ret && NativeString(field) !=
+ "std::string"; // Only for custom string types.
+ }
+
+ std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
+ bool is_constructor) {
+ auto &ptr_type = PtrType(field);
+ if (ptr_type != "naked") {
+ return (ptr_type != "default_ptr_type"
+ ? ptr_type
+ : parser_.opts.cpp_object_api_pointer_type) +
+ "<" + type + ">";
+ } else if (is_constructor) {
+ return "";
+ } else {
+ return type + " *";
+ }
+ }
+
+ std::string GenPtrGet(const FieldDef &field) {
+ auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get");
+ if (cpp_ptr_type_get) return cpp_ptr_type_get->constant;
+ auto &ptr_type = PtrType(&field);
+ return ptr_type == "naked" ? "" : ".get()";
+ }
+
+ std::string GenTypeNative(const Type &type, bool invector,
+ const FieldDef &field) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ return NativeString(&field);
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto type_name = GenTypeNative(type.VectorType(), true, field);
+ if (type.struct_def &&
+ type.struct_def->attributes.Lookup("native_custom_alloc")) {
+ auto native_custom_alloc =
+ type.struct_def->attributes.Lookup("native_custom_alloc");
+ return "std::vector<" + type_name + "," +
+ native_custom_alloc->constant + "<" + type_name + ">>";
+ } else
+ return "std::vector<" + type_name + ">";
+ }
+ case BASE_TYPE_STRUCT: {
+ auto type_name = WrapInNameSpace(*type.struct_def);
+ if (IsStruct(type)) {
+ auto native_type = type.struct_def->attributes.Lookup("native_type");
+ if (native_type) { type_name = native_type->constant; }
+ if (invector || field.native_inline) {
+ return type_name;
+ } else {
+ return GenTypeNativePtr(type_name, &field, false);
+ }
+ } else {
+ return GenTypeNativePtr(
+ NativeName(type_name, type.struct_def, parser_.opts), &field,
+ false);
+ }
+ }
+ case BASE_TYPE_UNION: {
+ return type.enum_def->name + "Union";
+ }
+ default: { return GenTypeBasic(type, true); }
+ }
+ }
+
+ // Return a C++ type for any type (scalar/pointer) specifically for
+ // using a flatbuffer.
+ std::string GenTypeGet(const Type &type, const char *afterbasic,
+ const char *beforeptr, const char *afterptr,
+ bool user_facing_type) {
+ if (IsScalar(type.base_type)) {
+ return GenTypeBasic(type, user_facing_type) + afterbasic;
+ } else if (IsArray(type)) {
+ auto element_type = type.VectorType();
+ return beforeptr +
+ (IsScalar(element_type.base_type)
+ ? GenTypeBasic(element_type, user_facing_type)
+ : GenTypePointer(element_type)) +
+ afterptr;
+ } else {
+ return beforeptr + GenTypePointer(type) + afterptr;
+ }
+ }
+
+ std::string GenEnumDecl(const EnumDef &enum_def) const {
+ const IDLOptions &opts = parser_.opts;
+ return (opts.scoped_enums ? "enum class " : "enum ") + Name(enum_def);
+ }
+
+ std::string GenEnumValDecl(const EnumDef &enum_def,
+ const std::string &enum_val) const {
+ const IDLOptions &opts = parser_.opts;
+ return opts.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
+ }
+
+ std::string GetEnumValUse(const EnumDef &enum_def,
+ const EnumVal &enum_val) const {
+ const IDLOptions &opts = parser_.opts;
+ if (opts.scoped_enums) {
+ return Name(enum_def) + "::" + Name(enum_val);
+ } else if (opts.prefixed_enums) {
+ return Name(enum_def) + "_" + Name(enum_val);
+ } else {
+ return Name(enum_val);
+ }
+ }
+
+ std::string StripUnionType(const std::string &name) {
+ return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
+ }
+
+ std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
+ bool native_type = false) {
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
+ return wrap ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace,
+ name)
+ : name;
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ return actual_type ? (native_type ? "std::string" : "flatbuffers::String")
+ : Name(ev);
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ return Name(ev);
+ }
+ }
+
+ std::string UnionVerifySignature(const EnumDef &enum_def) {
+ return "bool Verify" + Name(enum_def) +
+ "(flatbuffers::Verifier &verifier, const void *obj, " +
+ Name(enum_def) + " type)";
+ }
+
+ std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
+ return "bool Verify" + Name(enum_def) + "Vector" +
+ "(flatbuffers::Verifier &verifier, " +
+ "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
+ "const flatbuffers::Vector<uint8_t> *types)";
+ }
+
+ std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) {
+ return (inclass ? "static " : "") + std::string("void *") +
+ (inclass ? "" : Name(enum_def) + "Union::") +
+ "UnPack(const void *obj, " + Name(enum_def) +
+ " type, const flatbuffers::resolver_function_t *resolver)";
+ }
+
+ std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
+ return "flatbuffers::Offset<void> " +
+ (inclass ? "" : Name(enum_def) + "Union::") +
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
+ "const flatbuffers::rehasher_function_t *_rehasher" +
+ (inclass ? " = nullptr" : "") + ") const";
+ }
+
+ std::string TableCreateSignature(const StructDef &struct_def, bool predecl,
+ const IDLOptions &opts) {
+ return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
+ Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " +
+ NativeName(Name(struct_def), &struct_def, opts) +
+ " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
+ (predecl ? " = nullptr" : "") + ")";
+ }
+
+ std::string TablePackSignature(const StructDef &struct_def, bool inclass,
+ const IDLOptions &opts) {
+ return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" +
+ Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") +
+ "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " +
+ NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
+ "const flatbuffers::rehasher_function_t *_rehasher" +
+ (inclass ? " = nullptr" : "") + ")";
+ }
+
+ std::string TableUnPackSignature(const StructDef &struct_def, bool inclass,
+ const IDLOptions &opts) {
+ return NativeName(Name(struct_def), &struct_def, opts) + " *" +
+ (inclass ? "" : Name(struct_def) + "::") +
+ "UnPack(const flatbuffers::resolver_function_t *_resolver" +
+ (inclass ? " = nullptr" : "") + ") const";
+ }
+
+ std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass,
+ const IDLOptions &opts) {
+ return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" +
+ NativeName(Name(struct_def), &struct_def, opts) + " *" +
+ "_o, const flatbuffers::resolver_function_t *_resolver" +
+ (inclass ? " = nullptr" : "") + ") const";
+ }
+
+ void GenMiniReflectPre(const StructDef *struct_def) {
+ code_.SetValue("NAME", struct_def->name);
+ code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();";
+ code_ += "";
+ }
+
+ void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) {
+ code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
+ code_.SetValue("SEQ_TYPE",
+ struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
+ : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
+ auto num_fields =
+ struct_def ? struct_def->fields.vec.size() : enum_def->size();
+ code_.SetValue("NUM_FIELDS", NumToString(num_fields));
+ std::vector<std::string> names;
+ std::vector<Type> types;
+
+ if (struct_def) {
+ for (auto it = struct_def->fields.vec.begin();
+ it != struct_def->fields.vec.end(); ++it) {
+ const auto &field = **it;
+ names.push_back(Name(field));
+ types.push_back(field.value.type);
+ }
+ } else {
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ names.push_back(Name(ev));
+ types.push_back(enum_def->is_union ? ev.union_type
+ : Type(enum_def->underlying_type));
+ }
+ }
+ std::string ts;
+ std::vector<std::string> type_refs;
+ for (auto it = types.begin(); it != types.end(); ++it) {
+ auto &type = *it;
+ if (!ts.empty()) ts += ",\n ";
+ auto is_vector = type.base_type == BASE_TYPE_VECTOR;
+ auto bt = is_vector ? type.element : type.base_type;
+ auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
+ ? bt - BASE_TYPE_UTYPE + ET_UTYPE
+ : ET_SEQUENCE;
+ int ref_idx = -1;
+ std::string ref_name =
+ type.struct_def
+ ? WrapInNameSpace(*type.struct_def)
+ : type.enum_def ? WrapInNameSpace(*type.enum_def) : "";
+ if (!ref_name.empty()) {
+ auto rit = type_refs.begin();
+ for (; rit != type_refs.end(); ++rit) {
+ if (*rit == ref_name) {
+ ref_idx = static_cast<int>(rit - type_refs.begin());
+ break;
+ }
+ }
+ if (rit == type_refs.end()) {
+ ref_idx = static_cast<int>(type_refs.size());
+ type_refs.push_back(ref_name);
+ }
+ }
+ ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
+ NumToString(is_vector) + ", " + NumToString(ref_idx) + " }";
+ }
+ std::string rs;
+ for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
+ if (!rs.empty()) rs += ",\n ";
+ rs += *it + "TypeTable";
+ }
+ std::string ns;
+ for (auto it = names.begin(); it != names.end(); ++it) {
+ if (!ns.empty()) ns += ",\n ";
+ ns += "\"" + *it + "\"";
+ }
+ std::string vs;
+ const auto consecutive_enum_from_zero =
+ enum_def && enum_def->MinValue()->IsZero() &&
+ ((enum_def->size() - 1) == enum_def->Distance());
+ if (enum_def && !consecutive_enum_from_zero) {
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (!vs.empty()) vs += ", ";
+ vs += NumToStringCpp(enum_def->ToString(ev),
+ enum_def->underlying_type.base_type);
+ }
+ } else if (struct_def && struct_def->fixed) {
+ for (auto it = struct_def->fields.vec.begin();
+ it != struct_def->fields.vec.end(); ++it) {
+ const auto &field = **it;
+ vs += NumToString(field.value.offset);
+ vs += ", ";
+ }
+ vs += NumToString(struct_def->bytesize);
+ }
+ code_.SetValue("TYPES", ts);
+ code_.SetValue("REFS", rs);
+ code_.SetValue("NAMES", ns);
+ code_.SetValue("VALUES", vs);
+ code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {";
+ if (num_fields) {
+ code_ += " static const flatbuffers::TypeCode type_codes[] = {";
+ code_ += " {{TYPES}}";
+ code_ += " };";
+ }
+ if (!type_refs.empty()) {
+ code_ += " static const flatbuffers::TypeFunction type_refs[] = {";
+ code_ += " {{REFS}}";
+ code_ += " };";
+ }
+ if (!vs.empty()) {
+ // Problem with uint64_t values greater than 9223372036854775807ULL.
+ code_ += " static const int64_t values[] = { {{VALUES}} };";
+ }
+ auto has_names =
+ num_fields && parser_.opts.mini_reflect == IDLOptions::kTypesAndNames;
+ if (has_names) {
+ code_ += " static const char * const names[] = {";
+ code_ += " {{NAMES}}";
+ code_ += " };";
+ }
+ code_ += " static const flatbuffers::TypeTable tt = {";
+ code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
+ (num_fields ? "type_codes, " : "nullptr, ") +
+ (!type_refs.empty() ? "type_refs, " : "nullptr, ") +
+ (!vs.empty() ? "values, " : "nullptr, ") +
+ (has_names ? "names" : "nullptr");
+ code_ += " };";
+ code_ += " return &tt;";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Generate an enum declaration,
+ // an enum string lookup table,
+ // and an enum array of values
+
+ void GenEnum(const EnumDef &enum_def) {
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+ code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
+
+ GenComment(enum_def.doc_comment);
+ code_ += GenEnumDecl(enum_def) + "\\";
+ // MSVC doesn't support int64/uint64 enum without explicitly declared enum
+ // type. The value 4611686018427387904ULL is truncated to zero with warning:
+ // "warning C4309: 'initializing': truncation of constant value".
+ auto add_type = parser_.opts.scoped_enums;
+ add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_LONG);
+ add_type |= (enum_def.underlying_type.base_type == BASE_TYPE_ULONG);
+ if (add_type) code_ += " : {{BASE_TYPE}}\\";
+ code_ += " {";
+
+ code_.SetValue("SEP", ",");
+ auto add_sep = false;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ if (add_sep) code_ += "{{SEP}}";
+ GenComment(ev.doc_comment, " ");
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
+ code_.SetValue("VALUE",
+ NumToStringCpp(enum_def.ToString(ev),
+ enum_def.underlying_type.base_type));
+ code_ += " {{KEY}} = {{VALUE}}\\";
+ add_sep = true;
+ }
+ const EnumVal *minv = enum_def.MinValue();
+ const EnumVal *maxv = enum_def.MaxValue();
+
+ if (parser_.opts.scoped_enums || parser_.opts.prefixed_enums) {
+ FLATBUFFERS_ASSERT(minv && maxv);
+
+ code_.SetValue("SEP", ",\n");
+ if (enum_def.attributes.Lookup("bit_flags")) {
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE"));
+ code_.SetValue("VALUE", "0");
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY"));
+ code_.SetValue("VALUE",
+ NumToStringCpp(enum_def.AllFlags(),
+ enum_def.underlying_type.base_type));
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+ } else { // MIN & MAX are useless for bit_flags
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN"));
+ code_.SetValue("VALUE", GenEnumValDecl(enum_def, minv->name));
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+
+ code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX"));
+ code_.SetValue("VALUE", GenEnumValDecl(enum_def, maxv->name));
+ code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\";
+ }
+ }
+ code_ += "";
+ code_ += "};";
+
+ if (parser_.opts.scoped_enums && enum_def.attributes.Lookup("bit_flags")) {
+ code_ +=
+ "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})";
+ }
+ code_ += "";
+
+ // Generate an array of all enumeration values
+ auto num_fields = NumToString(enum_def.size());
+ code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" +
+ num_fields + "] {";
+ code_ += " static const {{ENUM_NAME}} values[] = {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ auto value = GetEnumValUse(enum_def, ev);
+ auto suffix = *it != enum_def.Vals().back() ? "," : "";
+ code_ += " " + value + suffix;
+ }
+ code_ += " };";
+ code_ += " return values;";
+ code_ += "}";
+ code_ += "";
+
+ // Generate a generate string table for enum values.
+ // Problem is, if values are very sparse that could generate really big
+ // tables. Ideally in that case we generate a map lookup instead, but for
+ // the moment we simply don't output a table at all.
+ auto range = enum_def.Distance();
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const uint64_t kMaxSparseness = 5;
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {";
+ code_ += " static const char * const names[" +
+ NumToString(range + 1 + 1) + "] = {";
+
+ auto val = enum_def.Vals().front();
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
+ code_ += " \"\",";
+ }
+ val = ev;
+ code_ += " \"" + Name(*ev) + "\",";
+ }
+ code_ += " nullptr";
+ code_ += " };";
+
+ code_ += " return names;";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
+
+ code_ += " if (e < " + GetEnumValUse(enum_def, *enum_def.MinValue()) +
+ " || e > " + GetEnumValUse(enum_def, *enum_def.MaxValue()) +
+ ") return \"\";";
+
+ code_ += " const size_t index = static_cast<size_t>(e)\\";
+ if (enum_def.MinValue()->IsNonZero()) {
+ auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
+ code_ += " - static_cast<size_t>(" + vals + ")\\";
+ }
+ code_ += ";";
+
+ code_ += " return EnumNames{{ENUM_NAME}}()[index];";
+ code_ += "}";
+ code_ += "";
+ } else {
+ code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {";
+
+ code_ += " switch (e) {";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" +
+ Name(ev) + "\";";
+ }
+
+ code_ += " default: return \"\";";
+ code_ += " }";
+
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Generate type traits for unions to map from a type to union enum value.
+ if (enum_def.is_union && !enum_def.uses_multiple_type_instances) {
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+
+ if (it == enum_def.Vals().begin()) {
+ code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
+ } else {
+ auto name = GetUnionElement(ev, true, true);
+ code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
+ }
+
+ auto value = GetEnumValUse(enum_def, ev);
+ code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";";
+ code_ += "};";
+ code_ += "";
+ }
+ }
+
+ if (parser_.opts.generate_object_based_api && enum_def.is_union) {
+ // Generate a union type
+ code_.SetValue("NAME", Name(enum_def));
+ FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
+ code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+
+ code_ += "struct {{NAME}}Union {";
+ code_ += " {{NAME}} type;";
+ code_ += " void *value;";
+ code_ += "";
+ code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
+ code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
+ code_ += " type({{NONE}}), value(nullptr)";
+ code_ += " { std::swap(type, u.type); std::swap(value, u.value); }";
+ code_ += " {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;";
+ code_ +=
+ " {{NAME}}Union &operator=(const {{NAME}}Union &u) "
+ "FLATBUFFERS_NOEXCEPT";
+ code_ +=
+ " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, "
+ "t.value); return *this; }";
+ code_ +=
+ " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
+ code_ +=
+ " { std::swap(type, u.type); std::swap(value, u.value); return "
+ "*this; }";
+ code_ += " ~{{NAME}}Union() { Reset(); }";
+ code_ += "";
+ code_ += " void Reset();";
+ code_ += "";
+ if (!enum_def.uses_multiple_type_instances) {
+ code_ += "#ifndef FLATBUFFERS_CPP98_STL";
+ code_ += " template <typename T>";
+ code_ += " void Set(T&& val) {";
+ code_ += " using RT = typename std::remove_reference<T>::type;";
+ code_ += " Reset();";
+ code_ += " type = {{NAME}}Traits<typename RT::TableType>::enum_value;";
+ code_ += " if (type != {{NONE}}) {";
+ code_ += " value = new RT(std::forward<T>(val));";
+ code_ += " }";
+ code_ += " }";
+ code_ += "#endif // FLATBUFFERS_CPP98_STL";
+ code_ += "";
+ }
+ code_ += " " + UnionUnPackSignature(enum_def, true) + ";";
+ code_ += " " + UnionPackSignature(enum_def, true) + ";";
+ code_ += "";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ const auto native_type =
+ NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, parser_.opts);
+ code_.SetValue("NATIVE_TYPE", native_type);
+ code_.SetValue("NATIVE_NAME", Name(ev));
+ code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
+
+ code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
+ code_ += " return type == {{NATIVE_ID}} ?";
+ code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
+ code_ += " }";
+
+ code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
+ code_ += " return type == {{NATIVE_ID}} ?";
+ code_ +=
+ " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
+ code_ += " }";
+ }
+ code_ += "};";
+ code_ += "";
+
+ if (parser_.opts.gen_compare) {
+ code_ += "";
+ code_ +=
+ "inline bool operator==(const {{NAME}}Union &lhs, const "
+ "{{NAME}}Union &rhs) {";
+ code_ += " if (lhs.type != rhs.type) return false;";
+ code_ += " switch (lhs.type) {";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
+ if (ev.IsNonZero()) {
+ const auto native_type =
+ NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, parser_.opts);
+ code_.SetValue("NATIVE_TYPE", native_type);
+ code_ += " case {{NATIVE_ID}}: {";
+ code_ +=
+ " return *(reinterpret_cast<const {{NATIVE_TYPE}} "
+ "*>(lhs.value)) ==";
+ code_ +=
+ " *(reinterpret_cast<const {{NATIVE_TYPE}} "
+ "*>(rhs.value));";
+ code_ += " }";
+ } else {
+ code_ += " case {{NATIVE_ID}}: {";
+ code_ += " return true;"; // "NONE" enum value.
+ code_ += " }";
+ }
+ }
+ code_ += " default: {";
+ code_ += " return false;";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ code_ += "";
+ code_ +=
+ "inline bool operator!=(const {{NAME}}Union &lhs, const "
+ "{{NAME}}Union &rhs) {";
+ code_ += " return !(lhs == rhs);";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ if (enum_def.is_union) {
+ code_ += UnionVerifySignature(enum_def) + ";";
+ code_ += UnionVectorVerifySignature(enum_def) + ";";
+ code_ += "";
+ }
+ }
+
+ void GenUnionPost(const EnumDef &enum_def) {
+ // Generate a verifier function for this union that can be called by the
+ // table verifier functions. It uses a switch case to select a specific
+ // verifier function to call, this should be safe even if the union type
+ // has been corrupted, since the verifiers will simply fail when called
+ // on the wrong type.
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+
+ code_ += "inline " + UnionVerifySignature(enum_def) + " {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+
+ if (ev.IsNonZero()) {
+ code_.SetValue("TYPE", GetUnionElement(ev, true, true));
+ code_ += " case {{LABEL}}: {";
+ auto getptr =
+ " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return verifier.Verify<{{TYPE}}>(static_cast<const "
+ "uint8_t *>(obj), 0);";
+ } else {
+ code_ += getptr;
+ code_ += " return verifier.VerifyTable(ptr);";
+ }
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ += getptr;
+ code_ += " return verifier.VerifyString(ptr);";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ code_ += " }";
+ } else {
+ code_ += " case {{LABEL}}: {";
+ code_ += " return true;"; // "NONE" enum value.
+ code_ += " }";
+ }
+ }
+ code_ += " default: return false;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
+ code_ += " if (!values || !types) return !values && !types;";
+ code_ += " if (values->size() != types->size()) return false;";
+ code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
+ code_ += " if (!Verify" + Name(enum_def) + "(";
+ code_ += " verifier, values->Get(i), types->GetEnum<" +
+ Name(enum_def) + ">(i))) {";
+ code_ += " return false;";
+ code_ += " }";
+ code_ += " }";
+ code_ += " return true;";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate union Unpack() and Pack() functions.
+ code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ code_.SetValue("TYPE", GetUnionElement(ev, true, true));
+ code_ += " case {{LABEL}}: {";
+ code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return new " +
+ WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
+ } else {
+ code_ += " return ptr->UnPack(resolver);";
+ }
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ += " return new std::string(ptr->c_str(), ptr->size());";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ code_ += " }";
+ }
+ code_ += " default: return nullptr;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline " + UnionPackSignature(enum_def, false) + " {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ code_.SetValue("TYPE",
+ NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, parser_.opts));
+ code_.SetValue("NAME", GetUnionElement(ev, false, true));
+ code_ += " case {{LABEL}}: {";
+ code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ if (ev.union_type.struct_def->fixed) {
+ code_ += " return _fbb.CreateStruct(*ptr).Union();";
+ } else {
+ code_ +=
+ " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
+ }
+ } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+ code_ += " return _fbb.CreateString(*ptr).Union();";
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ code_ += " }";
+ }
+ code_ += " default: return 0;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ // Union copy constructor
+ code_ +=
+ "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
+ "{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), "
+ "value(nullptr) {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ code_.SetValue("TYPE",
+ NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, parser_.opts));
+ code_ += " case {{LABEL}}: {";
+ bool copyable = true;
+ if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+ // Don't generate code to copy if table is not copyable.
+ // TODO(wvo): make tables copyable instead.
+ for (auto fit = ev.union_type.struct_def->fields.vec.begin();
+ fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
+ const auto &field = **fit;
+ if (!field.deprecated && field.value.type.struct_def &&
+ !field.native_inline) {
+ copyable = false;
+ break;
+ }
+ }
+ }
+ if (copyable) {
+ code_ +=
+ " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
+ "(u.value));";
+ } else {
+ code_ +=
+ " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable.";
+ }
+ code_ += " break;";
+ code_ += " }";
+ }
+ code_ += " default:";
+ code_ += " break;";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ // Union Reset() function.
+ FLATBUFFERS_ASSERT(enum_def.Lookup("NONE"));
+ code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE")));
+
+ code_ += "inline void {{ENUM_NAME}}Union::Reset() {";
+ code_ += " switch (type) {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ const auto &ev = **it;
+ if (ev.IsZero()) { continue; }
+ code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+ code_.SetValue("TYPE",
+ NativeName(GetUnionElement(ev, true, true, true),
+ ev.union_type.struct_def, parser_.opts));
+ code_ += " case {{LABEL}}: {";
+ code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
+ code_ += " delete ptr;";
+ code_ += " break;";
+ code_ += " }";
+ }
+ code_ += " default: break;";
+ code_ += " }";
+ code_ += " value = nullptr;";
+ code_ += " type = {{NONE}};";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ // Generates a value with optionally a cast applied if the field has a
+ // different underlying type from its interface type (currently only the
+ // case for enums. "from" specify the direction, true meaning from the
+ // underlying type to the interface type.
+ std::string GenUnderlyingCast(const FieldDef &field, bool from,
+ const std::string &val) {
+ if (from && field.value.type.base_type == BASE_TYPE_BOOL) {
+ return val + " != 0";
+ } else if ((field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) ||
+ field.value.type.base_type == BASE_TYPE_BOOL) {
+ return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" +
+ val + ")";
+ } else {
+ return val;
+ }
+ }
+
+ std::string GenFieldOffsetName(const FieldDef &field) {
+ std::string uname = Name(field);
+ std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
+ return "VT_" + uname;
+ }
+
+ void GenFullyQualifiedNameGetter(const StructDef &struct_def,
+ const std::string &name) {
+ if (!parser_.opts.generate_name_strings) { return; }
+ auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
+ code_.SetValue("NAME", fullname);
+ code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
+ code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
+ code_ += " return \"{{NAME}}\";";
+ code_ += " }";
+ }
+
+ std::string GenDefaultConstant(const FieldDef &field) {
+ if (IsFloat(field.value.type.base_type))
+ return float_const_gen_.GenFloatConstant(field);
+ else
+ return NumToStringCpp(field.value.constant, field.value.type.base_type);
+ }
+
+ 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);
+ if (ev) {
+ return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
+ GetEnumValUse(*field.value.type.enum_def, *ev));
+ } else {
+ return GenUnderlyingCast(
+ field, true,
+ NumToStringCpp(field.value.constant, field.value.type.base_type));
+ }
+ } else if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ return field.value.constant == "0" ? "false" : "true";
+ } else if (field.attributes.Lookup("cpp_type")) {
+ if (is_ctor) {
+ if (PtrType(&field) == "naked") {
+ return "nullptr";
+ } else {
+ return "";
+ }
+ } else {
+ return "0";
+ }
+ } else {
+ return GenDefaultConstant(field);
+ }
+ }
+
+ void GenParam(const FieldDef &field, bool direct, const char *prefix) {
+ code_.SetValue("PRE", prefix);
+ code_.SetValue("PARAM_NAME", Name(field));
+ if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
+ code_.SetValue("PARAM_TYPE", "const char *");
+ code_.SetValue("PARAM_VALUE", "nullptr");
+ } else if (direct && field.value.type.base_type == BASE_TYPE_VECTOR) {
+ const auto vtype = field.value.type.VectorType();
+ std::string type;
+ if (IsStruct(vtype)) {
+ type = WrapInNameSpace(*vtype.struct_def);
+ } else {
+ type = GenTypeWire(vtype, "", false);
+ }
+ code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *");
+ code_.SetValue("PARAM_VALUE", "nullptr");
+ } else {
+ code_.SetValue("PARAM_TYPE", GenTypeWire(field.value.type, " ", true));
+ code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false));
+ }
+ code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\";
+ }
+
+ // Generate a member, including a default value for scalars and raw pointers.
+ void GenMember(const FieldDef &field) {
+ if (!field.deprecated && // Deprecated fields won't be accessible.
+ field.value.type.base_type != BASE_TYPE_UTYPE &&
+ (field.value.type.base_type != BASE_TYPE_VECTOR ||
+ field.value.type.element != BASE_TYPE_UTYPE)) {
+ auto type = GenTypeNative(field.value.type, false, field);
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ auto full_type =
+ (cpp_type
+ ? (field.value.type.base_type == BASE_TYPE_VECTOR
+ ? "std::vector<" +
+ GenTypeNativePtr(cpp_type->constant, &field,
+ false) +
+ "> "
+ : GenTypeNativePtr(cpp_type->constant, &field, false))
+ : type + " ");
+ code_.SetValue("FIELD_TYPE", full_type);
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}};";
+ }
+ }
+
+ // Generate the default constructor for this struct. Properly initialize all
+ // scalar members with default values.
+ void GenDefaultConstructor(const StructDef &struct_def) {
+ std::string initializer_list;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated && // Deprecated fields won't be accessible.
+ field.value.type.base_type != BASE_TYPE_UTYPE) {
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ 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 "; }
+ initializer_list += Name(field);
+ initializer_list +=
+ "(" +
+ (native_default ? std::string(native_default->constant)
+ : GetDefaultScalarValue(field, true)) +
+ ")";
+ } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (IsStruct(field.value.type)) {
+ if (native_default) {
+ if (!initializer_list.empty()) {
+ initializer_list += ",\n ";
+ }
+ initializer_list +=
+ Name(field) + "(" + native_default->constant + ")";
+ }
+ }
+ } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) {
+ if (!initializer_list.empty()) { initializer_list += ",\n "; }
+ initializer_list += Name(field) + "(0)";
+ }
+ }
+ }
+ if (!initializer_list.empty()) {
+ initializer_list = "\n : " + initializer_list;
+ }
+
+ code_.SetValue("NATIVE_NAME",
+ NativeName(Name(struct_def), &struct_def, parser_.opts));
+ code_.SetValue("INIT_LIST", initializer_list);
+
+ code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {";
+ code_ += " }";
+ }
+
+ void GenCompareOperator(const StructDef &struct_def,
+ std::string accessSuffix = "") {
+ std::string compare_op;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated && // Deprecated fields won't be accessible.
+ field.value.type.base_type != BASE_TYPE_UTYPE &&
+ (field.value.type.base_type != BASE_TYPE_VECTOR ||
+ field.value.type.element != BASE_TYPE_UTYPE)) {
+ if (!compare_op.empty()) { compare_op += " &&\n "; }
+ auto accessor = Name(field) + accessSuffix;
+ compare_op += "(lhs." + accessor + " == rhs." + accessor + ")";
+ }
+ }
+
+ std::string cmp_lhs;
+ std::string cmp_rhs;
+ if (compare_op.empty()) {
+ cmp_lhs = "";
+ cmp_rhs = "";
+ compare_op = " return true;";
+ } else {
+ cmp_lhs = "lhs";
+ cmp_rhs = "rhs";
+ compare_op = " return\n " + compare_op + ";";
+ }
+
+ code_.SetValue("CMP_OP", compare_op);
+ code_.SetValue("CMP_LHS", cmp_lhs);
+ code_.SetValue("CMP_RHS", cmp_rhs);
+ code_ += "";
+ code_ +=
+ "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const "
+ "{{NATIVE_NAME}} &{{CMP_RHS}}) {";
+ code_ += "{{CMP_OP}}";
+ code_ += "}";
+
+ code_ += "";
+ code_ +=
+ "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const "
+ "{{NATIVE_NAME}} &rhs) {";
+ code_ += " return !(lhs == rhs);";
+ code_ += "}";
+ code_ += "";
+ }
+
+ void GenOperatorNewDelete(const StructDef &struct_def) {
+ if (auto native_custom_alloc =
+ struct_def.attributes.Lookup("native_custom_alloc")) {
+ code_ += " inline void *operator new (std::size_t count) {";
+ code_ += " return " + native_custom_alloc->constant +
+ "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
+ code_ += " }";
+ code_ += " inline void operator delete (void *ptr) {";
+ code_ += " return " + native_custom_alloc->constant +
+ "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>("
+ "ptr),1);";
+ code_ += " }";
+ }
+ }
+
+ void GenNativeTable(const StructDef &struct_def) {
+ const auto native_name =
+ NativeName(Name(struct_def), &struct_def, parser_.opts);
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("NATIVE_NAME", native_name);
+
+ // Generate a C++ object that can hold an unpacked version of this table.
+ code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
+ code_ += " typedef {{STRUCT_NAME}} TableType;";
+ GenFullyQualifiedNameGetter(struct_def, native_name);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ GenMember(**it);
+ }
+ GenOperatorNewDelete(struct_def);
+ GenDefaultConstructor(struct_def);
+ code_ += "};";
+ if (parser_.opts.gen_compare) GenCompareOperator(struct_def);
+ code_ += "";
+ }
+
+ // Generate the code to call the appropriate Verify function(s) for a field.
+ void GenVerifyCall(const FieldDef &field, const char *prefix) {
+ code_.SetValue("PRE", prefix);
+ code_.SetValue("NAME", Name(field));
+ code_.SetValue("REQUIRED", field.required ? "Required" : "");
+ code_.SetValue("SIZE", GenTypeSize(field.value.type));
+ code_.SetValue("OFFSET", GenFieldOffsetName(field));
+ if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
+ code_ +=
+ "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+ } else {
+ code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
+ }
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_UNION: {
+ code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+ code_.SetValue("SUFFIX", UnionTypeFieldSuffix());
+ code_ +=
+ "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), "
+ "{{NAME}}{{SUFFIX}}())\\";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING: {
+ code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
+
+ switch (field.value.type.element) {
+ case BASE_TYPE_STRING: {
+ code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (!field.value.type.struct_def->fixed) {
+ code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code_.SetValue("ENUM_NAME", field.value.type.enum_def->name);
+ code_ +=
+ "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), "
+ "{{NAME}}_type())\\";
+ break;
+ }
+ default: break;
+ }
+ break;
+ }
+ default: { break; }
+ }
+ }
+
+ // Generate CompareWithValue method for a key field.
+ void GenKeyFieldMethods(const FieldDef &field) {
+ FLATBUFFERS_ASSERT(field.key);
+ const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
+
+ code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
+ if (is_string) {
+ // use operator< of flatbuffers::String
+ code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();";
+ } else {
+ code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
+ }
+ code_ += " }";
+
+ if (is_string) {
+ code_ += " int KeyCompareWithValue(const char *val) const {";
+ code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);";
+ code_ += " }";
+ } else {
+ FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type));
+ auto type = GenTypeBasic(field.value.type, false);
+ if (parser_.opts.scoped_enums && field.value.type.enum_def &&
+ IsScalar(field.value.type.base_type)) {
+ type = GenTypeGet(field.value.type, " ", "const ", " *", true);
+ }
+ // Returns {field<val: -1, field==val: 0, field>val: +1}.
+ code_.SetValue("KEY_TYPE", type);
+ code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {";
+ code_ +=
+ " return static_cast<int>({{FIELD_NAME}}() > val) - "
+ "static_cast<int>({{FIELD_NAME}}() < val);";
+ code_ += " }";
+ }
+ }
+
+ // Generate an accessor struct, builder structs & function for a table.
+ void GenTable(const StructDef &struct_def) {
+ if (parser_.opts.generate_object_based_api) { GenNativeTable(struct_def); }
+
+ // Generate an accessor struct, with methods of the form:
+ // type name() const { return GetField<type>(offset, defaultval); }
+ GenComment(struct_def.doc_comment);
+
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_ +=
+ "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
+ " : private flatbuffers::Table {";
+ if (parser_.opts.generate_object_based_api) {
+ code_ += " typedef {{NATIVE_NAME}} NativeTableType;";
+ }
+ if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ code_ +=
+ " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
+ code_ += " return {{STRUCT_NAME}}TypeTable();";
+ code_ += " }";
+ }
+
+ GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
+
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ // We need to add a trailing comma to all elements except the last one as
+ // older versions of gcc complain about this.
+ code_.SetValue("SEP", "");
+ code_ +=
+ " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ // Deprecated fields won't be accessible.
+ continue;
+ }
+
+ code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\";
+ code_.SetValue("SEP", ",\n");
+ }
+ code_ += "";
+ code_ += " };";
+ }
+
+ // Generate the accessors.
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ // Deprecated fields won't be accessible.
+ continue;
+ }
+
+ const bool is_struct = IsStruct(field.value.type);
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+ code_.SetValue("FIELD_NAME", Name(field));
+
+ // Call a different accessor for pointers, that indirects.
+ std::string accessor = "";
+ if (is_scalar) {
+ accessor = "GetField<";
+ } else if (is_struct) {
+ accessor = "GetStruct<";
+ } else {
+ accessor = "GetPointer<";
+ }
+ auto offset_str = GenFieldOffsetName(field);
+ auto offset_type =
+ GenTypeGet(field.value.type, "", "const ", " *", false);
+
+ auto call = accessor + offset_type + ">(" + offset_str;
+ // Default value as second arg for non-pointer types.
+ if (is_scalar) { call += ", " + GenDefaultConstant(field); }
+ call += ")";
+
+ std::string afterptr = " *" + NullableExtension();
+ GenComment(field.doc_comment, " ");
+ code_.SetValue("FIELD_TYPE", GenTypeGet(field.value.type, " ", "const ",
+ afterptr.c_str(), true));
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+ code_.SetValue("NULLABLE_EXT", NullableExtension());
+
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+
+ if (field.value.type.base_type == BASE_TYPE_UNION) {
+ auto u = field.value.type.enum_def;
+
+ if (!field.value.type.enum_def->uses_multiple_type_instances)
+ code_ +=
+ " template<typename T> "
+ "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
+
+ for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+ auto &ev = **u_it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+ auto full_struct_name = GetUnionElement(ev, true, true);
+
+ // @TODO: Mby make this decisions more universal? How?
+ code_.SetValue("U_GET_TYPE",
+ EscapeKeyword(field.name + UnionTypeFieldSuffix()));
+ code_.SetValue(
+ "U_ELEMENT_TYPE",
+ WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+ code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+ code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+ code_.SetValue("U_NULLABLE", NullableExtension());
+
+ // `const Type *union_name_asType() const` accessor.
+ code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
+ code_ +=
+ " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
+ "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
+ ": nullptr;";
+ code_ += " }";
+ }
+ }
+
+ if (parser_.opts.mutable_buffer) {
+ if (is_scalar) {
+ const auto type = GenTypeWire(field.value.type, "", false);
+ code_.SetValue("SET_FN", "SetField<" + type + ">");
+ code_.SetValue("OFFSET_NAME", offset_str);
+ code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
+ code_.SetValue("FIELD_VALUE",
+ GenUnderlyingCast(field, false, "_" + Name(field)));
+ code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
+
+ code_ +=
+ " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
+ "_{{FIELD_NAME}}) {";
+ code_ +=
+ " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, "
+ "{{DEFAULT_VALUE}});";
+ code_ += " }";
+ } else {
+ auto postptr = " *" + NullableExtension();
+ auto type =
+ GenTypeGet(field.value.type, " ", "", postptr.c_str(), true);
+ auto underlying = accessor + type + ">(" + offset_str + ")";
+ code_.SetValue("FIELD_TYPE", type);
+ code_.SetValue("FIELD_VALUE",
+ GenUnderlyingCast(field, true, underlying));
+
+ code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+ }
+
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (nested) {
+ std::string qualified_name = nested->constant;
+ auto nested_root = parser_.LookupStruct(nested->constant);
+ if (nested_root == nullptr) {
+ qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
+ nested->constant);
+ nested_root = parser_.LookupStruct(qualified_name);
+ }
+ FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
+ (void)nested_root;
+ code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
+
+ code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
+ code_ +=
+ " return "
+ "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());";
+ code_ += " }";
+ }
+
+ if (field.flexbuffer) {
+ code_ +=
+ " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
+ " const {";
+ // Both Data() and size() are const-methods, therefore call order
+ // doesn't matter.
+ code_ +=
+ " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), "
+ "{{FIELD_NAME}}()->size());";
+ code_ += " }";
+ }
+
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) { GenKeyFieldMethods(field); }
+ }
+
+ // Generate a verifier function that can check a buffer from an untrusted
+ // source will never cause reads outside the buffer.
+ code_ += " bool Verify(flatbuffers::Verifier &verifier) const {";
+ code_ += " return VerifyTableStart(verifier)\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+ GenVerifyCall(field, " &&\n ");
+ }
+
+ code_ += " &&\n verifier.EndTable();";
+ code_ += " }";
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate the UnPack() pre declaration.
+ code_ +=
+ " " + TableUnPackSignature(struct_def, true, parser_.opts) + ";";
+ code_ +=
+ " " + TableUnPackToSignature(struct_def, true, parser_.opts) + ";";
+ code_ += " " + TablePackSignature(struct_def, true, parser_.opts) + ";";
+ }
+
+ code_ += "};"; // End of table.
+ code_ += "";
+
+ // Explicit specializations for union accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
+ continue;
+ }
+
+ auto u = field.value.type.enum_def;
+ if (u->uses_multiple_type_instances) continue;
+
+ code_.SetValue("FIELD_NAME", Name(field));
+
+ for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+ auto &ev = **u_it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+
+ auto full_struct_name = GetUnionElement(ev, true, true);
+
+ code_.SetValue(
+ "U_ELEMENT_TYPE",
+ WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+ code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+ code_.SetValue("U_ELEMENT_NAME", full_struct_name);
+ code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev));
+
+ // `template<> const T *union_name_as<T>() const` accessor.
+ code_ +=
+ "template<> "
+ "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
+ "<{{U_ELEMENT_NAME}}>() const {";
+ code_ += " return {{U_FIELD_NAME}}();";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ GenBuilders(struct_def);
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate a pre-declaration for a CreateX method that works with an
+ // unpacked C++ object.
+ code_ += TableCreateSignature(struct_def, true, parser_.opts) + ";";
+ code_ += "";
+ }
+ }
+
+ void GenBuilders(const StructDef &struct_def) {
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+ // Generate a builder struct:
+ code_ += "struct {{STRUCT_NAME}}Builder {";
+ code_ += " flatbuffers::FlatBufferBuilder &fbb_;";
+ code_ += " flatbuffers::uoffset_t start_;";
+
+ bool has_string_or_vector_fields = false;
+ 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");
+ }
+
+ 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_ += " }";
+ }
+ }
+
+ // Builder constructor
+ code_ +=
+ " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder "
+ "&_fbb)";
+ code_ += " : fbb_(_fbb) {";
+ code_ += " start_ = fbb_.StartTable();";
+ code_ += " }";
+
+ // Assignment operator;
+ code_ +=
+ " {{STRUCT_NAME}}Builder &operator="
+ "(const {{STRUCT_NAME}}Builder &);";
+
+ // Finish() function.
+ code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
+ code_ += " const auto end = fbb_.EndTable(start_);";
+ code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
+ code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
+ }
+ }
+ code_ += " return o;";
+ code_ += " }";
+ code_ += "};";
+ code_ += "";
+
+ // Generate a convenient CreateX function that uses the above builder
+ // to create a table in one go.
+ code_ +=
+ "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
+ "Create{{STRUCT_NAME}}(";
+ code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) { GenParam(field, false, ",\n "); }
+ }
+ code_ += ") {";
+
+ code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ const auto &field = **it;
+ 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}});";
+ }
+ }
+ }
+ code_ += " return builder_.Finish();";
+ code_ += "}";
+ code_ += "";
+
+ // Generate a CreateXDirect function with vector types as parameters
+ if (has_string_or_vector_fields) {
+ code_ +=
+ "inline flatbuffers::Offset<{{STRUCT_NAME}}> "
+ "Create{{STRUCT_NAME}}Direct(";
+ code_ += " flatbuffers::FlatBufferBuilder &_fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) { GenParam(field, true, ",\n "); }
+ }
+ // Need to call "Create" with the struct namespace.
+ const auto qualified_create_name =
+ struct_def.defined_namespace->GetFullyQualifiedName("Create");
+ code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
+ code_ += ") {";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ if (!field.shared) {
+ code_.SetValue("CREATE_STRING", "CreateString");
+ } else {
+ code_.SetValue("CREATE_STRING", "CreateSharedString");
+ }
+ code_ +=
+ " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
+ "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\";
+ const auto vtype = field.value.type.VectorType();
+ if (IsStruct(vtype)) {
+ const auto type = WrapInNameSpace(*vtype.struct_def);
+ code_ += "_fbb.CreateVectorOfStructs<" + type + ">\\";
+ } else {
+ const auto type = GenTypeWire(vtype, "", false);
+ code_ += "_fbb.CreateVector<" + type + ">\\";
+ }
+ code_ += "(*{{FIELD_NAME}}) : 0;";
+ }
+ }
+ }
+ code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
+ code_ += " _fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_ += ",\n {{FIELD_NAME}}\\";
+ if (field.value.type.base_type == BASE_TYPE_STRING ||
+ field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code_ += "__\\";
+ }
+ }
+ }
+ code_ += ");";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ std::string GenUnionUnpackVal(const FieldDef &afield,
+ const char *vec_elem_access,
+ const char *vec_type_access) {
+ return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" +
+ vec_elem_access + ", " +
+ EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" +
+ vec_type_access + ", _resolver)";
+ }
+
+ std::string GenUnpackVal(const Type &type, const std::string &val,
+ bool invector, const FieldDef &afield) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: {
+ if (FlexibleStringConstructor(&afield)) {
+ return NativeString(&afield) + "(" + val + "->c_str(), " + val +
+ "->size())";
+ } else {
+ return val + "->str()";
+ }
+ }
+ case BASE_TYPE_STRUCT: {
+ const auto name = WrapInNameSpace(*type.struct_def);
+ if (IsStruct(type)) {
+ auto native_type = type.struct_def->attributes.Lookup("native_type");
+ if (native_type) {
+ return "flatbuffers::UnPack(*" + val + ")";
+ } else if (invector || afield.native_inline) {
+ return "*" + val;
+ } else {
+ const auto ptype = GenTypeNativePtr(name, &afield, true);
+ return ptype + "(new " + name + "(*" + val + "))";
+ }
+ } else {
+ const auto ptype = GenTypeNativePtr(
+ NativeName(name, type.struct_def, parser_.opts), &afield, true);
+ return ptype + "(" + val + "->UnPack(_resolver))";
+ }
+ }
+ case BASE_TYPE_UNION: {
+ return GenUnionUnpackVal(
+ afield, invector ? "->Get(_i)" : "",
+ invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str()
+ : "");
+ }
+ default: {
+ return val;
+ break;
+ }
+ }
+ }
+
+ std::string GenUnpackFieldStatement(const FieldDef &field,
+ const FieldDef *union_field) {
+ std::string code;
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_VECTOR: {
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ std::string indexing;
+ if (field.value.type.enum_def) {
+ indexing += "static_cast<" +
+ WrapInNameSpace(*field.value.type.enum_def) + ">(";
+ }
+ indexing += "_e->Get(_i)";
+ if (field.value.type.enum_def) { indexing += ")"; }
+ if (field.value.type.element == BASE_TYPE_BOOL) { indexing += " != 0"; }
+
+ // Generate code that pushes data from _e to _o in the form:
+ // for (uoffset_t i = 0; i < _e->size(); ++i) {
+ // _o->field.push_back(_e->Get(_i));
+ // }
+ auto name = Name(field);
+ if (field.value.type.element == BASE_TYPE_UTYPE) {
+ name = StripUnionType(Name(field));
+ }
+ auto access =
+ field.value.type.element == BASE_TYPE_UTYPE
+ ? ".type"
+ : (field.value.type.element == BASE_TYPE_UNION ? ".value" : "");
+ code += "{ _o->" + name + ".resize(_e->size()); ";
+ code += "for (flatbuffers::uoffset_t _i = 0;";
+ code += " _i < _e->size(); _i++) { ";
+ if (cpp_type) {
+ // Generate code that resolves the cpp pointer type, of the form:
+ // if (resolver)
+ // (*resolver)(&_o->field, (hash_value_t)(_e));
+ // else
+ // _o->field = nullptr;
+ code += "//vector resolver, " + PtrType(&field) + "\n";
+ code += "if (_resolver) ";
+ code += "(*_resolver)";
+ code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + access +
+ "), ";
+ code += "static_cast<flatbuffers::hash_value_t>(" + indexing + "));";
+ if (PtrType(&field) == "naked") {
+ code += " else ";
+ code += "_o->" + name + "[_i]" + access + " = nullptr";
+ } else {
+ // code += " else ";
+ // code += "_o->" + name + "[_i]" + access + " = " +
+ // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+ code += "/* else do nothing */";
+ }
+ } else {
+ code += "_o->" + name + "[_i]" + access + " = ";
+ code += GenUnpackVal(field.value.type.VectorType(), indexing, true,
+ field);
+ }
+ code += "; } }";
+ break;
+ }
+ case BASE_TYPE_UTYPE: {
+ FLATBUFFERS_ASSERT(union_field->value.type.base_type ==
+ BASE_TYPE_UNION);
+ // Generate code that sets the union type, of the form:
+ // _o->field.type = _e;
+ code += "_o->" + union_field->name + ".type = _e;";
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ // Generate code that sets the union value, of the form:
+ // _o->field.value = Union::Unpack(_e, field_type(), resolver);
+ code += "_o->" + Name(field) + ".value = ";
+ code += GenUnionUnpackVal(field, "", "");
+ code += ";";
+ break;
+ }
+ default: {
+ auto cpp_type = field.attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ // Generate code that resolves the cpp pointer type, of the form:
+ // if (resolver)
+ // (*resolver)(&_o->field, (hash_value_t)(_e));
+ // else
+ // _o->field = nullptr;
+ code += "//scalar resolver, " + PtrType(&field) + " \n";
+ code += "if (_resolver) ";
+ code += "(*_resolver)";
+ code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
+ code += "static_cast<flatbuffers::hash_value_t>(_e));";
+ if (PtrType(&field) == "naked") {
+ code += " else ";
+ code += "_o->" + Name(field) + " = nullptr;";
+ } else {
+ // code += " else ";
+ // code += "_o->" + Name(field) + " = " +
+ // GenTypeNativePtr(cpp_type->constant, &field, true) + "();";
+ code += "/* else do nothing */;";
+ }
+ } else {
+ // Generate code for assigning the value, of the form:
+ // _o->field = value;
+ code += "_o->" + Name(field) + " = ";
+ code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
+ }
+ break;
+ }
+ }
+ return code;
+ }
+
+ std::string GenCreateParam(const FieldDef &field) {
+ const IDLOptions &opts = parser_.opts;
+
+ std::string value = "_o->";
+ if (field.value.type.base_type == BASE_TYPE_UTYPE) {
+ value += StripUnionType(Name(field));
+ value += ".type";
+ } else {
+ value += Name(field);
+ }
+ if (field.value.type.base_type != BASE_TYPE_VECTOR &&
+ field.attributes.Lookup("cpp_type")) {
+ auto type = GenTypeBasic(field.value.type, false);
+ value =
+ "_rehasher ? "
+ "static_cast<" +
+ type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0";
+ }
+
+ std::string code;
+ switch (field.value.type.base_type) {
+ // String fields are of the form:
+ // _fbb.CreateString(_o->field)
+ // or
+ // _fbb.CreateSharedString(_o->field)
+ case BASE_TYPE_STRING: {
+ if (!field.shared) {
+ code += "_fbb.CreateString(";
+ } else {
+ code += "_fbb.CreateSharedString(";
+ }
+ code += value;
+ code.push_back(')');
+
+ // For optional fields, check to see if there actually is any data
+ // in _o->field before attempting to access it. If there isn't,
+ // depending on set_empty_to_null either set it to 0 or an empty string.
+ if (!field.required) {
+ auto empty_value =
+ opts.set_empty_to_null ? "0" : "_fbb.CreateSharedString(\"\")";
+ code = value + ".empty() ? " + empty_value + " : " + code;
+ }
+ break;
+ }
+ // Vector fields come in several flavours, of the forms:
+ // _fbb.CreateVector(_o->field);
+ // _fbb.CreateVector((const utype*)_o->field.data(), _o->field.size());
+ // _fbb.CreateVectorOfStrings(_o->field)
+ // _fbb.CreateVectorOfStructs(_o->field)
+ // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) {
+ // return CreateT(_fbb, _o->Get(i), rehasher);
+ // });
+ case BASE_TYPE_VECTOR: {
+ auto vector_type = field.value.type.VectorType();
+ switch (vector_type.base_type) {
+ case BASE_TYPE_STRING: {
+ if (NativeString(&field) == "std::string") {
+ code += "_fbb.CreateVectorOfStrings(" + value + ")";
+ } else {
+ // Use by-function serialization to emulate
+ // CreateVectorOfStrings(); this works also with non-std strings.
+ code +=
+ "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>"
+ " ";
+ code += "(" + value + ".size(), ";
+ code += "[](size_t i, _VectorArgs *__va) { ";
+ code +=
+ "return __va->__fbb->CreateString(__va->_" + value + "[i]);";
+ code += " }, &_va )";
+ }
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(vector_type)) {
+ auto native_type =
+ field.value.type.struct_def->attributes.Lookup("native_type");
+ if (native_type) {
+ code += "_fbb.CreateVectorOfNativeStructs<";
+ code += WrapInNameSpace(*vector_type.struct_def) + ">";
+ } else {
+ code += "_fbb.CreateVectorOfStructs";
+ }
+ code += "(" + value + ")";
+ } else {
+ code += "_fbb.CreateVector<flatbuffers::Offset<";
+ code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
+ code += "(" + value + ".size(), ";
+ code += "[](size_t i, _VectorArgs *__va) { ";
+ code += "return Create" + vector_type.struct_def->name;
+ code += "(*__va->__fbb, __va->_" + value + "[i]" +
+ GenPtrGet(field) + ", ";
+ code += "__va->__rehasher); }, &_va )";
+ }
+ break;
+ }
+ case BASE_TYPE_BOOL: {
+ code += "_fbb.CreateVector(" + value + ")";
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ code +=
+ "_fbb.CreateVector<flatbuffers::"
+ "Offset<void>>(" +
+ value +
+ ".size(), [](size_t i, _VectorArgs *__va) { "
+ "return __va->_" +
+ value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
+ break;
+ }
+ case BASE_TYPE_UTYPE: {
+ value = StripUnionType(value);
+ code += "_fbb.CreateVector<uint8_t>(" + value +
+ ".size(), [](size_t i, _VectorArgs *__va) { "
+ "return static_cast<uint8_t>(__va->_" +
+ value + "[i].type); }, &_va)";
+ break;
+ }
+ default: {
+ if (field.value.type.enum_def) {
+ // For enumerations, we need to get access to the array data for
+ // the underlying storage type (eg. uint8_t).
+ const auto basetype = GenTypeBasic(
+ field.value.type.enum_def->underlying_type, false);
+ code += "_fbb.CreateVectorScalarCast<" + basetype +
+ ">(flatbuffers::data(" + value + "), " + value +
+ ".size())";
+ } else if (field.attributes.Lookup("cpp_type")) {
+ auto type = GenTypeBasic(vector_type, false);
+ code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), ";
+ code += "[](size_t i, _VectorArgs *__va) { ";
+ code += "return __va->__rehasher ? ";
+ code += "static_cast<" + type + ">((*__va->__rehasher)";
+ code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0";
+ code += "; }, &_va )";
+ } else {
+ code += "_fbb.CreateVector(" + value + ")";
+ }
+ break;
+ }
+ }
+
+ // If set_empty_to_null option is enabled, for optional fields, check to
+ // see if there actually is any data in _o->field before attempting to
+ // access it.
+ if (opts.set_empty_to_null && !field.required) {
+ code = value + ".size() ? " + code + " : 0";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ // _o->field.Pack(_fbb);
+ code += value + ".Pack(_fbb)";
+ break;
+ }
+ case BASE_TYPE_STRUCT: {
+ if (IsStruct(field.value.type)) {
+ auto native_type =
+ field.value.type.struct_def->attributes.Lookup("native_type");
+ if (native_type) {
+ code += "flatbuffers::Pack(" + value + ")";
+ } else if (field.native_inline) {
+ code += "&" + value;
+ } else {
+ code += value + " ? " + value + GenPtrGet(field) + " : 0";
+ }
+ } else {
+ // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
+ const auto type = field.value.type.struct_def->name;
+ code += value + " ? Create" + type;
+ code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)";
+ code += " : 0";
+ }
+ break;
+ }
+ default: {
+ code += value;
+ break;
+ }
+ }
+ return code;
+ }
+
+ // Generate code for tables that needs to come after the regular definition.
+ void GenTablePost(const StructDef &struct_def) {
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("NATIVE_NAME",
+ NativeName(Name(struct_def), &struct_def, parser_.opts));
+
+ if (parser_.opts.generate_object_based_api) {
+ // Generate the X::UnPack() method.
+ code_ += "inline " +
+ TableUnPackSignature(struct_def, false, parser_.opts) + " {";
+ code_ += " auto _o = new {{NATIVE_NAME}}();";
+ code_ += " UnPackTo(_o, _resolver);";
+ code_ += " return _o;";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "inline " +
+ TableUnPackToSignature(struct_def, false, parser_.opts) + " {";
+ code_ += " (void)_o;";
+ code_ += " (void)_resolver;";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) { continue; }
+
+ // Assign a value from |this| to |_o|. Values from |this| are stored
+ // in a variable |_e| by calling this->field_type(). The value is then
+ // assigned to |_o| using the GenUnpackFieldStatement.
+ const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE;
+ const auto statement =
+ GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
+
+ code_.SetValue("FIELD_NAME", Name(field));
+ auto prefix = " { auto _e = {{FIELD_NAME}}(); ";
+ auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
+ auto postfix = " };";
+ code_ += std::string(prefix) + check + statement + postfix;
+ }
+ code_ += "}";
+ code_ += "";
+
+ // Generate the X::Pack member function that simply calls the global
+ // CreateX function.
+ code_ += "inline " + TablePackSignature(struct_def, false, parser_.opts) +
+ " {";
+ code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
+ code_ += "}";
+ code_ += "";
+
+ // Generate a CreateX method that works with an unpacked C++ object.
+ code_ += "inline " +
+ TableCreateSignature(struct_def, false, parser_.opts) + " {";
+ code_ += " (void)_rehasher;";
+ code_ += " (void)_o;";
+
+ code_ +=
+ " struct _VectorArgs "
+ "{ flatbuffers::FlatBufferBuilder *__fbb; "
+ "const " +
+ NativeName(Name(struct_def), &struct_def, parser_.opts) +
+ "* __o; "
+ "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
+ "&_fbb, _o, _rehasher}; (void)_va;";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) { continue; }
+ code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
+ }
+ // Need to call "Create" with the struct namespace.
+ const auto qualified_create_name =
+ struct_def.defined_namespace->GetFullyQualifiedName("Create");
+ code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name));
+
+ code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}(";
+ code_ += " _fbb\\";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) { continue; }
+
+ bool pass_by_address = false;
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ if (IsStruct(field.value.type)) {
+ auto native_type =
+ field.value.type.struct_def->attributes.Lookup("native_type");
+ if (native_type) { pass_by_address = true; }
+ }
+ }
+
+ // Call the CreateX function using values from |_o|.
+ if (pass_by_address) {
+ code_ += ",\n &_" + Name(field) + "\\";
+ } else {
+ code_ += ",\n _" + Name(field) + "\\";
+ }
+ }
+ code_ += ");";
+ code_ += "}";
+ code_ += "";
+ }
+ }
+
+ static void GenPadding(
+ const FieldDef &field, std::string *code_ptr, int *id,
+ const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++) {
+ if (static_cast<int>(field.padding) & (1 << i)) {
+ f((1 << i) * 8, code_ptr, id);
+ }
+ }
+ FLATBUFFERS_ASSERT(!(field.padding & ~0xF));
+ }
+ }
+
+ static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
+ *code_ptr += " int" + NumToString(bits) + "_t padding" +
+ NumToString((*id)++) + "__;";
+ }
+
+ static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
+ (void)bits;
+ if (*code_ptr != "") *code_ptr += ",\n ";
+ *code_ptr += "padding" + NumToString((*id)++) + "__(0)";
+ }
+
+ static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
+ (void)bits;
+ *code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def) {
+ // Generate an accessor struct, with private variables of the form:
+ // type name_;
+ // Generates manual padding and alignment.
+ // Variables are private because they contain little endian data on all
+ // platforms.
+ GenComment(struct_def.doc_comment);
+ code_.SetValue("ALIGN", NumToString(struct_def.minalign));
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+ code_ +=
+ "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
+ "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
+ code_ += " private:";
+
+ int padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto &field_type = field.value.type;
+ code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false));
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("ARRAY",
+ IsArray(field_type)
+ ? "[" + NumToString(field_type.fixed_length) + "]"
+ : "");
+ code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};");
+
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingDefinition);
+ code_ += padding;
+ }
+ }
+
+ // Generate GetFullyQualifiedName
+ code_ += "";
+ code_ += " public:";
+
+ // Make TypeTable accessible via the generated struct.
+ if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+ code_ +=
+ " static const flatbuffers::TypeTable *MiniReflectTypeTable() {";
+ code_ += " return {{STRUCT_NAME}}TypeTable();";
+ code_ += " }";
+ }
+
+ GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
+
+ // Generate a default constructor.
+ code_ += " {{STRUCT_NAME}}() {";
+ code_ +=
+ " memset(static_cast<void *>(this), 0, sizeof({{STRUCT_NAME}}));";
+ code_ += " }";
+
+ // Generate a constructor that takes all fields as arguments,
+ // excluding arrays
+ std::string arg_list;
+ std::string init_list;
+ padding_id = 0;
+ auto first = struct_def.fields.vec.begin();
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (IsArray(field.value.type)) {
+ first++;
+ continue;
+ }
+ const auto member_name = Name(field) + "_";
+ const auto arg_name = "_" + Name(field);
+ const auto arg_type =
+ GenTypeGet(field.value.type, " ", "const ", " &", true);
+
+ if (it != first) { arg_list += ", "; }
+ arg_list += arg_type;
+ arg_list += arg_name;
+ if (!IsArray(field.value.type)) {
+ if (it != first && init_list != "") { init_list += ",\n "; }
+ init_list += member_name;
+ if (IsScalar(field.value.type.base_type)) {
+ auto type = GenUnderlyingCast(field, false, arg_name);
+ init_list += "(flatbuffers::EndianScalar(" + type + "))";
+ } else {
+ init_list += "(" + arg_name + ")";
+ }
+ }
+ if (field.padding) {
+ GenPadding(field, &init_list, &padding_id, PaddingInitializer);
+ }
+ }
+
+ if (!arg_list.empty()) {
+ code_.SetValue("ARG_LIST", arg_list);
+ code_.SetValue("INIT_LIST", init_list);
+ if (!init_list.empty()) {
+ code_ += " {{STRUCT_NAME}}({{ARG_LIST}})";
+ code_ += " : {{INIT_LIST}} {";
+ } else {
+ code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
+ }
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (IsArray(field.value.type)) {
+ const auto &member = Name(field) + "_";
+ code_ +=
+ " std::memset(" + member + ", 0, sizeof(" + member + "));";
+ }
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingNoop);
+ code_ += padding;
+ }
+ }
+ code_ += " }";
+ }
+
+ // Generate accessor methods of the form:
+ // type name() const { return flatbuffers::EndianScalar(name_); }
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+
+ auto field_type = GenTypeGet(field.value.type, " ",
+ IsArray(field.value.type) ? "" : "const ",
+ IsArray(field.value.type) ? "" : " &", true);
+ auto is_scalar = IsScalar(field.value.type.base_type);
+ auto member = Name(field) + "_";
+ auto value =
+ is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
+
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_TYPE", field_type);
+ code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
+
+ GenComment(field.doc_comment, " ");
+
+ // Generate a const accessor function.
+ if (IsArray(field.value.type)) {
+ auto underlying = GenTypeGet(field.value.type, "", "", "", false);
+ code_ += " const flatbuffers::Array<" + field_type + ", " +
+ NumToString(field.value.type.fixed_length) + "> *" +
+ "{{FIELD_NAME}}() const {";
+ code_ += " return reinterpret_cast<const flatbuffers::Array<" +
+ field_type + ", " +
+ NumToString(field.value.type.fixed_length) +
+ "> *>({{FIELD_VALUE}});";
+ code_ += " }";
+ } else {
+ code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+
+ // Generate a mutable accessor function.
+ if (parser_.opts.mutable_buffer) {
+ auto mut_field_type =
+ GenTypeGet(field.value.type, " ", "",
+ IsArray(field.value.type) ? "" : " &", true);
+ code_.SetValue("FIELD_TYPE", mut_field_type);
+ if (is_scalar) {
+ code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
+ code_.SetValue("FIELD_VALUE",
+ GenUnderlyingCast(field, false, "_" + Name(field)));
+
+ code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
+ code_ +=
+ " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
+ "{{FIELD_VALUE}});";
+ code_ += " }";
+ } else if (IsArray(field.value.type)) {
+ auto underlying = GenTypeGet(field.value.type, "", "", "", false);
+ code_ += " flatbuffers::Array<" + mut_field_type + ", " +
+ NumToString(field.value.type.fixed_length) +
+ "> *" + "mutable_{{FIELD_NAME}}() {";
+ code_ += " return reinterpret_cast<flatbuffers::Array<" +
+ mut_field_type + ", " +
+ NumToString(field.value.type.fixed_length) +
+ "> *>({{FIELD_VALUE}});";
+ code_ += " }";
+ } else {
+ code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
+ code_ += " return {{FIELD_VALUE}};";
+ code_ += " }";
+ }
+ }
+
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) { GenKeyFieldMethods(field); }
+ }
+ code_.SetValue("NATIVE_NAME", Name(struct_def));
+ GenOperatorNewDelete(struct_def);
+ code_ += "};";
+
+ code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
+ code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});";
+ if (parser_.opts.gen_compare) GenCompareOperator(struct_def, "()");
+ code_ += "";
+ }
+
+ // Set up the correct namespace. Only open a namespace if the existing one is
+ // different (closing/opening only what is necessary).
+ //
+ // The file must start and end with an empty (or null) namespace so that
+ // namespaces are properly opened and closed.
+ void SetNameSpace(const Namespace *ns) {
+ if (cur_name_space_ == ns) { return; }
+
+ // Compute the size of the longest common namespace prefix.
+ // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+ size_t new_size = ns ? ns->components.size() : 0;
+
+ size_t common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size]) {
+ common_prefix_size++;
+ }
+
+ // Close cur_name_space in reverse order to reach the common prefix.
+ // In the previous example, D then C are closed.
+ for (size_t j = old_size; j > common_prefix_size; --j) {
+ code_ += "} // namespace " + cur_name_space_->components[j - 1];
+ }
+ if (old_size != common_prefix_size) { code_ += ""; }
+
+ // open namespace parts to reach the ns namespace
+ // in the previous example, E, then F, then G are opened
+ for (auto j = common_prefix_size; j != new_size; ++j) {
+ code_ += "namespace " + ns->components[j] + " {";
+ }
+ if (new_size != common_prefix_size) { code_ += ""; }
+
+ cur_name_space_ = ns;
+ }
+
+ const TypedFloatConstantGenerator float_const_gen_;
+};
+
+} // namespace cpp
+
+bool GenerateCPP(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ cpp::CppGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string CPPMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ const auto filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ const auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_dart.cpp b/src/idl_gen_dart.cpp
new file mode 100644
index 0000000..2346a85
--- /dev/null
+++ b/src/idl_gen_dart.cpp
@@ -0,0 +1,914 @@
+/*
+ * Copyright 2018 Dan Field
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+#include <cassert>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.dart";
+}
+
+namespace dart {
+
+const std::string _kFb = "fb";
+// see https://www.dartlang.org/guides/language/language-tour#keywords
+// yeild*, async*, and sync* shouldn't be problems anyway but keeping them in
+static const char *keywords[] = {
+ "abstract", "deferred", "if", "super", "as", "do",
+ "implements", "switch", "assert", "dynamic", "import", "sync*",
+ "async", "else", "in", "this", "async*", "enum",
+ "is", "throw", "await", "export", "library", "true",
+ "break", "external", "new", "try", "case", "extends",
+ "null", "typedef", "catch", "factory", "operator", "var",
+ "class", "false", "part", "void", "const", "final",
+ "rethrow", "while", "continue", "finally", "return", "with",
+ "covariant", "for", "set", "yield", "default", "get",
+ "static", "yield*"
+};
+
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class DartGenerator : public BaseGenerator {
+ public:
+ typedef std::map<std::string, std::string> namespace_code_map;
+
+ DartGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", ".") {}
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ std::string code;
+ namespace_code_map namespace_code;
+ GenerateEnums(&namespace_code);
+ GenerateStructs(&namespace_code);
+
+ for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) {
+ code.clear();
+ code = code + "// " + FlatBuffersGeneratedWarning() + "\n";
+ code = code +
+ "// ignore_for_file: unused_import, unused_field, "
+ "unused_local_variable\n\n";
+
+ code += "library " + kv->first + ";\n\n";
+
+ code += "import 'dart:typed_data' show Uint8List;\n";
+ code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb +
+ ";\n\n";
+
+ if (parser_.opts.include_dependence_headers) {
+ GenIncludeDependencies(&code, kv->first);
+ }
+
+ for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end();
+ ++kv2) {
+ if (kv2->first != kv->first) {
+ code += "import '" +
+ GeneratedFileName("./", file_name_ + "_" + kv2->first) +
+ "' as " + ImportAliasName(kv2->first) + ";\n";
+ }
+ }
+ code += "\n";
+ code += kv->second;
+
+ if (!SaveFile(
+ GeneratedFileName(path_, file_name_ + "_" + kv->first).c_str(),
+ code, false)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ static std::string ImportAliasName(const std::string &ns) {
+ std::string ret;
+ ret.assign(ns);
+ size_t pos = ret.find('.');
+ while (pos != std::string::npos) {
+ ret.replace(pos, 1, "_");
+ pos = ret.find('.', pos + 1);
+ }
+
+ return ret;
+ }
+
+ static std::string BuildNamespaceName(const Namespace &ns) {
+ std::stringstream sstream;
+ std::copy(ns.components.begin(), ns.components.end() - 1,
+ std::ostream_iterator<std::string>(sstream, "."));
+
+ auto ret = sstream.str() + ns.components.back();
+ for (size_t i = 0; i < ret.size(); i++) {
+ auto lower = tolower(ret[i]);
+ if (lower != ret[i]) {
+ ret[i] = static_cast<char>(lower);
+ if (i != 0 && ret[i - 1] != '.') {
+ ret.insert(i, "_");
+ i++;
+ }
+ }
+ }
+ // std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
+ return ret;
+ }
+
+ void GenIncludeDependencies(std::string* code, const std::string& the_namespace) {
+ for (auto it = parser_.included_files_.begin();
+ it != parser_.included_files_.end(); ++it) {
+ if (it->second.empty()) continue;
+
+ auto noext = flatbuffers::StripExtension(it->second);
+ auto basename = flatbuffers::StripPath(noext);
+
+ *code += "import '" + GeneratedFileName("", basename + "_" + the_namespace) + "';\n";
+ }
+ }
+
+ static std::string EscapeKeyword(const std::string &name) {
+ for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+ if (name == keywords[i]) { return MakeCamel(name + "_", false); }
+ }
+
+ return MakeCamel(name, false);
+ }
+
+ void GenerateEnums(namespace_code_map *namespace_code) {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, namespace_code); // enum_code_ptr);
+ }
+ }
+
+ void GenerateStructs(namespace_code_map *namespace_code) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(struct_def, namespace_code);
+ }
+ }
+
+ // Generate a documentation comment, if available.
+ static void GenDocComment(const std::vector<std::string> &dc,
+ std::string *code_ptr,
+ const std::string &extra_lines,
+ const char *indent = nullptr) {
+ if (dc.empty() && extra_lines.empty()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ auto &code = *code_ptr;
+
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ if (indent) code += indent;
+ code += "/// " + *it + "\n";
+ }
+ if (!extra_lines.empty()) {
+ if (!dc.empty()) {
+ if (indent) code += indent;
+ code += "///\n";
+ }
+ if (indent) code += indent;
+ std::string::size_type start = 0;
+ for (;;) {
+ auto end = extra_lines.find('\n', start);
+ if (end != std::string::npos) {
+ code += "/// " + extra_lines.substr(start, end - start) + "\n";
+ start = end + 1;
+ } else {
+ code += "/// " + extra_lines.substr(start) + "\n";
+ break;
+ }
+ }
+ }
+ }
+
+ static void GenDocComment(std::string *code_ptr,
+ const std::string &extra_lines) {
+ GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
+ }
+
+ // Generate an enum declaration and an enum string lookup table.
+ void GenEnum(EnumDef &enum_def, namespace_code_map *namespace_code) {
+ if (enum_def.generated) return;
+ auto ns = BuildNamespaceName(*enum_def.defined_namespace);
+ std::string code;
+ GenDocComment(enum_def.doc_comment, &code, "");
+
+ auto name = enum_def.is_union ? enum_def.name + "TypeId" : enum_def.name;
+ auto is_bit_flags = enum_def.attributes.Lookup("bit_flags");
+
+ code += "class " + name + " {\n";
+ code += " final int value;\n";
+ code += " const " + name + "._(this.value);\n\n";
+ code += " factory " + name + ".fromValue(int value) {\n";
+ code += " if (value == null) value = 0;\n";
+
+ code += " if (!values.containsKey(value)) {\n";
+ code +=
+ " throw new StateError('Invalid value $value for bit flag enum ";
+ code += name + "');\n";
+ code += " }\n";
+
+ code += " return values[value];\n";
+ code += " }\n\n";
+
+ // this is meaningless for bit_flags
+ // however, note that unlike "regular" dart enums this enum can still have
+ // holes.
+ if (!is_bit_flags) {
+ code += " static const int minValue = " +
+ enum_def.ToString(*enum_def.MinValue()) + ";\n";
+ code += " static const int maxValue = " +
+ enum_def.ToString(*enum_def.MaxValue()) + ";\n";
+ }
+
+ code +=
+ " static bool containsValue(int value) =>"
+ " values.containsKey(value);\n\n";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+
+ if (!ev.doc_comment.empty()) {
+ if (it != enum_def.Vals().begin()) { code += '\n'; }
+ GenDocComment(ev.doc_comment, &code, "", " ");
+ }
+ code += " static const " + name + " " + ev.name + " = ";
+ code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n";
+ }
+
+ code += " static get values => {";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ code += enum_def.ToString(ev) + ": " + ev.name + ",";
+ }
+ code += "};\n\n";
+
+ code += " static const " + _kFb + ".Reader<" + name +
+ "> reader = const _" + name + "Reader();\n\n";
+ code += " @override\n";
+ code += " String toString() {\n";
+ code += " return '" + name + "{value: $value}';\n";
+ code += " }\n";
+ code += "}\n\n";
+
+ GenEnumReader(enum_def, name, &code);
+ (*namespace_code)[ns] += code;
+ }
+
+ void GenEnumReader(EnumDef &enum_def, const std::string &name,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += "class _" + name + "Reader extends " + _kFb + ".Reader<" + name +
+ "> {\n";
+ code += " const _" + name + "Reader();\n\n";
+ code += " @override\n";
+ code += " int get size => 1;\n\n";
+ code += " @override\n";
+ code +=
+ " " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n";
+ code += " new " + name + ".fromValue(const " + _kFb + "." +
+ GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n";
+ code += "}\n\n";
+ }
+
+ static std::string GenType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "Bool";
+ case BASE_TYPE_CHAR: return "Int8";
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_UCHAR: return "Uint8";
+ case BASE_TYPE_SHORT: return "Int16";
+ case BASE_TYPE_USHORT: return "Uint16";
+ case BASE_TYPE_INT: return "Int32";
+ case BASE_TYPE_UINT: return "Uint32";
+ case BASE_TYPE_LONG: return "Int64";
+ case BASE_TYPE_ULONG: return "Uint64";
+ case BASE_TYPE_FLOAT: return "Float32";
+ case BASE_TYPE_DOUBLE: return "Float64";
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION: return type.enum_def->name + "TypeId";
+ default: return "Table";
+ }
+ }
+
+ std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def,
+ bool parent_is_vector = false) {
+ if (type.base_type == BASE_TYPE_BOOL) {
+ return "const " + _kFb + ".BoolReader()";
+ } else if (type.base_type == BASE_TYPE_VECTOR) {
+ return "const " + _kFb + ".ListReader<" +
+ GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
+ GenReaderTypeName(type.VectorType(), current_namespace, def,
+ true) +
+ ")";
+ } else if (type.base_type == BASE_TYPE_STRING) {
+ return "const " + _kFb + ".StringReader()";
+ }
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def && parent_is_vector) {
+ return GenDartTypeName(type, current_namespace, def) + ".reader";
+ }
+ return "const " + _kFb + "." + GenType(type) + "Reader()";
+ } else {
+ return GenDartTypeName(type, current_namespace, def) + ".reader";
+ }
+ }
+
+ std::string GenDartTypeName(const Type &type, Namespace *current_namespace,
+ const FieldDef &def, bool addBuilder = false) {
+ if (type.enum_def) {
+ if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) {
+ return type.enum_def->name + "TypeId";
+ } else if (type.enum_def->is_union) {
+ return "dynamic";
+ } else if (type.base_type != BASE_TYPE_VECTOR) {
+ return type.enum_def->name;
+ }
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "bool";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR: return "int";
+ case BASE_TYPE_FLOAT:
+ case BASE_TYPE_DOUBLE: return "double";
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_STRUCT:
+ return MaybeWrapNamespace(
+ type.struct_def->name + (addBuilder ? "ObjectBuilder" : ""),
+ current_namespace, def);
+ case BASE_TYPE_VECTOR:
+ return "List<" +
+ GenDartTypeName(type.VectorType(), current_namespace, def,
+ addBuilder) +
+ ">";
+ default: assert(0); return "dynamic";
+ }
+ }
+
+ static const std::string MaybeWrapNamespace(const std::string &type_name,
+ Namespace *current_ns,
+ const FieldDef &field) {
+ auto curr_ns_str = BuildNamespaceName(*current_ns);
+ std::string field_ns_str = "";
+ if (field.value.type.struct_def) {
+ field_ns_str +=
+ BuildNamespaceName(*field.value.type.struct_def->defined_namespace);
+ } else if (field.value.type.enum_def) {
+ field_ns_str +=
+ BuildNamespaceName(*field.value.type.enum_def->defined_namespace);
+ }
+
+ if (field_ns_str != "" && field_ns_str != curr_ns_str) {
+ return ImportAliasName(field_ns_str) + "." + type_name;
+ } else {
+ return type_name;
+ }
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def,
+ namespace_code_map *namespace_code) {
+ if (struct_def.generated) return;
+
+ auto object_namespace = BuildNamespaceName(*struct_def.defined_namespace);
+ std::string code;
+
+ const auto &object_name = struct_def.name;
+
+ // Emit constructor
+
+ GenDocComment(struct_def.doc_comment, &code, "");
+
+ auto reader_name = "_" + object_name + "Reader";
+ auto builder_name = object_name + "Builder";
+ auto object_builder_name = object_name + "ObjectBuilder";
+
+ std::string reader_code, builder_code;
+
+ code += "class " + object_name + " {\n";
+
+ code += " " + object_name + "._(this._bc, this._bcOffset);\n";
+ if (!struct_def.fixed) {
+ code += " factory " + object_name + "(List<int> bytes) {\n";
+ code += " " + _kFb + ".BufferContext rootRef = new " + _kFb +
+ ".BufferContext.fromBytes(bytes);\n";
+ code += " return reader.read(rootRef, 0);\n";
+ code += " }\n";
+ }
+
+ code += "\n";
+ code += " static const " + _kFb + ".Reader<" + object_name +
+ "> reader = const " + reader_name + "();\n\n";
+
+ code += " final " + _kFb + ".BufferContext _bc;\n";
+ code += " final int _bcOffset;\n\n";
+
+ GenImplementationGetters(struct_def, &code);
+
+ code += "}\n\n";
+
+ GenReader(struct_def, &reader_name, &reader_code);
+ GenBuilder(struct_def, &builder_name, &builder_code);
+ GenObjectBuilder(struct_def, &object_builder_name, &builder_code);
+
+ code += reader_code;
+ code += builder_code;
+
+ (*namespace_code)[object_namespace] += code;
+ }
+
+ std::string NamespaceAliasFromUnionType(const std::string &in) {
+ if (in.find('_') == std::string::npos) { return in; }
+
+ std::stringstream ss(in);
+ std::string item;
+ std::vector<std::string> parts;
+ std::string ns;
+
+ while (std::getline(ss, item, '_')) { parts.push_back(item); }
+
+ for (auto it = parts.begin(); it != parts.end() - 1; ++it) {
+ auto &part = *it;
+
+ for (size_t i = 0; i < part.length(); i++) {
+ if (i && !isdigit(part[i]) &&
+ part[i] == static_cast<char>(toupper(part[i]))) {
+ ns += "_";
+ ns += static_cast<char>(tolower(part[i]));
+ } else {
+ ns += static_cast<char>(tolower(part[i]));
+ }
+ }
+ if (it != parts.end() - 2) { ns += "_"; }
+ }
+
+ return ns + "." + parts.back();
+ }
+
+ void GenImplementationGetters(const StructDef &struct_def,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ std::string field_name = MakeCamel(field.name, false);
+ std::string type_name = GenDartTypeName(
+ field.value.type, struct_def.defined_namespace, field, false);
+
+ GenDocComment(field.doc_comment, &code, "", " ");
+
+ code += " " + type_name + " get " + field_name;
+ if (field.value.type.base_type == BASE_TYPE_UNION) {
+ code += " {\n";
+ code += " switch (" + field_name + "Type?.value) {\n";
+ auto &enum_def = *field.value.type.enum_def;
+ for (auto en_it = enum_def.Vals().begin() + 1;
+ en_it != enum_def.Vals().end(); ++en_it) {
+ auto &ev = **en_it;
+
+ auto enum_name = NamespaceAliasFromUnionType(ev.name);
+ code += " case " + enum_def.ToString(ev) + ": return " +
+ enum_name + ".reader.vTableGet(_bc, _bcOffset, " +
+ NumToString(field.value.offset) + ", null);\n";
+ }
+ code += " default: return null;\n";
+ code += " }\n";
+ code += " }\n";
+ } else {
+ code += " => ";
+ if (field.value.type.enum_def &&
+ field.value.type.base_type != BASE_TYPE_VECTOR) {
+ code += "new " +
+ GenDartTypeName(field.value.type,
+ struct_def.defined_namespace, field) +
+ ".fromValue(";
+ }
+
+ code += GenReaderTypeName(field.value.type,
+ struct_def.defined_namespace, field);
+ if (struct_def.fixed) {
+ code +=
+ ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")";
+ } else {
+ code += ".vTableGet(_bc, _bcOffset, " +
+ NumToString(field.value.offset) + ", ";
+ if (!field.value.constant.empty() && field.value.constant != "0") {
+ if (IsBool(field.value.type.base_type)) {
+ code += "true";
+ } else {
+ code += field.value.constant;
+ }
+ } else {
+ if (IsBool(field.value.type.base_type)) {
+ code += "false";
+ } else if (IsScalar(field.value.type.base_type)) {
+ code += "0";
+ } else {
+ code += "null";
+ }
+ }
+ code += ")";
+ }
+ if (field.value.type.enum_def &&
+ field.value.type.base_type != BASE_TYPE_VECTOR) {
+ code += ")";
+ }
+ code += ";\n";
+ }
+ }
+
+ code += "\n";
+
+ code += " @override\n";
+ code += " String toString() {\n";
+ code += " return '" + struct_def.name + "{";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code +=
+ MakeCamel(field.name, false) + ": $" + MakeCamel(field.name, false);
+ if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+ }
+ code += "}';\n";
+ code += " }\n";
+ }
+
+ void GenReader(const StructDef &struct_def, std::string *reader_name_ptr,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &reader_name = *reader_name_ptr;
+ auto &impl_name = struct_def.name;
+
+ code += "class " + reader_name + " extends " + _kFb;
+ if (struct_def.fixed) {
+ code += ".StructReader<";
+ } else {
+ code += ".TableReader<";
+ }
+ code += impl_name + "> {\n";
+ code += " const " + reader_name + "();\n\n";
+
+ if (struct_def.fixed) {
+ code += " @override\n";
+ code += " int get size => " + NumToString(struct_def.bytesize) + ";\n\n";
+ }
+ code += " @override\n";
+ code += " " + impl_name +
+ " createObject(fb.BufferContext bc, int offset) => \n new " +
+ impl_name + "._(bc, offset);\n";
+ code += "}\n\n";
+ }
+
+ void GenBuilder(const StructDef &struct_def, std::string *builder_name_ptr,
+ std::string *code_ptr) {
+ if (struct_def.fields.vec.size() == 0) { return; }
+ auto &code = *code_ptr;
+ auto &builder_name = *builder_name_ptr;
+
+ code += "class " + builder_name + " {\n";
+ code += " " + builder_name + "(this.fbBuilder) {\n";
+ code += " assert(fbBuilder != null);\n";
+ code += " }\n\n";
+ code += " final " + _kFb + ".Builder fbBuilder;\n\n";
+
+ if (struct_def.fixed) {
+ StructBuilderBody(struct_def, code_ptr);
+ } else {
+ TableBuilderBody(struct_def, code_ptr);
+ }
+
+ code += "}\n\n";
+ }
+
+ void StructBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += " int finish(";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ if (IsStruct(field.value.type)) {
+ code += "fb.StructBuilder";
+ } else {
+ code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field);
+ }
+ code += " " + field.name;
+ if (it != struct_def.fields.vec.end() - 1) { code += ", "; }
+ }
+ code += ") {\n";
+
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+
+ if (field.padding) {
+ code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+ }
+
+ if (IsStruct(field.value.type)) {
+ code += " " + field.name + "();\n";
+ } else {
+ code += " fbBuilder.put" + GenType(field.value.type) + "(";
+ code += field.name;
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ }
+ }
+ code += " return fbBuilder.offset;\n";
+ code += " }\n\n";
+ }
+
+ void TableBuilderBody(const StructDef &struct_def, std::string *code_ptr) {
+ auto &code = *code_ptr;
+
+ code += " void begin() {\n";
+ code += " fbBuilder.startTable();\n";
+ code += " }\n\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+
+ if (IsScalar(field.value.type.base_type)) {
+ code += " int add" + MakeCamel(field.name) + "(";
+ code += GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field);
+ code += " " + MakeCamel(field.name, false) + ") {\n";
+ code += " fbBuilder.add" + GenType(field.value.type) + "(" +
+ NumToString(offset) + ", ";
+ code += MakeCamel(field.name, false);
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ } else if (IsStruct(field.value.type)) {
+ code += " int add" + MakeCamel(field.name) + "(int offset) {\n";
+ code +=
+ " fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n";
+ } else {
+ code += " int add" + MakeCamel(field.name) + "Offset(int offset) {\n";
+ code +=
+ " fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n";
+ }
+ code += " return fbBuilder.offset;\n";
+ code += " }\n";
+ }
+
+ code += "\n";
+ code += " int finish() {\n";
+ code += " return fbBuilder.endTable();\n";
+ code += " }\n";
+ }
+
+ void GenObjectBuilder(const StructDef &struct_def,
+ std::string *builder_name_ptr, std::string *code_ptr) {
+ auto &code = *code_ptr;
+ auto &builder_name = *builder_name_ptr;
+
+ code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += " final " +
+ GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field, true) +
+ " _" + MakeCamel(field.name, false) + ";\n";
+ }
+ code += "\n";
+ code += " " + builder_name + "(";
+ if (struct_def.fields.vec.size() != 0) {
+ code +=
+
+ "{\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += " " +
+ GenDartTypeName(field.value.type, struct_def.defined_namespace,
+ field, true) +
+ " " + MakeCamel(field.name, false) + ",\n";
+ }
+ code += " })\n";
+ code += " : ";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += "_" + MakeCamel(field.name, false) + " = " +
+ MakeCamel(field.name, false);
+ if (it == struct_def.fields.vec.end() - 1) {
+ code += ";\n\n";
+ } else {
+ code += ",\n ";
+ }
+ }
+ } else {
+ code += ");\n\n";
+ }
+
+ code += " /// Finish building, and store into the [fbBuilder].\n";
+ code += " @override\n";
+ code += " int finish(\n";
+ code += " " + _kFb + ".Builder fbBuilder) {\n";
+ code += " assert(fbBuilder != null);\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type))
+ continue;
+
+ code += " final int " + MakeCamel(field.name, false) + "Offset";
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code +=
+ " = _" + MakeCamel(field.name, false) + "?.isNotEmpty == true\n";
+ code += " ? fbBuilder.writeList";
+ switch (field.value.type.VectorType().base_type) {
+ case BASE_TYPE_STRING:
+ code += "(_" + MakeCamel(field.name, false) +
+ ".map((b) => fbBuilder.writeString(b)).toList())";
+ break;
+ case BASE_TYPE_STRUCT:
+ if (field.value.type.struct_def->fixed) {
+ code += "OfStructs(_" + MakeCamel(field.name, false) + ")";
+ } else {
+ code += "(_" + MakeCamel(field.name, false) +
+ ".map((b) => b.getOrCreateOffset(fbBuilder)).toList())";
+ }
+ break;
+ default:
+ code += GenType(field.value.type.VectorType()) + "(_" +
+ MakeCamel(field.name, false);
+ if (field.value.type.enum_def) { code += ".map((f) => f.value)"; }
+ code += ")";
+ }
+ code += "\n : null;\n";
+ } else if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) + ");\n";
+ } else {
+ code += " = _" + MakeCamel(field.name, false) +
+ "?.getOrCreateOffset(fbBuilder);\n";
+ }
+ }
+
+ code += "\n";
+ if (struct_def.fixed) {
+ StructObjectBuilderBody(struct_def, code_ptr);
+ } else {
+ TableObjectBuilderBody(struct_def, code_ptr);
+ }
+ code += " }\n\n";
+
+ code += " /// Convenience method to serialize to byte list.\n";
+ code += " @override\n";
+ code += " Uint8List toBytes([String fileIdentifier]) {\n";
+ code += " " + _kFb + ".Builder fbBuilder = new ";
+ code += _kFb + ".Builder();\n";
+ code += " int offset = finish(fbBuilder);\n";
+ code += " return fbBuilder.finish(offset, fileIdentifier);\n";
+ code += " }\n";
+ code += "}\n";
+ }
+
+ void StructObjectBuilderBody(const StructDef &struct_def,
+ std::string *code_ptr,
+ bool prependUnderscore = true) {
+ auto &code = *code_ptr;
+
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+
+ if (field.padding) {
+ code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n";
+ }
+
+ if (IsStruct(field.value.type)) {
+ code += " ";
+ if (prependUnderscore) { code += "_"; }
+ code += field.name + ".finish(fbBuilder);\n";
+ } else {
+ code += " fbBuilder.put" + GenType(field.value.type) + "(";
+ if (prependUnderscore) { code += "_"; }
+ code += field.name;
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ }
+ }
+
+ code += " return fbBuilder.offset;\n";
+ }
+
+ void TableObjectBuilderBody(const StructDef &struct_def,
+ std::string *code_ptr,
+ bool prependUnderscore = true) {
+ std::string &code = *code_ptr;
+ code += " fbBuilder.startTable();\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ if (IsScalar(field.value.type.base_type)) {
+ code += " fbBuilder.add" + GenType(field.value.type) + "(" +
+ NumToString(offset) + ", ";
+ if (prependUnderscore) { code += "_"; }
+ code += MakeCamel(field.name, false);
+ if (field.value.type.enum_def) { code += "?.value"; }
+ code += ");\n";
+ } else if (IsStruct(field.value.type)) {
+ code += " if (";
+ if (prependUnderscore) { code += "_"; }
+ code += MakeCamel(field.name, false) + " != null) {\n";
+ code += " fbBuilder.addStruct(" + NumToString(offset) + ", ";
+ code += "_" + MakeCamel(field.name, false) + ".finish(fbBuilder));\n";
+ code += " }\n";
+ } else {
+ code +=
+ " if (" + MakeCamel(field.name, false) + "Offset != null) {\n";
+ code += " fbBuilder.addOffset(" + NumToString(offset) + ", " +
+ MakeCamel(field.name, false) + "Offset);\n";
+ code += " }\n";
+ }
+ }
+ code += " return fbBuilder.endTable();\n";
+ }
+};
+} // namespace dart
+
+bool GenerateDart(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ dart::DartGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string DartMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ assert(parser.opts.lang <= IDLOptions::kMAX);
+
+ auto filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ auto make_rule = GeneratedFileName(path, filebase) + ": ";
+
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp
new file mode 100644
index 0000000..e5f3723
--- /dev/null
+++ b/src/idl_gen_fbs.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GenType(const Type &type, bool underlying = false) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRUCT:
+ return type.struct_def->defined_namespace->GetFullyQualifiedName(
+ type.struct_def->name);
+ case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]";
+ default:
+ if (type.enum_def && !underlying) {
+ return type.enum_def->defined_namespace->GetFullyQualifiedName(
+ type.enum_def->name);
+ } else {
+ return kTypeNames[type.base_type];
+ }
+ }
+}
+
+static void GenNameSpace(const Namespace &name_space, std::string *_schema,
+ const Namespace **last_namespace) {
+ if (*last_namespace == &name_space) return;
+ *last_namespace = &name_space;
+ auto &schema = *_schema;
+ schema += "namespace ";
+ for (auto it = name_space.components.begin();
+ it != name_space.components.end(); ++it) {
+ if (it != name_space.components.begin()) schema += ".";
+ schema += *it;
+ }
+ schema += ";\n\n";
+}
+
+// Generate a flatbuffer schema from the Parser's internal representation.
+std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
+ // Proto namespaces may clash with table names, escape the ones that were
+ // generated from a table:
+ for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
+ ++it) {
+ auto &ns = **it;
+ for (size_t i = 0; i < ns.from_table; i++) {
+ ns.components[ns.components.size() - 1 - i] += "_";
+ }
+ }
+
+ std::string schema;
+ schema += "// Generated from " + file_name + ".proto\n\n";
+ if (parser.opts.include_dependence_headers) {
+ // clang-format off
+ #ifdef FBS_GEN_INCLUDES // TODO: currently all in one file.
+ int num_includes = 0;
+ for (auto it = parser.included_files_.begin();
+ it != parser.included_files_.end(); ++it) {
+ if (it->second.empty())
+ continue;
+ auto basename = flatbuffers::StripPath(
+ flatbuffers::StripExtension(it->second));
+ schema += "include \"" + basename + ".fbs\";\n";
+ num_includes++;
+ }
+ if (num_includes) schema += "\n";
+ #endif
+ // clang-format on
+ }
+ // Generate code for all the enum declarations.
+ const Namespace *last_namespace = nullptr;
+ for (auto enum_def_it = parser.enums_.vec.begin();
+ enum_def_it != parser.enums_.vec.end(); ++enum_def_it) {
+ EnumDef &enum_def = **enum_def_it;
+ GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
+ GenComment(enum_def.doc_comment, &schema, nullptr);
+ if (enum_def.is_union)
+ schema += "union " + enum_def.name;
+ else
+ schema += "enum " + enum_def.name + " : ";
+ schema += GenType(enum_def.underlying_type, true) + " {\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, &schema, nullptr, " ");
+ if (enum_def.is_union)
+ schema += " " + GenType(ev.union_type) + ",\n";
+ else
+ schema += " " + ev.name + " = " + enum_def.ToString(ev) + ",\n";
+ }
+ schema += "}\n\n";
+ }
+ // Generate code for all structs/tables.
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ ++it) {
+ StructDef &struct_def = **it;
+ GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace);
+ GenComment(struct_def.doc_comment, &schema, nullptr);
+ schema += "table " + struct_def.name + " {\n";
+ for (auto field_it = struct_def.fields.vec.begin();
+ field_it != struct_def.fields.vec.end(); ++field_it) {
+ auto &field = **field_it;
+ if (field.value.type.base_type != BASE_TYPE_UTYPE) {
+ GenComment(field.doc_comment, &schema, nullptr, " ");
+ schema += " " + field.name + ":" + GenType(field.value.type);
+ if (field.value.constant != "0") schema += " = " + field.value.constant;
+ if (field.required) schema += " (required)";
+ schema += ";\n";
+ }
+ }
+ schema += "}\n\n";
+ }
+ return schema;
+}
+
+bool GenerateFBS(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ return SaveFile((path + file_name + ".fbs").c_str(),
+ GenerateFBS(parser, file_name), false);
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
new file mode 100644
index 0000000..8dca792
--- /dev/null
+++ b/src/idl_gen_general.cpp
@@ -0,0 +1,1667 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#if defined(FLATBUFFERS_CPP98_STL)
+# include <cctype>
+#endif // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+
+// These arrays need to correspond to the IDLOptions::k enum.
+
+struct LanguageParameters {
+ IDLOptions::Language language;
+ // Whether function names in the language typically start with uppercase.
+ bool first_camel_upper;
+ std::string file_extension;
+ std::string string_type;
+ std::string bool_type;
+ std::string open_curly;
+ std::string accessor_type;
+ std::string const_decl;
+ std::string unsubclassable_decl;
+ std::string enum_decl;
+ std::string enum_separator;
+ std::string getter_prefix;
+ std::string getter_suffix;
+ std::string inheritance_marker;
+ std::string namespace_ident;
+ std::string namespace_begin;
+ std::string namespace_end;
+ std::string set_bb_byteorder;
+ std::string get_bb_position;
+ std::string get_fbb_offset;
+ std::string accessor_prefix;
+ std::string accessor_prefix_static;
+ std::string optional_suffix;
+ std::string includes;
+ std::string class_annotation;
+ std::string generated_type_annotation;
+ CommentConfig comment_config;
+ const FloatConstantGenerator *float_gen;
+};
+
+const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
+ static TypedFloatConstantGenerator CSharpFloatGen(
+ "Double.", "Single.", "NaN", "PositiveInfinity", "NegativeInfinity");
+
+ static TypedFloatConstantGenerator JavaFloatGen(
+ "Double.", "Float.", "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY");
+
+ static const LanguageParameters language_parameters[] = {
+ {
+ IDLOptions::kJava,
+ false,
+ ".java",
+ "String",
+ "boolean ",
+ " {\n",
+ "class ",
+ " final ",
+ "final ",
+ "final class ",
+ ";\n",
+ "()",
+ "",
+ " extends ",
+ "package ",
+ ";",
+ "",
+ "_bb.order(ByteOrder.LITTLE_ENDIAN); ",
+ "position()",
+ "offset()",
+ "",
+ "",
+ "",
+ "import java.nio.*;\nimport java.lang.*;\nimport "
+ "java.util.*;\nimport com.google.flatbuffers.*;\n",
+ "\n@SuppressWarnings(\"unused\")\n",
+ "\n@javax.annotation.Generated(value=\"flatc\")\n",
+ {
+ "/**",
+ " *",
+ " */",
+ },
+ &JavaFloatGen
+ },
+ {
+ IDLOptions::kCSharp,
+ true,
+ ".cs",
+ "string",
+ "bool ",
+ "\n{\n",
+ "struct ",
+ " readonly ",
+ "",
+ "enum ",
+ ",\n",
+ " { get",
+ "} ",
+ " : ",
+ "namespace ",
+ "\n{",
+ "\n}\n",
+ "",
+ "Position",
+ "Offset",
+ "__p.",
+ "Table.",
+ "?",
+ "using global::System;\nusing global::FlatBuffers;\n\n",
+ "",
+ "",
+ {
+ nullptr,
+ "///",
+ nullptr,
+ },
+ &CSharpFloatGen
+ },
+ };
+
+ if (lang == IDLOptions::kJava) {
+ return language_parameters[0];
+ } else {
+ FLATBUFFERS_ASSERT(lang == IDLOptions::kCSharp);
+ return language_parameters[1];
+ }
+}
+
+namespace general {
+class GeneralGenerator : public BaseGenerator {
+ public:
+ GeneralGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "."),
+ lang_(GetLangParams(parser_.opts.lang)),
+ cur_name_space_(nullptr) {}
+
+ GeneralGenerator &operator=(const GeneralGenerator &);
+ bool generate() {
+ std::string one_file_code;
+ cur_name_space_ = parser_.current_namespace_;
+
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ std::string enumcode;
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, &enumcode);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
+ false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ std::string declcode;
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, &declcode);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
+ true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ true);
+ }
+ return true;
+ }
+
+ // Save out the generated code for a single class while adding
+ // declaration boilerplate.
+ bool SaveType(const std::string &defname, const Namespace &ns,
+ const std::string &classcode, bool needs_includes) const {
+ if (!classcode.length()) return true;
+
+ std::string code;
+ if (lang_.language == IDLOptions::kCSharp) {
+ code =
+ "// <auto-generated>\n"
+ "// " +
+ std::string(FlatBuffersGeneratedWarning()) +
+ "\n"
+ "// </auto-generated>\n\n";
+ } else {
+ code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+ }
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
+ code += "\n\n";
+ }
+ if (needs_includes) {
+ code += lang_.includes;
+ if (parser_.opts.gen_nullable) {
+ code += "\nimport javax.annotation.Nullable;\n";
+ }
+ code += lang_.class_annotation;
+ }
+ if (parser_.opts.gen_generated) {
+ code += lang_.generated_type_annotation;
+ }
+ code += classcode;
+ if (!namespace_name.empty()) code += lang_.namespace_end;
+ auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ std::string FunctionStart(char upper) const {
+ return std::string() + (lang_.language == IDLOptions::kJava
+ ? static_cast<char>(tolower(upper))
+ : upper);
+ }
+
+ std::string GenNullableAnnotation(const Type &t) const {
+ return lang_.language == IDLOptions::kJava && parser_.opts.gen_nullable &&
+ !IsScalar(DestinationType(t, true).base_type)
+ ? " @Nullable "
+ : "";
+ }
+
+ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const {
+ // clang-format off
+ static const char * const java_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #JTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+
+ static const char * const csharp_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ // clang-format on
+
+ if (enableLangOverrides) {
+ if (lang_.language == IDLOptions::kCSharp) {
+ if (IsEnum(type)) return WrapInNameSpace(*type.enum_def);
+ if (type.base_type == BASE_TYPE_STRUCT) {
+ return "Offset<" + WrapInNameSpace(*type.struct_def) + ">";
+ }
+ }
+ }
+
+ if (lang_.language == IDLOptions::kJava) {
+ return java_typename[type.base_type];
+ } else {
+ FLATBUFFERS_ASSERT(lang_.language == IDLOptions::kCSharp);
+ return csharp_typename[type.base_type];
+ }
+ }
+
+ std::string GenTypeBasic(const Type &type) const {
+ return GenTypeBasic(type, true);
+ }
+
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return lang_.string_type;
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
+ case BASE_TYPE_UNION:
+ // Unions in C# use a generic Table-derived type for better type safety
+ if (lang_.language == IDLOptions::kCSharp) return "TTable";
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return "Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type)
+ ? GenTypeBasic(type)
+ : (IsArray(type) ? GenTypeGet(type.VectorType())
+ : GenTypePointer(type));
+ }
+
+ // Find the destination type the user wants to receive the value in (e.g.
+ // one size higher signed types for unsigned serialized values in Java).
+ Type DestinationType(const Type &type, bool vectorelem) const {
+ if (lang_.language != IDLOptions::kJava) return type;
+ switch (type.base_type) {
+ // We use int for both uchar/ushort, since that generally means less
+ // casting than using short for uchar.
+ case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
+ case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
+ case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
+ case BASE_TYPE_ARRAY:
+ case BASE_TYPE_VECTOR:
+ if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return type;
+ }
+ }
+
+ std::string GenOffsetType(const StructDef &struct_def) const {
+ if (lang_.language == IDLOptions::kCSharp) {
+ return "Offset<" + WrapInNameSpace(struct_def) + ">";
+ } else {
+ return "int";
+ }
+ }
+
+ std::string GenOffsetConstruct(const StructDef &struct_def,
+ const std::string &variable_name) const {
+ if (lang_.language == IDLOptions::kCSharp) {
+ return "new Offset<" + WrapInNameSpace(struct_def) + ">(" +
+ variable_name + ")";
+ }
+ return variable_name;
+ }
+
+ std::string GenVectorOffsetType() const {
+ if (lang_.language == IDLOptions::kCSharp) {
+ return "VectorOffset";
+ } else {
+ return "int";
+ }
+ }
+
+ // Generate destination type name
+ std::string GenTypeNameDest(const Type &type) const {
+ return GenTypeGet(DestinationType(type, true));
+ }
+
+ // Mask to turn serialized value into destination type value.
+ std::string DestinationMask(const Type &type, bool vectorelem) const {
+ if (lang_.language != IDLOptions::kJava) return "";
+ switch (type.base_type) {
+ case BASE_TYPE_UCHAR: return " & 0xFF";
+ case BASE_TYPE_USHORT: return " & 0xFFFF";
+ case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
+ case BASE_TYPE_VECTOR:
+ if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default: return "";
+ }
+ }
+
+ // Casts necessary to correctly read serialized data
+ std::string DestinationCast(const Type &type) const {
+ if (IsSeries(type)) {
+ return DestinationCast(type.VectorType());
+ } else {
+ switch (lang_.language) {
+ case IDLOptions::kJava:
+ // Cast necessary to correctly read serialized unsigned values.
+ if (type.base_type == BASE_TYPE_UINT) return "(long)";
+ break;
+
+ case IDLOptions::kCSharp:
+ // Cast from raw integral types to enum.
+ if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")";
+ break;
+
+ default: break;
+ }
+ }
+ return "";
+ }
+
+ // Cast statements for mutator method parameters.
+ // In Java, parameters representing unsigned numbers need to be cast down to
+ // their respective type. For example, a long holding an unsigned int value
+ // would be cast down to int before being put onto the buffer. In C#, one cast
+ // directly cast an Enum to its underlying type, which is essential before
+ // putting it onto the buffer.
+ std::string SourceCast(const Type &type, bool castFromDest) const {
+ if (IsSeries(type)) {
+ return SourceCast(type.VectorType(), castFromDest);
+ } else {
+ switch (lang_.language) {
+ case IDLOptions::kJava:
+ if (castFromDest) {
+ if (type.base_type == BASE_TYPE_UINT)
+ return "(int)";
+ else if (type.base_type == BASE_TYPE_USHORT)
+ return "(short)";
+ else if (type.base_type == BASE_TYPE_UCHAR)
+ return "(byte)";
+ }
+ break;
+ case IDLOptions::kCSharp:
+ if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")";
+ break;
+ default: break;
+ }
+ }
+ return "";
+ }
+
+ std::string SourceCast(const Type &type) const { return SourceCast(type, true); }
+
+ std::string SourceCastBasic(const Type &type, bool castFromDest) const {
+ return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
+ }
+
+ std::string SourceCastBasic(const Type &type) const {
+ return SourceCastBasic(type, true);
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+ std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const {
+ auto& value = field.value;
+ if (enableLangOverrides) {
+ // handles both enum case and vector of enum case
+ if (lang_.language == IDLOptions::kCSharp &&
+ value.type.enum_def != nullptr &&
+ value.type.base_type != BASE_TYPE_UNION) {
+ return GenEnumDefaultValue(field);
+ }
+ }
+
+ auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+ case BASE_TYPE_ULONG: {
+ if (lang_.language != IDLOptions::kJava) return value.constant;
+ // Converts the ulong into its bits signed equivalent
+ uint64_t defaultValue = StringToUInt(value.constant.c_str());
+ return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
+ }
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG: return value.constant + longSuffix;
+ default:
+ if(IsFloat(value.type.base_type))
+ return lang_.float_gen->GenFloatConstant(field);
+ else
+ return value.constant;
+ }
+ }
+
+ std::string GenDefaultValue(const FieldDef &field) const {
+ return GenDefaultValue(field, true);
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field,
+ bool enableLangOverrides) const {
+ auto& value = field.value;
+ if (!IsScalar(value.type.base_type)) {
+ if (enableLangOverrides) {
+ if (lang_.language == IDLOptions::kCSharp) {
+ switch (value.type.base_type) {
+ case BASE_TYPE_STRING: return "default(StringOffset)";
+ case BASE_TYPE_STRUCT:
+ return "default(Offset<" +
+ WrapInNameSpace(*value.type.struct_def) + ">)";
+ case BASE_TYPE_VECTOR: return "default(VectorOffset)";
+ default: break;
+ }
+ }
+ }
+ return "0";
+ }
+ return GenDefaultValue(field, enableLangOverrides);
+ }
+
+ std::string GenDefaultValueBasic(const FieldDef &field) const {
+ return GenDefaultValueBasic(field, true);
+ }
+
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
+ std::string &code = *code_ptr;
+ if (enum_def.generated) return;
+
+ // Generate enum definitions of the form:
+ // public static (final) int name = value;
+ // In Java, we use ints rather than the Enum feature, because we want them
+ // to map directly to how they're used in C/C++ and file formats.
+ // That, and Java Enums are expensive, and not universally liked.
+ GenComment(enum_def.doc_comment, code_ptr, &lang_.comment_config);
+
+ // In C# this indicates enumeration values can be treated as bit flags.
+ if (lang_.language == IDLOptions::kCSharp && enum_def.attributes.Lookup("bit_flags")) {
+ code += "[System.FlagsAttribute]\n";
+ }
+ if (enum_def.attributes.Lookup("private")) {
+ // For Java, we leave the enum unmarked to indicate package-private
+ // For C# we mark the enum as internal
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += "internal ";
+ }
+ } else {
+ code += "public ";
+ }
+ code += lang_.enum_decl + enum_def.name;
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += lang_.inheritance_marker +
+ GenTypeBasic(enum_def.underlying_type, false);
+ }
+ code += lang_.open_curly;
+ if (lang_.language == IDLOptions::kJava) {
+ code += " private " + enum_def.name + "() { }\n";
+ }
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, &lang_.comment_config, " ");
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += " public static";
+ code += lang_.const_decl;
+ code += GenTypeBasic(enum_def.underlying_type, false);
+ }
+ code += (lang_.language == IDLOptions::kJava) ? " " : " ";
+ code += ev.name + " = ";
+ code += enum_def.ToString(ev);
+ code += lang_.enum_separator;
+ }
+
+ // Generate a generate string table for enum values.
+ // We do not do that for C# where this functionality is native.
+ if (lang_.language != IDLOptions::kCSharp) {
+ // Problem is, if values are very sparse that could generate really big
+ // tables. Ideally in that case we generate a map lookup instead, but for
+ // the moment we simply don't output a table at all.
+ auto range = enum_def.Distance();
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const uint64_t kMaxSparseness = 5;
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ code += "\n public static";
+ code += lang_.const_decl;
+ code += lang_.string_type;
+ code += "[] names = { ";
+ auto val = enum_def.Vals().front();
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+ code += "\"\", ";
+ val = ev;
+ code += "\"" + (*it)->name + "\", ";
+ }
+ code += "};\n\n";
+ code += " public static ";
+ code += lang_.string_type;
+ code += " " + MakeCamel("name", lang_.first_camel_upper);
+ code += "(int e) { return names[e";
+ if (enum_def.MinValue()->IsNonZero())
+ code += " - " + enum_def.MinValue()->name;
+ code += "]; }\n";
+ }
+ }
+
+ // Close the class
+ code += "}";
+ // Java does not need the closing semi-colon on class definitions.
+ code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+ code += "\n\n";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return lang_.accessor_prefix + "__string";
+ case BASE_TYPE_STRUCT: return lang_.accessor_prefix + "__struct";
+ case BASE_TYPE_UNION: return lang_.accessor_prefix + "__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
+ default: {
+ std::string getter =
+ lang_.accessor_prefix + "bb." + FunctionStart('G') + "et";
+ if (type.base_type == BASE_TYPE_BOOL) {
+ getter = "0!=" + getter;
+ } else if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
+ }
+ return getter;
+ }
+ }
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &data_buffer,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ auto dest_mask = DestinationMask(type, true);
+ auto dest_cast = DestinationCast(type);
+ auto getter = data_buffer + "." + FunctionStart('G') + "et";
+ if (GenTypeBasic(type, false) != "byte") {
+ getter += MakeCamel(GenTypeBasic(type, false));
+ }
+ getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
+ dest_mask;
+ return getter;
+ }
+
+ // Direct mutation is only allowed for scalar fields.
+ // Hence a setter method will only be generated for such fields.
+ std::string GenSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ std::string setter =
+ lang_.accessor_prefix + "bb." + FunctionStart('P') + "ut";
+ if (GenTypeBasic(type, false) != "byte" &&
+ type.base_type != BASE_TYPE_BOOL) {
+ setter += MakeCamel(GenTypeBasic(type, false));
+ }
+ return setter;
+ } else {
+ return "";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const Type &type) const {
+ return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false))
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t array_count = 0) const {
+ std::string &code = *code_ptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ const auto array_field = IsArray(field_type);
+ const auto &type = array_field ? field_type.VectorType()
+ : DestinationType(field_type, false);
+ const auto array_cnt = array_field ? (array_count + 1) : array_count;
+ if (IsStruct(type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructArgs(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), array_cnt);
+ } else {
+ code += ", ";
+ code += GenTypeBasic(type);
+ if (lang_.language == IDLOptions::kJava) {
+ for (size_t i = 0; i < array_cnt; i++) code += "[]";
+ } else if (lang_.language == IDLOptions::kCSharp) {
+ if (array_cnt > 0) {
+ code += "[";
+ for (size_t i = 1; i < array_cnt; i++) code += ",";
+ code += "]";
+ }
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ code += " ";
+ code += nameprefix;
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
+ const char *nameprefix, size_t index = 0,
+ bool in_array = false) const {
+ std::string &code = *code_ptr;
+ std::string indent((index + 1) * 2, ' ');
+ code += indent + " builder." + FunctionStart('P') + "rep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ if (field.padding) {
+ code += indent + " builder." + FunctionStart('P') + "ad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field_type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index,
+ in_array);
+ } else {
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for (int " + index_var + " = ";
+ code += NumToString(field_type.fixed_length);
+ code += "; " + index_var + " > 0; " + index_var + "--) {\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ GenStructBody(*field_type.struct_def, code_ptr,
+ (nameprefix + (field.name + "_")).c_str(), index + 1,
+ in_array);
+ } else {
+ code += IsArray(field_type) ? " " : "";
+ code += indent + " builder." + FunctionStart('P') + "ut";
+ code += GenMethod(type) + "(";
+ code += SourceCast(type);
+ auto argname =
+ nameprefix + MakeCamel(field.name, lang_.first_camel_upper);
+ code += argname;
+ size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+ if (lang_.language == IDLOptions::kJava) {
+ for (size_t i = 0; in_array && i < array_cnt; i++) {
+ code += "[_idx" + NumToString(i) + "-1]";
+ }
+ } else if (lang_.language == IDLOptions::kCSharp) {
+ if (array_cnt > 0) {
+ code += "[";
+ for (size_t i = 0; in_array && i < array_cnt; i++) {
+ code += "_idx" + NumToString(i) + "-1";
+ if (i != (array_cnt - 1)) code += ",";
+ }
+ code += "]";
+ }
+ } else {
+ FLATBUFFERS_ASSERT(0);
+ }
+ code += ");\n";
+ }
+ if (IsArray(field_type)) { code += indent + " }\n"; }
+ }
+ }
+ }
+
+ std::string GenByteBufferLength(const char *bb_name) const {
+ std::string bb_len = bb_name;
+ if (lang_.language == IDLOptions::kCSharp)
+ bb_len += ".Length";
+ else
+ bb_len += ".capacity()";
+ return bb_len;
+ }
+
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset = "";
+ key_offset += lang_.accessor_prefix_static + "__offset(" +
+ NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset +=
+ (lang_.language == IDLOptions::kCSharp ? ".Value, builder.DataBuffer)"
+ : ", _bb)");
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = " ";
+ key_getter += "int tableOffset = " + lang_.accessor_prefix_static;
+ key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
+ key_getter += ", bb);\n ";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ key_getter += "int comp = " + lang_.accessor_prefix_static;
+ key_getter += FunctionStart('C') + "ompareStrings(";
+ key_getter += GenOffsetGetter(key_field);
+ key_getter += ", byteKey, bb);\n";
+ } else {
+ auto get_val = GenGetterForLookupByKey(key_field, "bb");
+ if (lang_.language == IDLOptions::kCSharp) {
+ key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
+ } else {
+ key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
+ key_getter += get_val + ";\n";
+ key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
+ }
+ }
+ return key_getter;
+ }
+
+ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
+ std::string key_getter = "";
+ auto data_buffer =
+ (lang_.language == IDLOptions::kCSharp) ? "builder.DataBuffer" : "_bb";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ if (lang_.language == IDLOptions::kJava) key_getter += " return ";
+ key_getter += lang_.accessor_prefix_static;
+ key_getter += FunctionStart('C') + "ompareStrings(";
+ key_getter += GenOffsetGetter(key_field, "o1") + ", ";
+ key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
+ if (lang_.language == IDLOptions::kJava) key_getter += ";";
+ } else {
+ auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
+ if (lang_.language == IDLOptions::kCSharp) {
+ key_getter += field_getter;
+ field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+ key_getter += ".CompareTo(" + field_getter + ")";
+ } else {
+ key_getter +=
+ "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
+ key_getter +=
+ field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
+ key_getter += " val_2 = ";
+ field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
+ key_getter += field_getter + ";\n";
+ key_getter +=
+ " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
+ }
+ }
+ return key_getter;
+ }
+
+ void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+
+ // Generate a struct accessor class, with methods of the form:
+ // public type name() { return bb.getType(i + offset); }
+ // or for tables of the form:
+ // public type name() {
+ // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
+ // }
+ GenComment(struct_def.doc_comment, code_ptr, &lang_.comment_config);
+ if (struct_def.attributes.Lookup("private")) {
+ // For Java, we leave the struct unmarked to indicate package-private
+ // For C# we mark the struct as internal
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += "internal ";
+ }
+ } else {
+ code += "public ";
+ }
+ if (lang_.language == IDLOptions::kCSharp &&
+ struct_def.attributes.Lookup("csharp_partial")) {
+ // generate a partial class for this C# struct/table
+ code += "partial ";
+ } else {
+ code += lang_.unsubclassable_decl;
+ }
+ code += lang_.accessor_type + struct_def.name;
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += " : IFlatbufferObject";
+ code += lang_.open_curly;
+ code += " private ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += " __p;\n";
+
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n";
+ }
+
+ } else {
+ code += lang_.inheritance_marker;
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += lang_.open_curly;
+ }
+
+ if (!struct_def.fixed) {
+ // Generate verson check method.
+ // Force compile time error if not using the same version runtime.
+ code += " public static void ValidateVersion() {";
+ if (lang_.language == IDLOptions::kCSharp)
+ code += " FlatBufferConstants.";
+ else
+ code += " Constants.";
+ code += "FLATBUFFERS_1_11_1(); ";
+ code += "}\n";
+
+ // Generate a special accessor for the table that when used as the root
+ // of a FlatBuffer
+ std::string method_name =
+ FunctionStart('G') + "etRootAs" + struct_def.name;
+ std::string method_signature =
+ " public static " + struct_def.name + " " + method_name;
+
+ // create convenience method that doesn't require an existing object
+ code += method_signature + "(ByteBuffer _bb) ";
+ code += "{ return " + method_name + "(_bb, new " + struct_def.name +
+ "()); }\n";
+
+ // create method that allows object reuse
+ code +=
+ method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
+ code += lang_.set_bb_byteorder;
+ code += "return (obj.__assign(_bb." + FunctionStart('G') + "etInt(_bb.";
+ code += lang_.get_bb_position;
+ code += ") + _bb.";
+ code += lang_.get_bb_position;
+ code += ", _bb)); }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ if (parser_.file_identifier_.length()) {
+ // Check if a buffer has the identifier.
+ code += " public static ";
+ code += lang_.bool_type + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
+ code += lang_.accessor_prefix_static + "__has_identifier(_bb, \"";
+ code += parser_.file_identifier_;
+ code += "\"); }\n";
+ }
+ }
+ }
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code += " public void __init(int _i, ByteBuffer _bb) ";
+ code += "{ ";
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += "__p = new ";
+ code += struct_def.fixed ? "Struct" : "Table";
+ code += "(_i, _bb); ";
+ } else {
+ code += "__reset(_i, _bb); ";
+ }
+ code += "}\n";
+ code +=
+ " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
+ code += "{ __init(_i, _bb); return this; }\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenComment(field.doc_comment, code_ptr, &lang_.comment_config, " ");
+ std::string type_name = GenTypeGet(field.value.type);
+ std::string type_name_dest = GenTypeNameDest(field.value.type);
+ std::string conditional_cast = "";
+ std::string optional = "";
+ if (lang_.language == IDLOptions::kCSharp && !struct_def.fixed &&
+ (field.value.type.base_type == BASE_TYPE_STRUCT ||
+ field.value.type.base_type == BASE_TYPE_UNION ||
+ (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ (field.value.type.element == BASE_TYPE_STRUCT ||
+ field.value.type.element == BASE_TYPE_UNION)))) {
+ optional = lang_.optional_suffix;
+ conditional_cast = "(" + type_name_dest + optional + ")";
+ }
+ std::string dest_mask = DestinationMask(field.value.type, true);
+ std::string dest_cast = DestinationCast(field.value.type);
+ std::string src_cast = SourceCast(field.value.type);
+ std::string method_start = " public " +
+ (field.required ? "" : GenNullableAnnotation(field.value.type)) +
+ type_name_dest + optional + " " +
+ MakeCamel(field.name, lang_.first_camel_upper);
+ std::string obj = lang_.language == IDLOptions::kCSharp
+ ? "(new " + type_name + "())"
+ : "obj";
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that:
+ auto offset_prefix =
+ IsArray(field.value.type)
+ ? " { return "
+ : (" { int o = " + lang_.accessor_prefix + "__offset(" +
+ NumToString(field.value.offset) + "); return o != 0 ? ");
+ // Generate the accessors that don't do object reuse.
+ if (field.value.type.base_type == BASE_TYPE_STRUCT) {
+ // Calls the accessor that takes an accessor object with a new object.
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += method_start + "() { return ";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "(new ";
+ code += type_name + "()); }\n";
+ }
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ // Accessors for vectors of structs also take accessor objects, this
+ // generates a variant without that argument.
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += method_start + "(int j) { return ";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "(new " + type_name + "(), j); }\n";
+ }
+ } else if (field.value.type.base_type == BASE_TYPE_UNION ||
+ (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ field.value.type.VectorType().base_type == BASE_TYPE_UNION)) {
+ if (lang_.language == IDLOptions::kCSharp) {
+ // Union types in C# use generic Table-derived type for better type
+ // safety.
+ method_start += "<TTable>";
+ type_name = type_name_dest;
+ }
+ }
+ std::string getter = dest_cast + GenGetter(field.value.type);
+ code += method_start;
+ std::string default_cast = "";
+ // only create default casts for c# scalars or vectors of scalars
+ if (lang_.language == IDLOptions::kCSharp &&
+ (IsScalar(field.value.type.base_type) ||
+ (field.value.type.base_type == BASE_TYPE_VECTOR &&
+ IsScalar(field.value.type.element)))) {
+ // For scalars, default value will be returned by GetDefaultValue().
+ // If the scalar is an enum, GetDefaultValue() returns an actual c# enum
+ // that doesn't need to be casted. However, default values for enum
+ // elements of vectors are integer literals ("0") and are still casted
+ // for clarity.
+ if (field.value.type.enum_def == nullptr ||
+ field.value.type.base_type == BASE_TYPE_VECTOR) {
+ default_cast = "(" + type_name_dest + ")";
+ }
+ }
+ std::string member_suffix = "; ";
+ if (IsScalar(field.value.type.base_type)) {
+ code += lang_.getter_prefix;
+ member_suffix += lang_.getter_suffix;
+ if (struct_def.fixed) {
+ code += " { return " + getter;
+ code += "(" + lang_.accessor_prefix + "bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += dest_mask;
+ } else {
+ code += offset_prefix + getter;
+ code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
+ code += " : " + default_cast;
+ code += GenDefaultValue(field);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += "(" + type_name + " obj" + ")";
+ } else {
+ code += lang_.getter_prefix;
+ member_suffix += lang_.getter_suffix;
+ }
+ if (struct_def.fixed) {
+ code += " { return " + obj + ".__assign(" + lang_.accessor_prefix;
+ code += "bb_pos + " + NumToString(field.value.offset) + ", ";
+ code += lang_.accessor_prefix + "bb)";
+ } else {
+ code += offset_prefix + conditional_cast;
+ code += obj + ".__assign(";
+ code += field.value.type.struct_def->fixed
+ ? "o + " + lang_.accessor_prefix + "bb_pos"
+ : lang_.accessor_prefix + "__indirect(o + " +
+ lang_.accessor_prefix + "bb_pos)";
+ code += ", " + lang_.accessor_prefix + "bb) : null";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += lang_.getter_prefix;
+ member_suffix += lang_.getter_suffix;
+ code += offset_prefix + getter + "(o + " + lang_.accessor_prefix;
+ code += "bb_pos) : null";
+ break;
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_UNION &&
+ lang_.language == IDLOptions::kCSharp) {
+ conditional_cast = "(TTable?)";
+ getter += "<TTable>";
+ }
+ code += "(";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ if (lang_.language != IDLOptions::kCSharp)
+ code += type_name + " obj, ";
+ getter = obj + ".__assign";
+ } else if (vectortype.base_type == BASE_TYPE_UNION) {
+ if (lang_.language != IDLOptions::kCSharp)
+ code += type_name + " obj, ";
+ }
+ code += "int j)";
+ const auto body = offset_prefix + conditional_cast + getter + "(";
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ if (lang_.language != IDLOptions::kCSharp)
+ code += body + "obj, ";
+ else
+ code += " where TTable : struct, IFlatbufferObject" + body;
+ } else {
+ code += body;
+ }
+ auto index = lang_.accessor_prefix;
+ if (IsArray(field.value.type)) {
+ index += "bb_pos + " + NumToString(field.value.offset) + " + ";
+ } else {
+ index += "__vector(o) + ";
+ }
+ index += "j * " + NumToString(InlineSize(vectortype));
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += vectortype.struct_def->fixed
+ ? index
+ : lang_.accessor_prefix + "__indirect(" + index + ")";
+ code += ", " + lang_.accessor_prefix + "bb";
+ } else if (vectortype.base_type == BASE_TYPE_UNION) {
+ code += index + " - " + lang_.accessor_prefix + "bb_pos";
+ } else {
+ code += index;
+ }
+ code += ")" + dest_mask;
+ if (!IsArray(field.value.type)) {
+ code += " : ";
+ code +=
+ field.value.type.element == BASE_TYPE_BOOL
+ ? "false"
+ : (IsScalar(field.value.type.element) ? default_cast + "0"
+ : "null");
+ }
+
+ break;
+ }
+ case BASE_TYPE_UNION:
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += "() where TTable : struct, IFlatbufferObject";
+ code += offset_prefix + "(TTable?)" + getter;
+ code += "<TTable>(o) : null";
+ } else {
+ code += "(" + type_name + " obj)" + offset_prefix + getter;
+ code += "(obj, o) : null";
+ }
+ break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += member_suffix;
+ code += "}\n";
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code +=
+ " public int " + MakeCamel(field.name, lang_.first_camel_upper);
+ code += "Length";
+ code += lang_.getter_prefix;
+ code += offset_prefix;
+ code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
+ code += lang_.getter_suffix;
+ code += "}\n";
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &key_field = **kit;
+ if (key_field.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ code += " public " + qualified_name + lang_.optional_suffix + " ";
+ code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
+ code += GenTypeNameDest(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(";
+ if (lang_.language == IDLOptions::kJava)
+ code += "null, ";
+ code += lang_.accessor_prefix + "__vector(o), key, ";
+ code += lang_.accessor_prefix + "bb) : null; ";
+ code += "}\n";
+ if (lang_.language == IDLOptions::kJava) {
+ code += " public " + qualified_name + lang_.optional_suffix + " ";
+ code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
+ code += qualified_name + lang_.optional_suffix + " obj, ";
+ code += GenTypeNameDest(key_field.value.type) + " key)";
+ code += offset_prefix;
+ code += qualified_name + ".__lookup_by_key(obj, ";
+ code += lang_.accessor_prefix + "__vector(o), key, ";
+ code += lang_.accessor_prefix + "bb) : null; ";
+ code += "}\n";
+ }
+ break;
+ }
+ }
+ }
+ }
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ field.value.type.base_type == BASE_TYPE_STRING) {
+ switch (lang_.language) {
+ case IDLOptions::kJava:
+ code += " public ByteBuffer ";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "AsByteBuffer() { return ";
+ code += lang_.accessor_prefix + "__vector_as_bytebuffer(";
+ code += NumToString(field.value.offset) + ", ";
+ code +=
+ NumToString(field.value.type.base_type == BASE_TYPE_STRING
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ code += "); }\n";
+ code += " public ByteBuffer ";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "InByteBuffer(ByteBuffer _bb) { return ";
+ code += lang_.accessor_prefix + "__vector_in_bytebuffer(_bb, ";
+ code += NumToString(field.value.offset) + ", ";
+ code +=
+ NumToString(field.value.type.base_type == BASE_TYPE_STRING
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ code += "); }\n";
+ break;
+ case IDLOptions::kCSharp:
+ code += "#if ENABLE_SPAN_T\n";
+ code += " public Span<byte> Get";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "Bytes() { return ";
+ code += lang_.accessor_prefix + "__vector_as_span(";
+ code += NumToString(field.value.offset);
+ code += "); }\n";
+ code += "#else\n";
+ code += " public ArraySegment<byte>? Get";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "Bytes() { return ";
+ code += lang_.accessor_prefix + "__vector_as_arraysegment(";
+ code += NumToString(field.value.offset);
+ code += "); }\n";
+ code += "#endif\n";
+
+ // For direct blockcopying the data into a typed array
+ code += " public ";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += "[] Get";
+ code += MakeCamel(field.name, lang_.first_camel_upper);
+ code += "Array() { return ";
+ code += lang_.accessor_prefix + "__vector_as_array<";
+ code += GenTypeBasic(field.value.type.VectorType());
+ code += ">(";
+ code += NumToString(field.value.offset);
+ code += "); }\n";
+ break;
+ default: break;
+ }
+ }
+ // generate object accessors if is nested_flatbuffer
+ if (field.nested_flatbuffer) {
+ auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_method_name =
+ MakeCamel(field.name, lang_.first_camel_upper) + "As" +
+ field.nested_flatbuffer->name;
+ auto get_nested_method_name = nested_method_name;
+ if (lang_.language == IDLOptions::kCSharp) {
+ get_nested_method_name = "Get" + nested_method_name;
+ conditional_cast =
+ "(" + nested_type_name + lang_.optional_suffix + ")";
+ }
+ if (lang_.language != IDLOptions::kCSharp) {
+ code += " public " + nested_type_name + lang_.optional_suffix + " ";
+ code += nested_method_name + "() { return ";
+ code +=
+ get_nested_method_name + "(new " + nested_type_name + "()); }\n";
+ } else {
+ obj = "(new " + nested_type_name + "())";
+ }
+ code += " public " + nested_type_name + lang_.optional_suffix + " ";
+ code += get_nested_method_name + "(";
+ if (lang_.language != IDLOptions::kCSharp)
+ code += nested_type_name + " obj";
+ code += ") { int o = " + lang_.accessor_prefix + "__offset(";
+ code += NumToString(field.value.offset) + "); ";
+ code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
+ code += lang_.accessor_prefix;
+ code += "__indirect(" + lang_.accessor_prefix + "__vector(o)), ";
+ code += lang_.accessor_prefix + "bb) : null; }\n";
+ }
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto is_series = (IsSeries(field.value.type));
+ const auto &underlying_type =
+ is_series ? field.value.type.VectorType() : field.value.type;
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(byte)(" + field.name + " ? 1 : 0)"
+ : field.name;
+ auto mutator_prefix = MakeCamel("mutate", lang_.first_camel_upper);
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ auto mutator_params = (is_series ? "(int j, " : "(") +
+ GenTypeNameDest(underlying_type) + " " +
+ field.name + ") { ";
+ auto setter_index =
+ is_series
+ ? lang_.accessor_prefix +
+ (IsArray(field.value.type)
+ ? "bb_pos + " + NumToString(field.value.offset)
+ : "__vector(o)") +
+ +" + j * " + NumToString(InlineSize(underlying_type))
+ : (struct_def.fixed
+ ? lang_.accessor_prefix + "bb_pos + " +
+ NumToString(field.value.offset)
+ : "o + " + lang_.accessor_prefix + "bb_pos");
+ if (IsScalar(underlying_type.base_type)) {
+ code += " public ";
+ code += struct_def.fixed ? "void " : lang_.bool_type;
+ code += mutator_prefix + MakeCamel(field.name, true);
+ code += mutator_params;
+ if (struct_def.fixed) {
+ code += GenSetter(underlying_type) + "(" + setter_index + ", ";
+ code += src_cast + setter_parameter + "); }\n";
+ } else {
+ code += "int o = " + lang_.accessor_prefix + "__offset(";
+ code += NumToString(field.value.offset) + ");";
+ code += " if (o != 0) { " + GenSetter(underlying_type);
+ code += "(" + setter_index + ", " + src_cast + setter_parameter +
+ "); return true; } else { return false; } }\n";
+ }
+ }
+ }
+ }
+ code += "\n";
+ flatbuffers::FieldDef *key_field = nullptr;
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += FunctionStart('C') + "reate";
+ code += struct_def.name + "(FlatBufferBuilder builder";
+ GenStructArgs(struct_def, code_ptr, "");
+ code += ") {\n";
+ GenStructBody(struct_def, code_ptr, "");
+ code += " return ";
+ code += GenOffsetConstruct(
+ struct_def, "builder." + std::string(lang_.get_fbb_offset));
+ code += ";\n }\n";
+ } else {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // JVM specifications restrict default constructor params to be < 255.
+ // Longs and doubles take up 2 units, so we set the limit to be < 127.
+ if (has_no_struct_fields && num_fields && num_fields < 127) {
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += FunctionStart('C') + "reate" + struct_def.name;
+ code += "(FlatBufferBuilder builder";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ code += ",\n ";
+ code += GenTypeBasic(DestinationType(field.value.type, false));
+ code += " ";
+ code += field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+
+ // Java doesn't have defaults, which means this method must always
+ // supply all arguments, and thus won't compile when fields are added.
+ if (lang_.language != IDLOptions::kJava) {
+ code += " = ";
+ code += GenDefaultValueBasic(field);
+ }
+ }
+ code += ") {\n builder.";
+ code += FunctionStart('S') + "tartTable(";
+ code += NumToString(struct_def.fields.vec.size()) + ");\n";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated &&
+ (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code += " " + struct_def.name + ".";
+ code += FunctionStart('A') + "dd";
+ code += MakeCamel(field.name) + "(builder, " + field.name;
+ if (!IsScalar(field.value.type.base_type)) code += "Offset";
+ code += ");\n";
+ }
+ }
+ }
+ code += " return " + struct_def.name + ".";
+ code += FunctionStart('E') + "nd" + struct_def.name;
+ code += "(builder);\n }\n\n";
+ }
+ // Generate a set of static methods that allow table construction,
+ // of the form:
+ // public static void addName(FlatBufferBuilder builder, short name)
+ // { builder.addShort(id, name, default); }
+ // Unlike the Create function, these always work.
+ code += " public static void " + FunctionStart('S') + "tart";
+ code += struct_def.name;
+ code += "(FlatBufferBuilder builder) { builder.";
+ code += FunctionStart('S') + "tartTable(";
+ code += NumToString(struct_def.fields.vec.size()) + "); }\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ code += " public static void " + FunctionStart('A') + "dd";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(DestinationType(field.value.type, false));
+ auto argname = MakeCamel(field.name, false);
+ if (!IsScalar(field.value.type.base_type)) argname += "Offset";
+ code += " " + argname + ") { builder." + FunctionStart('A') + "dd";
+ code += GenMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ code += SourceCastBasic(field.value.type);
+ code += argname;
+ if (!IsScalar(field.value.type.base_type) &&
+ field.value.type.base_type != BASE_TYPE_UNION &&
+ lang_.language == IDLOptions::kCSharp) {
+ code += ".Value";
+ }
+ code += ", ";
+ if (lang_.language == IDLOptions::kJava)
+ code += SourceCastBasic(field.value.type);
+ code += GenDefaultValue(field, false);
+ code += "); }\n";
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ if (!IsStruct(vector_type)) {
+ // Generate a method to create a vector from a Java array.
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += FunctionStart('C') + "reate";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder." + FunctionStart('S') + "tartVector(";
+ code += NumToString(elem_size);
+ code += ", data." + FunctionStart('L') + "ength, ";
+ code += NumToString(alignment);
+ code += "); for (int i = data.";
+ code += FunctionStart('L') + "ength - 1; i >= 0; i--) builder.";
+ code += FunctionStart('A') + "dd";
+ code += GenMethod(vector_type);
+ code += "(";
+ code += SourceCastBasic(vector_type, false);
+ code += "data[i]";
+ if (lang_.language == IDLOptions::kCSharp &&
+ (vector_type.base_type == BASE_TYPE_STRUCT ||
+ vector_type.base_type == BASE_TYPE_STRING))
+ code += ".Value";
+ code += "); return ";
+ code += "builder." + FunctionStart('E') + "ndVector(); }\n";
+ // For C#, include a block copy method signature.
+ if (lang_.language == IDLOptions::kCSharp) {
+ code += " public static " + GenVectorOffsetType() + " ";
+ code += FunctionStart('C') + "reate";
+ code += MakeCamel(field.name);
+ code += "VectorBlock(FlatBufferBuilder builder, ";
+ code += GenTypeBasic(vector_type) + "[] data) ";
+ code += "{ builder." + FunctionStart('S') + "tartVector(";
+ code += NumToString(elem_size);
+ code += ", data." + FunctionStart('L') + "ength, ";
+ code += NumToString(alignment);
+ code += "); builder.Add(data); return builder.EndVector(); }\n";
+ }
+ }
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ code += " public static void " + FunctionStart('S') + "tart";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder builder, int numElems) ";
+ code += "{ builder." + FunctionStart('S') + "tartVector(";
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += "); }\n";
+ }
+ }
+ code += " public static " + GenOffsetType(struct_def) + " ";
+ code += FunctionStart('E') + "nd" + struct_def.name;
+ code += "(FlatBufferBuilder builder) {\n int o = builder.";
+ code += FunctionStart('E') + "ndTable();\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += " builder." + FunctionStart('R') + "equired(o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n";
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string size_prefix[] = { "", "SizePrefixed" };
+ for (int i = 0; i < 2; ++i) {
+ code += " public static void ";
+ code += FunctionStart('F') + "inish" + size_prefix[i] +
+ struct_def.name;
+ code += "Buffer(FlatBufferBuilder builder, " +
+ GenOffsetType(struct_def);
+ code += " offset) {";
+ code += " builder." + FunctionStart('F') + "inish" + size_prefix[i] +
+ "(offset";
+ if (lang_.language == IDLOptions::kCSharp) { code += ".Value"; }
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += "); }\n";
+ }
+ }
+ }
+ // Only generate key compare function for table,
+ // because `key_field` is not set for struct
+ if (struct_def.has_key && !struct_def.fixed) {
+ FLATBUFFERS_ASSERT(key_field);
+ if (lang_.language == IDLOptions::kJava) {
+ code += "\n @Override\n protected int keysCompare(";
+ code += "Integer o1, Integer o2, ByteBuffer _bb) {";
+ code += GenKeyGetter(key_field);
+ code += " }\n";
+ } else {
+ code += "\n public static VectorOffset ";
+ code += "CreateSortedVectorOf" + struct_def.name;
+ code += "(FlatBufferBuilder builder, ";
+ code += "Offset<" + struct_def.name + ">";
+ code += "[] offsets) {\n";
+ code += " Array.Sort(offsets, (Offset<" + struct_def.name +
+ "> o1, Offset<" + struct_def.name + "> o2) => " +
+ GenKeyGetter(key_field);
+ code += ");\n";
+ code += " return builder.CreateVectorOfTables(offsets);\n }\n";
+ }
+
+ code += "\n public static " + struct_def.name + lang_.optional_suffix;
+ code += " __lookup_by_key(";
+ if (lang_.language == IDLOptions::kJava)
+ code += struct_def.name + " obj, ";
+ code += "int vectorLocation, ";
+ code += GenTypeNameDest(key_field->value.type);
+ code += " key, ByteBuffer bb) {\n";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ code += " byte[] byteKey = ";
+ if (lang_.language == IDLOptions::kJava)
+ code += "key.getBytes(Table.UTF8_CHARSET.get());\n";
+ else
+ code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
+ }
+ code += " int span = ";
+ code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
+ code += " int start = 0;\n";
+ code += " while (span != 0) {\n";
+ code += " int middle = span / 2;\n";
+ code += GenLookupKeyGetter(key_field);
+ code += " if (comp > 0) {\n";
+ code += " span = middle;\n";
+ code += " } else if (comp < 0) {\n";
+ code += " middle++;\n";
+ code += " start += middle;\n";
+ code += " span -= middle;\n";
+ code += " } else {\n";
+ code += " return ";
+ if (lang_.language == IDLOptions::kJava)
+ code += "(obj == null ? new " + struct_def.name + "() : obj)";
+ else
+ code += "new " + struct_def.name + "()";
+ code += ".__assign(tableOffset, bb);\n";
+ code += " }\n }\n";
+ code += " return null;\n";
+ code += " }\n";
+ }
+ code += "}";
+ // Java does not need the closing semi-colon on class definitions.
+ code += (lang_.language != IDLOptions::kJava) ? ";" : "";
+ code += "\n\n";
+ }
+ const LanguageParameters &lang_;
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
+};
+} // namespace general
+
+bool GenerateGeneral(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ general::GeneralGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string GeneralMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
+ const auto &lang = GetLangParams(parser.opts.lang);
+
+ std::string make_rule;
+
+ for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ if (!make_rule.empty()) make_rule += " ";
+ std::string directory =
+ BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace);
+ make_rule += directory + enum_def.name + lang.file_extension;
+ }
+
+ for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end();
+ ++it) {
+ auto &struct_def = **it;
+ if (!make_rule.empty()) make_rule += " ";
+ std::string directory = BaseGenerator::NamespaceDir(
+ parser, path, *struct_def.defined_namespace);
+ make_rule += directory + struct_def.name + lang.file_extension;
+ }
+
+ make_rule += ": ";
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+std::string BinaryFileName(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin";
+ return path + file_name + "." + ext;
+}
+
+bool GenerateBinary(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ return !parser.builder_.GetSize() ||
+ flatbuffers::SaveFile(
+ BinaryFileName(parser, path, file_name).c_str(),
+ reinterpret_cast<char *>(parser.builder_.GetBufferPointer()),
+ parser.builder_.GetSize(), true);
+}
+
+std::string BinaryMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (!parser.builder_.GetSize()) return "";
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule =
+ BinaryFileName(parser, path, filebase) + ": " + file_name;
+ auto included_files =
+ parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
new file mode 100644
index 0000000..5e62b61
--- /dev/null
+++ b/src/idl_gen_go.cpp
@@ -0,0 +1,1009 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <sstream>
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#ifdef _WIN32
+# include <direct.h>
+# define PATH_SEPARATOR "\\"
+# define mkdir(n, m) _mkdir(n)
+#else
+# include <sys/stat.h>
+# define PATH_SEPARATOR "/"
+#endif
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.go";
+}
+
+namespace go {
+
+// see https://golang.org/ref/spec#Keywords
+static const char * const g_golang_keywords[] = {
+ "break", "default", "func", "interface", "select", "case", "defer",
+ "go", "map", "struct", "chan", "else", "goto", "package",
+ "switch", "const", "fallthrough", "if", "range", "type", "continue",
+ "for", "import", "return", "var",
+};
+
+static std::string GoIdentity(const std::string &name) {
+ for (size_t i = 0;
+ i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) {
+ if (name == g_golang_keywords[i]) { return MakeCamel(name + "_", false); }
+ }
+
+ return MakeCamel(name, false);
+}
+
+class GoGenerator : public BaseGenerator {
+ public:
+ GoGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name, const std::string &go_namespace)
+ : BaseGenerator(parser, path, file_name, "" /* not used*/,
+ "" /* not used */),
+ cur_name_space_(nullptr) {
+ std::istringstream iss(go_namespace);
+ std::string component;
+ while (std::getline(iss, component, '.')) {
+ go_namespace_.components.push_back(component);
+ }
+ }
+
+ bool generate() {
+ std::string one_file_code;
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ tracked_imported_namespaces_.clear();
+ std::string enumcode;
+ GenEnum(**it, &enumcode);
+ if (parser_.opts.one_file) {
+ one_file_code += enumcode;
+ } else {
+ if (!SaveType(**it, enumcode, false, true)) return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ tracked_imported_namespaces_.clear();
+ std::string declcode;
+ GenStruct(**it, &declcode);
+ if (parser_.opts.one_file) {
+ one_file_code += declcode;
+ } else {
+ if (!SaveType(**it, declcode, true, false)) return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ std::string code = "";
+ const bool is_enum = !parser_.enums_.vec.empty();
+ BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code);
+ code += one_file_code;
+ const std::string filename = GeneratedFileName(path_, file_name_);
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ return true;
+ }
+
+ private:
+ Namespace go_namespace_;
+ Namespace *cur_name_space_;
+
+ struct NamespacePtrLess {
+ bool operator()(const Namespace *a, const Namespace *b) const {
+ return *a < *b;
+ }
+ };
+ std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that.
+ std::string OffsetPrefix(const FieldDef &field) {
+ return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" +
+ NumToString(field.value.offset) + "))\n\tif o != 0 {\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "type " + struct_def.name + " struct {\n\t";
+
+ // _ is reserved in flatbuffers field names, so no chance of name conflict:
+ code += "_tab ";
+ code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table";
+ code += "\n}\n\n";
+ }
+
+ // Construct the name of the type for this enum.
+ std::string GetEnumTypeName(const EnumDef &enum_def) {
+ return WrapInNameSpaceAndTrack(enum_def.defined_namespace, GoIdentity(enum_def.name));
+ }
+
+ // Create a type for the enum values.
+ void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "type " + GetEnumTypeName(enum_def) + " ";
+ code += GenTypeBasic(enum_def.underlying_type) + "\n\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "const (\n";
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t";
+ code += enum_def.name;
+ code += ev.name;
+ code += " ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += GetEnumTypeName(enum_def);
+ code += " = ";
+ code += enum_def.ToString(ev) + "\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ")\n\n";
+ }
+
+ // Begin enum name map.
+ void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "var EnumNames";
+ code += enum_def.name;
+ code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n";
+ }
+
+ // A single enum name member.
+ void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t";
+ code += enum_def.name;
+ code += ev.name;
+ code += ": ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += "\"";
+ code += ev.name;
+ code += "\",\n";
+ }
+
+ // End enum name map.
+ void EndEnumNames(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n\n";
+ }
+
+ // Generate String() method on enum type.
+ void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func (v " + enum_def.name + ") String() string {\n";
+ code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n";
+ code += "\t\treturn s\n";
+ code += "\t}\n";
+ code += "\treturn \""+ enum_def.name;
+ code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n";
+ code += "}\n\n";
+ }
+
+ // Begin enum value map.
+ void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "var EnumValues";
+ code += enum_def.name;
+ code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n";
+ }
+
+ // A single enum value member.
+ void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev,
+ size_t max_name_length, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\t\"";
+ code += ev.name;
+ code += "\": ";
+ code += std::string(max_name_length - ev.name.length(), ' ');
+ code += enum_def.name;
+ code += ev.name;
+ code += ",\n";
+ }
+
+ // End enum value map.
+ void EndEnumValues(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n\n";
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "func GetRootAs";
+ code += struct_def.name;
+ code += "(buf []byte, offset flatbuffers.UOffsetT) ";
+ code += "*" + struct_def.name + "";
+ code += " {\n";
+ code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n";
+ code += "\tx := &" + struct_def.name + "{}\n";
+ code += "\tx.Init(buf, n+offset)\n";
+ code += "\treturn x\n";
+ code += "}\n\n";
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " Init(buf []byte, i flatbuffers.UOffsetT) ";
+ code += "{\n";
+ code += "\trcv._tab.Bytes = buf\n";
+ code += "\trcv._tab.Pos = i\n";
+ code += "}\n\n";
+ }
+
+ // Implement the table accessor
+ void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " Table() flatbuffers.Table ";
+ code += "{\n";
+
+ if (struct_def.fixed) {
+ code += "\treturn rcv._tab.Table\n";
+ } else {
+ code += "\treturn rcv._tab\n";
+ }
+ code += "}\n\n";
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name) + "Length(";
+ code += ") int " + OffsetPrefix(field);
+ code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n";
+ code += "\treturn 0\n}\n\n";
+ }
+
+ // Get a [ubyte] vector as a byte slice.
+ void GetUByteSlice(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name) + "Bytes(";
+ code += ") []byte " + OffsetPrefix(field);
+ code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n";
+ code += "\treturn nil\n}\n\n";
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "() " + TypeName(field) + " {\n";
+ code += "\treturn " + CastToEnum(
+ field.value.type,
+ getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" +
+ NumToString(field.value.offset) + "))");
+ code += "\n}\n";
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "() " + TypeName(field) + " ";
+ code += OffsetPrefix(field) + "\t\treturn ";
+ code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)");
+ code += "\n\t}\n";
+ code += "\treturn " + GenConstant(field) + "\n";
+ code += "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(obj *" + TypeName(field);
+ code += ") *" + TypeName(field);
+ code += " {\n";
+ code += "\tif obj == nil {\n";
+ code += "\t\tobj = new(" + TypeName(field) + ")\n";
+ code += "\t}\n";
+ code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+";
+ code += NumToString(field.value.offset) + ")";
+ code += "\n\treturn obj\n";
+ code += "}\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(obj *";
+ code += TypeName(field);
+ code += ") *" + TypeName(field) + " " + OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code += "\t\tx := o + rcv._tab.Pos\n";
+ } else {
+ code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n";
+ }
+ code += "\t\tif obj == nil {\n";
+ code += "\t\t\tobj = new(" + TypeName(field) + ")\n";
+ code += "\t\t}\n";
+ code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
+ code += "\t\treturn obj\n\t}\n\treturn nil\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "() " + TypeName(field) + " ";
+ code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type);
+ code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name) + "(";
+ code += "obj " + GenTypePointer(field.value.type) + ") bool ";
+ code += OffsetPrefix(field);
+ code += "\t\t" + GenGetter(field.value.type);
+ code += "(obj, o)\n\t\treturn true\n\t}\n";
+ code += "\treturn false\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(obj *" + TypeName(field);
+ code += ", j int) bool " + OffsetPrefix(field);
+ code += "\t\tx := rcv._tab.Vector(o)\n";
+ code += "\t\tx += flatbuffers.UOffsetT(j) * ";
+ code += NumToString(InlineSize(vectortype)) + "\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code += "\t\tx = rcv._tab.Indirect(x)\n";
+ }
+ code += "\t\tobj.Init(rcv._tab.Bytes, x)\n";
+ code += "\t\treturn true\n\t}\n";
+ code += "\treturn false\n";
+ code += "}\n\n";
+ }
+
+ // Get the value of a vector's non-struct member.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += " " + MakeCamel(field.name);
+ code += "(j int) " + TypeName(field) + " ";
+ code += OffsetPrefix(field);
+ code += "\t\ta := rcv._tab.Vector(o)\n";
+ code += "\t\treturn " + CastToEnum(
+ field.value.type,
+ GenGetter(field.value.type) + "(a + flatbuffers.UOffsetT(j*" +
+ NumToString(InlineSize(vectortype)) + "))");
+ code += "\n\t}\n";
+ if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += "\treturn nil\n";
+ } else if (vectortype.base_type == BASE_TYPE_BOOL) {
+ code += "\treturn false\n";
+ } else {
+ code += "\treturn 0\n";
+ }
+ code += "}\n\n";
+ }
+
+ // Begin the creator function signature.
+ void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ if (code.substr(code.length() - 2) != "\n\n") {
+ // a previous mutate has not put an extra new line
+ code += "\n";
+ }
+ code += "func Create" + struct_def.name;
+ code += "(builder *flatbuffers.Builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", ") + nameprefix;
+ code += GoIdentity(field.name);
+ code += " " + TypeName(field);
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ") flatbuffers.UOffsetT {\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding)
+ code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ code += "\tbuilder.Prepend" + GenMethod(field) + "(";
+ code += CastToBaseType(field.value.type, nameprefix + GoIdentity(field.name)) + ")\n";
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\treturn builder.Offset()\n";
+ code += "}\n";
+ }
+
+ // Get the value of a table's starting offset.
+ void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func " + struct_def.name + "Start";
+ code += "(builder *flatbuffers.Builder) {\n";
+ code += "\tbuilder.StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ")\n}\n";
+ }
+
+ // Set the value of a table's field.
+ void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
+ const size_t offset, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
+ code += "(builder *flatbuffers.Builder, ";
+ code += GoIdentity(field.name) + " ";
+ if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ code += "flatbuffers.UOffsetT";
+ } else {
+ code += TypeName(field);
+ }
+ code += ") {\n";
+ code += "\tbuilder.Prepend";
+ code += GenMethod(field) + "Slot(";
+ code += NumToString(offset) + ", ";
+ if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ code += "flatbuffers.UOffsetT";
+ code += "(";
+ code += GoIdentity(field.name) + ")";
+ } else {
+ code += CastToBaseType(field.value.type, GoIdentity(field.name));
+ }
+ code += ", " + GenConstant(field);
+ code += ")\n}\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ void BuildVectorOfTable(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func " + struct_def.name + "Start";
+ code += MakeCamel(field.name);
+ code += "Vector(builder *flatbuffers.Builder, numElems int) ";
+ code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += ")\n}\n";
+ }
+
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func " + struct_def.name + "End";
+ code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT ";
+ code += "{\n\treturn builder.EndObject()\n}\n";
+ }
+
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "func (rcv *" + struct_def.name + ")";
+ }
+
+ // Generate a struct field getter, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, "");
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ GetVectorLen(struct_def, field, code_ptr);
+ if (field.value.type.element == BASE_TYPE_UCHAR) {
+ GetUByteSlice(struct_def, field, code_ptr);
+ }
+ }
+ }
+
+ // Mutate the value of a struct's scalar.
+ void MutateScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string type = MakeCamel(GenTypeBasic(field.value.type));
+ std::string setter = "rcv._tab.Mutate" + type;
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter;
+ code += "(rcv._tab.Pos+flatbuffers.UOffsetT(";
+ code += NumToString(field.value.offset) + "), ";
+ code += CastToBaseType(field.value.type, "n") + ")\n}\n\n";
+ }
+
+ // Mutate the value of a table's scalar.
+ void MutateScalarFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string type = MakeCamel(GenTypeBasic(field.value.type));
+ std::string setter = "rcv._tab.Mutate" + type + "Slot";
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(n " + TypeName(field) + ") bool {\n\treturn ";
+ code += setter + "(" + NumToString(field.value.offset) + ", ";
+ code += CastToBaseType(field.value.type, "n") + ")\n";
+ code += "}\n\n";
+ }
+
+ // Mutate an element of a vector of scalars.
+ void MutateElementOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+ std::string type = MakeCamel(GenTypeBasic(vectortype));
+ std::string setter = "rcv._tab.Mutate" + type;
+ GenReceiver(struct_def, code_ptr);
+ code += " Mutate" + MakeCamel(field.name);
+ code += "(j int, n " + TypeName(field) + ") bool ";
+ code += OffsetPrefix(field);
+ code += "\t\ta := rcv._tab.Vector(o)\n";
+ code += "\t\treturn " + setter + "(";
+ code += "a+flatbuffers.UOffsetT(j*";
+ code += NumToString(InlineSize(vectortype)) + "), ";
+ code += CastToBaseType(vectortype, "n") + ")\n";
+ code += "\t}\n";
+ code += "\treturn false\n";
+ code += "}\n\n";
+ }
+
+ // Generate a struct field setter, conditioned on its child type(s).
+ void GenStructMutator(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, "");
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ MutateScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ MutateScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ if (IsScalar(field.value.type.element)) {
+ MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr);
+ }
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ cur_name_space_ = struct_def.defined_namespace;
+
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ BeginClass(struct_def, code_ptr);
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ // Generate _tab accessor
+ GenTableAccessor(struct_def, code_ptr);
+
+ // Generate struct fields accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ GenStructMutator(struct_def, field, code_ptr);
+ }
+
+ // Generate builders
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ auto max_name_length = MaxNameLength(enum_def);
+ cur_name_space_ = enum_def.defined_namespace;
+
+ GenComment(enum_def.doc_comment, code_ptr, nullptr);
+ GenEnumType(enum_def, code_ptr);
+ BeginEnum(code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, "\t");
+ EnumMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnum(code_ptr);
+
+ BeginEnumNames(enum_def, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ EnumNameMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnumNames(code_ptr);
+
+ BeginEnumValues(enum_def, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto &ev = **it;
+ EnumValueMember(enum_def, ev, max_name_length, code_ptr);
+ }
+ EndEnumValues(code_ptr);
+
+ EnumStringer(enum_def, code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "rcv._tab.ByteVector";
+ case BASE_TYPE_UNION: return "rcv._tab.Union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type));
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const FieldDef &field) {
+ return IsScalar(field.value.type.base_type)
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetT");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #GTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+ return ctypename[type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "[]byte";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def);
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ if (type.enum_def != nullptr) {
+ return GetEnumTypeName(*type.enum_def);
+ }
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ // If type is an enum, returns value with a cast to the enum type, otherwise
+ // returns value as-is.
+ std::string CastToEnum(const Type &type, std::string value) {
+ if (type.enum_def == nullptr) {
+ return value;
+ } else {
+ return GenTypeGet(type) + "(" + value + ")";
+ }
+ }
+
+ // If type is an enum, returns value with a cast to the enum base type,
+ // otherwise returns value as-is.
+ std::string CastToBaseType(const Type &type, std::string value) {
+ if (type.enum_def == nullptr) {
+ return value;
+ } else {
+ return GenTypeBasic(type) + "(" + value + ")";
+ }
+ }
+
+ std::string GenConstant(const FieldDef &field) {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_BOOL: return field.value.constant == "0" ? "false" : "true";;
+ default: return field.value.constant;
+ }
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ const bool is_enum, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code = code + "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n";
+ code += "package " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "import (\n";
+ if (is_enum) {
+ code += "\t\"strconv\"\n\n";
+ }
+ if (!parser_.opts.go_import.empty()) {
+ code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
+ } else {
+ code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
+ }
+ if (tracked_imported_namespaces_.size() > 0) {
+ code += "\n";
+ for (auto it = tracked_imported_namespaces_.begin();
+ it != tracked_imported_namespaces_.end();
+ ++it) {
+ code += "\t" + NamespaceImportName(*it) + " \"" + \
+ NamespaceImportPath(*it) + "\"\n";
+ }
+ }
+ code += ")\n\n";
+ } else {
+ if (is_enum) {
+ code += "import \"strconv\"\n\n";
+ }
+ }
+ }
+
+ // Save out the generated code for a Go Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ const bool needs_imports, const bool is_enum) {
+ if (!classcode.length()) return true;
+
+ Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace
+ : go_namespace_;
+ std::string code = "";
+ BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code);
+ code += classcode;
+ // Strip extra newlines at end of file to make it gofmt-clean.
+ while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") {
+ code.pop_back();
+ }
+ std::string filename = NamespaceDir(ns) + def.name + ".go";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ // Create the full name of the imported namespace (format: A__B__C).
+ std::string NamespaceImportName(const Namespace *ns) {
+ std::string s = "";
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+ if (s.size() == 0) {
+ s += *it;
+ } else {
+ s += "__" + *it;
+ }
+ }
+ return s;
+ }
+
+ // Create the full path for the imported namespace (format: A/B/C).
+ std::string NamespaceImportPath(const Namespace *ns) {
+ std::string s = "";
+ for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+ if (s.size() == 0) {
+ s += *it;
+ } else {
+ s += "/" + *it;
+ }
+ }
+ return s;
+ }
+
+ // Ensure that a type is prefixed with its go package import name if it is
+ // used outside of its namespace.
+ std::string WrapInNameSpaceAndTrack(const Namespace *ns,
+ const std::string &name) {
+ if (CurrentNameSpace() == ns) return name;
+
+ tracked_imported_namespaces_.insert(ns);
+
+ std::string import_name = NamespaceImportName(ns);
+ return import_name + "." + name;
+ }
+
+ std::string WrapInNameSpaceAndTrack(const Definition &def) {
+ return WrapInNameSpaceAndTrack(def.defined_namespace, def.name);
+ }
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ static size_t MaxNameLength(const EnumDef &enum_def) {
+ size_t max = 0;
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ max = std::max((*it)->name.length(), max);
+ }
+ return max;
+ }
+};
+} // namespace go
+
+bool GenerateGo(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp
new file mode 100644
index 0000000..1d5e8e5
--- /dev/null
+++ b/src/idl_gen_grpc.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include "src/compiler/cpp_generator.h"
+#include "src/compiler/go_generator.h"
+#include "src/compiler/java_generator.h"
+
+#if defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable : 4512) // C4512: 'class' : assignment operator could
+// not be generated
+#endif
+
+namespace flatbuffers {
+
+class FlatBufMethod : public grpc_generator::Method {
+ public:
+ enum Streaming {
+ kNone, kClient, kServer, kBiDi
+ };
+
+ FlatBufMethod(const RPCCall *method) : method_(method) {
+ streaming_ = kNone;
+ auto val = method_->attributes.Lookup("streaming");
+ if (val) {
+ if (val->constant == "client") streaming_ = kClient;
+ if (val->constant == "server") streaming_ = kServer;
+ if (val->constant == "bidi") streaming_ = kBiDi;
+ }
+ }
+
+ grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+ grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+ std::vector<grpc::string> GetAllComments() const {
+ return method_->doc_comment;
+ }
+
+ std::string name() const { return method_->name; }
+
+ std::string GRPCType(const StructDef &sd) const {
+ return "flatbuffers::grpc::Message<" + sd.name + ">";
+ }
+
+ std::string get_input_type_name() const { return (*method_->request).name; }
+
+ std::string get_output_type_name() const { return (*method_->response).name; }
+
+ bool get_module_and_message_path_input(grpc::string * /*str*/,
+ grpc::string /*generator_file_name*/,
+ bool /*generate_in_pb2_grpc*/,
+ grpc::string /*import_prefix*/) const {
+ return true;
+ }
+
+ bool get_module_and_message_path_output(
+ grpc::string * /*str*/, grpc::string /*generator_file_name*/,
+ bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
+ return true;
+ }
+
+ std::string input_type_name() const { return GRPCType(*method_->request); }
+
+ std::string output_type_name() const { return GRPCType(*method_->response); }
+
+ bool NoStreaming() const { return streaming_ == kNone; }
+
+ bool ClientStreaming() const { return streaming_ == kClient; }
+
+ bool ServerStreaming() const { return streaming_ == kServer; }
+
+ bool BidiStreaming() const { return streaming_ == kBiDi; }
+
+ private:
+ const RPCCall *method_;
+ Streaming streaming_;
+};
+
+class FlatBufService : public grpc_generator::Service {
+ public:
+ FlatBufService(const ServiceDef *service) : service_(service) {}
+
+ grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+ grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+ std::vector<grpc::string> GetAllComments() const {
+ return service_->doc_comment;
+ }
+
+ std::string name() const { return service_->name; }
+
+ int method_count() const {
+ return static_cast<int>(service_->calls.vec.size());
+ }
+
+ std::unique_ptr<const grpc_generator::Method> method(int i) const {
+ return std::unique_ptr<const grpc_generator::Method>(
+ new FlatBufMethod(service_->calls.vec[i]));
+ }
+
+ private:
+ const ServiceDef *service_;
+};
+
+class FlatBufPrinter : public grpc_generator::Printer {
+ public:
+ FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {}
+
+ void Print(const std::map<std::string, std::string> &vars,
+ const char *string_template) {
+ std::string s = string_template;
+ // Replace any occurrences of strings in "vars" that are surrounded
+ // by the escape character by what they're mapped to.
+ size_t pos;
+ while ((pos = s.find(escape_char_)) != std::string::npos) {
+ // Found an escape char, must also find the closing one.
+ size_t pos2 = s.find(escape_char_, pos + 1);
+ // If placeholder not closed, ignore.
+ if (pos2 == std::string::npos) break;
+ auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
+ // If unknown placeholder, ignore.
+ if (it == vars.end()) break;
+ // Subtitute placeholder.
+ s.replace(pos, pos2 - pos + 1, it->second);
+ }
+ Print(s.c_str());
+ }
+
+ void Print(const char *s) {
+ if (s == nullptr || *s == '\0') { return; }
+ // Add this string, but for each part separated by \n, add indentation.
+ for (;;) {
+ // Current indentation.
+ str_->insert(str_->end(), indent_ * 2, ' ');
+ // See if this contains more than one line.
+ const char *lf = strchr(s, '\n');
+ if (lf) {
+ (*str_) += std::string(s, lf + 1);
+ s = lf + 1;
+ if (!*s) break; // Only continue if there's more lines.
+ } else {
+ (*str_) += s;
+ break;
+ }
+ }
+ }
+
+ void Indent() { indent_++; }
+
+ void Outdent() {
+ indent_--;
+ FLATBUFFERS_ASSERT(indent_ >= 0);
+ }
+
+ private:
+ std::string *str_;
+ char escape_char_;
+ int indent_;
+};
+
+class FlatBufFile : public grpc_generator::File {
+ public:
+ enum Language {
+ kLanguageGo, kLanguageCpp, kLanguageJava
+ };
+
+ FlatBufFile(const Parser &parser, const std::string &file_name,
+ Language language)
+ : parser_(parser), file_name_(file_name), language_(language) {}
+
+ FlatBufFile &operator=(const FlatBufFile &);
+
+ grpc::string GetLeadingComments(const grpc::string) const { return ""; }
+
+ grpc::string GetTrailingComments(const grpc::string) const { return ""; }
+
+ std::vector<grpc::string> GetAllComments() const {
+ return std::vector<grpc::string>();
+ }
+
+ std::string filename() const { return file_name_; }
+
+ std::string filename_without_ext() const {
+ return StripExtension(file_name_);
+ }
+
+ std::string message_header_ext() const { return "_generated.h"; }
+
+ std::string service_header_ext() const { return ".grpc.fb.h"; }
+
+ std::string package() const {
+ return parser_.current_namespace_->GetFullyQualifiedName("");
+ }
+
+ std::vector<std::string> package_parts() const {
+ return parser_.current_namespace_->components;
+ }
+
+ std::string additional_headers() const {
+ switch (language_) {
+ case kLanguageCpp: {
+ return "#include \"flatbuffers/grpc.h\"\n";
+ }
+ case kLanguageGo: {
+ return "import \"github.com/google/flatbuffers/go\"";
+ }
+ case kLanguageJava: {
+ return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
+ }
+ }
+ return "";
+ }
+
+ int service_count() const {
+ return static_cast<int>(parser_.services_.vec.size());
+ }
+
+ std::unique_ptr<const grpc_generator::Service> service(int i) const {
+ return std::unique_ptr<const grpc_generator::Service>(
+ new FlatBufService(parser_.services_.vec[i]));
+ }
+
+ std::unique_ptr<grpc_generator::Printer> CreatePrinter(
+ std::string *str) const {
+ return std::unique_ptr<grpc_generator::Printer>(new FlatBufPrinter(str));
+ }
+
+ private:
+ const Parser &parser_;
+ const std::string &file_name_;
+ const Language language_;
+};
+
+class GoGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+ GoGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "" /*Unused*/),
+ parser_(parser),
+ path_(path),
+ file_name_(file_name) {}
+
+ bool generate() {
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
+ grpc_go_generator::Parameters p;
+ p.custom_method_io_type = "flatbuffers.Builder";
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ const Definition *def = parser_.services_.vec[i];
+ p.package_name = LastNamespacePart(*(def->defined_namespace));
+ p.service_prefix = def->defined_namespace->GetFullyQualifiedName(""); // file.package();
+ std::string output =
+ grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
+ std::string filename =
+ NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
+ if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
+ }
+ return true;
+ }
+
+ protected:
+ const Parser &parser_;
+ const std::string &path_, &file_name_;
+};
+
+bool GenerateGoGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return GoGRPCGenerator(parser, path, file_name).generate();
+}
+
+bool GenerateCppGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+
+ grpc_cpp_generator::Parameters generator_parameters;
+ // TODO(wvo): make the other parameters in this struct configurable.
+ generator_parameters.use_system_headers = true;
+
+ FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
+
+ std::string header_code =
+ grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
+
+ std::string source_code =
+ grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
+ grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
+
+ return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
+ header_code, false) &&
+ flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
+ source_code, false);
+}
+
+class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
+ public:
+ JavaGRPCGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "." /*separator*/) {}
+
+ bool generate() {
+ FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
+ grpc_java_generator::Parameters p;
+ for (int i = 0; i < file.service_count(); i++) {
+ auto service = file.service(i);
+ const Definition *def = parser_.services_.vec[i];
+ p.package_name =
+ def->defined_namespace->GetFullyQualifiedName(""); // file.package();
+ std::string output =
+ grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
+ std::string filename =
+ NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
+ if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
+ }
+ return true;
+ }
+};
+
+bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ int nservices = 0;
+ for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
+ ++it) {
+ if (!(*it)->generated) nservices++;
+ }
+ if (!nservices) return true;
+ return JavaGRPCGenerator(parser, path, file_name).generate();
+}
+
+} // namespace flatbuffers
+
+#if defined(_MSC_VER)
+# pragma warning(pop)
+#endif
diff --git a/src/idl_gen_js_ts.cpp b/src/idl_gen_js_ts.cpp
new file mode 100644
index 0000000..9c89c1a
--- /dev/null
+++ b/src/idl_gen_js_ts.cpp
@@ -0,0 +1,1405 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+#include <cassert>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+const std::string kGeneratedFileNamePostfix = "_generated";
+
+struct JsTsLanguageParameters {
+ IDLOptions::Language language;
+ std::string file_extension;
+};
+
+struct ReexportDescription {
+ std::string symbol;
+ std::string source_namespace;
+ std::string target_namespace;
+};
+
+enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 };
+
+const JsTsLanguageParameters &GetJsLangParams(IDLOptions::Language lang) {
+ static JsTsLanguageParameters js_language_parameters[] = {
+ {
+ IDLOptions::kJs,
+ ".js",
+ },
+ {
+ IDLOptions::kTs,
+ ".ts",
+ },
+ };
+
+ if (lang == IDLOptions::kJs) {
+ return js_language_parameters[0];
+ } else {
+ FLATBUFFERS_ASSERT(lang == IDLOptions::kTs);
+ return js_language_parameters[1];
+ }
+}
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name,
+ const JsTsLanguageParameters &lang) {
+ return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
+}
+
+namespace jsts {
+// Iterate through all definitions we haven't generate code for (enums, structs,
+// and tables) and output them to a single file.
+class JsTsGenerator : public BaseGenerator {
+ public:
+ typedef std::unordered_set<std::string> imported_fileset;
+ typedef std::unordered_multimap<std::string, ReexportDescription>
+ reexport_map;
+
+ JsTsGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "."),
+ lang_(GetJsLangParams(parser_.opts.lang)) {}
+ // Iterate through all definitions we haven't generate code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ imported_fileset imported_files;
+ reexport_map reexports;
+
+ std::string enum_code, struct_code, import_code, exports_code, code;
+ generateEnums(&enum_code, &exports_code, reexports);
+ generateStructs(&struct_code, &exports_code, imported_files);
+ generateImportDependencies(&import_code, imported_files);
+ generateReexports(&import_code, reexports, imported_files);
+
+ code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
+
+ // Generate code for all the namespace declarations.
+ GenNamespaces(&code, &exports_code);
+
+ // Output the main declaration code from above.
+ code += import_code;
+
+ code += enum_code;
+ code += struct_code;
+
+ if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
+ !parser_.opts.skip_js_exports) {
+ if (parser_.opts.use_ES6_js_export_format)
+ code += "// Exports for ECMAScript6 Modules\n";
+ else
+ code += "// Exports for Node.js and RequireJS\n";
+ code += exports_code;
+ }
+
+ return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
+ false);
+ }
+
+ private:
+ JsTsLanguageParameters lang_;
+
+ // Generate code for imports
+ void generateImportDependencies(std::string *code_ptr,
+ const imported_fileset &imported_files) {
+ std::string &code = *code_ptr;
+ for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
+ const auto &file = *it;
+ const auto basename =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file));
+ if (basename != file_name_) {
+ code += GenPrefixedImport(file, basename);
+ }
+ }
+ }
+
+ // Generate reexports, which might not have been explicitly imported using the
+ // "export import" trick
+ void generateReexports(std::string *code_ptr, const reexport_map &reexports,
+ imported_fileset imported_files) {
+ if (!parser_.opts.reexport_ts_modules ||
+ lang_.language != IDLOptions::kTs) {
+ return;
+ }
+
+ std::string &code = *code_ptr;
+ for (auto it = reexports.begin(); it != reexports.end(); ++it) {
+ const auto &file = *it;
+ const auto basename =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
+ if (basename != file_name_) {
+ if (imported_files.find(file.first) == imported_files.end()) {
+ code += GenPrefixedImport(file.first, basename);
+ imported_files.emplace(file.first);
+ }
+
+ code += "export namespace " + file.second.target_namespace + " { \n";
+ code += "export import " + file.second.symbol + " = ";
+ code += GenFileNamespacePrefix(file.first) + "." +
+ file.second.source_namespace + "." + file.second.symbol +
+ "; }\n";
+ }
+ }
+ }
+
+ // Generate code for all enums.
+ void generateEnums(std::string *enum_code_ptr, std::string *exports_code_ptr,
+ reexport_map &reexports) {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, false);
+ GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports, true);
+ }
+ }
+
+ // Generate code for all structs.
+ void generateStructs(std::string *decl_code_ptr,
+ std::string *exports_code_ptr,
+ imported_fileset &imported_files) {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
+ imported_files);
+ }
+ }
+ void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
+ if (lang_.language == IDLOptions::kTs &&
+ parser_.opts.skip_flatbuffers_import) {
+ return;
+ }
+
+ std::set<std::string> namespaces;
+
+ for (auto it = parser_.namespaces_.begin(); it != parser_.namespaces_.end();
+ ++it) {
+ std::string namespace_so_far;
+
+ // Gather all parent namespaces for this namespace
+ for (auto component = (*it)->components.begin();
+ component != (*it)->components.end(); ++component) {
+ if (!namespace_so_far.empty()) { namespace_so_far += '.'; }
+ namespace_so_far += *component;
+ namespaces.insert(namespace_so_far);
+ }
+ }
+
+ // Make sure parent namespaces come before child namespaces
+ std::vector<std::string> sorted_namespaces(namespaces.begin(),
+ namespaces.end());
+ std::sort(sorted_namespaces.begin(), sorted_namespaces.end());
+
+ // Emit namespaces in a form that Closure Compiler can optimize
+ std::string &code = *code_ptr;
+ std::string &exports = *exports_ptr;
+ for (auto it = sorted_namespaces.begin(); it != sorted_namespaces.end();
+ ++it) {
+ if (lang_.language == IDLOptions::kTs) {
+ if (it->find('.') == std::string::npos) {
+ code += "import { flatbuffers } from \"./flatbuffers\"\n";
+ break;
+ }
+ } else {
+ code += "/**\n * @const\n * @namespace\n */\n";
+ if (it->find('.') == std::string::npos) {
+ code += "var ";
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
+ } else if (parser_.opts.use_ES6_js_export_format) {
+ exports += "export {" + *it + "};\n";
+ } else {
+ exports += "this." + *it + " = " + *it + ";\n";
+ }
+ }
+ code += *it + " = " + *it + " || {};\n\n";
+ }
+ }
+ }
+
+ // Generate a documentation comment, if available.
+ static void GenDocComment(const std::vector<std::string> &dc,
+ std::string *code_ptr,
+ const std::string &extra_lines,
+ const char *indent = nullptr) {
+ if (dc.empty() && extra_lines.empty()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ std::string &code = *code_ptr;
+ if (indent) code += indent;
+ code += "/**\n";
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ if (indent) code += indent;
+ code += " *" + *it + "\n";
+ }
+ if (!extra_lines.empty()) {
+ if (!dc.empty()) {
+ if (indent) code += indent;
+ code += " *\n";
+ }
+ if (indent) code += indent;
+ std::string::size_type start = 0;
+ for (;;) {
+ auto end = extra_lines.find('\n', start);
+ if (end != std::string::npos) {
+ code += " * " + extra_lines.substr(start, end - start) + "\n";
+ start = end + 1;
+ } else {
+ code += " * " + extra_lines.substr(start) + "\n";
+ break;
+ }
+ }
+ }
+ if (indent) code += indent;
+ code += " */\n";
+ }
+
+ static void GenDocComment(std::string *code_ptr,
+ const std::string &extra_lines) {
+ GenDocComment(std::vector<std::string>(), code_ptr, extra_lines);
+ }
+
+ std::string GenTypeAnnotation(AnnotationType annotation_type,
+ const std::string &type_name,
+ const std::string &arg_name,
+ bool include_newline = true) {
+ std::string result = "";
+ switch (annotation_type) {
+ case kParam: {
+ result += "@param";
+ break;
+ }
+ case kType: {
+ if (lang_.language != IDLOptions::kTs) {
+ result += "@type";
+ } else {
+ return "";
+ }
+ break;
+ }
+ case kReturns: {
+ result += "@returns";
+ break;
+ }
+ }
+ switch (lang_.language) {
+ case IDLOptions::kTs: {
+ result += " " + type_name;
+ break;
+ }
+ default: { result += " {" + type_name + "}"; }
+ }
+ if (!arg_name.empty()) {
+ result += " " + arg_name;
+ }
+ if (include_newline) {
+ result += "\n";
+ }
+
+ return result;
+ }
+
+ // Generate an enum declaration and an enum string lookup table.
+ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
+ std::string *exports_ptr, reexport_map &reexports,
+ bool reverse) {
+ if (enum_def.generated) return;
+ if (reverse && lang_.language == IDLOptions::kTs) return; // FIXME.
+ std::string &code = *code_ptr;
+ std::string &exports = *exports_ptr;
+ GenDocComment(enum_def.doc_comment, code_ptr,
+ reverse ? "@enum {string}" : "@enum {number}");
+ std::string ns = GetNameSpace(enum_def);
+ std::string enum_def_name = enum_def.name + (reverse ? "Name" : "");
+ if (lang_.language == IDLOptions::kTs) {
+ if (!ns.empty()) { code += "export namespace " + ns + "{\n"; }
+ code += "export enum " + enum_def.name + "{\n";
+ } else {
+ if (enum_def.defined_namespace->components.empty()) {
+ code += "var ";
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportSymbol('" + enum_def_name + "', " +
+ enum_def.name + ");\n";
+ } else if (parser_.opts.use_ES6_js_export_format) {
+ exports += "export {" + enum_def_name + "};\n";
+ } else {
+ exports += "this." + enum_def_name + " = " + enum_def_name + ";\n";
+ }
+ }
+ code += WrapInNameSpace(enum_def) + (reverse ? "Name" : "") + " = {\n";
+ }
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ if (!ev.doc_comment.empty()) {
+ if (it != enum_def.Vals().begin()) { code += '\n'; }
+ GenDocComment(ev.doc_comment, code_ptr, "", " ");
+ }
+
+ // Generate mapping between EnumName: EnumValue(int)
+ if (reverse) {
+ code += " " + enum_def.ToString(ev);
+ code += lang_.language == IDLOptions::kTs ? "= " : ": ";
+ code += "'" + ev.name + "'";
+ } else {
+ code += " " + ev.name;
+ code += lang_.language == IDLOptions::kTs ? "= " : ": ";
+ code += enum_def.ToString(ev);
+ }
+
+ code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n";
+
+ if (ev.union_type.struct_def) {
+ ReexportDescription desc = { ev.name,
+ GetNameSpace(*ev.union_type.struct_def),
+ GetNameSpace(enum_def) };
+ reexports.insert(
+ std::make_pair(ev.union_type.struct_def->file, std::move(desc)));
+ }
+ }
+
+ if (lang_.language == IDLOptions::kTs && !ns.empty()) { code += "}"; }
+ code += "};\n\n";
+ }
+
+ static std::string GenType(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL:
+ case BASE_TYPE_CHAR: return "Int8";
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_UCHAR: return "Uint8";
+ case BASE_TYPE_SHORT: return "Int16";
+ case BASE_TYPE_USHORT: return "Uint16";
+ case BASE_TYPE_INT: return "Int32";
+ case BASE_TYPE_UINT: return "Uint32";
+ case BASE_TYPE_LONG: return "Int64";
+ case BASE_TYPE_ULONG: return "Uint64";
+ case BASE_TYPE_FLOAT: return "Float32";
+ case BASE_TYPE_DOUBLE: return "Float64";
+ case BASE_TYPE_STRING: return "String";
+ case BASE_TYPE_VECTOR: return GenType(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ default: return "Table";
+ }
+ }
+
+ std::string GenGetter(const Type &type, const std::string &arguments) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return GenBBAccess() + ".__string" + arguments;
+ case BASE_TYPE_STRUCT: return GenBBAccess() + ".__struct" + arguments;
+ case BASE_TYPE_UNION: return GenBBAccess() + ".__union" + arguments;
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments);
+ default: {
+ auto getter =
+ GenBBAccess() + ".read" + MakeCamel(GenType(type)) + arguments;
+ if (type.base_type == BASE_TYPE_BOOL) { getter = "!!" + getter; }
+ if (type.enum_def) {
+ getter = "/** " +
+ GenTypeAnnotation(kType, WrapInNameSpace(*type.enum_def), "",
+ false) +
+ " */ (" + getter + ")";
+ }
+ return getter;
+ }
+ }
+ }
+
+ std::string GenBBAccess() {
+ return lang_.language == IDLOptions::kTs ? "this.bb!" : "this.bb";
+ }
+
+ std::string GenDefaultValue(const Value &value, const std::string &context) {
+ if (value.type.enum_def) {
+ if (auto val = value.type.enum_def->FindByValue(value.constant)) {
+ if (lang_.language == IDLOptions::kTs) {
+ return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
+ value.type.enum_def->file) +
+ "." + val->name;
+ } else {
+ return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
+ }
+ } else {
+ return "/** " +
+ GenTypeAnnotation(kType, WrapInNameSpace(*value.type.enum_def),
+ "", false) +
+ "} */ (" + value.constant + ")";
+ }
+ }
+
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+
+ case BASE_TYPE_STRING: return "null";
+
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ int64_t constant = StringToInt(value.constant.c_str());
+ return context + ".createLong(" +
+ NumToString(static_cast<int32_t>(constant)) + ", " +
+ NumToString(static_cast<int32_t>(constant >> 32)) + ")";
+ }
+
+ default: return value.constant;
+ }
+ }
+
+ std::string GenTypeName(const Type &type, bool input,
+ bool allowNull = false) {
+ if (!input) {
+ if (type.base_type == BASE_TYPE_STRING ||
+ type.base_type == BASE_TYPE_STRUCT) {
+ std::string name;
+ if (type.base_type == BASE_TYPE_STRING) {
+ name = "string|Uint8Array";
+ } else {
+ name = WrapInNameSpace(*type.struct_def);
+ }
+ return (allowNull) ? (name + "|null") : (name);
+ }
+ }
+
+ switch (type.base_type) {
+ case BASE_TYPE_BOOL: return "boolean";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: return "flatbuffers.Long";
+ default:
+ if (IsScalar(type.base_type)) {
+ if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
+ return "number";
+ }
+ return "flatbuffers.Offset";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ static std::string GenWriteMethod(const Type &type) {
+ // Forward to signed versions since unsigned versions don't exist
+ switch (type.base_type) {
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR));
+ case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT));
+ case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT));
+ case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG));
+ default: break;
+ }
+
+ return IsScalar(type.base_type) ? MakeCamel(GenType(type))
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ template<typename T> static std::string MaybeAdd(T value) {
+ return value != 0 ? " + " + NumToString(value) : "";
+ }
+
+ template<typename T> static std::string MaybeScale(T value) {
+ return value != 1 ? " * " + NumToString(value) : "";
+ }
+
+ static std::string GenFileNamespacePrefix(const std::string &file) {
+ return "NS" + std::to_string(HashFnv1a<uint64_t>(file.c_str()));
+ }
+
+ std::string GenPrefixedImport(const std::string &full_file_name,
+ const std::string &base_name) {
+ // Either keep the include path as it was
+ // or use only the base_name + kGeneratedFileNamePostfix
+ std::string path;
+ if (parser_.opts.keep_include_path) {
+ auto it = parser_.included_files_.find(full_file_name);
+ FLATBUFFERS_ASSERT(it != parser_.included_files_.end());
+ path =
+ flatbuffers::StripExtension(it->second) + kGeneratedFileNamePostfix;
+ } else {
+ path = base_name + kGeneratedFileNamePostfix;
+ }
+
+ // Add the include prefix and make the path always relative
+ path = flatbuffers::ConCatPathFileName(parser_.opts.include_prefix, path);
+ path = std::string(".") + kPathSeparator + path;
+
+ return "import * as " + GenFileNamespacePrefix(full_file_name) +
+ " from \"" + path + "\";\n";
+ }
+
+ // Adds a source-dependent prefix, for of import * statements.
+ std::string GenPrefixedTypeName(const std::string &typeName,
+ const std::string &file) {
+ const auto basename =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file));
+ if (basename == file_name_ || parser_.opts.generate_all) {
+ return typeName;
+ }
+ return GenFileNamespacePrefix(file) + "." + typeName;
+ }
+
+ void GenStructArgs(const StructDef &struct_def, std::string *annotations,
+ std::string *arguments, const std::string &nameprefix) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructArgs(*field.value.type.struct_def, annotations, arguments,
+ nameprefix + field.name + "_");
+ } else {
+ *annotations +=
+ GenTypeAnnotation(kParam, GenTypeName(field.value.type, true),
+ nameprefix + field.name);
+ if (lang_.language == IDLOptions::kTs) {
+ *arguments += ", " + nameprefix + field.name + ": " +
+ GenTypeName(field.value.type, true);
+ } else {
+ *arguments += ", " + nameprefix + field.name;
+ }
+ }
+ }
+ }
+
+ static void GenStructBody(const StructDef &struct_def, std::string *body,
+ const std::string &nameprefix) {
+ *body += " builder.prep(";
+ *body += NumToString(struct_def.minalign) + ", ";
+ *body += NumToString(struct_def.bytesize) + ");\n";
+
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding) {
+ *body += " builder.pad(" + NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ GenStructBody(*field.value.type.struct_def, body,
+ nameprefix + field.name + "_");
+ } else {
+ *body += " builder.write" + GenWriteMethod(field.value.type) + "(";
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { *body += "+"; }
+ *body += nameprefix + field.name + ");\n";
+ }
+ }
+ }
+
+ void GenerateRootAccessor(StructDef &struct_def, std::string *code_ptr,
+ std::string &code, std::string &object_name, bool size_prefixed) {
+ if (!struct_def.fixed) {
+ GenDocComment(code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
+ GenTypeAnnotation(kParam, object_name + "=", "obj") +
+ GenTypeAnnotation(kReturns, object_name, "", false));
+ std::string sizePrefixed("SizePrefixed");
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" + Verbose(struct_def, "As");
+ code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name +
+ "):" + object_name + " {\n";
+ } else {
+ code += object_name + ".get" + (size_prefixed ? sizePrefixed : "") + "Root" + Verbose(struct_def, "As");
+ code += " = function(bb, obj) {\n";
+ }
+ code += " return (obj || new " + object_name;
+ code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
+ code += "};\n\n";
+ }
+ }
+
+ void GenerateFinisher(StructDef &struct_def, std::string *code_ptr,
+ std::string &code, std::string &object_name, bool size_prefixed) {
+ if (parser_.root_struct_def_ == &struct_def) {
+ std::string sizePrefixed("SizePrefixed");
+ GenDocComment(
+ code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+ GenTypeAnnotation(kParam, "flatbuffers.Offset", "offset",
+ false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static finish" + (size_prefixed ? sizePrefixed : "") + Verbose(struct_def) + "Buffer";
+ code +=
+ "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
+ } else {
+ code += object_name + ".finish" + (size_prefixed ? sizePrefixed : "") + Verbose(struct_def) + "Buffer";
+ code += " = function(builder, offset) {\n";
+ }
+
+ code += " builder.finish(offset";
+ if (!parser_.file_identifier_.empty()) {
+ code += ", '" + parser_.file_identifier_ + "'";
+ }
+ if (size_prefixed) {
+ if (parser_.file_identifier_.empty()) {
+ code += ", undefined";
+ }
+ code += ", true";
+ }
+ code += ");\n";
+ code += "};\n\n";
+ }
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const Parser &parser, StructDef &struct_def,
+ std::string *code_ptr, std::string *exports_ptr,
+ imported_fileset &imported_files) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+ std::string &exports = *exports_ptr;
+
+ std::string object_name;
+ std::string object_namespace = GetNameSpace(struct_def);
+
+ // Emit constructor
+ if (lang_.language == IDLOptions::kTs) {
+ object_name = struct_def.name;
+ GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+ if (!object_namespace.empty()) {
+ code += "export namespace " + object_namespace + "{\n";
+ }
+ code += "export class " + struct_def.name;
+ code += " {\n";
+ if (lang_.language != IDLOptions::kTs) {
+ code += " /**\n";
+ code += " * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
+ code += " */\n";
+ }
+ code += " bb: flatbuffers.ByteBuffer|null = null;\n";
+ code += "\n";
+ if (lang_.language != IDLOptions::kTs) {
+ code += " /**\n";
+ code += " * " + GenTypeAnnotation(kType, "number", "");
+ code += " */\n";
+ }
+ code += " bb_pos:number = 0;\n";
+ } else {
+ bool isStatement = struct_def.defined_namespace->components.empty();
+ object_name = WrapInNameSpace(struct_def);
+ GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+ if (isStatement) {
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportSymbol('" + struct_def.name + "', " +
+ struct_def.name + ");\n";
+ } else if (parser_.opts.use_ES6_js_export_format) {
+ exports += "export {" + struct_def.name + "};\n";
+ } else {
+ exports +=
+ "this." + struct_def.name + " = " + struct_def.name + ";\n";
+ }
+ code += "function " + object_name;
+ } else {
+ code += object_name + " = function";
+ }
+ code += "() {\n";
+ code += " /**\n";
+ code += " * " + GenTypeAnnotation(kType, "flatbuffers.ByteBuffer", "");
+ code += " */\n";
+ code += " this.bb = null;\n";
+ code += "\n";
+ code += " /**\n";
+ code += " * " + GenTypeAnnotation(kType, "number", "");
+ code += " */\n";
+ code += " this.bb_pos = 0;\n";
+ code += isStatement ? "}\n\n" : "};\n\n";
+ }
+
+ // Generate the __init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ code += "/**\n";
+ code += " * " + GenTypeAnnotation(kParam, "number", "i");
+ code += " * " + GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb");
+ code += " * " + GenTypeAnnotation(kReturns, object_name, "");
+ code += " */\n";
+
+ if (lang_.language == IDLOptions::kTs) {
+ code +=
+ "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n";
+ } else {
+ code += object_name + ".prototype.__init = function(i, bb) {\n";
+ }
+
+ code += " this.bb_pos = i;\n";
+ code += " this.bb = bb;\n";
+ code += " return this;\n";
+ code += "};\n\n";
+
+ // Generate special accessors for the table that when used as the root of a
+ // FlatBuffer
+ GenerateRootAccessor(struct_def, code_ptr, code, object_name, false);
+ GenerateRootAccessor(struct_def, code_ptr, code, object_name, true);
+
+ // Generate the identifier check method
+ if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def &&
+ !parser_.file_identifier_.empty()) {
+ GenDocComment(
+ code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.ByteBuffer", "bb") +
+ GenTypeAnnotation(kReturns, "boolean", "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ code +=
+ "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean "
+ "{\n";
+ } else {
+ code += object_name + ".bufferHasIdentifier = function(bb) {\n";
+ }
+
+ code += " return bb.__has_identifier('" + parser_.file_identifier_;
+ code += "');\n};\n\n";
+ }
+
+ // Emit field accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset_prefix =
+ " var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
+ NumToString(field.value.offset) + ");\n return offset ? ";
+
+ // Emit a scalar field
+ if (IsScalar(field.value.type.base_type) ||
+ field.value.type.base_type == BASE_TYPE_STRING) {
+ GenDocComment(
+ field.doc_comment, code_ptr,
+ std::string(field.value.type.base_type == BASE_TYPE_STRING
+ ? GenTypeAnnotation(kParam, "flatbuffers.Encoding=",
+ "optionalEncoding")
+ : "") +
+ GenTypeAnnotation(kReturns,
+ GenTypeName(field.value.type, false, true),
+ "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ std::string prefix = MakeCamel(field.name, false) + "(";
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += prefix + "):string|null\n";
+ code += prefix + "optionalEncoding:flatbuffers.Encoding" +
+ "):" + GenTypeName(field.value.type, false, true) + "\n";
+ code += prefix + "optionalEncoding?:any";
+ } else {
+ code += prefix;
+ }
+ if (field.value.type.enum_def) {
+ code +=
+ "):" +
+ GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
+ field.value.type.enum_def->file) +
+ " {\n";
+
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(field.value.type.enum_def->file);
+ }
+ } else {
+ code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
+ }
+ } else {
+ code += object_name + ".prototype." + MakeCamel(field.name, false);
+ code += " = function(";
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ code += "optionalEncoding";
+ }
+ code += ") {\n";
+ }
+
+ if (struct_def.fixed) {
+ code +=
+ " return " +
+ GenGetter(field.value.type,
+ "(this.bb_pos" + MaybeAdd(field.value.offset) + ")") +
+ ";\n";
+ } else {
+ std::string index = "this.bb_pos + offset";
+ if (field.value.type.base_type == BASE_TYPE_STRING) {
+ index += ", optionalEncoding";
+ }
+ code += offset_prefix +
+ GenGetter(field.value.type, "(" + index + ")") + " : " +
+ GenDefaultValue(field.value, GenBBAccess());
+ code += ";\n";
+ }
+ }
+
+ // Emit an object field
+ else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ auto type = WrapInNameSpace(*field.value.type.struct_def);
+ GenDocComment(
+ field.doc_comment, code_ptr,
+ GenTypeAnnotation(kParam, type + "=", "obj") +
+ GenTypeAnnotation(kReturns, type + "|null", "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ type =
+ GenPrefixedTypeName(type, field.value.type.struct_def->file);
+ code += MakeCamel(field.name, false);
+ code += "(obj?:" + type + "):" + type + "|null {\n";
+ } else {
+ code +=
+ object_name + ".prototype." + MakeCamel(field.name, false);
+ code += " = function(obj) {\n";
+ }
+
+ if (struct_def.fixed) {
+ code += " return (obj || new " + type;
+ code += ").__init(this.bb_pos";
+ code +=
+ MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
+ } else {
+ code += offset_prefix + "(obj || new " + type + ").__init(";
+ code += field.value.type.struct_def->fixed
+ ? "this.bb_pos + offset"
+ : GenBBAccess() + ".__indirect(this.bb_pos + offset)";
+ code += ", " + GenBBAccess() + ") : null;\n";
+ }
+
+ if (lang_.language == IDLOptions::kTs && !parser_.opts.generate_all) {
+ imported_files.insert(field.value.type.struct_def->file);
+ }
+
+ break;
+ }
+
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ auto vectortypename = GenTypeName(vectortype, false);
+ auto inline_size = InlineSize(vectortype);
+ auto index = GenBBAccess() +
+ ".__vector(this.bb_pos + offset) + index" +
+ MaybeScale(inline_size);
+ std::string args = GenTypeAnnotation(kParam, "number", "index");
+ std::string ret_type;
+ bool is_union = false;
+ switch (vectortype.base_type) {
+ case BASE_TYPE_STRUCT:
+ args += GenTypeAnnotation(kParam, vectortypename + "=", "obj");
+ ret_type = vectortypename;
+ break;
+ case BASE_TYPE_STRING:
+ args += GenTypeAnnotation(
+ kParam, "flatbuffers.Encoding=", "optionalEncoding");
+ ret_type = vectortypename;
+ break;
+ case BASE_TYPE_UNION:
+ args += GenTypeAnnotation(kParam, "flatbuffers.Table=", "obj");
+ ret_type = "?flatbuffers.Table";
+ is_union = true;
+ break;
+ default: ret_type = vectortypename;
+ }
+ GenDocComment(
+ field.doc_comment, code_ptr,
+ args + GenTypeAnnotation(kReturns, ret_type, "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ std::string prefix = MakeCamel(field.name, false);
+ if (is_union) { prefix += "<T extends flatbuffers.Table>"; }
+ prefix += "(index: number";
+ if (is_union) {
+ vectortypename = "T";
+ code += prefix + ", obj:T";
+ } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ vectortypename = GenPrefixedTypeName(
+ vectortypename, vectortype.struct_def->file);
+ code += prefix + ", obj?:" + vectortypename;
+
+ if (!parser_.opts.generate_all) {
+ imported_files.insert(vectortype.struct_def->file);
+ }
+ } else if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += prefix + "):string\n";
+ code += prefix + ",optionalEncoding:flatbuffers.Encoding" +
+ "):" + vectortypename + "\n";
+ code += prefix + ",optionalEncoding?:any";
+ } else {
+ code += prefix;
+ }
+ code += "):" + vectortypename + "|null {\n";
+ } else {
+ code +=
+ object_name + ".prototype." + MakeCamel(field.name, false);
+ code += " = function(index";
+ if (vectortype.base_type == BASE_TYPE_STRUCT || is_union) {
+ code += ", obj";
+ } else if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += ", optionalEncoding";
+ }
+ code += ") {\n";
+ }
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += offset_prefix + "(obj || new " + vectortypename;
+ code += ").__init(";
+ code += vectortype.struct_def->fixed
+ ? index
+ : GenBBAccess() + ".__indirect(" + index + ")";
+ code += ", " + GenBBAccess() + ")";
+ } else {
+ if (is_union) {
+ index = "obj, " + index;
+ } else if (vectortype.base_type == BASE_TYPE_STRING) {
+ index += ", optionalEncoding";
+ }
+ code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
+ }
+ code += " : ";
+ if (field.value.type.element == BASE_TYPE_BOOL) {
+ code += "false";
+ } else if (field.value.type.element == BASE_TYPE_LONG ||
+ field.value.type.element == BASE_TYPE_ULONG) {
+ code += GenBBAccess() + ".createLong(0, 0)";
+ } else if (IsScalar(field.value.type.element)) {
+ if (field.value.type.enum_def) {
+ code += "/** " +
+ GenTypeAnnotation(
+ kType, WrapInNameSpace(*field.value.type.enum_def),
+ "", false) +
+ " */ (" + field.value.constant + ")";
+ } else {
+ code += "0";
+ }
+ } else {
+ code += "null";
+ }
+ code += ";\n";
+ break;
+ }
+
+ case BASE_TYPE_UNION:
+ GenDocComment(
+ field.doc_comment, code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.Table", "obj") +
+ GenTypeAnnotation(kReturns, "?flatbuffers.Table", "",
+ false));
+ if (lang_.language == IDLOptions::kTs) {
+ code += MakeCamel(field.name, false);
+ code += "<T extends flatbuffers.Table>(obj:T):T|null {\n";
+ } else {
+ code +=
+ object_name + ".prototype." + MakeCamel(field.name, false);
+ code += " = function(obj) {\n";
+ }
+
+ code += offset_prefix +
+ GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
+ " : null;\n";
+ break;
+
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ code += "};\n\n";
+
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportProperty(" + object_name + ".prototype, '" +
+ MakeCamel(field.name, false) + "', " + object_name +
+ ".prototype." + MakeCamel(field.name, false) + ");\n";
+ }
+
+ // Adds the mutable scalar value to the output
+ if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
+ std::string annotations = GenTypeAnnotation(
+ kParam, GenTypeName(field.value.type, true), "value");
+ GenDocComment(
+ code_ptr,
+ annotations + GenTypeAnnotation(kReturns, "boolean", "", false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ std::string type;
+ if (field.value.type.enum_def) {
+ type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
+ field.value.type.enum_def->file);
+ } else {
+ type = GenTypeName(field.value.type, true);
+ }
+
+ code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
+ } else {
+ code += object_name + ".prototype.mutate_" + field.name +
+ " = function(value) {\n";
+ }
+
+ code += " var offset = " + GenBBAccess() + ".__offset(this.bb_pos, " +
+ NumToString(field.value.offset) + ");\n\n";
+ code += " if (offset === 0) {\n";
+ code += " return false;\n";
+ code += " }\n\n";
+
+ // special case for bools, which are treated as uint8
+ code += " " + GenBBAccess() + ".write" +
+ MakeCamel(GenType(field.value.type)) +
+ "(this.bb_pos + offset, ";
+ if (field.value.type.base_type == BASE_TYPE_BOOL &&
+ lang_.language == IDLOptions::kTs) {
+ code += "+";
+ }
+
+ code += "value);\n";
+ code += " return true;\n";
+ code += "};\n\n";
+
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportProperty(" + object_name +
+ ".prototype, 'mutate_" + field.name + "', " + object_name +
+ ".prototype.mutate_" + field.name + ");\n";
+ }
+ }
+
+ // Emit vector helpers
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ // Emit a length helper
+ GenDocComment(code_ptr,
+ GenTypeAnnotation(kReturns, "number", "", false));
+ if (lang_.language == IDLOptions::kTs) {
+ code += MakeCamel(field.name, false);
+ code += "Length():number {\n" + offset_prefix;
+ } else {
+ code += object_name + ".prototype." + MakeCamel(field.name, false);
+ code += "Length = function() {\n" + offset_prefix;
+ }
+
+ code +=
+ GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
+
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportProperty(" + object_name + ".prototype, '" +
+ MakeCamel(field.name, false) + "Length', " + object_name +
+ ".prototype." + MakeCamel(field.name, false) +
+ "Length);\n";
+ }
+
+ // For scalar types, emit a typed array helper
+ auto vectorType = field.value.type.VectorType();
+ if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
+ GenDocComment(code_ptr, GenTypeAnnotation(
+ kReturns, GenType(vectorType) + "Array",
+ "", false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += MakeCamel(field.name, false);
+ code += "Array():" + GenType(vectorType) + "Array|null {\n" +
+ offset_prefix;
+ } else {
+ code += object_name + ".prototype." + MakeCamel(field.name, false);
+ code += "Array = function() {\n" + offset_prefix;
+ }
+
+ code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() +
+ ".bytes().buffer, " + GenBBAccess() +
+ ".bytes().byteOffset + " + GenBBAccess() +
+ ".__vector(this.bb_pos + offset), " + GenBBAccess() +
+ ".__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
+
+ if (parser_.opts.use_goog_js_export_format) {
+ exports += "goog.exportProperty(" + object_name + ".prototype, '" +
+ MakeCamel(field.name, false) + "Array', " + object_name +
+ ".prototype." + MakeCamel(field.name, false) +
+ "Array);\n";
+ }
+ }
+ }
+ }
+
+ // Emit a factory constructor
+ if (struct_def.fixed) {
+ std::string annotations =
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
+ std::string arguments;
+ GenStructArgs(struct_def, &annotations, &arguments, "");
+ GenDocComment(code_ptr, annotations + GenTypeAnnotation(
+ kReturns, "flatbuffers.Offset",
+ "", false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static create" + Verbose(struct_def) +
+ "(builder:flatbuffers.Builder";
+ code += arguments + "):flatbuffers.Offset {\n";
+ } else {
+ code += object_name + ".create" + Verbose(struct_def);
+ code += " = function(builder";
+ code += arguments + ") {\n";
+ }
+
+ GenStructBody(struct_def, &code, "");
+ code += " return builder.offset();\n};\n\n";
+ } else {
+ // Generate a method to start building a new object
+ GenDocComment(code_ptr, GenTypeAnnotation(kParam, "flatbuffers.Builder",
+ "builder", false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static start" + Verbose(struct_def) +
+ "(builder:flatbuffers.Builder) {\n";
+ } else {
+ code += object_name + ".start" + Verbose(struct_def);
+ code += " = function(builder) {\n";
+ }
+
+ code += " builder.startObject(" +
+ NumToString(struct_def.fields.vec.size()) + ");\n";
+ code += "};\n\n";
+
+ // Generate a set of static methods that allow table construction
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ const auto argname = GetArgName(field);
+
+ // Generate the field insertion method
+ GenDocComment(
+ code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+ GenTypeAnnotation(kParam, GenTypeName(field.value.type, true),
+ argname, false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static add" + MakeCamel(field.name);
+ code += "(builder:flatbuffers.Builder, " + argname + ":" +
+ GetArgType(field) + ") {\n";
+ } else {
+ code += object_name + ".add" + MakeCamel(field.name);
+ code += " = function(builder, " + argname + ") {\n";
+ }
+
+ code += " builder.addField" + GenWriteMethod(field.value.type) + "(";
+ code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += argname + ", ";
+ if (!IsScalar(field.value.type.base_type)) {
+ code += "0";
+ } else {
+ if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += GenDefaultValue(field.value, "builder");
+ }
+ code += ");\n};\n\n";
+
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+
+ // Generate a method to create a vector from a JavaScript array
+ if (!IsStruct(vector_type)) {
+ GenDocComment(
+ code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+ GenTypeAnnotation(
+ kParam,
+ "Array.<" + GenTypeName(vector_type, true) + ">",
+ "data") +
+ GenTypeAnnotation(kReturns, "flatbuffers.Offset", "",
+ false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static create" + MakeCamel(field.name);
+ std::string type = GenTypeName(vector_type, true) + "[]";
+ if (type == "number[]") { type += " | Uint8Array"; }
+ code += "Vector(builder:flatbuffers.Builder, data:" + type +
+ "):flatbuffers.Offset {\n";
+ } else {
+ code += object_name + ".create" + MakeCamel(field.name);
+ code += "Vector = function(builder, data) {\n";
+ }
+
+ code += " builder.startVector(" + NumToString(elem_size);
+ code += ", data.length, " + NumToString(alignment) + ");\n";
+ code += " for (var i = data.length - 1; i >= 0; i--) {\n";
+ code += " builder.add" + GenWriteMethod(vector_type) + "(";
+ if (vector_type.base_type == BASE_TYPE_BOOL) { code += "+"; }
+ code += "data[i]);\n";
+ code += " }\n";
+ code += " return builder.endVector();\n";
+ code += "};\n\n";
+ }
+
+ // Generate a method to start a vector, data to be added manually
+ // after
+ GenDocComment(
+ code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+ GenTypeAnnotation(kParam, "number", "numElems", false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static start" + MakeCamel(field.name);
+ code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
+ } else {
+ code += object_name + ".start" + MakeCamel(field.name);
+ code += "Vector = function(builder, numElems) {\n";
+ }
+
+ code += " builder.startVector(" + NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment) + ");\n";
+ code += "};\n\n";
+ }
+ }
+
+ // Generate a method to stop building a new object
+ GenDocComment(
+ code_ptr,
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder") +
+ GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false));
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static end" + Verbose(struct_def);
+ code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
+ } else {
+ code += object_name + ".end" + Verbose(struct_def);
+ code += " = function(builder) {\n";
+ }
+
+ code += " var offset = builder.endObject();\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += " builder.requiredField(offset, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += " return offset;\n";
+ code += "};\n\n";
+
+ // Generate the methods to complete buffer construction
+ GenerateFinisher(struct_def, code_ptr, code, object_name, false);
+ GenerateFinisher(struct_def, code_ptr, code, object_name, true);
+
+ // Generate a convenient CreateX function
+ if (lang_.language == IDLOptions::kJs) {
+ std::string paramDoc =
+ GenTypeAnnotation(kParam, "flatbuffers.Builder", "builder");
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated)
+ continue;
+ paramDoc +=
+ GenTypeAnnotation(kParam, GetArgType(field), GetArgName(field));
+ }
+ paramDoc +=
+ GenTypeAnnotation(kReturns, "flatbuffers.Offset", "", false);
+
+ GenDocComment(code_ptr, paramDoc);
+ }
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "static create" + Verbose(struct_def);
+ code += "(builder:flatbuffers.Builder";
+ } else {
+ code += object_name + ".create" + Verbose(struct_def);
+ code += " = function(builder";
+ }
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated)
+ continue;
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += ", " + GetArgName(field) + ":" + GetArgType(field);
+ } else {
+ code += ", " + GetArgName(field);
+ }
+ }
+
+ if (lang_.language == IDLOptions::kTs) {
+ code += "):flatbuffers.Offset {\n";
+ code += " " + struct_def.name + ".start" + Verbose(struct_def) +
+ "(builder);\n";
+ } else {
+ code += ") {\n";
+ code += " " + object_name + ".start" + Verbose(struct_def) +
+ "(builder);\n";
+ }
+
+ std::string methodPrefix =
+ lang_.language == IDLOptions::kTs ? struct_def.name : object_name;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated)
+ continue;
+
+ code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "(";
+ code += "builder, " + GetArgName(field) + ");\n";
+ }
+
+ code += " return " + methodPrefix + ".end" + Verbose(struct_def) +
+ "(builder);\n";
+ code += "}\n";
+ if (lang_.language == IDLOptions::kJs)
+ code += "\n";
+ }
+
+ if (lang_.language == IDLOptions::kTs) {
+ if (!object_namespace.empty()) {
+ code += "}\n";
+ }
+ code += "}\n";
+ }
+ }
+
+ std::string GetArgType(const FieldDef &field) {
+ if (field.value.type.enum_def)
+ return GenPrefixedTypeName(GenTypeName(field.value.type, true),
+ field.value.type.enum_def->file);
+ return GenTypeName(field.value.type, true);
+ }
+
+ static std::string GetArgName(const FieldDef &field) {
+ auto argname = MakeCamel(field.name, false);
+ if (!IsScalar(field.value.type.base_type)) { argname += "Offset"; }
+
+ return argname;
+ }
+
+ std::string Verbose(const StructDef &struct_def,
+ const char* prefix = "")
+ {
+ return parser_.opts.js_ts_short_names ? "" : prefix + struct_def.name;
+ }
+};
+} // namespace jsts
+
+bool GenerateJSTS(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ jsts::JsTsGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string JSTSMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX);
+ const auto &lang = GetJsLangParams(parser.opts.lang);
+
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
+
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_json_schema.cpp b/src/idl_gen_json_schema.cpp
new file mode 100644
index 0000000..27e2cd4
--- /dev/null
+++ b/src/idl_gen_json_schema.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + ".schema.json";
+}
+
+namespace jsons {
+
+std::string GenNativeType(BaseType type) {
+ switch (type) {
+ case BASE_TYPE_BOOL: return "boolean";
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_FLOAT:
+ case BASE_TYPE_DOUBLE: return "number";
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_ARRAY: return "array";
+ default: return "";
+ }
+}
+
+template<class T> std::string GenFullName(const T *enum_def) {
+ std::string full_name;
+ const auto &name_spaces = enum_def->defined_namespace->components;
+ for (auto ns = name_spaces.cbegin(); ns != name_spaces.cend(); ++ns) {
+ full_name.append(*ns + "_");
+ }
+ full_name.append(enum_def->name);
+ return full_name;
+}
+
+template<class T> std::string GenTypeRef(const T *enum_def) {
+ return "\"$ref\" : \"#/definitions/" + GenFullName(enum_def) + "\"";
+}
+
+std::string GenType(const std::string &name) {
+ return "\"type\" : \"" + name + "\"";
+}
+
+std::string GenType(const Type &type) {
+ if (type.enum_def != nullptr && !type.enum_def->is_union) {
+ // it is a reference to an enum type
+ return GenTypeRef(type.enum_def);
+ }
+ switch (type.base_type) {
+ case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case BASE_TYPE_VECTOR: {
+ std::string typeline;
+ typeline.append("\"type\" : \"array\", \"items\" : { ");
+ if (type.element == BASE_TYPE_STRUCT) {
+ typeline.append(GenTypeRef(type.struct_def));
+ } else {
+ typeline.append(GenType(GenNativeType(type.element)));
+ }
+ typeline.append(" }");
+ return typeline;
+ }
+ case BASE_TYPE_STRUCT: {
+ return GenTypeRef(type.struct_def);
+ }
+ case BASE_TYPE_UNION: {
+ std::string union_type_string("\"anyOf\": [");
+ const auto &union_types = type.enum_def->Vals();
+ for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) {
+ auto &union_type = *ut;
+ if (union_type->union_type.base_type == BASE_TYPE_NONE) { continue; }
+ if (union_type->union_type.base_type == BASE_TYPE_STRUCT) {
+ union_type_string.append(
+ "{ " + GenTypeRef(union_type->union_type.struct_def) + " }");
+ }
+ if (union_type != *type.enum_def->Vals().rbegin()) {
+ union_type_string.append(",");
+ }
+ }
+ union_type_string.append("]");
+ return union_type_string;
+ }
+ case BASE_TYPE_UTYPE: return GenTypeRef(type.enum_def);
+ default: return GenType(GenNativeType(type.base_type));
+ }
+}
+
+class JsonSchemaGenerator : public BaseGenerator {
+ private:
+ CodeWriter code_;
+
+ public:
+ JsonSchemaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "") {}
+
+ explicit JsonSchemaGenerator(const BaseGenerator &base_generator)
+ : BaseGenerator(base_generator) {}
+
+ bool generate() {
+ code_.Clear();
+ code_ += "{";
+ code_ += " \"$schema\": \"http://json-schema.org/draft-04/schema#\",";
+ code_ += " \"definitions\": {";
+ for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend();
+ ++e) {
+ code_ += " \"" + GenFullName(*e) + "\" : {";
+ code_ += " " + GenType("string") + ",";
+ std::string enumdef(" \"enum\": [");
+ for (auto enum_value = (*e)->Vals().begin();
+ enum_value != (*e)->Vals().end(); ++enum_value) {
+ enumdef.append("\"" + (*enum_value)->name + "\"");
+ if (*enum_value != (*e)->Vals().back()) { enumdef.append(", "); }
+ }
+ enumdef.append("]");
+ code_ += enumdef;
+ code_ += " },"; // close type
+ }
+ for (auto s = parser_.structs_.vec.cbegin();
+ s != parser_.structs_.vec.cend(); ++s) {
+ const auto &structure = *s;
+ code_ += " \"" + GenFullName(structure) + "\" : {";
+ code_ += " " + GenType("object") + ",";
+ std::string comment;
+ const auto &comment_lines = structure->doc_comment;
+ for (auto comment_line = comment_lines.cbegin();
+ comment_line != comment_lines.cend(); ++comment_line) {
+ comment.append(*comment_line);
+ }
+ if (comment.size() > 0) {
+ code_ += " \"description\" : \"" + comment + "\",";
+ }
+ code_ += " \"properties\" : {";
+
+ const auto &properties = structure->fields.vec;
+ for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) {
+ const auto &property = *prop;
+ std::string arrayInfo = "";
+ if (IsArray(property->value.type)) {
+ arrayInfo = ",\n \"minItems\": " +
+ NumToString(property->value.type.fixed_length) +
+ ",\n \"maxItems\": " +
+ NumToString(property->value.type.fixed_length);
+ }
+ std::string typeLine =
+ " \"" + property->name + "\" : {\n" + " " +
+ GenType(property->value.type) + arrayInfo + "\n }";
+ if (property != properties.back()) { typeLine.append(","); }
+ code_ += typeLine;
+ }
+ code_ += " },"; // close properties
+
+ std::vector<FieldDef *> requiredProperties;
+ std::copy_if(properties.begin(), properties.end(),
+ back_inserter(requiredProperties),
+ [](FieldDef const *prop) { return prop->required; });
+ if (requiredProperties.size() > 0) {
+ std::string required_string(" \"required\" : [");
+ for (auto req_prop = requiredProperties.cbegin();
+ req_prop != requiredProperties.cend(); ++req_prop) {
+ required_string.append("\"" + (*req_prop)->name + "\"");
+ if (*req_prop != requiredProperties.back()) {
+ required_string.append(", ");
+ }
+ }
+ required_string.append("],");
+ code_ += required_string;
+ }
+ code_ += " \"additionalProperties\" : false";
+ std::string closeType(" }");
+ if (*s != parser_.structs_.vec.back()) { closeType.append(","); }
+ code_ += closeType; // close type
+ }
+ code_ += " },"; // close definitions
+
+ // mark root type
+ code_ += " \"$ref\" : \"#/definitions/" +
+ GenFullName(parser_.root_struct_def_) + "\"";
+
+ code_ += "}"; // close schema root
+ const std::string file_path = GeneratedFileName(path_, file_name_);
+ const std::string final_code = code_.ToString();
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+};
+} // namespace jsons
+
+bool GenerateJsonSchema(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ jsons::JsonSchemaGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp
new file mode 100644
index 0000000..3ced7b3
--- /dev/null
+++ b/src/idl_gen_kotlin.cpp
@@ -0,0 +1,1527 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <functional>
+#include <unordered_set>
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+#if defined(FLATBUFFERS_CPP98_STL)
+#include <cctype>
+#endif // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+
+namespace kotlin {
+
+typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
+static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
+ "POSITIVE_INFINITY",
+ "NEGATIVE_INFINITY");
+
+static const CommentConfig comment_config = {"/**", " *", " */"};
+static const std::string ident_pad = " ";
+static const char *keywords[] = {
+ "package", "as", "typealias", "class", "this", "super",
+ "val", "var", "fun", "for", "null", "true",
+ "false", "is", "in", "throw", "return", "break",
+ "continue", "object", "if", "try", "else", "while",
+ "do", "when", "interface", "typeof", "Any", "Character"};
+
+// Escape Keywords
+static std::string Esc(const std::string &name) {
+ for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+ if (name == keywords[i]) {
+ return MakeCamel(name + "_", false);
+ }
+ }
+
+ return MakeCamel(name, false);
+}
+
+class KotlinGenerator : public BaseGenerator {
+ public:
+ KotlinGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "."),
+ cur_name_space_(nullptr) {}
+
+ KotlinGenerator &operator=(const KotlinGenerator &);
+ bool generate() FLATBUFFERS_OVERRIDE {
+ std::string one_file_code;
+
+ cur_name_space_ = parser_.current_namespace_;
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ CodeWriter enumWriter(ident_pad);
+ auto &enum_def = **it;
+ if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+ GenEnum(enum_def, enumWriter);
+ if (parser_.opts.one_file) {
+ one_file_code += enumWriter.ToString();
+ } else {
+ if (!SaveType(enum_def.name, *enum_def.defined_namespace,
+ enumWriter.ToString(), false))
+ return false;
+ }
+ }
+
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ CodeWriter structWriter(ident_pad);
+ auto &struct_def = **it;
+ if (!parser_.opts.one_file)
+ cur_name_space_ = struct_def.defined_namespace;
+ GenStruct(struct_def, structWriter);
+ if (parser_.opts.one_file) {
+ one_file_code += structWriter.ToString();
+ } else {
+ if (!SaveType(struct_def.name, *struct_def.defined_namespace,
+ structWriter.ToString(), true))
+ return false;
+ }
+ }
+
+ if (parser_.opts.one_file) {
+ return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+ true);
+ }
+ return true;
+ }
+
+ // Save out the generated code for a single class while adding
+ // declaration boilerplate.
+ bool SaveType(const std::string &defname, const Namespace &ns,
+ const std::string &classcode, bool needs_includes) const {
+ if (!classcode.length()) return true;
+
+ std::string code =
+ "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ std::string namespace_name = FullNamespace(".", ns);
+ if (!namespace_name.empty()) {
+ code += "package " + namespace_name;
+ code += "\n\n";
+ }
+ if (needs_includes) {
+ code += "import java.nio.*\n";
+ code += "import kotlin.math.sign\n";
+ code += "import com.google.flatbuffers.*\n\n";
+ }
+ code += classcode;
+ auto filename = NamespaceDir(ns) + defname + ".kt";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE {
+ return cur_name_space_;
+ }
+
+ static bool IsEnum(const Type &type) {
+ return type.enum_def != nullptr && IsInteger(type.base_type);
+ }
+
+ static std::string GenTypeBasic(const BaseType &type) {
+ // clang-format off
+ static const char * const kotlin_typename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #KTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ return kotlin_typename[type];
+
+ }
+
+ std::string GenTypePointer(const Type &type) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return "String";
+ case BASE_TYPE_VECTOR:
+ return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT:
+ return WrapInNameSpace(*type.struct_def);
+ default:
+ return "Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) const {
+ return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
+ : GenTypePointer(type);
+ }
+
+ std::string GenEnumDefaultValue(const FieldDef &field) const {
+ auto &value = field.value;
+ FLATBUFFERS_ASSERT(value.type.enum_def);
+ auto &enum_def = *value.type.enum_def;
+ auto enum_val = enum_def.FindByValue(value.constant);
+ return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+ : value.constant;
+ }
+
+
+ // Generate default values to compare against a default value when
+ // `force_defaults` is `false`.
+ // Main differences are:
+ // - Floats are upcasted to doubles
+ // - Unsigned are casted to signed
+ std::string GenFBBDefaultValue(const FieldDef &field) const {
+ auto out = GenDefaultValue(field, true);
+ // All FlatBufferBuilder default floating point values are doubles
+ if (field.value.type.base_type == BASE_TYPE_FLOAT) {
+ if (out.find("Float") != std::string::npos) {
+ out.replace(0, 5, "Double");
+ }
+ }
+ //Guarantee all values are doubles
+ if (out.back() == 'f')
+ out.pop_back();
+ return out;
+ }
+
+
+ // FlatBufferBuilder only store signed types, so this function
+ // returns a cast for unsigned values
+ std::string GenFBBValueCast(const FieldDef &field) const {
+ if (IsUnsigned(field.value.type.base_type)) {
+ return CastToSigned(field.value.type);
+ }
+ return "";
+ }
+
+ std::string GenDefaultValue(const FieldDef &field,
+ bool force_signed = false) const {
+ auto &value = field.value;
+ auto base_type = field.value.type.base_type;
+ if (IsFloat(base_type)) {
+ auto val = KotlinFloatGen.GenFloatConstant(field);
+ if (base_type == BASE_TYPE_DOUBLE &&
+ val.back() == 'f') {
+ val.pop_back();
+ }
+ return val;
+ }
+
+ if (base_type == BASE_TYPE_BOOL) {
+ return value.constant == "0" ? "false" : "true";
+ }
+
+ std::string suffix = "";
+
+ if (base_type == BASE_TYPE_LONG || !force_signed) {
+ suffix = LiteralSuffix(base_type);
+ }
+ return value.constant + suffix;
+ }
+
+ void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
+ if (enum_def.generated) return;
+
+ GenerateComment(enum_def.doc_comment, writer, &comment_config);
+
+ writer += "@Suppress(\"unused\")";
+ writer += "@ExperimentalUnsignedTypes";
+ writer += "class " + Esc(enum_def.name) + " private constructor() {";
+ writer.IncrementIdentLevel();
+
+ GenerateCompanionObject(writer, [&](){
+ // Write all properties
+ auto vals = enum_def.Vals();
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ auto &ev = **it;
+ auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
+ auto val = enum_def.ToString(ev);
+ auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
+ writer.SetValue("name", Esc(ev.name));
+ writer.SetValue("type", field_type);
+ writer.SetValue("val", val + suffix);
+ GenerateComment(ev.doc_comment, writer, &comment_config);
+ writer += "const val {{name}}: {{type}} = {{val}}";
+ }
+
+ // Generate a generate string table for enum values.
+ // Problem is, if values are very sparse that could generate really
+ // big tables. Ideally in that case we generate a map lookup
+ // instead, but for the moment we simply don't output a table at all.
+ auto range = enum_def.Distance();
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const uint64_t kMaxSparseness = 5;
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ GeneratePropertyOneLine(writer, "names", "Array<String>",
+ [&](){
+ writer += "arrayOf(\\";
+ auto val = enum_def.Vals().front();
+ for (auto it = vals.begin(); it != vals.end(); ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+ writer += "\"\", \\";
+ val = ev;
+ writer += "\"" + (*it)->name + "\"\\";
+ if (it+1 != vals.end()) {
+ writer += ", \\";
+ }
+ }
+ writer += ")";
+ });
+ GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){
+ writer += "names[e\\";
+ if (enum_def.MinValue()->IsNonZero())
+ writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
+ writer += "]";
+ });
+ }
+ });
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string ByteBufferGetter(const Type &type, std::string bb_var_name) const {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING:
+ return "__string";
+ case BASE_TYPE_STRUCT:
+ return "__struct";
+ case BASE_TYPE_UNION:
+ return "__union";
+ case BASE_TYPE_VECTOR:
+ return ByteBufferGetter(type.VectorType(), bb_var_name);
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ return bb_var_name + ".getInt";
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT:
+ return bb_var_name + ".getShort";
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_LONG:
+ return bb_var_name + ".getLong";
+ case BASE_TYPE_FLOAT:
+ return bb_var_name + ".getFloat";
+ case BASE_TYPE_DOUBLE:
+ return bb_var_name + ".getDouble";
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE:
+ return bb_var_name + ".get";
+ case BASE_TYPE_BOOL:
+ return "0.toByte() != " + bb_var_name + ".get";
+ default:
+ return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
+ }
+ }
+
+ std::string ByteBufferSetter(const Type &type) const {
+ if (IsScalar(type.base_type)) {
+ switch (type.base_type) {
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ return "bb.putInt";
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT:
+ return "bb.putShort";
+ case BASE_TYPE_ULONG:
+ case BASE_TYPE_LONG:
+ return "bb.putLong";
+ case BASE_TYPE_FLOAT:
+ return "bb.putFloat";
+ case BASE_TYPE_DOUBLE:
+ return "bb.putDouble";
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_BOOL:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE:
+ return "bb.put";
+ default:
+ return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
+ }
+ }
+ return "";
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
+ const std::string &bb_var_name,
+ const char *num = nullptr) const {
+ auto type = key_field->value.type;
+ return ByteBufferGetter(type, bb_var_name) + "(" + GenOffsetGetter(key_field, num) + ")";
+
+ }
+
+ // Returns the method name for use with add/put calls.
+ static std::string GenMethod(const Type &type) {
+ return IsScalar(type.base_type) ? ToSignedType(type)
+ : (IsStruct(type) ? "Struct" : "Offset");
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
+ const char *nameprefix) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure
+ // names don't clash, and to make it obvious these arguments are
+ // constructing a nested struct, prefix the name with the field
+ // name.
+ GenStructArgs(*field.value.type.struct_def, writer,
+ (nameprefix + (field.name + "_")).c_str());
+ } else {
+ writer += std::string(", ") + nameprefix + "\\";
+ writer += MakeCamel(field.name) + ": \\";
+ writer += GenTypeBasic(field.value.type.base_type) + "\\";
+ }
+ }
+ }
+
+ // Recusively generate struct construction statements of the form:
+ // builder.putType(name);
+ // and insert manual padding.
+ static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
+ const char *nameprefix) {
+ writer.SetValue("align", NumToString(struct_def.minalign));
+ writer.SetValue("size", NumToString(struct_def.bytesize));
+ writer += "builder.prep({{align}}, {{size}})";
+ auto fields_vec = struct_def.fields.vec;
+ for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
+ auto &field = **it;
+
+ if (field.padding) {
+ writer.SetValue("pad", NumToString(field.padding));
+ writer += "builder.pad({{pad}})";
+ }
+ if (IsStruct(field.value.type)) {
+ GenStructBody(*field.value.type.struct_def, writer,
+ (nameprefix + (field.name + "_")).c_str());
+ } else {
+ writer.SetValue("type", GenMethod(field.value.type));
+ writer.SetValue("argname", nameprefix +
+ MakeCamel(field.name, false));
+ writer.SetValue("cast", CastToSigned(field.value.type));
+ writer += "builder.put{{type}}({{argname}}{{cast}})";
+ }
+ }
+ }
+
+ std::string GenByteBufferLength(const char *bb_name) const {
+ std::string bb_len = bb_name;
+ bb_len += ".capacity()";
+ return bb_len;
+ }
+
+ std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+ const char *num = nullptr) const {
+ std::string key_offset = "__offset(" +
+ NumToString(key_field->value.offset) + ", ";
+ if (num) {
+ key_offset += num;
+ key_offset += ", _bb)";
+ } else {
+ key_offset += GenByteBufferLength("bb");
+ key_offset += " - tableOffset, bb)";
+ }
+ return key_offset;
+ }
+
+ void GenStruct(StructDef &struct_def, CodeWriter &writer) const {
+ if (struct_def.generated) return;
+
+ GenerateComment(struct_def.doc_comment, writer, &comment_config);
+ auto fixed = struct_def.fixed;
+
+ writer.SetValue("struct_name", Esc(struct_def.name));
+ writer.SetValue("superclass", fixed ? "Struct" : "Table");
+
+ writer += "@Suppress(\"unused\")";
+ writer += "@ExperimentalUnsignedTypes";
+ writer += "class {{struct_name}} : {{superclass}}() {\n";
+
+ writer.IncrementIdentLevel();
+
+ {
+ // Generate the __init() method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", [&]() {
+ writer += "__reset(_i, _bb)";
+ });
+
+ // Generate assign method
+ GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
+ Esc(struct_def.name), [&]() {
+ writer += "__init(_i, _bb)";
+ writer += "return this";
+ });
+
+ // Generate all getters
+ GenerateStructGetters(struct_def, writer);
+
+ // Generate Static Fields
+ GenerateCompanionObject(writer, [&](){
+
+ if (!struct_def.fixed) {
+ FieldDef *key_field = nullptr;
+
+ // Generate verson check method.
+ // Force compile time error if not using the same version
+ // runtime.
+ GenerateFunOneLine(writer, "validateVersion", "", "", [&](){
+ writer += "Constants.FLATBUFFERS_1_11_1()";
+ });
+
+ GenerateGetRootAsAccessors(Esc(struct_def.name), writer);
+ GenerateBufferHasIdentifier(struct_def, writer);
+ GenerateTableCreator(struct_def, writer);
+
+ GenerateStartStructMethod(struct_def, writer);
+
+ // Static Add for fields
+ auto fields = struct_def.fields.vec;
+ int field_pos = -1;
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ auto &field = **it;
+ field_pos++;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+ GenerateAddField(NumToString(field_pos), field, writer);
+
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ auto vector_type = field.value.type.VectorType();
+ if (!IsStruct(vector_type)) {
+ GenerateCreateVectorField(field, writer);
+ }
+ GenerateStartVectorField(field, writer);
+ }
+ }
+
+ GenerateEndStructMethod(struct_def, writer);
+ auto file_identifier = parser_.file_identifier_;
+ if (parser_.root_struct_def_ == &struct_def) {
+ GenerateFinishStructBuffer(struct_def,
+ file_identifier,
+ writer);
+ GenerateFinishSizePrefixed(struct_def,
+ file_identifier,
+ writer);
+ }
+
+ if (struct_def.has_key) {
+ GenerateLookupByKey(key_field, struct_def, writer);
+ }
+ } else {
+ GenerateStaticConstructor(struct_def, writer);
+ }
+ });
+ }
+
+ // class closing
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ // TODO: move key_field to reference instead of pointer
+ void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
+ CodeWriter &writer) const {
+ std::stringstream params;
+ params << "obj: " << Esc(struct_def.name) << "?" << ", ";
+ params << "vectorLocation: Int, ";
+ params << "key: " << GenTypeGet(key_field->value.type) << ", ";
+ params << "bb: ByteBuffer";
+
+ auto statements = [&]() {
+ auto base_type = key_field->value.type.base_type;
+ writer.SetValue("struct_name", Esc(struct_def.name));
+ if (base_type == BASE_TYPE_STRING) {
+ writer += "val byteKey = key."
+ "toByteArray(Table.UTF8_CHARSET.get()!!)";
+ }
+ writer += "var span = bb.getInt(vectorLocation - 4)";
+ writer += "var start = 0";
+ writer += "while (span != 0) {";
+ writer.IncrementIdentLevel();
+ writer += "var middle = span / 2";
+ writer += "val tableOffset = __indirect(vector"
+ "Location + 4 * (start + middle), bb)";
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ writer += "val comp = compareStrings(\\";
+ writer += GenOffsetGetter(key_field) + "\\";
+ writer += ", byteKey, bb)";
+ } else {
+ auto cast = CastToUsigned(key_field->value.type);
+ auto get_val = GenLookupByKey(key_field, "bb");
+ writer += "val value = " + get_val + cast;
+ writer += "val comp = value.compareTo(key)";
+ }
+ writer += "when {";
+ writer.IncrementIdentLevel();
+ writer += "comp > 0 -> span = middle";
+ writer += "comp < 0 -> {";
+ writer.IncrementIdentLevel();
+ writer += "middle++";
+ writer += "start += middle";
+ writer += "span -= middle";
+ writer.DecrementIdentLevel();
+ writer += "}"; // end comp < 0
+ writer += "else -> {";
+ writer.IncrementIdentLevel();
+ writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
+ writer.DecrementIdentLevel();
+ writer += "}"; // end else
+ writer.DecrementIdentLevel();
+ writer += "}"; // end when
+ writer.DecrementIdentLevel();
+ writer += "}"; // end while
+ writer += "return null";
+ };
+ GenerateFun(writer, "__lookup_by_key",
+ params.str(),
+ Esc(struct_def.name) + "?",
+ statements);
+ }
+
+ void GenerateFinishSizePrefixed(StructDef &struct_def,
+ const std::string &identifier,
+ CodeWriter &writer) const {
+ auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
+ auto params = "builder: FlatBufferBuilder, offset: Int";
+ auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
+ GenerateFunOneLine(writer, method_name, params, "", [&]() {
+ writer += "builder.finishSizePrefixed(offset" + id + ")";
+ });
+ }
+ void GenerateFinishStructBuffer(StructDef &struct_def,
+ const std::string &identifier,
+ CodeWriter &writer) const {
+ auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : "";
+ auto params = "builder: FlatBufferBuilder, offset: Int";
+ auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
+ GenerateFunOneLine(writer, method_name, params, "", [&]() {
+ writer += "builder.finish(offset" + id + ")";
+ });
+ }
+
+ void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer) const {
+ // Generate end{{TableName}}(builder: FlatBufferBuilder) method
+ auto name = "end" + Esc(struct_def.name);
+ auto params = "builder: FlatBufferBuilder";
+ auto returns = "Int";
+ auto field_vec = struct_def.fields.vec;
+
+ GenerateFun(writer, name, params, returns, [&](){
+ writer += "val o = builder.endTable()";
+ writer.IncrementIdentLevel();
+ for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated || !field.required) {
+ continue;
+ }
+ writer.SetValue("offset", NumToString(field.value.offset));
+ writer += "builder.required(o, {{offset}})";
+ }
+ writer.DecrementIdentLevel();
+ writer += "return o";
+ });
+ }
+
+ // Generate a method to create a vector from a Kotlin array.
+ void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer) const {
+ auto vector_type = field.value.type.VectorType();
+ auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
+ auto params = "builder: FlatBufferBuilder, data: " +
+ GenTypeBasic(vector_type.base_type) + "Array";
+ writer.SetValue("size", NumToString(InlineSize(vector_type)));
+ writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+ writer.SetValue("root", GenMethod(vector_type));
+ writer.SetValue("cast", CastToSigned(vector_type));
+
+ GenerateFun(writer, method_name, params, "Int", [&](){
+ writer += "builder.startVector({{size}}, data.size, {{align}})";
+ writer += "for (i in data.size - 1 downTo 0) {";
+ writer.IncrementIdentLevel();
+ writer += "builder.add{{root}}(data[i]{{cast}})";
+ writer.DecrementIdentLevel();
+ writer += "}";
+ writer += "return builder.endVector()";
+ });
+ }
+
+ void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const {
+ // Generate a method to start a vector, data to be added manually
+ // after.
+ auto vector_type = field.value.type.VectorType();
+ auto params = "builder: FlatBufferBuilder, numElems: Int";
+ writer.SetValue("size", NumToString(InlineSize(vector_type)));
+ writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+
+ GenerateFunOneLine(writer,
+ "start" + MakeCamel(Esc(field.name) + "Vector", true),
+ params,
+ "",
+ [&]() {
+ writer += "builder.startVector({{size}}, numElems, {{align}})";
+ });
+ }
+
+ void GenerateAddField(std::string field_pos, FieldDef &field,
+ CodeWriter &writer) const {
+ auto field_type = GenTypeBasic(field.value.type.base_type);
+ auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
+ GenerateFunOneLine(writer, "add" + MakeCamel(Esc(field.name), true),
+ "builder: FlatBufferBuilder, " + secondArg, "", [&](){
+ auto method = GenMethod(field.value.type);
+ writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
+ writer.SetValue("method_name", method);
+ writer.SetValue("pos", field_pos);
+ writer.SetValue("default", GenFBBDefaultValue(field));
+ writer.SetValue("cast", GenFBBValueCast(field));
+
+ writer += "builder.add{{method_name}}({{pos}}, \\";
+ writer += "{{field_name}}{{cast}}, {{default}})";
+ });
+ }
+
+ static std::string ToSignedType(const Type & type) {
+ switch(type.base_type) {
+ case BASE_TYPE_UINT:
+ return GenTypeBasic(BASE_TYPE_INT);
+ case BASE_TYPE_ULONG:
+ return GenTypeBasic(BASE_TYPE_LONG);
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_NONE:
+ case BASE_TYPE_UTYPE:
+ return GenTypeBasic(BASE_TYPE_CHAR);
+ case BASE_TYPE_USHORT:
+ return GenTypeBasic(BASE_TYPE_SHORT);
+ case BASE_TYPE_VECTOR:
+ return ToSignedType(type.VectorType());
+ default:
+ return GenTypeBasic(type.base_type);
+ }
+ }
+
+ static std::string FlexBufferBuilderCast(const std::string &method,
+ FieldDef &field,
+ bool isFirst) {
+ auto field_type = GenTypeBasic(field.value.type.base_type);
+ std::string to_type;
+ if (method == "Boolean")
+ to_type = "Boolean";
+ else if (method == "Long")
+ to_type = "Long";
+ else if (method == "Int" || method == "Offset" || method == "Struct")
+ to_type = "Int";
+ else if (method == "Byte" || method.empty())
+ to_type = isFirst ? "Byte" : "Int";
+ else if (method == "Short")
+ to_type = isFirst ? "Short" : "Int";
+ else if (method == "Double")
+ to_type = "Double";
+ else if (method == "Float")
+ to_type = isFirst ? "Float" : "Double";
+ else if (method == "UByte")
+
+ if (field_type != to_type)
+ return ".to" + to_type + "()";
+ return "";
+ }
+
+ // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
+ void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code) const {
+ GenerateFunOneLine(code, "start" + Esc(struct_def.name),
+ "builder: FlatBufferBuilder", "", [&] () {
+ code += "builder.startTable("+ NumToString(struct_def.fields.vec.size()) + ")";
+ });
+ }
+
+ void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer) const {
+ // Generate a method that creates a table in one go. This is only possible
+ // when the table has no struct fields, since those have to be created
+ // inline, and there's no way to do so in Java.
+ bool has_no_struct_fields = true;
+ int num_fields = 0;
+ auto fields_vec = struct_def.fields.vec;
+
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (IsStruct(field.value.type)) {
+ has_no_struct_fields = false;
+ } else {
+ num_fields++;
+ }
+ }
+ // JVM specifications restrict default constructor params to be < 255.
+ // Longs and doubles take up 2 units, so we set the limit to be < 127.
+ if (has_no_struct_fields && num_fields && num_fields < 127) {
+ // Generate a table constructor of the form:
+ // public static int createName(FlatBufferBuilder builder, args...)
+
+ auto name = "create" + Esc(struct_def.name);
+ std::stringstream params;
+ params << "builder: FlatBufferBuilder";
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ params << ", " << MakeCamel(Esc(field.name), false);
+ if (!IsScalar(field.value.type.base_type)){
+ params << "Offset: ";
+ } else {
+ params << ": ";
+ }
+ params << GenTypeBasic(field.value.type.base_type);
+ }
+
+ GenerateFun(writer, name, params.str(), "Int", [&]() {
+ writer.SetValue("vec_size", NumToString(fields_vec.size()));
+
+ writer += "builder.startTable({{vec_size}})";
+
+ auto sortbysize = struct_def.sortbysize;
+ auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
+ for (size_t size = largest; size; size /= 2) {
+ for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
+ ++it) {
+ auto &field = **it;
+ auto base_type_size = SizeOf(field.value.type.base_type);
+ if (!field.deprecated &&
+ (!sortbysize || size == base_type_size)) {
+ writer.SetValue("camel_field_name",
+ MakeCamel(Esc(field.name), true));
+ writer.SetValue("field_name",
+ MakeCamel(Esc(field.name), false));
+
+ writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
+ if (!IsScalar(field.value.type.base_type)){
+ writer += "Offset\\";
+ }
+ writer += ")";
+ }
+ }
+ }
+ writer += "return end{{struct_name}}(builder)";
+ });
+ }
+
+ }
+ void GenerateBufferHasIdentifier(StructDef &struct_def,
+ CodeWriter &writer) const {
+ auto file_identifier = parser_.file_identifier_;
+ // Check if a buffer has the identifier.
+ if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
+ return;
+ auto name = MakeCamel(Esc(struct_def.name), false);
+ GenerateFunOneLine(writer, name + "BufferHasIdentifier",
+ "_bb: ByteBuffer",
+ "Boolean",
+ [&]() {
+ writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
+ });
+ }
+
+ void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
+ auto fields_vec = struct_def.fields.vec;
+ FieldDef *key_field = nullptr;
+ for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.key) key_field = &field;
+
+ GenerateComment(field.doc_comment, writer, &comment_config);
+
+ auto field_name = MakeCamel(Esc(field.name), false);
+ auto field_type = GenTypeGet(field.value.type);
+ auto field_default_value = GenDefaultValue(field);
+ auto return_type = GenTypeGet(field.value.type);
+ auto bbgetter = ByteBufferGetter(field.value.type, "bb");
+ auto ucast = CastToUsigned(field);
+ auto offset_val = NumToString(field.value.offset);
+ auto offset_prefix = "val o = __offset(" + offset_val
+ + "); return o != 0 ? ";
+ auto value_base_type = field.value.type.base_type;
+ // Most field accessors need to retrieve and test the field offset
+ // first, this is the offset value for that:
+ writer.SetValue("offset", NumToString(field.value.offset));
+ writer.SetValue("return_type", return_type);
+ writer.SetValue("field_type", field_type);
+ writer.SetValue("field_name", field_name);
+ writer.SetValue("field_default", field_default_value);
+ writer.SetValue("bbgetter", bbgetter);
+ writer.SetValue("ucast", ucast);
+
+ auto opt_ret_type = return_type + "?";
+ // Generate the accessors that don't do object reuse.
+ if (value_base_type == BASE_TYPE_STRUCT) {
+ // Calls the accessor that takes an accessor object with a
+ // new object.
+ // val pos
+ // get() = pos(Vec3())
+ GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){
+ writer += "{{field_name}}({{field_type}}())";
+ });
+ } else if (value_base_type == BASE_TYPE_VECTOR &&
+ field.value.type.element == BASE_TYPE_STRUCT) {
+ // Accessors for vectors of structs also take accessor objects,
+ // this generates a variant without that argument.
+ // ex: fun weapons(j: Int) = weapons(Weapon(), j)
+ GenerateFunOneLine(writer, field_name, "j: Int", opt_ret_type, [&](){
+ writer += "{{field_name}}({{return_type}}(), j)";
+ });
+ }
+
+ if (IsScalar(value_base_type)) {
+ if (struct_def.fixed) {
+ GenerateGetterOneLine(writer, field_name, return_type, [&](){
+ writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
+ });
+ } else {
+ GenerateGetter(writer, field_name, return_type, [&](){
+ writer += "val o = __offset({{offset}})";
+ writer += "return if(o != 0) {{bbgetter}}"
+ "(o + bb_pos){{ucast}} else "
+ "{{field_default}}";
+ });
+ }
+ } else {
+ switch (value_base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ // create getter with object reuse
+ // ex:
+ // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
+ // ? adds nullability annotation
+ GenerateFunOneLine(writer,
+ field_name, "obj: " + field_type ,
+ return_type + "?", [&](){
+ writer += "obj.__assign(bb_pos + {{offset}}, bb)";
+ });
+ } else {
+ // create getter with object reuse
+ // ex:
+ // fun pos(obj: Vec3) : Vec3? {
+ // val o = __offset(4)
+ // return if(o != 0) {
+ // obj.__assign(o + bb_pos, bb)
+ // else {
+ // null
+ // }
+ // }
+ // ? adds nullability annotation
+ GenerateFun(writer, field_name, "obj: " + field_type,
+ return_type + "?", [&](){
+ auto fixed = field.value.type.struct_def->fixed;
+
+ writer.SetValue("seek", Indirect("o + bb_pos", fixed));
+ OffsetWrapper(writer,
+ offset_val,
+ [&]() { writer += "obj.__assign({{seek}}, bb)"; },
+ [&]() { writer += "null"; });
+ });
+ }
+ break;
+ case BASE_TYPE_STRING:
+ // create string getter
+ // e.g.
+ // val Name : String?
+ // get() = {
+ // val o = __offset(10)
+ // return if (o != 0) __string(o + bb_pos) else null
+ // }
+ // ? adds nullability annotation
+ GenerateGetter(writer, field_name, return_type + "?", [&](){
+
+ writer += "val o = __offset({{offset}})";
+ writer += "return if (o != 0) __string(o + bb_pos) else null";
+ });
+ break;
+ case BASE_TYPE_VECTOR: {
+ // e.g.
+ // fun inventory(j: Int) : UByte {
+ // val o = __offset(14)
+ // return if (o != 0) {
+ // bb.get(__vector(o) + j * 1).toUByte()
+ // } else {
+ // 0
+ // }
+ // }
+
+ auto vectortype = field.value.type.VectorType();
+ std::string params = "j: Int";
+ std::string nullable = IsScalar(vectortype.base_type) ? ""
+ : "?";
+
+ if (vectortype.base_type == BASE_TYPE_STRUCT ||
+ vectortype.base_type == BASE_TYPE_UNION) {
+ params = "obj: " + field_type + ", j: Int";
+ }
+
+
+ writer.SetValue("toType", "YYYYY");
+
+ auto ret_type = return_type + nullable;
+ GenerateFun(writer, field_name, params, ret_type, [&](){
+ auto inline_size = NumToString(InlineSize(vectortype));
+ auto index = "__vector(o) + j * " + inline_size;
+ auto not_found = NotFoundReturn(field.value.type.element);
+ auto found = "";
+ writer.SetValue("index", index);
+ switch(vectortype.base_type) {
+ case BASE_TYPE_STRUCT: {
+ bool fixed = vectortype.struct_def->fixed;
+ writer.SetValue("index", Indirect(index, fixed));
+ found = "obj.__assign({{index}}, bb)";
+ break;
+ }
+ case BASE_TYPE_UNION:
+ found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
+ break;
+ default:
+ found = "{{bbgetter}}({{index}}){{ucast}}";
+ }
+ OffsetWrapper(writer, offset_val,
+ [&]() { writer += found; } ,
+ [&]() { writer += not_found; });
+ });
+ break;
+ }
+ case BASE_TYPE_UNION:
+ GenerateFun(writer, field_name, "obj: " + field_type,
+ return_type + "?", [&](){
+ writer += OffsetWrapperOneLine(offset_val,
+ bbgetter + "(obj, o)",
+ "null");
+ });
+ break;
+ default:
+ FLATBUFFERS_ASSERT(0);
+ }
+ }
+
+ if (value_base_type == BASE_TYPE_VECTOR) {
+ // Generate Lenght functions for vectors
+ GenerateGetter(writer, field_name + "Length", "Int", [&](){
+ writer += OffsetWrapperOneLine(offset_val,
+ "__vector_len(o)", "0");
+ });
+
+ // See if we should generate a by-key accessor.
+ if (field.value.type.element == BASE_TYPE_STRUCT &&
+ !field.value.type.struct_def->fixed) {
+ auto &sd = *field.value.type.struct_def;
+ auto &fields = sd.fields.vec;
+ for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+ auto &kfield = **kit;
+ if (kfield.key) {
+ auto qualified_name = WrapInNameSpace(sd);
+ auto name = MakeCamel(Esc(field.name), false) + "ByKey";
+ auto params = "key: " + GenTypeGet(kfield.value.type);
+ auto rtype = qualified_name + "?";
+ GenerateFun(writer, name, params, rtype, [&] () {
+ OffsetWrapper(writer, offset_val,
+ [&] () {
+ writer += qualified_name +
+ ".__lookup_by_key(null, __vector(o), key, bb)";
+ },
+ [&] () {
+ writer += "null";
+ });
+ });
+
+ auto param2 = "obj: " + qualified_name +
+ ", key: " +
+ GenTypeGet(kfield.value.type);
+ GenerateFun(writer, name, param2, rtype, [&](){
+ OffsetWrapper(writer, offset_val,
+ [&] () {
+ writer += qualified_name +
+ ".__lookup_by_key(obj, __vector(o), key, bb)";
+ },
+ [&]() { writer += "null"; });
+ });
+
+ break;
+ }
+ }
+ }
+ }
+
+ if ((value_base_type == BASE_TYPE_VECTOR &&
+ IsScalar(field.value.type.VectorType().base_type)) ||
+ value_base_type == BASE_TYPE_STRING) {
+
+ auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
+ ? 1
+ : InlineSize(field.value.type.VectorType()));
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ // e.g.
+ // val inventoryByteBuffer: ByteBuffer
+ // get = __vector_as_bytebuffer(14, 1)
+
+ GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
+ "ByteBuffer", [&](){
+ writer.SetValue("end", end_idx);
+ writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
+ });
+
+ // Generate a ByteBuffer accessor for strings & vectors of scalars.
+ // e.g.
+ // fun inventoryInByteBuffer(_bb: Bytebuffer):
+ // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
+ GenerateFunOneLine(writer, field_name + "InByteBuffer",
+ "_bb: ByteBuffer", "ByteBuffer", [&](){
+ writer.SetValue("end", end_idx);
+ writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
+ });
+ }
+
+ // generate object accessors if is nested_flatbuffer
+ //fun testnestedflatbufferAsMonster() : Monster?
+ //{ return testnestedflatbufferAsMonster(new Monster()); }
+
+ if (field.nested_flatbuffer) {
+ auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+ auto nested_method_name =
+ field_name + "As" +
+ field.nested_flatbuffer->name;
+
+ GenerateGetterOneLine(writer,
+ nested_method_name,
+ nested_type_name + "?", [&](){
+ writer += nested_method_name + "(" + nested_type_name + "())";
+ });
+
+ GenerateFun(writer,
+ nested_method_name,
+ "obj: " + nested_type_name,
+ nested_type_name + "?", [&](){
+ OffsetWrapper(writer, offset_val,
+ [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; },
+ [&]() { writer += "null";});
+ });
+ }
+
+ // Generate mutators for scalar fields or vectors of scalars.
+ if (parser_.opts.mutable_buffer) {
+ auto value_type = field.value.type;
+ auto underlying_type = value_base_type == BASE_TYPE_VECTOR
+ ? value_type.VectorType()
+ : value_type;
+ auto name = "mutate" + MakeCamel(Esc(field.name), true);
+ auto size = NumToString(InlineSize(underlying_type));
+ auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
+ // A vector mutator also needs the index of the vector element it should
+ // mutate.
+ if (value_base_type == BASE_TYPE_VECTOR)
+ params.insert(0, "j: Int, ");
+
+ // Boolean parameters have to be explicitly converted to byte
+ // representation.
+ auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+ ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
+ : Esc(field.name);
+
+ auto setter_index = value_base_type == BASE_TYPE_VECTOR
+ ? "__vector(o) + j * " + size
+ : (struct_def.fixed
+ ? "bb_pos + " + offset_val
+ : "o + bb_pos");
+ if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
+ IsScalar(value_type.VectorType().base_type))) {
+
+ auto statements = [&] () {
+ writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
+ writer.SetValue("index", setter_index);
+ writer.SetValue("params", setter_parameter);
+ writer.SetValue("cast", CastToSigned(field));
+ if (struct_def.fixed) {
+ writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+ } else {
+ OffsetWrapper(writer, offset_val, [&](){
+ writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+ writer += "true";
+ }, [&](){ writer += "false";});
+ }
+ };
+
+ if (struct_def.fixed) {
+ GenerateFunOneLine(writer, name, params, "ByteBuffer",
+ statements);
+ } else {
+ GenerateFun(writer, name, params, "Boolean",
+ statements);
+ }
+ }
+ }
+ }
+ if (struct_def.has_key && !struct_def.fixed) {
+ // Key Comparison method
+ GenerateOverrideFun(
+ writer,
+ "keysCompare",
+ "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() {
+ if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+ writer.SetValue("offset", NumToString(key_field->value.offset));
+ writer += " return compareStrings(__offset({{offset}}, o1, "
+ "_bb), __offset({{offset}}, o2, _bb), _bb)";
+
+ } else {
+ auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
+ auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
+ writer += "val val_1 = " + getter1;
+ writer += "val val_2 = " + getter2;
+ writer += "return (val_1 - val_2).sign";
+ }
+ });
+ }
+ }
+
+ static std::string CastToUsigned(const FieldDef &field) {
+ return CastToUsigned(field.value.type);
+ }
+
+ static std::string CastToUsigned(const Type type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT:
+ return ".toUInt()";
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE:
+ return ".toUByte()";
+ case BASE_TYPE_USHORT:
+ return ".toUShort()";
+ case BASE_TYPE_ULONG:
+ return ".toULong()";
+ case BASE_TYPE_VECTOR:
+ return CastToUsigned(type.VectorType());
+ default:
+ return "";
+ }
+ }
+
+ static std::string CastToSigned(const FieldDef &field) {
+ return CastToSigned(field.value.type);
+ }
+
+ static std::string CastToSigned(const Type type) {
+ switch (type.base_type) {
+ case BASE_TYPE_UINT:
+ return ".toInt()";
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE:
+ return ".toByte()";
+ case BASE_TYPE_USHORT:
+ return ".toShort()";
+ case BASE_TYPE_ULONG:
+ return ".toLong()";
+ case BASE_TYPE_VECTOR:
+ return CastToSigned(type.VectorType());
+ default:
+ return "";
+ }
+ }
+
+ static std::string LiteralSuffix(const BaseType type) {
+ switch (type) {
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_UTYPE:
+ case BASE_TYPE_USHORT:
+ return "u";
+ case BASE_TYPE_ULONG:
+ return "UL";
+ case BASE_TYPE_LONG:
+ return "L";
+ default:
+ return "";
+ }
+ }
+
+ void GenerateCompanionObject(CodeWriter &code,
+ const std::function<void()> &callback) const {
+ code += "companion object {";
+ code.IncrementIdentLevel();
+ callback();
+ code.DecrementIdentLevel();
+ code += "}";
+ }
+
+ // Generate a documentation comment, if available.
+ void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
+ const CommentConfig *config) const {
+ if (dc.begin() == dc.end()) {
+ // Don't output empty comment blocks with 0 lines of comment content.
+ return;
+ }
+
+ if (config != nullptr && config->first_line != nullptr) {
+ writer += std::string(config->first_line);
+ }
+ std::string line_prefix =
+ ((config != nullptr && config->content_line_prefix != nullptr)
+ ? config->content_line_prefix
+ : "///");
+ for (auto it = dc.begin(); it != dc.end(); ++it) {
+ writer += line_prefix + *it;
+ }
+ if (config != nullptr && config->last_line != nullptr) {
+ writer += std::string(config->last_line);
+ }
+ }
+
+ static void GenerateGetRootAsAccessors(const std::string &struct_name,
+ CodeWriter &writer) {
+ // Generate a special accessor for the table that when used as the root
+ // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
+ writer.SetValue("gr_name", struct_name);
+ writer.SetValue("gr_method", "getRootAs" + struct_name);
+
+ // create convenience method that doesn't require an existing object
+ writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
+ writer += "{{gr_method}}(_bb, {{gr_name}}())";
+
+ // create method that allows object reuse
+ // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
+ writer += "fun {{gr_method}}"
+ "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
+ writer.IncrementIdentLevel();
+ writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
+ writer += "return (obj.__assign(_bb.getInt(_bb.position())"
+ " + _bb.position(), _bb))";
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ static void GenerateStaticConstructor(const StructDef &struct_def,
+ CodeWriter &code) {
+ // create a struct constructor function
+ auto params = StructConstructorParams(struct_def);
+ GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){
+ GenStructBody(struct_def, code, "");
+ code += "return builder.offset()";
+ });
+ }
+
+ static std::string StructConstructorParams(const StructDef &struct_def,
+ const std::string &prefix = "") {
+ //builder: FlatBufferBuilder
+ std::stringstream out;
+ auto field_vec = struct_def.fields.vec;
+ if (prefix.empty()) {
+ out << "builder: FlatBufferBuilder";
+ }
+ for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure
+ // names don't clash, and to make it obvious these arguments are
+ // constructing a nested struct, prefix the name with the field
+ // name.
+ out << StructConstructorParams(*field.value.type.struct_def,
+ prefix + (Esc(field.name) + "_"));
+ } else {
+ out << ", " << prefix << MakeCamel(Esc(field.name), false)
+ << ": "
+ << GenTypeBasic(field.value.type.base_type);
+ }
+ }
+ return out.str();
+ }
+
+ static void GeneratePropertyOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype = x
+ writer.SetValue("_name", name);
+ writer.SetValue("_type", type);
+ writer += "val {{_name}} : {{_type}} = \\";
+ body();
+ }
+ static void GenerateGetterOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype get() = x
+ writer.SetValue("_name", name);
+ writer.SetValue("_type", type);
+ writer += "val {{_name}} : {{_type}} get() = \\";
+ body();
+ }
+
+ static void GenerateGetter(CodeWriter &writer,
+ const std::string &name,
+ const std::string &type,
+ const std::function<void()> &body) {
+ // Generates Kotlin getter for properties
+ // e.g.:
+ // val prop: Mytype
+ // get() = {
+ // return x
+ // }
+ writer.SetValue("name", name);
+ writer.SetValue("type", type);
+ writer += "val {{name}} : {{type}}";
+ writer.IncrementIdentLevel();
+ writer += "get() {";
+ writer.IncrementIdentLevel();
+ body();
+ writer.DecrementIdentLevel();
+ writer += "}";
+ writer.DecrementIdentLevel();
+ }
+
+ static void GenerateFun(CodeWriter &writer,
+ const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::function<void()> &body) {
+ // Generates Kotlin function
+ // e.g.:
+ // fun path(j: Int): Vec3 {
+ // return path(Vec3(), j)
+ // }
+ auto noreturn = returnType.empty();
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
+ writer += "fun {{name}}({{params}}) {{return_type}} {";
+ writer.IncrementIdentLevel();
+ body();
+ writer.DecrementIdentLevel();
+ writer += "}";
+ }
+
+ static void GenerateFunOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::function<void()> &body) {
+ // Generates Kotlin function
+ // e.g.:
+ // fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type_p", returnType.empty() ? "" :
+ " : " + returnType);
+ writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
+ body();
+ }
+
+ static void GenerateOverrideFun(CodeWriter &writer,
+ const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::function<void()> &body) {
+ // Generates Kotlin function
+ // e.g.:
+ // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer += "override \\";
+ GenerateFun(writer, name, params, returnType, body);
+ }
+
+ static void GenerateOverrideFunOneLine(CodeWriter &writer,
+ const std::string &name,
+ const std::string ¶ms,
+ const std::string &returnType,
+ const std::string &statement) {
+ // Generates Kotlin function
+ // e.g.:
+ // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+ writer.SetValue("name", name);
+ writer.SetValue("params", params);
+ writer.SetValue("return_type", returnType.empty() ? "" :
+ " : " + returnType);
+ writer += "override fun {{name}}({{params}}){{return_type}} = \\";
+ writer += statement;
+ }
+
+ static std::string OffsetWrapperOneLine(const std::string &offset,
+ const std::string &found,
+ const std::string ¬_found) {
+ return "val o = __offset(" + offset + "); return if (o != 0) " + found +
+ " else " + not_found;
+ }
+
+ static void OffsetWrapper(CodeWriter &code,
+ const std::string &offset,
+ const std::function<void()> &found,
+ const std::function<void()> ¬_found) {
+ code += "val o = __offset(" + offset + ")";
+ code +="return if (o != 0) {";
+ code.IncrementIdentLevel();
+ found();
+ code.DecrementIdentLevel();
+ code += "} else {";
+ code.IncrementIdentLevel();
+ not_found();
+ code.DecrementIdentLevel();
+ code += "}";
+ }
+
+ static std::string Indirect(const std::string &index, bool fixed) {
+ // We apply __indirect() and struct is not fixed.
+ if (!fixed)
+ return "__indirect(" + index + ")";
+ return index;
+ }
+
+ static std::string NotFoundReturn(BaseType el) {
+ switch (el) {
+ case BASE_TYPE_FLOAT:
+ return "0.0f";
+ case BASE_TYPE_DOUBLE:
+ return "0.0";
+ case BASE_TYPE_BOOL:
+ return "false";
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_INT:
+ case BASE_TYPE_CHAR:
+ case BASE_TYPE_SHORT:
+ return "0";
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_UCHAR:
+ case BASE_TYPE_USHORT:
+ case BASE_TYPE_UTYPE:
+ return "0u";
+ case BASE_TYPE_ULONG:
+ return "0uL";
+ default:
+ return "null";
+ }
+ }
+
+ // This tracks the current namespace used to determine if a type need to be
+ // prefixed by its namespace
+ const Namespace *cur_name_space_;
+};
+} // namespace kotlin
+
+bool GenerateKotlin(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ kotlin::KotlinGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/src/idl_gen_lobster.cpp b/src/idl_gen_lobster.cpp
new file mode 100644
index 0000000..ef9e474
--- /dev/null
+++ b/src/idl_gen_lobster.cpp
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <unordered_set>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace lobster {
+
+class LobsterGenerator : public BaseGenerator {
+ public:
+ LobsterGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */, "_") {
+ static const char * const keywords[] = {
+ "nil", "true", "false", "return", "struct", "class", "import", "int",
+ "float", "string", "any", "def", "is", "from", "program", "private",
+ "coroutine", "resource", "enum", "typeof", "var", "let", "pakfile",
+ "switch", "case", "default", "namespace", "not", "and", "or", "bool",
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string NormalizedName(const Definition &definition) const {
+ return EscapeKeyword(definition.name);
+ }
+
+ std::string NormalizedName(const EnumVal &ev) const {
+ return EscapeKeyword(ev.name);
+ }
+
+ std::string NamespacedName(const Definition &def) {
+ return WrapInNameSpace(def.defined_namespace, NormalizedName(def));
+ }
+
+ std::string GenTypeName(const Type &type) {
+ auto bits = NumToString(SizeOf(type.base_type) * 8);
+ if (IsInteger(type.base_type)) return "int" + bits;
+ if (IsFloat(type.base_type)) return "float" + bits;
+ if (type.base_type == BASE_TYPE_STRING) return "string";
+ if (type.base_type == BASE_TYPE_STRUCT) return "table";
+ return "none";
+ }
+
+ std::string LobsterType(const Type &type) {
+ if (IsFloat(type.base_type)) return "float";
+ if (IsScalar(type.base_type) && type.enum_def) return NormalizedName(*type.enum_def);
+ if (!IsScalar(type.base_type)) return "flatbuffers_offset";
+ return "int";
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const Type &type) {
+ return IsScalar(type.base_type)
+ ? MakeCamel(GenTypeBasic(type))
+ : (IsStruct(type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ // This uses Python names for now..
+ std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+ return ctypename[type.base_type];
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, " ");
+ std::string &code = *code_ptr;
+ auto offsets = NumToString(field.value.offset);
+ auto def = " def " + NormalizedName(field);
+ if (IsScalar(field.value.type.base_type)) {
+ std::string acc;
+ if (struct_def.fixed) {
+ acc = "buf_.read_" + GenTypeName(field.value.type) +
+ "_le(pos_ + " + offsets + ")";
+
+ } else {
+ acc = "buf_.flatbuffers_field_" +
+ GenTypeName(field.value.type) + "(pos_, " + offsets + ", " +
+ field.value.constant + ")";
+ }
+ if (field.value.type.enum_def)
+ acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")";
+ code += def + "():\n return " + acc + "\n";
+ return;
+ }
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT: {
+ auto name = NamespacedName(*field.value.type.struct_def);
+ code += def + "():\n ";
+ if (struct_def.fixed) {
+ code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n";
+ } else {
+ code += std::string("let o = buf_.flatbuffers_field_") +
+ (field.value.type.struct_def->fixed ? "struct" : "table") +
+ "(pos_, " + offsets + ")\n return if o: " + name +
+ " { buf_, o } else: nil\n";
+ }
+ break;
+ }
+ case BASE_TYPE_STRING:
+ code += def + "():\n return buf_.flatbuffers_field_string(pos_, " +
+ offsets + ")\n";
+ break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ code += def + "(i:int):\n return ";
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets +
+ ") + i * " + NumToString(InlineSize(vectortype));
+ if (!(vectortype.struct_def->fixed)) {
+ start = "buf_.flatbuffers_indirect(" + start + ")";
+ }
+ code += NamespacedName(*field.value.type.struct_def) + " { buf_, " +
+ start + " }\n";
+ } else {
+ if (vectortype.base_type == BASE_TYPE_STRING)
+ code += "buf_.flatbuffers_string";
+ else
+ code += "buf_.read_" + GenTypeName(vectortype) + "_le";
+ code += "(buf_.flatbuffers_field_vector(pos_, " + offsets +
+ ") + i * " + NumToString(InlineSize(vectortype)) + ")\n";
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: {
+ for (auto it = field.value.type.enum_def->Vals().begin();
+ it != field.value.type.enum_def->Vals().end(); ++it) {
+ auto &ev = **it;
+ if (ev.IsNonZero()) {
+ code += def + "_as_" + ev.name + "():\n return " +
+ NamespacedName(*ev.union_type.struct_def) +
+ " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets +
+ ") }\n";
+ }
+ }
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code += def +
+ "_length():\n return buf_.flatbuffers_field_vector_len(pos_, " +
+ offsets + ")\n";
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "struct " + NormalizedName(struct_def) +
+ "Builder:\n b_:flatbuffers_builder\n";
+ code += " def start():\n b_.StartObject(" +
+ NumToString(struct_def.fields.vec.size()) + ")\n return this\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ auto offset = it - struct_def.fields.vec.begin();
+ code += " def add_" + NormalizedName(field) + "(" +
+ NormalizedName(field) + ":" + LobsterType(field.value.type) +
+ "):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" +
+ NumToString(offset) + ", " + NormalizedName(field);
+ if (IsScalar(field.value.type.base_type))
+ code += ", " + field.value.constant;
+ code += ")\n return this\n";
+ }
+ code += " def end():\n return b_.EndObject()\n\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ code += "def " + NormalizedName(struct_def) + "Start" +
+ MakeCamel(NormalizedName(field)) +
+ "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size) + ", n_, " + NumToString(alignment) +
+ ")\n";
+ if (vector_type.base_type != BASE_TYPE_STRUCT ||
+ !vector_type.struct_def->fixed) {
+ code += "def " + NormalizedName(struct_def) + "Create" +
+ MakeCamel(NormalizedName(field)) +
+ "Vector(b_:flatbuffers_builder, v_:[" +
+ LobsterType(vector_type) + "]):\n b_.StartVector(" +
+ NumToString(elem_size) + ", v_.length, " +
+ NumToString(alignment) +
+ ")\n reverse(v_) e_: b_.Prepend" +
+ GenMethod(vector_type) +
+ "(e_)\n return b_.EndVector(v_.length)\n";
+ }
+ code += "\n";
+ }
+ }
+ }
+
+ void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+ CheckNameSpace(struct_def, &code);
+ code += "class " + NormalizedName(struct_def) + "\n\n";
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+ std::string &code = *code_ptr;
+ CheckNameSpace(struct_def, &code);
+ GenComment(struct_def.doc_comment, code_ptr, nullptr, "");
+ code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+ code += "\n";
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ code += "def GetRootAs" + NormalizedName(struct_def) + "(buf:string): return " +
+ NormalizedName(struct_def) +
+ " { buf, buf.flatbuffers_indirect(0) }\n\n";
+ }
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+ std::string &code = *code_ptr;
+ CheckNameSpace(enum_def, &code);
+ GenComment(enum_def.doc_comment, code_ptr, nullptr, "");
+ code += "enum " + NormalizedName(enum_def) + ":\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, " ");
+ code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " +
+ enum_def.ToString(ev) + "\n";
+ }
+ code += "\n";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += ", " + (nameprefix + NormalizedName(field)) + ":" +
+ LobsterType(field.value.type);
+ }
+ }
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " +
+ NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding)
+ code += " b_.Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ } else {
+ code += " b_.Prepend" + GenMethod(field.value.type) + "(" +
+ nameprefix + NormalizedName(field) + ")\n";
+ }
+ }
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "def Create" + NormalizedName(struct_def) +
+ "(b_:flatbuffers_builder";
+ StructBuilderArgs(struct_def, "", code_ptr);
+ code += "):\n";
+ StructBuilderBody(struct_def, "", code_ptr);
+ code += " return b_.Offset()\n\n";
+ }
+
+ void CheckNameSpace(const Definition &def, std::string *code_ptr) {
+ auto ns = GetNameSpace(def);
+ if (ns == current_namespace_) return;
+ current_namespace_ = ns;
+ std::string &code = *code_ptr;
+ code += "namespace " + ns + "\n\n";
+ }
+
+ bool generate() {
+ std::string code;
+ code += std::string("// ") + FlatBuffersGeneratedWarning() +
+ "\nimport flatbuffers\n\n";
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ GenEnum(enum_def, &code);
+ }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStructPreDecl(struct_def, &code);
+ }
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ GenStruct(struct_def, &code);
+ }
+ return SaveFile((path_ + file_name_ + "_generated.lobster").c_str(),
+ code, false);
+ }
+
+ private:
+ std::unordered_set<std::string> keywords_;
+ std::string current_namespace_;
+};
+
+} // namespace lobster
+
+bool GenerateLobster(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ lobster::LobsterGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp
new file mode 100644
index 0000000..10df231
--- /dev/null
+++ b/src/idl_gen_lua.cpp
@@ -0,0 +1,731 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ // independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+namespace lua {
+
+ // Hardcode spaces per indentation.
+ const CommentConfig def_comment = { nullptr, "--", nullptr };
+ const char * Indent = " ";
+ const char * Comment = "-- ";
+ const char * End = "end\n";
+ const char * EndFunc = "end\n";
+ const char * SelfData = "self.view";
+ const char * SelfDataPos = "self.view.pos";
+ const char * SelfDataBytes = "self.view.bytes";
+
+ class LuaGenerator : public BaseGenerator {
+ public:
+ LuaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */,
+ "" /* not used */) {
+ static const char * const keywords[] = {
+ "and",
+ "break",
+ "do",
+ "else",
+ "elseif",
+ "end",
+ "false",
+ "for",
+ "function",
+ "goto",
+ "if",
+ "in",
+ "local",
+ "nil",
+ "not",
+ "or",
+ "repeat",
+ "return",
+ "then",
+ "true",
+ "until",
+ "while"
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that.
+ std::string OffsetPrefix(const FieldDef &field) {
+ return std::string(Indent) +
+ "local o = " + SelfData + ":Offset(" + NumToString(field.value.offset) + ")\n" +
+ Indent + "if o ~= 0 then\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
+ code += "local " + NormalizedMetaName(struct_def) + " = {} -- the class metatable\n";
+ code += "\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + class_name + " = {\n";
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : "_" + name;
+ }
+
+ std::string NormalizedName(const Definition &definition) const {
+ return EscapeKeyword(definition.name);
+ }
+
+ std::string NormalizedName(const EnumVal &ev) const {
+ return EscapeKeyword(ev.name);
+ }
+
+ std::string NormalizedMetaName(const Definition &definition) const {
+ return EscapeKeyword(definition.name) + "_mt";
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + NormalizedName(ev) + " = " +
+ enum_def.ToString(ev) + ",\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ void GenerateNewObjectPrototype(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".New()\n";
+ code += std::string(Indent) + "local o = {}\n";
+ code += std::string(Indent) + "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) + "})\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".GetRootAs" + NormalizedName(struct_def) + "(buf, offset)\n";
+ code += std::string(Indent) + "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
+ code += std::string(Indent) + "local o = " + NormalizedName(struct_def) + ".New()\n";
+ code += std::string(Indent) + "o:Init(buf, n + offset)\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += "Init(buf, pos)\n";
+ code += std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
+ code += EndFunc;
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "Length()\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
+ code += std::string(Indent) + End;
+ code += std::string(Indent) + "return 0\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += std::string(Indent) + "return " + getter;
+ code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) + ")\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ getter += std::string("o + ") + SelfDataPos + ")";
+ auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
+ if (is_bool) {
+ getter = "(" + getter + " ~= 0)";
+ }
+ code += std::string(Indent) + Indent + "return " + getter + "\n";
+ code += std::string(Indent) + End;
+ std::string default_value;
+ if (is_bool) {
+ default_value = field.value.constant == "0" ? "false" : "true";
+ }
+ else {
+ default_value = field.value.constant;
+ }
+ code += std::string(Indent) + "return " + default_value + "\n";
+ code += EndFunc;
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(obj)\n";
+ code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " + SelfDataPos + " + ";
+ code += NumToString(field.value.offset) + ")\n";
+ code += std::string(Indent) + "return obj\n";
+ code += EndFunc;
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code += std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
+ }
+ else {
+ code += std::string(Indent) + Indent + "local x = " + SelfData + ":Indirect(o + " + SelfDataPos + ")\n";
+ }
+ code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
+ code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
+ code += std::string("o + ") + SelfDataPos + ")\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "()\n";
+ code += OffsetPrefix(field);
+
+ // TODO(rw): this works and is not the good way to it:
+ //bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+ //if (is_native_table) {
+ // code += std::string(Indent) + Indent + "from flatbuffers.table import Table\n";
+ //} else {
+ // code += std::string(Indent) + Indent +
+ // code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ //}
+ code += std::string(Indent) + Indent + "local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
+ code += std::string(Indent) + Indent + GenGetter(field.value.type) + "obj, o)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + ")\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code += std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
+ }
+ code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
+ code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent;
+ code += "return " + GenGetter(field.value.type);
+ code += "a + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + "))\n";
+ code += std::string(Indent) + End;
+ if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += std::string(Indent) + "return ''\n";
+ }
+ else {
+ code += std::string(Indent) + "return 0\n";
+ }
+ code += EndFunc;
+ }
+
+ // Begin the creator function signature.
+ void BeginBuilderArgs(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".Create" + NormalizedName(struct_def);
+ code += "(builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ }
+ else {
+ std::string &code = *code_ptr;
+ code += std::string(", ") + nameprefix;
+ code += MakeCamel(NormalizedName(field), false);
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ")\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "builder:Prep(" + NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding)
+ code += std::string(Indent) + "builder:Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ }
+ else {
+ code += std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
+ code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "return builder:Offset()\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a table's starting offset.
+ void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Start";
+ code += "(builder) ";
+ code += "builder:StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ") end\n";
+ }
+
+ // Set the value of a table's field.
+ void BuildFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field, const size_t offset,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Add" + MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += ") ";
+ code += "builder:Prepend";
+ code += GenMethod(field) + "Slot(";
+ code += NumToString(offset) + ", ";
+ // todo: i don't need to cast in Lua, but am I missing something?
+ // if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ // code += "flatbuffers.N.UOffsetTFlags.py_type";
+ // code += "(";
+ // code += MakeCamel(NormalizedName(field), false) + ")";
+ // } else {
+ code += MakeCamel(NormalizedName(field), false);
+ // }
+ code += ", " + field.value.constant;
+ code += ") end\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ void BuildVectorOfTable(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems) return builder:StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += ") end\n";
+ }
+
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".End";
+ code += "(builder) ";
+ code += "return builder:EndObject() end\n";
+ }
+
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedMetaName(struct_def) + ":";
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, &def_comment);
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ }
+ else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ }
+ else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ }
+ else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ }
+ else {
+ GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ GetVectorLen(struct_def, field, code_ptr);
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def,
+ std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+ BeginClass(struct_def, code_ptr);
+
+ GenerateNewObjectPrototype(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ }
+ else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+ BeginEnum(NormalizedName(enum_def), code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, &def_comment, Indent);
+ EnumMember(enum_def, ev, code_ptr);
+ }
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return std::string(SelfData) + ":String(";
+ case BASE_TYPE_UNION: return std::string(SelfData) + ":Union(";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default:
+ return std::string(SelfData) + ":Get(flatbuffers.N." +
+ MakeCamel(GenTypeGet(type)) + ", ";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const FieldDef &field) {
+ return IsScalar(field.value.type.base_type)
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+ return ctypename[type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string GetNamespace(const Type &type) {
+ return type.struct_def->defined_namespace->GetFullyQualifiedName(type.struct_def->name);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ std::string TypeNameWithNamespace(const FieldDef &field) {
+ return GetNamespace(field.value.type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, declcode, true)) return false;
+ }
+ return true;
+ }
+
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
+ code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "local flatbuffers = require('flatbuffers')\n\n";
+ }
+ }
+
+ // Save out the generated code for a Lua Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string namespace_dir = path_;
+ auto &namespaces = def.defined_namespace->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+ namespace_dir += *it;
+ //std::string init_py_filename = namespace_dir + "/__init__.py";
+ //SaveFile(init_py_filename.c_str(), "", false);
+ }
+
+ std::string code = "";
+ BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+ code += classcode;
+ code += "\n";
+ code += "return " + NormalizedName(def) + " " + Comment + "return the module";
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua";
+ return SaveFile(filename.c_str(), code, false);
+ }
+ private:
+ std::unordered_set<std::string> keywords_;
+ };
+
+} // namespace lua
+
+bool GenerateLua(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ lua::LuaGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
new file mode 100644
index 0000000..9d81415
--- /dev/null
+++ b/src/idl_gen_php.cpp
@@ -0,0 +1,940 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+namespace php {
+// Hardcode spaces per indentation.
+const std::string Indent = " ";
+class PhpGenerator : public BaseGenerator {
+ public:
+ PhpGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "\\", "\\") {}
+ bool generate() {
+ if (!GenerateEnums()) return false;
+ if (!GenerateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool GenerateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool GenerateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, declcode, true)) return false;
+ }
+ return true;
+ }
+
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ std::string *code_ptr) {
+ auto &code = *code_ptr;
+ code += "<?php\n";
+ code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
+
+ if (!name_space_name.empty()) {
+ code += "namespace " + name_space_name + ";\n\n";
+ }
+
+ if (needs_imports) {
+ code += "use \\Google\\FlatBuffers\\Struct;\n";
+ code += "use \\Google\\FlatBuffers\\Table;\n";
+ code += "use \\Google\\FlatBuffers\\ByteBuffer;\n";
+ code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n";
+ code += "\n";
+ }
+ }
+
+ // Save out the generated code for a Php Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string code = "";
+ BeginFile(FullNamespace("\\", *def.defined_namespace), needs_imports,
+ &code);
+ code += classcode;
+
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + def.name + ".php";
+ return SaveFile(filename.c_str(), code, false);
+ }
+
+ // Begin a class declaration.
+ static void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ if (struct_def.fixed) {
+ code += "class " + struct_def.name + " extends Struct\n";
+ } else {
+ code += "class " + struct_def.name + " extends Table\n";
+ }
+ code += "{\n";
+ }
+
+ static void EndClass(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ // Begin enum code with a class declaration.
+ static void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "class " + class_name + "\n{\n";
+ }
+
+ // A single enum member.
+ static void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "const ";
+ code += ev.name;
+ code += " = ";
+ code += enum_def.ToString(ev) + ";\n";
+ }
+
+ // End enum code.
+ static void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ // Initialize a new struct or table from existing data.
+ static void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param ByteBuffer $bb\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function getRootAs";
+ code += struct_def.name;
+ code += "(ByteBuffer $bb)\n";
+ code += Indent + "{\n";
+
+ code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
+ code += Indent + Indent;
+ code += "return ($obj->init($bb->getInt($bb->getPosition())";
+ code += " + $bb->getPosition(), $bb));\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ static void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int $_i offset\n";
+ code += Indent + " * @param ByteBuffer $_bb\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " **/\n";
+ code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$this->bb_pos = $_i;\n";
+ code += Indent + Indent + "$this->bb = $_bb;\n";
+ code += Indent + Indent + "return $this;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the length of a vector.
+ static void GetVectorLen(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return int\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "Length()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(";
+ code += NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a [ubyte] vector as a byte array.
+ static void GetUByte(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return string\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "Bytes()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return $this->__vector_as_bytes(";
+ code += NumToString(field.value.offset) + ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a struct's scalar.
+ static void GetScalarFieldOfStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return ";
+ code += GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function " + getter;
+ code += MakeCamel(field.name) + "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return ";
+
+ code += "$this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "($this->bb_pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += ";\n";
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n" + Indent + Indent +
+ "return $o != 0 ? ";
+ code += "$this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)";
+ code += " : " + GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$obj = new ";
+ code += GenTypeGet(field.value.type) + "();\n";
+ code += Indent + Indent + "$obj->init($this->bb_pos + ";
+ code += NumToString(field.value.offset) + ", $this->bb);";
+ code += "\n" + Indent + Indent + "return $obj;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$obj = new ";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $obj->init(";
+ if (field.value.type.struct_def->fixed) {
+ code += "$o + $this->bb_pos, $this->bb) : ";
+ } else {
+ code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
+ }
+ code += GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a string.
+ void GetStringField(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name) + "($obj)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__union($obj, $o) : null;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent + "$obj = new ";
+ code += MakeCamel(GenTypeGet(field.value.type)) + "();\n";
+
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ code += Indent + Indent;
+ code += "return $o != 0 ? $obj->init($this->bb_pos +" +
+ NumToString(field.value.offset) + ", $this->bb) : null;\n";
+ } else {
+ code += Indent + Indent + "return $o != 0 ? $obj->init(";
+ code += field.value.type.struct_def->fixed
+ ? "$o + $this->bb_pos"
+ : "$this->__indirect($o + $this->bb_pos)";
+ code += ", $this->bb) : null;\n";
+ }
+ break;
+ case BASE_TYPE_STRING:
+ code += "// base_type_string\n";
+ // TODO(chobie): do we need this?
+ break;
+ case BASE_TYPE_VECTOR:
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ code += Indent + Indent + "return $o != 0 ? $obj->init(";
+ if (vectortype.struct_def->fixed) {
+ code += "$this->__vector($o) + $j *";
+ code += NumToString(InlineSize(vectortype));
+ } else {
+ code += "$this->__indirect($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ")";
+ }
+ code += ", $this->bb) : null;\n";
+ }
+ break;
+ case BASE_TYPE_UNION:
+ code += Indent + Indent + "return $o != 0 ? $this->";
+ code += GenGetter(field.value.type) + "($obj, $o); null;\n";
+ break;
+ default: break;
+ }
+
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int offset\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+
+ if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) {
+ code += Indent + Indent;
+ code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ") : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ } else {
+ code += Indent + Indent + "return $o != 0 ? $this->bb->get";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "($this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + ") : ";
+ code += GenDefaultValue(field.value) + ";\n";
+ }
+ code += Indent + "}\n\n";
+ }
+
+ // Get the value of a vector's union member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param int offset\n";
+ code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public function get";
+ code += MakeCamel(field.name);
+ code += "($j, $obj)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $this->__offset(" +
+ NumToString(field.value.offset) + ");\n";
+ code += Indent + Indent + "return $o != 0 ? ";
+ code += "$this->__union($obj, $this->__vector($o) + $j * ";
+ code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ static void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious
+ // these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", $") + nameprefix;
+ code += MakeCamel(field.name, false);
+ }
+ }
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ static void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + Indent + "$builder->prep(";
+ code += NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ");\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding) {
+ code += Indent + Indent + "$builder->pad(";
+ code += NumToString(field.padding) + ");\n";
+ }
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (field.name + "_")).c_str(), code_ptr);
+ } else {
+ code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
+ code += nameprefix + MakeCamel(field.name, false) + ");\n";
+ }
+ }
+ }
+
+ // Get the value of a table's starting offset.
+ static void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function start" + struct_def.name;
+ code += "(FlatBufferBuilder $builder)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ");\n";
+ code += Indent + "}\n\n";
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return " + struct_def.name + "\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create" + struct_def.name;
+ code += "(FlatBufferBuilder $builder, ";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+
+ if (field.deprecated) continue;
+ code += "$" + field.name;
+ if (!(it == (--struct_def.fields.vec.end()))) { code += ", "; }
+ }
+ code += ")\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ");\n";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ code += Indent + Indent + "self::add";
+ code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n";
+ }
+
+ code += Indent + Indent + "$o = $builder->endObject();\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += Indent + Indent + "$builder->required($o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += Indent + Indent + "return $o;\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Set the value of a table's field.
+ static void BuildFieldOfTable(const FieldDef &field, const size_t offset,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function ";
+ code += "add" + MakeCamel(field.name);
+ code += "(FlatBufferBuilder $builder, ";
+ code += "$" + MakeCamel(field.name, false);
+ code += ")\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->add";
+ code += GenMethod(field) + "X(";
+ code += NumToString(offset) + ", ";
+
+ code += "$" + MakeCamel(field.name, false);
+ code += ", ";
+
+ if (field.value.type.base_type == BASE_TYPE_BOOL) {
+ code += "false";
+ } else {
+ code += field.value.constant;
+ }
+ code += ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param array offset array\n";
+ code += Indent + " * @return int vector offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder $builder, array $data)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startVector(";
+ code += NumToString(elem_size);
+ code += ", count($data), " + NumToString(alignment);
+ code += ");\n";
+ code += Indent + Indent;
+ code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
+ if (IsScalar(field.value.type.VectorType().base_type)) {
+ code += Indent + Indent + Indent;
+ code += "$builder->put";
+ code += MakeCamel(GenTypeBasic(field.value.type.VectorType()));
+ code += "($data[$i]);\n";
+ } else {
+ code += Indent + Indent + Indent;
+ code += "$builder->putOffset($data[$i]);\n";
+ }
+ code += Indent + Indent + "}\n";
+ code += Indent + Indent + "return $builder->endVector();\n";
+ code += Indent + "}\n\n";
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @param int $numElems\n";
+ code += Indent + " * @return void\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function start";
+ code += MakeCamel(field.name);
+ code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->startVector(";
+ code += NumToString(elem_size);
+ code += ", $numElems, " + NumToString(alignment);
+ code += ");\n";
+ code += Indent + "}\n\n";
+ }
+
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "/**\n";
+ code += Indent + " * @param FlatBufferBuilder $builder\n";
+ code += Indent + " * @return int table offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function end" + struct_def.name;
+ code += "(FlatBufferBuilder $builder)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$o = $builder->endObject();\n";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code += Indent + Indent + "$builder->required($o, ";
+ code += NumToString(field.value.offset);
+ code += "); // " + field.name + "\n";
+ }
+ }
+ code += Indent + Indent + "return $o;\n";
+ code += Indent + "}\n";
+
+ if (parser_.root_struct_def_ == &struct_def) {
+ code += "\n";
+ code += Indent + "public static function finish";
+ code += struct_def.name;
+ code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->finish($offset";
+
+ if (parser_.file_identifier_.length())
+ code += ", \"" + parser_.file_identifier_ + "\"";
+ code += ");\n";
+ code += Indent + "}\n";
+ }
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, Indent.c_str());
+
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(field, code_ptr);
+ }
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(field, code_ptr);
+ } else {
+ GetStructFieldOfTable(field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING: GetStringField(field, code_ptr); break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_UNION) {
+ GetMemberOfVectorOfUnion(field, code_ptr);
+ } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ GetVectorLen(field, code_ptr);
+ if (field.value.type.element == BASE_TYPE_UCHAR) {
+ GetUByte(field, code_ptr);
+ }
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ if (field.value.type.base_type == BASE_TYPE_UNION) {
+ std::string &code = *code_ptr;
+ code += Indent + "public static function add";
+ code += MakeCamel(field.name);
+ code += "(FlatBufferBuilder $builder, $offset)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "$builder->addOffsetX(";
+ code += NumToString(offset) + ", $offset, 0);\n";
+ code += Indent + "}\n\n";
+ } else {
+ BuildFieldOfTable(field, offset, code_ptr);
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ BuildVectorOfTable(field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, nullptr);
+ BeginClass(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+
+ std::string &code = *code_ptr;
+ if (!struct_def.fixed) {
+ if (parser_.file_identifier_.length()) {
+ // Return the identifier
+ code += Indent + "public static function " + struct_def.name;
+ code += "Identifier()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return \"";
+ code += parser_.file_identifier_ + "\";\n";
+ code += Indent + "}\n\n";
+
+ // Check if a buffer has the identifier.
+ code += Indent + "public static function " + struct_def.name;
+ code += "BufferHasIdentifier(ByteBuffer $buf)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return self::";
+ code += "__has_identifier($buf, self::";
+ code += struct_def.name + "Identifier());\n";
+ code += Indent + "}\n\n";
+ }
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code += Indent + "public static function " + struct_def.name;
+ code += "Extension()\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "return \"" + parser_.file_extension_;
+ code += "\";\n";
+ code += Indent + "}\n\n";
+ }
+ }
+
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ EndClass(code_ptr);
+ }
+
+ // Generate enum declarations.
+ static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, nullptr);
+ BeginEnum(enum_def.name, code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, Indent.c_str());
+ EnumMember(enum_def, ev, code_ptr);
+ }
+
+ std::string &code = *code_ptr;
+ code += "\n";
+ code += Indent + "private static $names = array(\n";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + ev.name + "\",\n";
+ }
+
+ code += Indent + ");\n\n";
+ code += Indent + "public static function Name($e)\n";
+ code += Indent + "{\n";
+ code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
+ code += Indent + Indent + Indent + "throw new \\Exception();\n";
+ code += Indent + Indent + "}\n";
+ code += Indent + Indent + "return self::$names[$e];\n";
+ code += Indent + "}\n";
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ static std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "__string";
+ case BASE_TYPE_STRUCT: return "__struct";
+ case BASE_TYPE_UNION: return "__union";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default: return "Get";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ static std::string GenMethod(const FieldDef &field) {
+ return IsScalar(field.value.type.base_type)
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "Offset");
+ }
+
+ static std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #NTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+ return ctypename[type.base_type];
+ }
+
+ std::string GenDefaultValue(const Value &value) {
+ if (value.type.enum_def) {
+ if (auto val = value.type.enum_def->FindByValue(value.constant)) {
+ return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
+ }
+ }
+
+ switch (value.type.base_type) {
+ case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
+
+ case BASE_TYPE_STRING: return "null";
+
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG:
+ if (value.constant != "0") {
+ int64_t constant = StringToInt(value.constant.c_str());
+ return NumToString(constant);
+ }
+ return "0";
+
+ default: return value.constant;
+ }
+ }
+
+ static std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "Table";
+ }
+ }
+
+ static std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ static void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\n";
+ code += Indent + "/**\n";
+ code += Indent + " * @return int offset\n";
+ code += Indent + " */\n";
+ code += Indent + "public static function create" + struct_def.name;
+ code += "(FlatBufferBuilder $builder";
+ StructBuilderArgs(struct_def, "", code_ptr);
+ code += ")\n";
+ code += Indent + "{\n";
+
+ StructBuilderBody(struct_def, "", code_ptr);
+
+ code += Indent + Indent + "return $builder->offset();\n";
+ code += Indent + "}\n";
+ }
+};
+} // namespace php
+
+bool GeneratePhp(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ php::PhpGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+} // namespace flatbuffers
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
new file mode 100644
index 0000000..c8db359
--- /dev/null
+++ b/src/idl_gen_python.cpp
@@ -0,0 +1,823 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+namespace python {
+
+// Hardcode spaces per indentation.
+const CommentConfig def_comment = { nullptr, "#", nullptr };
+const std::string Indent = " ";
+
+class PythonGenerator : public BaseGenerator {
+ public:
+ PythonGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */,
+ "" /* not used */),
+ float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
+ static const char * const keywords[] = {
+ "False",
+ "None",
+ "True",
+ "and",
+ "as",
+ "assert",
+ "break",
+ "class",
+ "continue",
+ "def",
+ "del",
+ "elif",
+ "else",
+ "except",
+ "finally",
+ "for",
+ "from",
+ "global",
+ "if",
+ "import",
+ "in",
+ "is",
+ "lambda",
+ "nonlocal",
+ "not",
+ "or",
+ "pass",
+ "raise",
+ "return",
+ "try",
+ "while",
+ "with",
+ "yield"
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that.
+ std::string OffsetPrefix(const FieldDef &field) {
+ return "\n" + Indent + Indent +
+ "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
+ "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
+ Indent + Indent + "if o != 0:\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "class " + NormalizedName(struct_def) + "(object):\n";
+ code += Indent + "__slots__ = ['_tab']";
+ code += "\n\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(const std::string &class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "class " + class_name + "(object):\n";
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string NormalizedName(const Definition &definition) const {
+ return EscapeKeyword(definition.name);
+ }
+
+ std::string NormalizedName(const EnumVal &ev) const {
+ return EscapeKeyword(ev.name);
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent;
+ code += NormalizedName(ev);
+ code += " = ";
+ code += enum_def.ToString(ev) + "\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "\n";
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += Indent + "@classmethod\n";
+ code += Indent + "def GetRootAs";
+ code += NormalizedName(struct_def);
+ code += "(cls, buf, offset):";
+ code += "\n";
+ code += Indent + Indent;
+ code += "n = flatbuffers.encode.Get";
+ code += "(flatbuffers.packer.uoffset, buf, offset)\n";
+ code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
+ code += Indent + Indent + "x.Init(buf, n + offset)\n";
+ code += Indent + Indent + "return x\n";
+ code += "\n";
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += "Init(self, buf, pos):\n";
+ code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
+ code += "\n";
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "Length(self";
+ code += "):" + OffsetPrefix(field);
+ code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
+ code += Indent + Indent + "return 0\n\n";
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self): return " + getter;
+ code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+ code += NumToString(field.value.offset) + "))\n";
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self):";
+ code += OffsetPrefix(field);
+ getter += "o + self._tab.Pos)";
+ auto is_bool = IsBool(field.value.type.base_type);
+ if (is_bool) {
+ getter = "bool(" + getter + ")";
+ }
+ code += Indent + Indent + Indent + "return " + getter + "\n";
+ std::string default_value;
+ if (is_bool) {
+ default_value = field.value.constant == "0" ? "False" : "True";
+ } else {
+ default_value = IsFloat(field.value.type.base_type)
+ ? float_const_gen_.GenFloatConstant(field)
+ : field.value.constant;
+ }
+ code += Indent + Indent + "return " + default_value + "\n\n";
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self, obj):\n";
+ code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+ code += NumToString(field.value.offset) + ")";
+ code += "\n" + Indent + Indent + "return obj\n\n";
+ }
+
+ // Get the value of a fixed size array.
+ void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ const auto vec_type = field.value.type.VectorType();
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ if (IsStruct(vec_type)) {
+ code += "(self, obj, i):\n";
+ code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
+ code += NumToString(field.value.offset) + " + i * ";
+ code += NumToString(InlineSize(vec_type));
+ code += ")\n" + Indent + Indent + "return obj\n\n";
+ } else {
+ auto getter = GenGetter(vec_type);
+ code += "(self): return [" + getter;
+ code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
+ code += NumToString(field.value.offset) + " + i * ";
+ code += NumToString(InlineSize(vec_type));
+ code += ")) for i in range(";
+ code += NumToString(field.value.type.fixed_length) + ")]\n";
+ }
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self):";
+ code += OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
+ } else {
+ code += Indent + Indent + Indent;
+ code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
+ }
+ code += Indent + Indent + Indent;
+ code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
+ code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
+ code += Indent + Indent + Indent + "return obj\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self):";
+ code += OffsetPrefix(field);
+ code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
+ code += "o + self._tab.Pos)\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "(self):";
+ code += OffsetPrefix(field);
+
+ // TODO(rw): this works and is not the good way to it:
+ bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+ if (is_native_table) {
+ code += Indent + Indent + Indent + "from flatbuffers.table import Table\n";
+ } else {
+ code += Indent + Indent + Indent;
+ code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ }
+ code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
+ code += Indent + Indent + Indent + GenGetter(field.value.type);
+ code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self, j):" + OffsetPrefix(field);
+ code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
+ code += Indent + Indent + Indent;
+ code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
+ code += NumToString(InlineSize(vectortype)) + "\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
+ }
+ code += Indent + Indent + Indent;
+ code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
+ code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
+ code += Indent + Indent + Indent + "return obj\n";
+ code += Indent + Indent + "return None\n\n";
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(self, j):";
+ code += OffsetPrefix(field);
+ code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
+ code += Indent + Indent + Indent;
+ code += "return " + GenGetter(field.value.type);
+ code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
+ code += NumToString(InlineSize(vectortype)) + "))\n";
+ if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += Indent + Indent + "return \"\"\n";
+ } else {
+ code += Indent + Indent + "return 0\n";
+ }
+ code += "\n";
+ }
+
+ // Returns a non-struct vector as a numpy array. Much faster
+ // than iterating over the vector element by element.
+ void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ // Currently, we only support accessing as numpy array if
+ // the vector type is a scalar.
+ if (!(IsScalar(vectortype.base_type))) { return; }
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
+ code += OffsetPrefix(field);
+
+ code += Indent + Indent + Indent;
+ code += "return ";
+ code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
+ code += MakeCamel(GenTypeGet(field.value.type));
+ code += "Flags, o)\n";
+
+ if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += Indent + Indent + "return \"\"\n";
+ } else {
+ code += Indent + Indent + "return 0\n";
+ }
+ code += "\n";
+ }
+
+ // Begin the creator function signature.
+ void BeginBuilderArgs(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "\n";
+ code += "def Create" + NormalizedName(struct_def);
+ code += "(builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ if (IsStruct(type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field_type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr);
+ } else {
+ std::string &code = *code_ptr;
+ code += std::string(", ") + nameprefix;
+ code += MakeCamel(NormalizedName(field), false);
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "):\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
+ std::string *code_ptr, size_t index = 0,
+ bool in_array = false) {
+ std::string &code = *code_ptr;
+ std::string indent(index * 4, ' ');
+ code +=
+ indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ const auto &field_type = field.value.type;
+ const auto &type =
+ IsArray(field_type) ? field_type.VectorType() : field_type;
+ if (field.padding)
+ code +=
+ indent + " builder.Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field_type)) {
+ StructBuilderBody(*field_type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(),
+ code_ptr, index, in_array);
+ } else {
+ const auto index_var = "_idx" + NumToString(index);
+ if (IsArray(field_type)) {
+ code += indent + " for " + index_var + " in range(";
+ code += NumToString(field_type.fixed_length);
+ code += " , 0, -1):\n";
+ in_array = true;
+ }
+ if (IsStruct(type)) {
+ StructBuilderBody(
+ *field_type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
+ index + 1, in_array);
+ } else {
+ code += IsArray(field_type) ? " " : "";
+ code += indent + " builder.Prepend" + GenMethod(field) + "(";
+ code += nameprefix + MakeCamel(NormalizedName(field), false);
+ size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
+ for (size_t i = 0; in_array && i < array_cnt; i++) {
+ code += "[_idx" + NumToString(i) + "-1]";
+ }
+ code += ")\n";
+ }
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += " return builder.Offset()\n";
+ }
+
+ // Get the value of a table's starting offset.
+ void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "def " + NormalizedName(struct_def) + "Start";
+ code += "(builder): ";
+ code += "builder.StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ")\n";
+ }
+
+ // Set the value of a table's field.
+ void BuildFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field, const size_t offset,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "def " + NormalizedName(struct_def) + "Add" + MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += "): ";
+ code += "builder.Prepend";
+ code += GenMethod(field) + "Slot(";
+ code += NumToString(offset) + ", ";
+ if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ code += "flatbuffers.number_types.UOffsetTFlags.py_type";
+ code += "(";
+ code += MakeCamel(NormalizedName(field), false) + ")";
+ } else {
+ code += MakeCamel(NormalizedName(field), false);
+ }
+ code += ", ";
+ code += IsFloat(field.value.type.base_type)
+ ? float_const_gen_.GenFloatConstant(field)
+ : field.value.constant;
+ code += ")\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ void BuildVectorOfTable(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "def " + NormalizedName(struct_def) + "Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems): return builder.StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += ")\n";
+ }
+
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "def " + NormalizedName(struct_def) + "End";
+ code += "(builder): ";
+ code += "return builder.EndObject()\n";
+ }
+
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += Indent + "# " + NormalizedName(struct_def) + "\n";
+ code += Indent + "def ";
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ } else if (IsArray(field.value.type)) {
+ GetArrayOfStruct(struct_def, field, code_ptr);
+ } else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ } else {
+ GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ GetVectorLen(struct_def, field, code_ptr);
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def,
+ std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate function to check for proper file identifier
+ void GenHasFileIdentifier(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string escapedID;
+ // In the event any of file_identifier characters are special(NULL, \, etc),
+ // problems occur. To prevent this, convert all chars to their hex-escaped
+ // equivalent.
+ for (auto it = parser_.file_identifier_.begin();
+ it != parser_.file_identifier_.end(); ++it) {
+ escapedID += "\\x" + IntToStringHex(*it, 2);
+ }
+
+ code += Indent + "@classmethod\n";
+ code += Indent + "def " + NormalizedName(struct_def);
+ code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
+ code += "\n";
+ code += Indent + Indent;
+ code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
+ code += escapedID;
+ code += "\", size_prefixed=size_prefixed)\n";
+ code += "\n";
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, &def_comment);
+ BeginClass(struct_def, code_ptr);
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ if (parser_.file_identifier_.length()){
+ // Generate a special function to test file_identifier
+ GenHasFileIdentifier(struct_def, code_ptr);
+ }
+ }
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ } else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, &def_comment);
+ BeginEnum(NormalizedName(enum_def), code_ptr);
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
+ EnumMember(enum_def, ev, code_ptr);
+ }
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "self._tab.String(";
+ case BASE_TYPE_UNION: return "self._tab.Union(";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default:
+ return "self._tab.Get(flatbuffers.number_types." +
+ MakeCamel(GenTypeGet(type)) + "Flags, ";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const FieldDef &field) {
+ return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+ return ctypename[IsArray(type) ? type.VectorType().base_type
+ : type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, declcode, true)) return false;
+ }
+ return true;
+ }
+
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string &name_space_name, const bool needs_imports,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
+ code += "# namespace: " + name_space_name + "\n\n";
+ if (needs_imports) { code += "import flatbuffers\n\n"; }
+ }
+
+ // Save out the generated code for a Python Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string namespace_dir = path_;
+ auto &namespaces = def.defined_namespace->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+ namespace_dir += *it;
+ std::string init_py_filename = namespace_dir + "/__init__.py";
+ SaveFile(init_py_filename.c_str(), "", false);
+ }
+
+ std::string code = "";
+ BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+ code += classcode;
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
+ return SaveFile(filename.c_str(), code, false);
+ }
+ private:
+ std::unordered_set<std::string> keywords_;
+ const SimpleFloatConstantGenerator float_const_gen_;
+};
+
+} // namespace python
+
+bool GeneratePython(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ python::PythonGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp
new file mode 100644
index 0000000..936ac83
--- /dev/null
+++ b/src/idl_gen_rust.cpp
@@ -0,0 +1,1825 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + "_generated.rs";
+}
+
+// Convert a camelCaseIdentifier or CamelCaseIdentifier to a
+// snake_case_indentifier.
+std::string MakeSnakeCase(const std::string &in) {
+ std::string s;
+ for (size_t i = 0; i < in.length(); i++) {
+ if (i == 0) {
+ s += static_cast<char>(tolower(in[0]));
+ } else if (in[i] == '_') {
+ s += '_';
+ } else if (!islower(in[i])) {
+ // Prevent duplicate underscores for Upper_Snake_Case strings
+ // and UPPERCASE strings.
+ if (islower(in[i - 1])) {
+ s += '_';
+ }
+ s += static_cast<char>(tolower(in[i]));
+ } else {
+ s += in[i];
+ }
+ }
+ return s;
+}
+
+// Convert a string to all uppercase.
+std::string MakeUpper(const std::string &in) {
+ std::string s;
+ for (size_t i = 0; i < in.length(); i++) {
+ s += static_cast<char>(toupper(in[i]));
+ }
+ return s;
+}
+
+// Encapsulate all logical field types in this enum. This allows us to write
+// field logic based on type switches, instead of branches on the properties
+// set on the Type.
+// TODO(rw): for backwards compatibility, we can't use a strict `enum class`
+// declaration here. could we use the `-Wswitch-enum` warning to
+// achieve the same effect?
+enum FullType {
+ ftInteger = 0,
+ ftFloat = 1,
+ ftBool = 2,
+
+ ftStruct = 3,
+ ftTable = 4,
+
+ ftEnumKey = 5,
+ ftUnionKey = 6,
+
+ ftUnionValue = 7,
+
+ // TODO(rw): bytestring?
+ ftString = 8,
+
+ ftVectorOfInteger = 9,
+ ftVectorOfFloat = 10,
+ ftVectorOfBool = 11,
+ ftVectorOfEnumKey = 12,
+ ftVectorOfStruct = 13,
+ ftVectorOfTable = 14,
+ ftVectorOfString = 15,
+ ftVectorOfUnionValue = 16,
+};
+
+// Convert a Type to a FullType (exhaustive).
+FullType GetFullType(const Type &type) {
+ // N.B. The order of these conditionals matters for some types.
+
+ if (type.base_type == BASE_TYPE_STRING) {
+ return ftString;
+ } else if (type.base_type == BASE_TYPE_STRUCT) {
+ if (type.struct_def->fixed) {
+ return ftStruct;
+ } else {
+ return ftTable;
+ }
+ } else if (type.base_type == BASE_TYPE_VECTOR) {
+ switch (GetFullType(type.VectorType())) {
+ case ftInteger: {
+ return ftVectorOfInteger;
+ }
+ case ftFloat: {
+ return ftVectorOfFloat;
+ }
+ case ftBool: {
+ return ftVectorOfBool;
+ }
+ case ftStruct: {
+ return ftVectorOfStruct;
+ }
+ case ftTable: {
+ return ftVectorOfTable;
+ }
+ case ftString: {
+ return ftVectorOfString;
+ }
+ case ftEnumKey: {
+ return ftVectorOfEnumKey;
+ }
+ case ftUnionKey:
+ case ftUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported");
+ break;
+ }
+ default: {
+ FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported");
+ }
+ }
+ } else if (type.enum_def != nullptr) {
+ if (type.enum_def->is_union) {
+ if (type.base_type == BASE_TYPE_UNION) {
+ return ftUnionValue;
+ } else if (IsInteger(type.base_type)) {
+ return ftUnionKey;
+ } else {
+ FLATBUFFERS_ASSERT(false && "unknown union field type");
+ }
+ } else {
+ return ftEnumKey;
+ }
+ } else if (IsScalar(type.base_type)) {
+ if (IsBool(type.base_type)) {
+ return ftBool;
+ } else if (IsInteger(type.base_type)) {
+ return ftInteger;
+ } else if (IsFloat(type.base_type)) {
+ return ftFloat;
+ } else {
+ FLATBUFFERS_ASSERT(false && "unknown number type");
+ }
+ }
+
+ FLATBUFFERS_ASSERT(false && "completely unknown type");
+
+ // this is only to satisfy the compiler's return analysis.
+ return ftBool;
+}
+
+// If the second parameter is false then wrap the first with Option<...>
+std::string WrapInOptionIfNotRequired(std::string s, bool required) {
+ if (required) {
+ return s;
+ } else {
+ return "Option<" + s + ">";
+ }
+}
+
+// If the second parameter is false then add .unwrap()
+std::string AddUnwrapIfRequired(std::string s, bool required) {
+ if (required) {
+ return s + ".unwrap()";
+ } else {
+ return s;
+ }
+}
+
+namespace rust {
+
+class RustGenerator : public BaseGenerator {
+ public:
+ RustGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "", "::"),
+ cur_name_space_(nullptr) {
+ const char *keywords[] = {
+ // list taken from:
+ // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html
+ //
+ // we write keywords one per line so that we can easily compare them with
+ // changes to that webpage in the future.
+
+ // currently-used keywords
+ "as",
+ "break",
+ "const",
+ "continue",
+ "crate",
+ "else",
+ "enum",
+ "extern",
+ "false",
+ "fn",
+ "for",
+ "if",
+ "impl",
+ "in",
+ "let",
+ "loop",
+ "match",
+ "mod",
+ "move",
+ "mut",
+ "pub",
+ "ref",
+ "return",
+ "Self",
+ "self",
+ "static",
+ "struct",
+ "super",
+ "trait",
+ "true",
+ "type",
+ "unsafe",
+ "use",
+ "where",
+ "while",
+
+ // future possible keywords
+ "abstract",
+ "alignof",
+ "become",
+ "box",
+ "do",
+ "final",
+ "macro",
+ "offsetof",
+ "override",
+ "priv",
+ "proc",
+ "pure",
+ "sizeof",
+ "typeof",
+ "unsized",
+ "virtual",
+ "yield",
+
+ // other rust terms we should not use
+ "std",
+ "usize",
+ "isize",
+ "u8",
+ "i8",
+ "u16",
+ "i16",
+ "u32",
+ "i32",
+ "u64",
+ "i64",
+ "u128",
+ "i128",
+ "f32",
+ "f64",
+
+ // These are terms the code generator can implement on types.
+ //
+ // In Rust, the trait resolution rules (as described at
+ // https://github.com/rust-lang/rust/issues/26007) mean that, as long
+ // as we impl table accessors as inherent methods, we'll never create
+ // conflicts with these keywords. However, that's a fairly nuanced
+ // implementation detail, and how we implement methods could change in
+ // the future. as a result, we proactively block these out as reserved
+ // words.
+ "follow",
+ "push",
+ "size",
+ "alignment",
+ "to_little_endian",
+ "from_little_endian",
+ nullptr };
+ for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ }
+
+ // Iterate through all definitions we haven't generated code for (enums,
+ // structs, and tables) and output them to a single file.
+ bool generate() {
+ code_.Clear();
+ code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+ assert(!cur_name_space_);
+
+ // Generate imports for the global scope in case no namespace is used
+ // in the schema file.
+ GenNamespaceImports(0);
+ code_ += "";
+
+ // Generate all code in their namespaces, once, because Rust does not
+ // permit re-opening modules.
+ //
+ // TODO(rw): Use a set data structure to reduce namespace evaluations from
+ // O(n**2) to O(n).
+ for (auto ns_it = parser_.namespaces_.begin();
+ ns_it != parser_.namespaces_.end();
+ ++ns_it) {
+ const auto &ns = *ns_it;
+
+ // Generate code for all the enum declarations.
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ const auto &enum_def = **it;
+ if (enum_def.defined_namespace != ns) { continue; }
+ if (!enum_def.generated) {
+ SetNameSpace(enum_def.defined_namespace);
+ GenEnum(enum_def);
+ }
+ }
+
+ // Generate code for all structs.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.defined_namespace != ns) { continue; }
+ if (struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenStruct(struct_def);
+ }
+ }
+
+ // Generate code for all tables.
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ const auto &struct_def = **it;
+ if (struct_def.defined_namespace != ns) { continue; }
+ if (!struct_def.fixed && !struct_def.generated) {
+ SetNameSpace(struct_def.defined_namespace);
+ GenTable(struct_def);
+ }
+ }
+
+ // Generate global helper functions.
+ if (parser_.root_struct_def_) {
+ auto &struct_def = *parser_.root_struct_def_;
+ if (struct_def.defined_namespace != ns) { continue; }
+ SetNameSpace(struct_def.defined_namespace);
+ GenRootTableFuncs(struct_def);
+ }
+ }
+ if (cur_name_space_) SetNameSpace(nullptr);
+
+ const auto file_path = GeneratedFileName(path_, file_name_);
+ const auto final_code = code_.ToString();
+ return SaveFile(file_path.c_str(), final_code, false);
+ }
+
+ private:
+ CodeWriter code_;
+
+ std::set<std::string> keywords_;
+
+ // This tracks the current namespace so we can insert namespace declarations.
+ const Namespace *cur_name_space_;
+
+ const Namespace *CurrentNameSpace() const { return cur_name_space_; }
+
+ // Determine if a Type needs a lifetime template parameter when used in the
+ // Rust builder args.
+ bool TableBuilderTypeNeedsLifetime(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ case ftUnionKey:
+ case ftUnionValue: { return false; }
+ default: { return true; }
+ }
+ }
+
+ // Determine if a table args rust type needs a lifetime template parameter.
+ bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const {
+ FLATBUFFERS_ASSERT(!struct_def.fixed);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ continue;
+ }
+
+ if (TableBuilderTypeNeedsLifetime(field.value.type)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Determine if a Type needs to be copied (for endian safety) when used in a
+ // Struct.
+ bool StructMemberAccessNeedsCopy(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger: // requires endian swap
+ case ftFloat: // requires endian swap
+ case ftBool: // no endian-swap, but do the copy for UX consistency
+ case ftEnumKey: { return true; } // requires endian swap
+ case ftStruct: { return false; } // no endian swap
+ default: {
+ // logic error: no other types can be struct members.
+ FLATBUFFERS_ASSERT(false && "invalid struct member type");
+ return false; // only to satisfy compiler's return analysis
+ }
+ }
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : name + "_";
+ }
+
+ std::string Name(const Definition &def) const {
+ return EscapeKeyword(def.name);
+ }
+
+ std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); }
+
+ std::string WrapInNameSpace(const Definition &def) const {
+ return WrapInNameSpace(def.defined_namespace, Name(def));
+ }
+ std::string WrapInNameSpace(const Namespace *ns,
+ const std::string &name) const {
+ if (CurrentNameSpace() == ns) return name;
+ std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns);
+ return prefix + name;
+ }
+
+ // Determine the namespace traversal needed from the Rust crate root.
+ // This may be useful in the future for referring to included files, but is
+ // currently unused.
+ std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const {
+ std::stringstream stream;
+
+ stream << "::";
+ for (auto d = dst->components.begin(); d != dst->components.end(); ++d) {
+ stream << MakeSnakeCase(*d) + "::";
+ }
+ return stream.str();
+ }
+
+ // Determine the relative namespace traversal needed to reference one
+ // namespace from another namespace. This is useful because it does not force
+ // the user to have a particular file layout. (If we output absolute
+ // namespace paths, that may require users to organize their Rust crates in a
+ // particular way.)
+ std::string GetRelativeNamespaceTraversal(const Namespace *src,
+ const Namespace *dst) const {
+ // calculate the path needed to reference dst from src.
+ // example: f(A::B::C, A::B::C) -> (none)
+ // example: f(A::B::C, A::B) -> super::
+ // example: f(A::B::C, A::B::D) -> super::D
+ // example: f(A::B::C, A) -> super::super::
+ // example: f(A::B::C, D) -> super::super::super::D
+ // example: f(A::B::C, D::E) -> super::super::super::D::E
+ // example: f(A, D::E) -> super::D::E
+ // does not include leaf object (typically a struct type).
+
+ size_t i = 0;
+ std::stringstream stream;
+
+ auto s = src->components.begin();
+ auto d = dst->components.begin();
+ for(;;) {
+ if (s == src->components.end()) { break; }
+ if (d == dst->components.end()) { break; }
+ if (*s != *d) { break; }
+ ++s;
+ ++d;
+ ++i;
+ }
+
+ for (; s != src->components.end(); ++s) {
+ stream << "super::";
+ }
+ for (; d != dst->components.end(); ++d) {
+ stream << MakeSnakeCase(*d) + "::";
+ }
+ return stream.str();
+ }
+
+ // Generate a comment from the schema.
+ void GenComment(const std::vector<std::string> &dc, const char *prefix = "") {
+ std::string text;
+ ::flatbuffers::GenComment(dc, &text, nullptr, prefix);
+ code_ += text + "\\";
+ }
+
+ // Return a Rust type from the table in idl.h.
+ std::string GetTypeBasic(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ case ftUnionKey: { break; }
+ default: { FLATBUFFERS_ASSERT(false && "incorrect type given");}
+ }
+
+ // clang-format off
+ static const char * const ctypename[] = {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, KTYPE) \
+ #RTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+
+ if (type.enum_def) { return WrapInNameSpace(*type.enum_def); }
+ return ctypename[type.base_type];
+ }
+
+ // Look up the native type for an enum. This will always be an integer like
+ // u8, i32, etc.
+ std::string GetEnumTypeForDecl(const Type &type) {
+ const auto ft = GetFullType(type);
+ if (!(ft == ftEnumKey || ft == ftUnionKey)) {
+ FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl");
+ }
+
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \
+ RTYPE, KTYPE) \
+ #RTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+
+ // Enums can be bools, but their Rust representation must be a u8, as used
+ // in the repr attribute (#[repr(bool)] is an invalid attribute).
+ if (type.base_type == BASE_TYPE_BOOL) return "u8";
+ return ctypename[type.base_type];
+ }
+
+ // Return a Rust type for any type (scalar, table, struct) specifically for
+ // using a FlatBuffer.
+ std::string GetTypeGet(const Type &type) const {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ case ftUnionKey: {
+ return GetTypeBasic(type); }
+ case ftTable: {
+ return WrapInNameSpace(type.struct_def->defined_namespace,
+ type.struct_def->name) + "<'a>"; }
+ default: {
+ return WrapInNameSpace(type.struct_def->defined_namespace,
+ type.struct_def->name); }
+ }
+ }
+
+ std::string GetEnumValUse(const EnumDef &enum_def,
+ const EnumVal &enum_val) const {
+ return Name(enum_def) + "::" + Name(enum_val);
+ }
+
+ // Generate an enum declaration,
+ // an enum string lookup table,
+ // an enum match function,
+ // and an enum array of values
+ void GenEnum(const EnumDef &enum_def) {
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+ code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type));
+
+ GenComment(enum_def.doc_comment);
+ code_ += "#[allow(non_camel_case_types)]";
+ code_ += "#[repr({{BASE_TYPE}})]";
+ code_ += "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]";
+ code_ += "pub enum " + Name(enum_def) + " {";
+
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+
+ GenComment(ev.doc_comment, " ");
+ code_.SetValue("KEY", Name(ev));
+ code_.SetValue("VALUE", enum_def.ToString(ev));
+ code_ += " {{KEY}} = {{VALUE}},";
+ }
+ const EnumVal *minv = enum_def.MinValue();
+ const EnumVal *maxv = enum_def.MaxValue();
+ FLATBUFFERS_ASSERT(minv && maxv);
+
+ code_ += "";
+ code_ += "}";
+ code_ += "";
+
+ code_.SetValue("ENUM_NAME", Name(enum_def));
+ code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def)));
+ code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def))));
+ code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv));
+ code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv));
+
+ // Generate enum constants, and impls for Follow, EndianScalar, and Push.
+ code_ += "const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
+ code_ += "{{ENUM_MIN_BASE_VALUE}};";
+ code_ += "const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}} = \\";
+ code_ += "{{ENUM_MAX_BASE_VALUE}};";
+ code_ += "";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
+ code_ += " type Inner = Self;";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " flatbuffers::read_scalar_at::<Self>(buf, loc)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {";
+ code_ += " #[inline]";
+ code_ += " fn to_little_endian(self) -> Self {";
+ code_ += " let n = {{BASE_TYPE}}::to_le(self as {{BASE_TYPE}});";
+ code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
+ code_ += " unsafe { *p }";
+ code_ += " }";
+ code_ += " #[inline]";
+ code_ += " fn from_little_endian(self) -> Self {";
+ code_ += " let n = {{BASE_TYPE}}::from_le(self as {{BASE_TYPE}});";
+ code_ += " let p = &n as *const {{BASE_TYPE}} as *const {{ENUM_NAME}};";
+ code_ += " unsafe { *p }";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {";
+ code_ += " type Output = {{ENUM_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+ code_ += " flatbuffers::emplace_scalar::<{{ENUM_NAME}}>"
+ "(dst, *self);";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+
+ // Generate an array of all enumeration values.
+ auto num_fields = NumToString(enum_def.size());
+ code_ += "#[allow(non_camel_case_types)]";
+ code_ += "const ENUM_VALUES_{{ENUM_NAME_CAPS}}:[{{ENUM_NAME}}; " +
+ num_fields + "] = [";
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
+ const auto &ev = **it;
+ auto value = GetEnumValUse(enum_def, ev);
+ auto suffix = *it != enum_def.Vals().back() ? "," : "";
+ code_ += " " + value + suffix;
+ }
+ code_ += "];";
+ code_ += "";
+
+ // Generate a string table for enum values.
+ // Problem is, if values are very sparse that could generate really big
+ // tables. Ideally in that case we generate a map lookup instead, but for
+ // the moment we simply don't output a table at all.
+ auto range = enum_def.Distance();
+ // Average distance between values above which we consider a table
+ // "too sparse". Change at will.
+ static const uint64_t kMaxSparseness = 5;
+ if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+ code_ += "#[allow(non_camel_case_types)]";
+ code_ += "const ENUM_NAMES_{{ENUM_NAME_CAPS}}:[&'static str; " +
+ NumToString(range + 1) + "] = [";
+
+ auto val = enum_def.Vals().front();
+ for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
+ ++it) {
+ auto ev = *it;
+ for (auto k = enum_def.Distance(val, ev); k > 1; --k) {
+ code_ += " \"\",";
+ }
+ val = ev;
+ auto suffix = *it != enum_def.Vals().back() ? "," : "";
+ code_ += " \"" + Name(*ev) + "\"" + suffix;
+ }
+ code_ += "];";
+ code_ += "";
+
+ code_ +=
+ "pub fn enum_name_{{ENUM_NAME_SNAKE}}(e: {{ENUM_NAME}}) -> "
+ "&'static str {";
+
+ code_ += " let index = e as {{BASE_TYPE}}\\";
+ if (enum_def.MinValue()->IsNonZero()) {
+ auto vals = GetEnumValUse(enum_def, *enum_def.MinValue());
+ code_ += " - " + vals + " as {{BASE_TYPE}}\\";
+ }
+ code_ += ";";
+
+ code_ += " ENUM_NAMES_{{ENUM_NAME_CAPS}}[index as usize]";
+ code_ += "}";
+ code_ += "";
+ }
+
+ if (enum_def.is_union) {
+ // Generate tyoesafe offset(s) for unions
+ code_.SetValue("NAME", Name(enum_def));
+ code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset");
+ code_ += "pub struct {{UNION_OFFSET_NAME}} {}";
+ }
+ }
+
+ std::string GetFieldOffsetName(const FieldDef &field) {
+ return "VT_" + MakeUpper(Name(field));
+ }
+
+ std::string GetDefaultConstant(const FieldDef &field) {
+ return field.value.type.base_type == BASE_TYPE_FLOAT
+ ? field.value.constant + ""
+ : field.value.constant;
+ }
+
+ std::string GetDefaultScalarValue(const FieldDef &field) {
+ switch (GetFullType(field.value.type)) {
+ case ftInteger: { return GetDefaultConstant(field); }
+ case ftFloat: { return GetDefaultConstant(field); }
+ case ftBool: {
+ return field.value.constant == "0" ? "false" : "true";
+ }
+ case ftUnionKey:
+ case ftEnumKey: {
+ auto ev = field.value.type.enum_def->FindByValue(field.value.constant);
+ assert(ev);
+ return WrapInNameSpace(field.value.type.enum_def->defined_namespace,
+ GetEnumValUse(*field.value.type.enum_def, *ev));
+ }
+
+ // All pointer-ish types have a default value of None, because they are
+ // wrapped in Option.
+ default: { return "None"; }
+ }
+ }
+
+ // Create the return type for fields in the *BuilderArgs structs that are
+ // used to create Tables.
+ //
+ // Note: we could make all inputs to the BuilderArgs be an Option, as well
+ // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to
+ // know if the value is default or not, because there are three ways to
+ // return a default value:
+ // 1) return a stored value that happens to be the default,
+ // 2) return a hardcoded value because the relevant vtable field is not in
+ // the vtable, or
+ // 3) return a hardcoded value because the vtable field value is set to zero.
+ std::string TableBuilderArgsDefnType(const FieldDef &field,
+ const std::string &lifetime) {
+ const Type& type = field.value.type;
+
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool: {
+ const auto typname = GetTypeBasic(type);
+ return typname;
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "Option<&" + lifetime + " " + typname + ">";
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime + \
+ ">>>";
+ }
+ case ftString: {
+ return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
+ }
+ case ftEnumKey:
+ case ftUnionKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return typname;
+ }
+ case ftUnionValue: {
+ return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
+ }
+
+ case ftVectorOfInteger:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", " + typname + ">>>";
+ }
+ case ftVectorOfBool: {
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", bool>>>";
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", " + typname + ">>>";
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", " + typname + ">>>";
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", flatbuffers::ForwardsUOffset<" + typname + \
+ "<" + lifetime + ">>>>>";
+ }
+ case ftVectorOfString: {
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", flatbuffers::ForwardsUOffset<&" + lifetime + \
+ " str>>>>";
+ }
+ case ftVectorOfUnionValue: {
+ const auto typname = WrapInNameSpace(*type.enum_def) + \
+ "UnionTableOffset";
+ return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + \
+ lifetime + ", flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Table<" + lifetime + ">>>>";
+ }
+ }
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+
+ std::string TableBuilderArgsDefaultValue(const FieldDef &field) {
+ return GetDefaultScalarValue(field);
+ }
+ std::string TableBuilderAddFuncDefaultValue(const FieldDef &field) {
+ // All branches of switch do the same action!
+ switch (GetFullType(field.value.type)) {
+ case ftUnionKey:
+ case ftEnumKey: {
+ const std::string basetype = GetTypeBasic(field.value.type); //<- never used
+ return GetDefaultScalarValue(field);
+ }
+
+ default: { return GetDefaultScalarValue(field); }
+ }
+ }
+
+ std::string TableBuilderArgsAddFuncType(const FieldDef &field,
+ const std::string &lifetime) {
+ const Type& type = field.value.type;
+
+ switch (GetFullType(field.value.type)) {
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", " + typname + ">>";
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", flatbuffers::ForwardsUOffset<" + typname + \
+ "<" + lifetime + ">>>>";
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", " + typname + ">>";
+ }
+ case ftVectorOfBool: {
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", bool>>";
+ }
+ case ftVectorOfString: {
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>";
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", " + typname + ">>";
+ }
+ case ftVectorOfUnionValue: {
+ return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + \
+ ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + \
+ lifetime + ">>>";
+ }
+ case ftEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return typname;
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "&" + lifetime + " " + typname + "";
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>";
+ }
+ case ftInteger:
+ case ftFloat: {
+ const auto typname = GetTypeBasic(type);
+ return typname;
+ }
+ case ftBool: {
+ return "bool";
+ }
+ case ftString: {
+ return "flatbuffers::WIPOffset<&" + lifetime + " str>";
+ }
+ case ftUnionKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return typname;
+ }
+ case ftUnionValue: {
+ return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>";
+ }
+ }
+
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+
+ std::string TableBuilderArgsAddFuncBody(const FieldDef &field) {
+ const Type& type = field.value.type;
+
+ switch (GetFullType(field.value.type)) {
+ case ftInteger:
+ case ftFloat: {
+ const auto typname = GetTypeBasic(field.value.type);
+ return "self.fbb_.push_slot::<" + typname + ">";
+ }
+ case ftBool: {
+ return "self.fbb_.push_slot::<bool>";
+ }
+
+ case ftEnumKey:
+ case ftUnionKey: {
+ const auto underlying_typname = GetTypeBasic(type);
+ return "self.fbb_.push_slot::<" + underlying_typname + ">";
+ }
+
+ case ftStruct: {
+ const std::string typname = WrapInNameSpace(*type.struct_def);
+ return "self.fbb_.push_slot_always::<&" + typname + ">";
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + \
+ typname + ">>";
+ }
+
+ case ftUnionValue:
+ case ftString:
+ case ftVectorOfInteger:
+ case ftVectorOfFloat:
+ case ftVectorOfBool:
+ case ftVectorOfEnumKey:
+ case ftVectorOfStruct:
+ case ftVectorOfTable:
+ case ftVectorOfString:
+ case ftVectorOfUnionValue: {
+ return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>";
+ }
+ }
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+
+ std::string GenTableAccessorFuncReturnType(const FieldDef &field,
+ const std::string &lifetime) {
+ const Type& type = field.value.type;
+
+ switch (GetFullType(field.value.type)) {
+ case ftInteger:
+ case ftFloat: {
+ const auto typname = GetTypeBasic(type);
+ return typname;
+ }
+ case ftBool: {
+ return "bool";
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapInOptionIfNotRequired("&" + lifetime + " " + typname, field.required);
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">", field.required);
+ }
+ case ftEnumKey:
+ case ftUnionKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return typname;
+ }
+
+ case ftUnionValue: {
+ return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">", field.required);
+ }
+ case ftString: {
+ return WrapInOptionIfNotRequired("&" + lifetime + " str", field.required);
+ }
+ case ftVectorOfInteger:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ if (IsOneByte(type.VectorType().base_type)) {
+ return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
+ }
+ return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
+ }
+ case ftVectorOfBool: {
+ return WrapInOptionIfNotRequired("&" + lifetime + " [bool]", field.required);
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", " + typname + ">", field.required);
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]", field.required);
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<" + \
+ typname + "<" + lifetime + ">>>", field.required);
+ }
+ case ftVectorOfString: {
+ return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime + ", flatbuffers::ForwardsUOffset<&" + \
+ lifetime + " str>>", field.required);
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+ // TODO(rw): when we do support these, we should consider using the
+ // Into trait to convert tables to typesafe union values.
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+ }
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+
+ std::string GenTableAccessorFuncBody(const FieldDef &field,
+ const std::string &lifetime,
+ const std::string &offset_prefix) {
+ const std::string offset_name = offset_prefix + "::" + \
+ GetFieldOffsetName(field);
+ const Type& type = field.value.type;
+
+ switch (GetFullType(field.value.type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool: {
+ const auto typname = GetTypeBasic(type);
+ const auto default_value = GetDefaultScalarValue(field);
+ return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + \
+ default_value + ")).unwrap()";
+ }
+ case ftStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return AddUnwrapIfRequired("self._tab.get::<" + typname + ">(" + offset_name + ", None)", field.required);
+ }
+ case ftTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<" + \
+ typname + "<" + lifetime + ">>>(" + offset_name + ", None)", field.required);
+ }
+ case ftUnionValue: {
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Table<" + lifetime + ">>>(" + offset_name + \
+ ", None)", field.required);
+ }
+ case ftUnionKey:
+ case ftEnumKey: {
+ const auto underlying_typname = GetTypeBasic(type); //<- never used
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ const auto default_value = GetDefaultScalarValue(field);
+ return "self._tab.get::<" + typname + ">(" + offset_name + \
+ ", Some(" + default_value + ")).unwrap()";
+ }
+ case ftString: {
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + \
+ offset_name + ", None)", field.required);
+ }
+
+ case ftVectorOfInteger:
+ case ftVectorOfFloat: {
+ const auto typname = GetTypeBasic(type.VectorType());
+ std::string s = "self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" + lifetime + ", " + typname + \
+ ">>>(" + offset_name + ", None)";
+ // single-byte values are safe to slice
+ if (IsOneByte(type.VectorType().base_type)) {
+ s += ".map(|v| v.safe_slice())";
+ }
+ return AddUnwrapIfRequired(s, field.required);
+ }
+ case ftVectorOfBool: {
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" + lifetime + ", bool>>>(" + \
+ offset_name + ", None).map(|v| v.safe_slice())", field.required);
+ }
+ case ftVectorOfEnumKey: {
+ const auto typname = WrapInNameSpace(*type.enum_def);
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" + lifetime + ", " + typname + ">>>(" + \
+ offset_name + ", None)", field.required);
+ }
+ case ftVectorOfStruct: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<" + typname + ">>>(" + \
+ offset_name + ", None).map(|v| v.safe_slice() )", field.required);
+ }
+ case ftVectorOfTable: {
+ const auto typname = WrapInNameSpace(*type.struct_def);
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + typname + \
+ "<" + lifetime + ">>>>>(" + offset_name + ", None)", field.required);
+ }
+ case ftVectorOfString: {
+ return AddUnwrapIfRequired("self._tab.get::<flatbuffers::ForwardsUOffset<"
+ "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + \
+ lifetime + " str>>>>(" + offset_name + ", None)", field.required);
+ }
+ case ftVectorOfUnionValue: {
+ FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+ }
+ return "INVALID_CODE_GENERATION"; // for return analysis
+ }
+
+ bool TableFieldReturnsOption(const Type& type) {
+ switch (GetFullType(type)) {
+ case ftInteger:
+ case ftFloat:
+ case ftBool:
+ case ftEnumKey:
+ case ftUnionKey:
+ return false;
+ default: return true;
+ }
+ }
+
+ // Generate an accessor struct, builder struct, and create function for a
+ // table.
+ void GenTable(const StructDef &struct_def) {
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+ code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
+ code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def)));
+
+ // Generate an offset type, the base type, the Follow impl, and the
+ // init_from_table impl.
+ code_ += "pub enum {{OFFSET_TYPELABEL}} {}";
+ code_ += "#[derive(Copy, Clone, Debug, PartialEq)]";
+ code_ += "";
+
+ GenComment(struct_def.doc_comment);
+
+ code_ += "pub struct {{STRUCT_NAME}}<'a> {";
+ code_ += " pub _tab: flatbuffers::Table<'a>,";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {";
+ code_ += " type Inner = {{STRUCT_NAME}}<'a>;";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " Self {";
+ code_ += " _tab: flatbuffers::Table { buf: buf, loc: loc },";
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "impl<'a> {{STRUCT_NAME}}<'a> {";
+ code_ += " #[inline]";
+ code_ += " pub fn init_from_table(table: flatbuffers::Table<'a>) -> "
+ "Self {";
+ code_ += " {{STRUCT_NAME}} {";
+ code_ += " _tab: table,";
+ code_ += " }";
+ code_ += " }";
+
+ // Generate a convenient create* function that uses the above builder
+ // to create a table in one function call.
+ code_.SetValue("MAYBE_US",
+ struct_def.fields.vec.size() == 0 ? "_" : "");
+ code_.SetValue("MAYBE_LT",
+ TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : "");
+ code_ += " #[allow(unused_mut)]";
+ code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(";
+ code_ += " _fbb: "
+ "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,";
+ code_ += " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})"
+ " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {";
+
+ code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);";
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
+ size; size /= 2) {
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ const auto &field = **it;
+ // TODO(rw): fully understand this sortbysize usage
+ if (!field.deprecated && (!struct_def.sortbysize ||
+ size == SizeOf(field.value.type.base_type))) {
+ code_.SetValue("FIELD_NAME", Name(field));
+ if (TableFieldReturnsOption(field.value.type)) {
+ code_ += " if let Some(x) = args.{{FIELD_NAME}} "
+ "{ builder.add_{{FIELD_NAME}}(x); }";
+ } else {
+ code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});";
+ }
+ }
+ }
+ }
+ code_ += " builder.finish()";
+ code_ += " }";
+ code_ += "";
+
+ // Generate field id constants.
+ if (struct_def.fields.vec.size() > 0) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ // Deprecated fields won't be accessible.
+ continue;
+ }
+
+ code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
+ code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
+ code_ += " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = "
+ "{{OFFSET_VALUE}};";
+ }
+ code_ += "";
+ }
+
+ // Generate the accessors. Each has one of two forms:
+ //
+ // If a value can be None:
+ // pub fn name(&'a self) -> Option<user_facing_type> {
+ // self._tab.get::<internal_type>(offset, defaultval)
+ // }
+ //
+ // If a value is always Some:
+ // pub fn name(&'a self) -> user_facing_type {
+ // self._tab.get::<internal_type>(offset, defaultval).unwrap()
+ // }
+ const auto offset_prefix = Name(struct_def);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated) {
+ // Deprecated fields won't be accessible.
+ continue;
+ }
+
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("RETURN_TYPE",
+ GenTableAccessorFuncReturnType(field, "'a"));
+ code_.SetValue("FUNC_BODY",
+ GenTableAccessorFuncBody(field, "'a", offset_prefix));
+
+ GenComment(field.doc_comment, " ");
+ code_ += " #[inline]";
+ code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {";
+ code_ += " {{FUNC_BODY}}";
+ code_ += " }";
+
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) {
+ GenKeyFieldMethods(field);
+ }
+
+ // Generate a nested flatbuffer field, if applicable.
+ auto nested = field.attributes.Lookup("nested_flatbuffer");
+ if (nested) {
+ std::string qualified_name = nested->constant;
+ auto nested_root = parser_.LookupStruct(nested->constant);
+ if (nested_root == nullptr) {
+ qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
+ nested->constant);
+ nested_root = parser_.LookupStruct(qualified_name);
+ }
+ FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
+ (void)nested_root;
+
+ code_.SetValue("OFFSET_NAME",
+ offset_prefix + "::" + GetFieldOffsetName(field));
+ code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> "
+ " Option<{{STRUCT_NAME}}<'a>> {";
+ code_ += " match self.{{FIELD_NAME}}() {";
+ code_ += " None => { None }";
+ code_ += " Some(data) => {";
+ code_ += " use self::flatbuffers::Follow;";
+ code_ += " Some(<flatbuffers::ForwardsUOffset"
+ "<{{STRUCT_NAME}}<'a>>>::follow(data, 0))";
+ code_ += " },";
+ code_ += " }";
+ code_ += " }";
+ }
+ }
+
+ // Explicit specializations for union accessors
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) {
+ continue;
+ }
+
+ auto u = field.value.type.enum_def;
+
+ code_.SetValue("FIELD_NAME", Name(field));
+
+ for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) {
+ auto &ev = **u_it;
+ if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; }
+
+ auto table_init_type = WrapInNameSpace(
+ ev.union_type.struct_def->defined_namespace,
+ ev.union_type.struct_def->name);
+
+ code_.SetValue("U_ELEMENT_ENUM_TYPE",
+ WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev)));
+ code_.SetValue("U_ELEMENT_TABLE_TYPE", table_init_type);
+ code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev)));
+
+ code_ += " #[inline]";
+ code_ += " #[allow(non_snake_case)]";
+ code_ += " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> "
+ "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {";
+ code_ += " if self.{{FIELD_NAME}}_type() == {{U_ELEMENT_ENUM_TYPE}} {";
+ code_ += " self.{{FIELD_NAME}}().map(|u| "
+ "{{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))";
+ code_ += " } else {";
+ code_ += " None";
+ code_ += " }";
+ code_ += " }";
+ code_ += "";
+ }
+ }
+
+ code_ += "}"; // End of table impl.
+ code_ += "";
+
+ // Generate an args struct:
+ code_.SetValue("MAYBE_LT",
+ TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : "");
+ code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ code_.SetValue("PARAM_NAME", Name(field));
+ code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a "));
+ code_ += " pub {{PARAM_NAME}}: {{PARAM_TYPE}},";
+ }
+ }
+ code_ += "}";
+
+ // Generate an impl of Default for the *Args type:
+ code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {";
+ code_ += " #[inline]";
+ code_ += " fn default() -> Self {";
+ code_ += " {{STRUCT_NAME}}Args {";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ code_.SetValue("PARAM_VALUE", TableBuilderArgsDefaultValue(field));
+ code_.SetValue("REQ", field.required ? " // required field" : "");
+ code_.SetValue("PARAM_NAME", Name(field));
+ code_ += " {{PARAM_NAME}}: {{PARAM_VALUE}},{{REQ}}";
+ }
+ }
+ code_ += " }";
+ code_ += " }";
+ code_ += "}";
+
+ // Generate a builder struct:
+ code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
+ code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
+ code_ += " start_: flatbuffers::WIPOffset<"
+ "flatbuffers::TableUnfinishedWIPOffset>,";
+ code_ += "}";
+
+ // Generate builder functions:
+ code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {";
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated) {
+ const bool is_scalar = IsScalar(field.value.type.base_type);
+
+ std::string offset = GetFieldOffsetName(field);
+
+ // Generate functions to add data, which take one of two forms.
+ //
+ // If a value has a default:
+ // fn add_x(x_: type) {
+ // fbb_.push_slot::<type>(offset, x_, Some(default));
+ // }
+ //
+ // If a value does not have a default:
+ // fn add_x(x_: type) {
+ // fbb_.push_slot_always::<type>(offset, x_);
+ // }
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset);
+ code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b "));
+ code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field));
+ code_ += " #[inline]";
+ code_ += " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: "
+ "{{FIELD_TYPE}}) {";
+ if (is_scalar) {
+ code_.SetValue("FIELD_DEFAULT_VALUE",
+ TableBuilderAddFuncDefaultValue(field));
+ code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, "
+ "{{FIELD_DEFAULT_VALUE}});";
+ } else {
+ code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});";
+ }
+ code_ += " }";
+ }
+ }
+
+ // Struct initializer (all fields required);
+ code_ += " #[inline]";
+ code_ +=
+ " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> "
+ "{{STRUCT_NAME}}Builder<'a, 'b> {";
+ code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size()));
+ code_ += " let start = _fbb.start_table();";
+ code_ += " {{STRUCT_NAME}}Builder {";
+ code_ += " fbb_: _fbb,";
+ code_ += " start_: start,";
+ code_ += " }";
+ code_ += " }";
+
+ // finish() function.
+ code_ += " #[inline]";
+ code_ += " pub fn finish(self) -> "
+ "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {";
+ code_ += " let o = self.fbb_.end_table(self.start_);";
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (!field.deprecated && field.required) {
+ code_.SetValue("FIELD_NAME", MakeSnakeCase(Name(field)));
+ code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
+ code_ += " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}},"
+ "\"{{FIELD_NAME}}\");";
+ }
+ }
+ code_ += " flatbuffers::WIPOffset::new(o.value())";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ }
+
+ // Generate functions to compare tables and structs by key. This function
+ // must only be called if the field key is defined.
+ void GenKeyFieldMethods(const FieldDef &field) {
+ FLATBUFFERS_ASSERT(field.key);
+
+ code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, ""));
+
+ code_ += " #[inline]";
+ code_ += " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> "
+ " bool {";
+ code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()";
+ code_ += " }";
+ code_ += "";
+ code_ += " #[inline]";
+ code_ += " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> "
+ " ::std::cmp::Ordering {";
+ code_ += " let key = self.{{FIELD_NAME}}();";
+ code_ += " key.cmp(&val)";
+ code_ += " }";
+ }
+
+ // Generate functions for accessing the root table object. This function
+ // must only be called if the root table is defined.
+ void GenRootTableFuncs(const StructDef &struct_def) {
+ FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined");
+ auto name = Name(struct_def);
+
+ code_.SetValue("STRUCT_NAME", name);
+ code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name));
+ code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name)));
+
+ // The root datatype accessors:
+ code_ += "#[inline]";
+ code_ +=
+ "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])"
+ " -> {{STRUCT_NAME}}<'a> {";
+ code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)";
+ code_ += "}";
+ code_ += "";
+
+ code_ += "#[inline]";
+ code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}"
+ "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {";
+ code_ += " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>"
+ "(buf)";
+ code_ += "}";
+ code_ += "";
+
+ if (parser_.file_identifier_.length()) {
+ // Declare the identifier
+ code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &'static str\\";
+ code_ += " = \"" + parser_.file_identifier_ + "\";";
+ code_ += "";
+
+ // Check if a buffer has the identifier.
+ code_ += "#[inline]";
+ code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\";
+ code_ += "(buf: &[u8]) -> bool {";
+ code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
+ code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false);";
+ code_ += "}";
+ code_ += "";
+ code_ += "#[inline]";
+ code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\";
+ code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {";
+ code_ += " return flatbuffers::buffer_has_identifier(buf, \\";
+ code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true);";
+ code_ += "}";
+ code_ += "";
+ }
+
+ if (parser_.file_extension_.length()) {
+ // Return the extension
+ code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &'static str = \\";
+ code_ += "\"" + parser_.file_extension_ + "\";";
+ code_ += "";
+ }
+
+ // Finish a buffer with a given root object:
+ code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset");
+ code_ += "#[inline]";
+ code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>(";
+ code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,";
+ code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ if (parser_.file_identifier_.length()) {
+ code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ } else {
+ code_ += " fbb.finish(root, None);";
+ }
+ code_ += "}";
+ code_ += "";
+ code_ += "#[inline]";
+ code_ += "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer"
+ "<'a, 'b>("
+ "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, "
+ "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {";
+ if (parser_.file_identifier_.length()) {
+ code_ += " fbb.finish_size_prefixed(root, "
+ "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));";
+ } else {
+ code_ += " fbb.finish_size_prefixed(root, None);";
+ }
+ code_ += "}";
+ }
+
+ static void GenPadding(
+ const FieldDef &field, std::string *code_ptr, int *id,
+ const std::function<void(int bits, std::string *code_ptr, int *id)> &f) {
+ if (field.padding) {
+ for (int i = 0; i < 4; i++) {
+ if (static_cast<int>(field.padding) & (1 << i)) {
+ f((1 << i) * 8, code_ptr, id);
+ }
+ }
+ assert(!(field.padding & ~0xF));
+ }
+ }
+
+ static void PaddingDefinition(int bits, std::string *code_ptr, int *id) {
+ *code_ptr += " padding" + NumToString((*id)++) + "__: u" + \
+ NumToString(bits) + ",";
+ }
+
+ static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
+ (void)bits;
+ *code_ptr += "padding" + NumToString((*id)++) + "__: 0,";
+ }
+
+ // Generate an accessor struct with constructor for a flatbuffers struct.
+ void GenStruct(const StructDef &struct_def) {
+ // Generates manual padding and alignment.
+ // Variables are private because they contain little endian data on all
+ // platforms.
+ GenComment(struct_def.doc_comment);
+ code_.SetValue("ALIGN", NumToString(struct_def.minalign));
+ code_.SetValue("STRUCT_NAME", Name(struct_def));
+
+ code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}";
+ code_ += "#[repr(C, align({{ALIGN}}))]";
+
+ // PartialEq is useful to derive because we can correctly compare structs
+ // for equality by just comparing their underlying byte data. This doesn't
+ // hold for PartialOrd/Ord.
+ code_ += "#[derive(Clone, Copy, Debug, PartialEq)]";
+ code_ += "pub struct {{STRUCT_NAME}} {";
+
+ int padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type));
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_ += " {{FIELD_NAME}}_: {{FIELD_TYPE}},";
+
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingDefinition);
+ code_ += padding;
+ }
+ }
+
+ code_ += "} // pub struct {{STRUCT_NAME}}";
+
+ // Generate impls for SafeSliceAccess (because all structs are endian-safe),
+ // Follow for the value type, Follow for the reference type, Push for the
+ // value type, and Push for the reference type.
+ code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {";
+ code_ += " type Inner = &'a {{STRUCT_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {";
+ code_ += " type Inner = &'a {{STRUCT_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {";
+ code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)";
+ code_ += " }";
+ code_ += "}";
+ code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {";
+ code_ += " type Output = {{STRUCT_NAME}};";
+ code_ += " #[inline]";
+ code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+ code_ += " let src = unsafe {";
+ code_ += " ::std::slice::from_raw_parts("
+ "self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+ code_ += " };";
+ code_ += " dst.copy_from_slice(src);";
+ code_ += " }";
+ code_ += "}";
+ code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {";
+ code_ += " type Output = {{STRUCT_NAME}};";
+ code_ += "";
+ code_ += " #[inline]";
+ code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {";
+ code_ += " let src = unsafe {";
+ code_ += " ::std::slice::from_raw_parts("
+ "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())";
+ code_ += " };";
+ code_ += " dst.copy_from_slice(src);";
+ code_ += " }";
+ code_ += "}";
+ code_ += "";
+ code_ += "";
+
+ // Generate a constructor that takes all fields as arguments.
+ code_ += "impl {{STRUCT_NAME}} {";
+ std::string arg_list;
+ std::string init_list;
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ const auto member_name = Name(field) + "_";
+ const auto reference = StructMemberAccessNeedsCopy(field.value.type)
+ ? "" : "&'a ";
+ const auto arg_name = "_" + Name(field);
+ const auto arg_type = reference + GetTypeGet(field.value.type);
+
+ if (it != struct_def.fields.vec.begin()) {
+ arg_list += ", ";
+ }
+ arg_list += arg_name + ": ";
+ arg_list += arg_type;
+ init_list += " " + member_name;
+ if (StructMemberAccessNeedsCopy(field.value.type)) {
+ init_list += ": " + arg_name + ".to_little_endian(),\n";
+ } else {
+ init_list += ": *" + arg_name + ",\n";
+ }
+ }
+
+ code_.SetValue("ARG_LIST", arg_list);
+ code_.SetValue("INIT_LIST", init_list);
+ code_ += " pub fn new<'a>({{ARG_LIST}}) -> Self {";
+ code_ += " {{STRUCT_NAME}} {";
+ code_ += "{{INIT_LIST}}";
+ padding_id = 0;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+ if (field.padding) {
+ std::string padding;
+ GenPadding(field, &padding, &padding_id, PaddingInitializer);
+ code_ += " " + padding;
+ }
+ }
+ code_ += " }";
+ code_ += " }";
+
+ // Generate accessor methods for the struct.
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ const auto &field = **it;
+
+ auto field_type = TableBuilderArgsAddFuncType(field, "'a");
+ auto member = "self." + Name(field) + "_";
+ auto value = StructMemberAccessNeedsCopy(field.value.type) ?
+ member + ".from_little_endian()" : member;
+
+ code_.SetValue("FIELD_NAME", Name(field));
+ code_.SetValue("FIELD_TYPE", field_type);
+ code_.SetValue("FIELD_VALUE", value);
+ code_.SetValue("REF", IsStruct(field.value.type) ? "&" : "");
+
+ GenComment(field.doc_comment, " ");
+ code_ += " pub fn {{FIELD_NAME}}<'a>(&'a self) -> {{FIELD_TYPE}} {";
+ code_ += " {{REF}}{{FIELD_VALUE}}";
+ code_ += " }";
+
+ // Generate a comparison function for this field if it is a key.
+ if (field.key) {
+ GenKeyFieldMethods(field);
+ }
+ }
+ code_ += "}";
+ code_ += "";
+ }
+
+ void GenNamespaceImports(const int white_spaces) {
+ std::string indent = std::string(white_spaces, ' ');
+ code_ += "";
+ code_ += indent + "use std::mem;";
+ code_ += indent + "use std::cmp::Ordering;";
+ code_ += "";
+ code_ += indent + "extern crate flatbuffers;";
+ code_ += indent + "use self::flatbuffers::EndianScalar;";
+ }
+
+ // Set up the correct namespace. This opens a namespace if the current
+ // namespace is different from the target namespace. This function
+ // closes and opens the namespaces only as necessary.
+ //
+ // The file must start and end with an empty (or null) namespace so that
+ // namespaces are properly opened and closed.
+ void SetNameSpace(const Namespace *ns) {
+ if (cur_name_space_ == ns) { return; }
+
+ // Compute the size of the longest common namespace prefix.
+ // If cur_name_space is A::B::C::D and ns is A::B::E::F::G,
+ // the common prefix is A::B:: and we have old_size = 4, new_size = 5
+ // and common_prefix_size = 2
+ size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0;
+ size_t new_size = ns ? ns->components.size() : 0;
+
+ size_t common_prefix_size = 0;
+ while (common_prefix_size < old_size && common_prefix_size < new_size &&
+ ns->components[common_prefix_size] ==
+ cur_name_space_->components[common_prefix_size]) {
+ common_prefix_size++;
+ }
+
+ // Close cur_name_space in reverse order to reach the common prefix.
+ // In the previous example, D then C are closed.
+ for (size_t j = old_size; j > common_prefix_size; --j) {
+ code_ += "} // pub mod " + cur_name_space_->components[j - 1];
+ }
+ if (old_size != common_prefix_size) { code_ += ""; }
+
+ // open namespace parts to reach the ns namespace
+ // in the previous example, E, then F, then G are opened
+ for (auto j = common_prefix_size; j != new_size; ++j) {
+ code_ += "#[allow(unused_imports, dead_code)]";
+ code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {";
+ // Generate local namespace imports.
+ GenNamespaceImports(2);
+ }
+ if (new_size != common_prefix_size) { code_ += ""; }
+
+ cur_name_space_ = ns;
+ }
+};
+
+} // namespace rust
+
+bool GenerateRust(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ rust::RustGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+std::string RustMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+
+ auto included_files = parser.GetIncludedFilesRecursive(file_name);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
+
+// TODO(rw): Generated code should import other generated files.
+// TODO(rw): Generated code should refer to namespaces in included files in a
+// way that makes them referrable.
+// TODO(rw): Generated code should indent according to nesting level.
+// TODO(rw): Generated code should generate endian-safe Debug impls.
+// TODO(rw): Generated code could use a Rust-only enum type to access unions,
+// instead of making the user use _type() to manually switch.
diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp
new file mode 100644
index 0000000..9825dce
--- /dev/null
+++ b/src/idl_gen_text.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flexbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+ int indent, const IDLOptions &opts, std::string *_text);
+
+// If indentation is less than 0, that indicates we don't want any newlines
+// either.
+const char *NewLine(const IDLOptions &opts) {
+ return opts.indent_step >= 0 ? "\n" : "";
+}
+
+int Indent(const IDLOptions &opts) { return std::max(opts.indent_step, 0); }
+
+// Output an identifier with or without quotes depending on strictness.
+void OutputIdentifier(const std::string &name, const IDLOptions &opts,
+ std::string *_text) {
+ std::string &text = *_text;
+ if (opts.strict_json) text += "\"";
+ text += name;
+ if (opts.strict_json) text += "\"";
+}
+
+// Print (and its template specialization below for pointers) generate text
+// for a single FlatBuffer value into JSON format.
+// The general case for scalars:
+template<typename T>
+bool Print(T val, Type type, int /*indent*/, Type * /*union_type*/,
+ const IDLOptions &opts, std::string *_text) {
+ std::string &text = *_text;
+ if (type.enum_def && opts.output_enum_identifiers) {
+ std::vector<EnumVal const *> enum_values;
+ if (auto ev = type.enum_def->ReverseLookup(static_cast<int64_t>(val))) {
+ enum_values.push_back(ev);
+ } else if (val && type.enum_def->attributes.Lookup("bit_flags")) {
+ for (auto it = type.enum_def->Vals().begin(),
+ e = type.enum_def->Vals().end();
+ it != e; ++it) {
+ if ((*it)->GetAsUInt64() & static_cast<uint64_t>(val))
+ enum_values.push_back(*it);
+ }
+ }
+ if (!enum_values.empty()) {
+ text += '\"';
+ for (auto it = enum_values.begin(), e = enum_values.end(); it != e; ++it)
+ text += (*it)->name + ' ';
+ text[text.length() - 1] = '\"';
+ return true;
+ }
+ }
+
+ if (type.base_type == BASE_TYPE_BOOL) {
+ text += val != 0 ? "true" : "false";
+ } else {
+ text += NumToString(val);
+ }
+
+ return true;
+}
+
+// Print a vector or an array of JSON values, comma seperated, wrapped in "[]".
+template<typename T, typename Container>
+bool PrintContainer(const Container &c, size_t size, Type type, int indent,
+ const IDLOptions &opts, std::string *_text) {
+ std::string &text = *_text;
+ text += "[";
+ text += NewLine(opts);
+ for (uoffset_t i = 0; i < size; i++) {
+ if (i) {
+ if (!opts.protobuf_ascii_alike) text += ",";
+ text += NewLine(opts);
+ }
+ text.append(indent + Indent(opts), ' ');
+ if (IsStruct(type)) {
+ if (!Print(reinterpret_cast<const void *>(c.Data() +
+ i * type.struct_def->bytesize),
+ type, indent + Indent(opts), nullptr, opts, _text)) {
+ return false;
+ }
+ } else {
+ if (!Print(c[i], type, indent + Indent(opts), nullptr, opts, _text)) {
+ return false;
+ }
+ }
+ }
+ text += NewLine(opts);
+ text.append(indent, ' ');
+ text += "]";
+ return true;
+}
+
+template<typename T>
+bool PrintVector(const Vector<T> &v, Type type, int indent,
+ const IDLOptions &opts, std::string *_text) {
+ return PrintContainer<T, Vector<T>>(v, v.size(), type, indent, opts, _text);
+}
+
+// Print an array a sequence of JSON values, comma separated, wrapped in "[]".
+template<typename T>
+bool PrintArray(const Array<T, 0xFFFF> &a, size_t size, Type type, int indent,
+ const IDLOptions &opts, std::string *_text) {
+ return PrintContainer<T, Array<T, 0xFFFF>>(a, size, type, indent, opts,
+ _text);
+}
+
+// Specialization of Print above for pointer types.
+template<>
+bool Print<const void *>(const void *val, Type type, int indent,
+ Type *union_type, const IDLOptions &opts,
+ std::string *_text) {
+ switch (type.base_type) {
+ case BASE_TYPE_UNION:
+ // If this assert hits, you have an corrupt buffer, a union type field
+ // was not present or was out of range.
+ FLATBUFFERS_ASSERT(union_type);
+ return Print<const void *>(val, *union_type, indent, nullptr, opts,
+ _text);
+ case BASE_TYPE_STRUCT:
+ if (!GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val),
+ indent, opts, _text)) {
+ return false;
+ }
+ break;
+ case BASE_TYPE_STRING: {
+ auto s = reinterpret_cast<const String *>(val);
+ if (!EscapeString(s->c_str(), s->size(), _text, opts.allow_non_utf8,
+ opts.natural_utf8)) {
+ return false;
+ }
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ const auto vec_type = type.VectorType();
+ // Call PrintVector above specifically for each element type:
+ // clang-format off
+ switch (vec_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!PrintVector<CTYPE>( \
+ *reinterpret_cast<const Vector<CTYPE> *>(val), \
+ vec_type, indent, opts, _text)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ }
+ // clang-format on
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ const auto vec_type = type.VectorType();
+ // Call PrintArray above specifically for each element type:
+ // clang-format off
+ switch (vec_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!PrintArray<CTYPE>( \
+ *reinterpret_cast<const Array<CTYPE, 0xFFFF> *>(val), \
+ type.fixed_length, \
+ vec_type, indent, opts, _text)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0);
+ }
+ // clang-format on
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ return true;
+}
+
+template<typename T> static T GetFieldDefault(const FieldDef &fd) {
+ T val;
+ auto check = StringToNumber(fd.value.constant.c_str(), &val);
+ (void)check;
+ FLATBUFFERS_ASSERT(check);
+ return val;
+}
+
+// Generate text for a scalar field.
+template<typename T>
+static bool GenField(const FieldDef &fd, const Table *table, bool fixed,
+ const IDLOptions &opts, int indent, std::string *_text) {
+ return Print(
+ fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>(
+ fd.value.offset)
+ : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)),
+ fd.value.type, indent, nullptr, opts, _text);
+}
+
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+ int indent, const IDLOptions &opts, std::string *_text);
+
+// Generate text for non-scalar field.
+static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
+ int indent, Type *union_type, const IDLOptions &opts,
+ std::string *_text) {
+ const void *val = nullptr;
+ if (fixed) {
+ // The only non-scalar fields in structs are structs or arrays.
+ FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type));
+ val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>(
+ fd.value.offset);
+ } else if (fd.flexbuffer) {
+ auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+ auto root = flexbuffers::GetRoot(vec->data(), vec->size());
+ root.ToString(true, opts.strict_json, *_text);
+ return true;
+ } else if (fd.nested_flatbuffer) {
+ auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+ auto root = GetRoot<Table>(vec->data());
+ return GenStruct(*fd.nested_flatbuffer, root, indent, opts, _text);
+ } else {
+ val = IsStruct(fd.value.type)
+ ? table->GetStruct<const void *>(fd.value.offset)
+ : table->GetPointer<const void *>(fd.value.offset);
+ }
+ return Print(val, fd.value.type, indent, union_type, opts, _text);
+}
+
+// Generate text for a struct or table, values separated by commas, indented,
+// and bracketed by "{}"
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+ int indent, const IDLOptions &opts, std::string *_text) {
+ std::string &text = *_text;
+ text += "{";
+ int fieldout = 0;
+ Type *union_type = nullptr;
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ FieldDef &fd = **it;
+ auto is_present = struct_def.fixed || table->CheckField(fd.value.offset);
+ auto output_anyway = opts.output_default_scalars_in_json &&
+ IsScalar(fd.value.type.base_type) && !fd.deprecated;
+ if (is_present || output_anyway) {
+ if (fieldout++) {
+ if (!opts.protobuf_ascii_alike) text += ",";
+ }
+ text += NewLine(opts);
+ text.append(indent + Indent(opts), ' ');
+ OutputIdentifier(fd.name, opts, _text);
+ if (!opts.protobuf_ascii_alike ||
+ (fd.value.type.base_type != BASE_TYPE_STRUCT &&
+ fd.value.type.base_type != BASE_TYPE_VECTOR))
+ text += ":";
+ text += " ";
+ switch (fd.value.type.base_type) {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
+ opts, indent + Indent(opts), _text)) { \
+ return false; \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // Generate drop-thru case statements for all pointer types:
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM:
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
+ FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
+ union_type, opts, _text)) {
+ return false;
+ }
+ break;
+ // clang-format on
+ }
+ if (fd.value.type.base_type == BASE_TYPE_UTYPE) {
+ auto enum_val = fd.value.type.enum_def->ReverseLookup(
+ table->GetField<uint8_t>(fd.value.offset, 0), true);
+ union_type = enum_val ? &enum_val->union_type : nullptr;
+ }
+ }
+ }
+ text += NewLine(opts);
+ text.append(indent, ' ');
+ text += "}";
+ return true;
+}
+
+// Generate a text representation of a flatbuffer in JSON format.
+bool GenerateTextFromTable(const Parser &parser, const void *table,
+ const std::string &table_name, std::string *_text) {
+ auto struct_def = parser.LookupStruct(table_name);
+ if (struct_def == nullptr) {
+ return false;
+ }
+ auto &text = *_text;
+ text.reserve(1024); // Reduce amount of inevitable reallocs.
+ auto root = static_cast<const Table *>(table);
+ if (!GenStruct(*struct_def, root, 0, parser.opts, &text)) {
+ return false;
+ }
+ text += NewLine(parser.opts);
+ return true;
+}
+
+// Generate a text representation of a flatbuffer in JSON format.
+bool GenerateText(const Parser &parser, const void *flatbuffer,
+ std::string *_text) {
+ std::string &text = *_text;
+ FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType()
+ text.reserve(1024); // Reduce amount of inevitable reallocs.
+ auto root = parser.opts.size_prefixed ?
+ GetSizePrefixedRoot<Table>(flatbuffer) : GetRoot<Table>(flatbuffer);
+ if (!GenStruct(*parser.root_struct_def_, root, 0, parser.opts, _text)) {
+ return false;
+ }
+ text += NewLine(parser.opts);
+ return true;
+}
+
+std::string TextFileName(const std::string &path,
+ const std::string &file_name) {
+ return path + file_name + ".json";
+}
+
+bool GenerateTextFile(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true;
+ std::string text;
+ if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) {
+ return false;
+ }
+ return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text,
+ false);
+}
+
+std::string TextMakeRule(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ if (!parser.builder_.GetSize() || !parser.root_struct_def_) return "";
+ std::string filebase =
+ flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
+ std::string make_rule = TextFileName(path, filebase) + ": " + file_name;
+ auto included_files =
+ parser.GetIncludedFilesRecursive(parser.root_struct_def_->file);
+ for (auto it = included_files.begin(); it != included_files.end(); ++it) {
+ make_rule += " " + *it;
+ }
+ return make_rule;
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
new file mode 100644
index 0000000..31b315c
--- /dev/null
+++ b/src/idl_parser.cpp
@@ -0,0 +1,3518 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <list>
+#include <string>
+#include <utility>
+
+#include <cmath>
+
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Reflects the version at the compiling time of binary(lib/dll/so).
+const char *FLATBUFFERS_VERSION() {
+ // clang-format off
+ return
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "."
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "."
+ FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION);
+ // clang-format on
+}
+
+const double kPi = 3.14159265358979323846;
+
+const char *const kTypeNames[] = {
+// clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ IDLTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ nullptr
+};
+
+const char kTypeSizes[] = {
+// clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ sizeof(CTYPE),
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+};
+
+// The enums in the reflection schema should match the ones we use internally.
+// Compare the last element to check if these go out of sync.
+static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::Union),
+ "enums don't match");
+
+// Any parsing calls have to be wrapped in this macro, which automates
+// handling of recursive error checking a bit. It will check the received
+// CheckedError object, and return straight away on error.
+#define ECHECK(call) \
+ { \
+ auto ce = (call); \
+ if (ce.Check()) return ce; \
+ }
+
+// These two functions are called hundreds of times below, so define a short
+// form:
+#define NEXT() ECHECK(Next())
+#define EXPECT(tok) ECHECK(Expect(tok))
+
+static bool ValidateUTF8(const std::string &str) {
+ const char *s = &str[0];
+ const char *const sEnd = s + str.length();
+ while (s < sEnd) {
+ if (FromUTF8(&s) < 0) { return false; }
+ }
+ return true;
+}
+
+// Convert an underscore_based_indentifier in to camelCase.
+// Also uppercases the first character if first is true.
+std::string MakeCamel(const std::string &in, bool first) {
+ std::string s;
+ for (size_t i = 0; i < in.length(); i++) {
+ if (!i && first)
+ s += static_cast<char>(toupper(in[0]));
+ else if (in[i] == '_' && i + 1 < in.length())
+ s += static_cast<char>(toupper(in[++i]));
+ else
+ s += in[i];
+ }
+ return s;
+}
+
+void DeserializeDoc( std::vector<std::string> &doc,
+ const Vector<Offset<String>> *documentation) {
+ if (documentation == nullptr) return;
+ for (uoffset_t index = 0; index < documentation->size(); index++)
+ doc.push_back(documentation->Get(index)->str());
+}
+
+void Parser::Message(const std::string &msg) {
+ if (!error_.empty()) error_ += "\n"; // log all warnings and errors
+ error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
+ // clang-format off
+
+ #ifdef _WIN32 // MSVC alike
+ error_ +=
+ "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")";
+ #else // gcc alike
+ if (file_being_parsed_.length()) error_ += ":";
+ error_ += NumToString(line_) + ": " + NumToString(CursorPosition());
+ #endif
+ // clang-format on
+ error_ += ": " + msg;
+}
+
+void Parser::Warning(const std::string &msg) { Message("warning: " + msg); }
+
+CheckedError Parser::Error(const std::string &msg) {
+ Message("error: " + msg);
+ return CheckedError(true);
+}
+
+inline CheckedError NoError() { return CheckedError(false); }
+
+CheckedError Parser::RecurseError() {
+ return Error("maximum parsing recursion of " +
+ NumToString(FLATBUFFERS_MAX_PARSING_DEPTH) + " reached");
+}
+
+template<typename F> CheckedError Parser::Recurse(F f) {
+ if (recurse_protection_counter >= (FLATBUFFERS_MAX_PARSING_DEPTH))
+ return RecurseError();
+ recurse_protection_counter++;
+ auto ce = f();
+ recurse_protection_counter--;
+ return ce;
+}
+
+template<typename T> std::string TypeToIntervalString() {
+ return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " +
+ NumToString((flatbuffers::numeric_limits<T>::max)()) + "]";
+}
+
+// atot: template version of atoi/atof: convert a string to an instance of T.
+template<typename T>
+inline CheckedError atot(const char *s, Parser &parser, T *val) {
+ auto done = StringToNumber(s, val);
+ if (done) return NoError();
+ if (0 == *val)
+ return parser.Error("invalid number: \"" + std::string(s) + "\"");
+ else
+ return parser.Error("invalid number: \"" + std::string(s) + "\"" +
+ ", constant does not fit " + TypeToIntervalString<T>());
+}
+template<>
+inline CheckedError atot<Offset<void>>(const char *s, Parser &parser,
+ Offset<void> *val) {
+ (void)parser;
+ *val = Offset<void>(atoi(s));
+ return NoError();
+}
+
+std::string Namespace::GetFullyQualifiedName(const std::string &name,
+ size_t max_components) const {
+ // Early exit if we don't have a defined namespace.
+ if (components.empty() || !max_components) { return name; }
+ std::string stream_str;
+ for (size_t i = 0; i < std::min(components.size(), max_components); i++) {
+ if (i) { stream_str += '.'; }
+ stream_str += std::string(components[i]);
+ }
+ if (name.length()) {
+ stream_str += '.';
+ stream_str += name;
+ }
+ return stream_str;
+}
+
+// Declare tokens we'll use. Single character tokens are represented by their
+// ascii character code (e.g. '{'), others above 256.
+// clang-format off
+#define FLATBUFFERS_GEN_TOKENS(TD) \
+ TD(Eof, 256, "end of file") \
+ TD(StringConstant, 257, "string constant") \
+ TD(IntegerConstant, 258, "integer constant") \
+ TD(FloatConstant, 259, "float constant") \
+ TD(Identifier, 260, "identifier")
+#ifdef __GNUC__
+__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
+#endif
+enum {
+ #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
+ FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
+ #undef FLATBUFFERS_TOKEN
+};
+
+static std::string TokenToString(int t) {
+ static const char * const tokens[] = {
+ #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
+ FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
+ #undef FLATBUFFERS_TOKEN
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ IDLTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ };
+ if (t < 256) { // A single ascii char token.
+ std::string s;
+ s.append(1, static_cast<char>(t));
+ return s;
+ } else { // Other tokens.
+ return tokens[t - 256];
+ }
+}
+// clang-format on
+
+std::string Parser::TokenToStringId(int t) const {
+ return t == kTokenIdentifier ? attribute_ : TokenToString(t);
+}
+
+// Parses exactly nibbles worth of hex digits into a number, or error.
+CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
+ FLATBUFFERS_ASSERT(nibbles > 0);
+ for (int i = 0; i < nibbles; i++)
+ if (!is_xdigit(cursor_[i]))
+ return Error("escape code must be followed by " + NumToString(nibbles) +
+ " hex digits");
+ std::string target(cursor_, cursor_ + nibbles);
+ *val = StringToUInt(target.c_str(), 16);
+ cursor_ += nibbles;
+ return NoError();
+}
+
+CheckedError Parser::SkipByteOrderMark() {
+ if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
+ cursor_++;
+ if (static_cast<unsigned char>(*cursor_) != 0xbb)
+ return Error("invalid utf-8 byte order mark");
+ cursor_++;
+ if (static_cast<unsigned char>(*cursor_) != 0xbf)
+ return Error("invalid utf-8 byte order mark");
+ cursor_++;
+ return NoError();
+}
+
+static inline bool IsIdentifierStart(char c) {
+ return is_alpha(c) || (c == '_');
+}
+
+CheckedError Parser::Next() {
+ doc_comment_.clear();
+ bool seen_newline = cursor_ == source_;
+ attribute_.clear();
+ attr_is_trivial_ascii_string_ = true;
+ for (;;) {
+ char c = *cursor_++;
+ token_ = c;
+ switch (c) {
+ case '\0':
+ cursor_--;
+ token_ = kTokenEof;
+ return NoError();
+ case ' ':
+ case '\r':
+ case '\t': break;
+ case '\n':
+ MarkNewLine();
+ seen_newline = true;
+ break;
+ case '{':
+ case '}':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case ',':
+ case ':':
+ case ';':
+ case '=': return NoError();
+ case '\"':
+ case '\'': {
+ int unicode_high_surrogate = -1;
+
+ while (*cursor_ != c) {
+ if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0)
+ return Error("illegal character in string constant");
+ if (*cursor_ == '\\') {
+ attr_is_trivial_ascii_string_ = false; // has escape sequence
+ cursor_++;
+ if (unicode_high_surrogate != -1 && *cursor_ != 'u') {
+ return Error(
+ "illegal Unicode sequence (unpaired high surrogate)");
+ }
+ switch (*cursor_) {
+ case 'n':
+ attribute_ += '\n';
+ cursor_++;
+ break;
+ case 't':
+ attribute_ += '\t';
+ cursor_++;
+ break;
+ case 'r':
+ attribute_ += '\r';
+ cursor_++;
+ break;
+ case 'b':
+ attribute_ += '\b';
+ cursor_++;
+ break;
+ case 'f':
+ attribute_ += '\f';
+ cursor_++;
+ break;
+ case '\"':
+ attribute_ += '\"';
+ cursor_++;
+ break;
+ case '\'':
+ attribute_ += '\'';
+ cursor_++;
+ break;
+ case '\\':
+ attribute_ += '\\';
+ cursor_++;
+ break;
+ case '/':
+ attribute_ += '/';
+ cursor_++;
+ break;
+ case 'x': { // Not in the JSON standard
+ cursor_++;
+ uint64_t val;
+ ECHECK(ParseHexNum(2, &val));
+ attribute_ += static_cast<char>(val);
+ break;
+ }
+ case 'u': {
+ cursor_++;
+ uint64_t val;
+ ECHECK(ParseHexNum(4, &val));
+ if (val >= 0xD800 && val <= 0xDBFF) {
+ if (unicode_high_surrogate != -1) {
+ return Error(
+ "illegal Unicode sequence (multiple high surrogates)");
+ } else {
+ unicode_high_surrogate = static_cast<int>(val);
+ }
+ } else if (val >= 0xDC00 && val <= 0xDFFF) {
+ if (unicode_high_surrogate == -1) {
+ return Error(
+ "illegal Unicode sequence (unpaired low surrogate)");
+ } else {
+ int code_point = 0x10000 +
+ ((unicode_high_surrogate & 0x03FF) << 10) +
+ (val & 0x03FF);
+ ToUTF8(code_point, &attribute_);
+ unicode_high_surrogate = -1;
+ }
+ } else {
+ if (unicode_high_surrogate != -1) {
+ return Error(
+ "illegal Unicode sequence (unpaired high surrogate)");
+ }
+ ToUTF8(static_cast<int>(val), &attribute_);
+ }
+ break;
+ }
+ default: return Error("unknown escape code in string constant");
+ }
+ } else { // printable chars + UTF-8 bytes
+ if (unicode_high_surrogate != -1) {
+ return Error(
+ "illegal Unicode sequence (unpaired high surrogate)");
+ }
+ // reset if non-printable
+ attr_is_trivial_ascii_string_ &= check_ascii_range(*cursor_, ' ', '~');
+
+ attribute_ += *cursor_++;
+ }
+ }
+ if (unicode_high_surrogate != -1) {
+ return Error("illegal Unicode sequence (unpaired high surrogate)");
+ }
+ cursor_++;
+ if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 &&
+ !ValidateUTF8(attribute_)) {
+ return Error("illegal UTF-8 sequence");
+ }
+ token_ = kTokenStringConstant;
+ return NoError();
+ }
+ case '/':
+ if (*cursor_ == '/') {
+ const char *start = ++cursor_;
+ while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++;
+ if (*start == '/') { // documentation comment
+ if (!seen_newline)
+ return Error(
+ "a documentation comment should be on a line on its own");
+ doc_comment_.push_back(std::string(start + 1, cursor_));
+ }
+ break;
+ } else if (*cursor_ == '*') {
+ cursor_++;
+ // TODO: make nested.
+ while (*cursor_ != '*' || cursor_[1] != '/') {
+ if (*cursor_ == '\n') MarkNewLine();
+ if (!*cursor_) return Error("end of file in comment");
+ cursor_++;
+ }
+ cursor_ += 2;
+ break;
+ }
+ FLATBUFFERS_FALLTHROUGH(); // else fall thru
+ default:
+ const auto has_sign = (c == '+') || (c == '-');
+ // '-'/'+' and following identifier - can be a predefined constant like:
+ // NAN, INF, PI, etc.
+ if (IsIdentifierStart(c) || (has_sign && IsIdentifierStart(*cursor_))) {
+ // Collect all chars of an identifier:
+ const char *start = cursor_ - 1;
+ while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++;
+ attribute_.append(start, cursor_);
+ token_ = has_sign ? kTokenStringConstant : kTokenIdentifier;
+ return NoError();
+ }
+
+ auto dot_lvl = (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen
+ if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum?
+ // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4).
+ if (is_digit(c) || has_sign || !dot_lvl) {
+ const auto start = cursor_ - 1;
+ auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1;
+ if (!is_digit(c) && is_digit(*cursor_)){
+ start_digits = cursor_; // see digit in cursor_ position
+ c = *cursor_++;
+ }
+ // hex-float can't begind with '.'
+ auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X');
+ if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it
+ // Read an integer number or mantisa of float-point number.
+ do {
+ if (use_hex) {
+ while (is_xdigit(*cursor_)) cursor_++;
+ } else {
+ while (is_digit(*cursor_)) cursor_++;
+ }
+ } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0));
+ // Exponent of float-point number.
+ if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
+ // The exponent suffix of hexadecimal float number is mandatory.
+ if (use_hex && !dot_lvl) start_digits = cursor_;
+ if ((use_hex && is_alpha_char(*cursor_, 'P')) ||
+ is_alpha_char(*cursor_, 'E')) {
+ dot_lvl = 0; // Emulate dot to signal about float-point number.
+ cursor_++;
+ if (*cursor_ == '+' || *cursor_ == '-') cursor_++;
+ start_digits = cursor_; // the exponent-part has to have digits
+ // Exponent is decimal integer number
+ while (is_digit(*cursor_)) cursor_++;
+ if (*cursor_ == '.') {
+ cursor_++; // If see a dot treat it as part of invalid number.
+ dot_lvl = -1; // Fall thru to Error().
+ }
+ }
+ }
+ // Finalize.
+ if ((dot_lvl >= 0) && (cursor_ > start_digits)) {
+ attribute_.append(start, cursor_);
+ token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant;
+ return NoError();
+ } else {
+ return Error("invalid number: " + std::string(start, cursor_));
+ }
+ }
+ std::string ch;
+ ch = c;
+ if (false == check_ascii_range(c, ' ', '~')) ch = "code: " + NumToString(c);
+ return Error("illegal character: " + ch);
+ }
+ }
+}
+
+// Check if a given token is next.
+bool Parser::Is(int t) const { return t == token_; }
+
+bool Parser::IsIdent(const char *id) const {
+ return token_ == kTokenIdentifier && attribute_ == id;
+}
+
+// Expect a given token to be next, consume it, or error if not present.
+CheckedError Parser::Expect(int t) {
+ if (t != token_) {
+ return Error("expecting: " + TokenToString(t) +
+ " instead got: " + TokenToStringId(token_));
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) {
+ while (Is('.')) {
+ NEXT();
+ *id += ".";
+ *id += attribute_;
+ if (last) *last = attribute_;
+ EXPECT(kTokenIdentifier);
+ }
+ return NoError();
+}
+
+EnumDef *Parser::LookupEnum(const std::string &id) {
+ // Search thru parent namespaces.
+ for (int components = static_cast<int>(current_namespace_->components.size());
+ components >= 0; components--) {
+ auto ed = enums_.Lookup(
+ current_namespace_->GetFullyQualifiedName(id, components));
+ if (ed) return ed;
+ }
+ return nullptr;
+}
+
+StructDef *Parser::LookupStruct(const std::string &id) const {
+ auto sd = structs_.Lookup(id);
+ if (sd) sd->refcount++;
+ return sd;
+}
+
+CheckedError Parser::ParseTypeIdent(Type &type) {
+ std::string id = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseNamespacing(&id, nullptr));
+ auto enum_def = LookupEnum(id);
+ if (enum_def) {
+ type = enum_def->underlying_type;
+ if (enum_def->is_union) type.base_type = BASE_TYPE_UNION;
+ } else {
+ type.base_type = BASE_TYPE_STRUCT;
+ type.struct_def = LookupCreateStruct(id);
+ }
+ return NoError();
+}
+
+// Parse any IDL type.
+CheckedError Parser::ParseType(Type &type) {
+ if (token_ == kTokenIdentifier) {
+ if (IsIdent("bool")) {
+ type.base_type = BASE_TYPE_BOOL;
+ NEXT();
+ } else if (IsIdent("byte") || IsIdent("int8")) {
+ type.base_type = BASE_TYPE_CHAR;
+ NEXT();
+ } else if (IsIdent("ubyte") || IsIdent("uint8")) {
+ type.base_type = BASE_TYPE_UCHAR;
+ NEXT();
+ } else if (IsIdent("short") || IsIdent("int16")) {
+ type.base_type = BASE_TYPE_SHORT;
+ NEXT();
+ } else if (IsIdent("ushort") || IsIdent("uint16")) {
+ type.base_type = BASE_TYPE_USHORT;
+ NEXT();
+ } else if (IsIdent("int") || IsIdent("int32")) {
+ type.base_type = BASE_TYPE_INT;
+ NEXT();
+ } else if (IsIdent("uint") || IsIdent("uint32")) {
+ type.base_type = BASE_TYPE_UINT;
+ NEXT();
+ } else if (IsIdent("long") || IsIdent("int64")) {
+ type.base_type = BASE_TYPE_LONG;
+ NEXT();
+ } else if (IsIdent("ulong") || IsIdent("uint64")) {
+ type.base_type = BASE_TYPE_ULONG;
+ NEXT();
+ } else if (IsIdent("float") || IsIdent("float32")) {
+ type.base_type = BASE_TYPE_FLOAT;
+ NEXT();
+ } else if (IsIdent("double") || IsIdent("float64")) {
+ type.base_type = BASE_TYPE_DOUBLE;
+ NEXT();
+ } else if (IsIdent("string")) {
+ type.base_type = BASE_TYPE_STRING;
+ NEXT();
+ } else {
+ ECHECK(ParseTypeIdent(type));
+ }
+ } else if (token_ == '[') {
+ NEXT();
+ Type subtype;
+ ECHECK(Recurse([&]() { return ParseType(subtype); }));
+ if (IsSeries(subtype)) {
+ // We could support this, but it will complicate things, and it's
+ // easier to work around with a struct around the inner vector.
+ return Error("nested vector types not supported (wrap in table first)");
+ }
+ if (token_ == ':') {
+ NEXT();
+ if (token_ != kTokenIntegerConstant) {
+ return Error("length of fixed-length array must be an integer value");
+ }
+ uint16_t fixed_length = 0;
+ bool check = StringToNumber(attribute_.c_str(), &fixed_length);
+ if (!check || fixed_length < 1) {
+ return Error(
+ "length of fixed-length array must be positive and fit to "
+ "uint16_t type");
+ }
+ // Check if enum arrays are used in C++ without specifying --scoped-enums
+ if ((opts.lang_to_generate & IDLOptions::kCpp) && !opts.scoped_enums &&
+ IsEnum(subtype)) {
+ return Error(
+ "--scoped-enums must be enabled to use enum arrays in C++\n");
+ }
+ type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def,
+ fixed_length);
+ NEXT();
+ } else {
+ type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
+ }
+ type.element = subtype.base_type;
+ EXPECT(']');
+ } else {
+ return Error("illegal type syntax");
+ }
+ return NoError();
+}
+
+CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
+ const Type &type, FieldDef **dest) {
+ auto &field = *new FieldDef();
+ field.value.offset =
+ FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size()));
+ field.name = name;
+ field.file = struct_def.file;
+ field.value.type = type;
+ if (struct_def.fixed) { // statically compute the field offset
+ auto size = InlineSize(type);
+ auto alignment = InlineAlignment(type);
+ // structs_ need to have a predictable format, so we need to align to
+ // the largest scalar
+ struct_def.minalign = std::max(struct_def.minalign, alignment);
+ struct_def.PadLastField(alignment);
+ field.value.offset = static_cast<voffset_t>(struct_def.bytesize);
+ struct_def.bytesize += size;
+ }
+ if (struct_def.fields.Add(name, &field))
+ return Error("field already exists: " + name);
+ *dest = &field;
+ return NoError();
+}
+
+CheckedError Parser::ParseField(StructDef &struct_def) {
+ std::string name = attribute_;
+
+ if (LookupStruct(name))
+ return Error("field name can not be the same as table/struct name");
+
+ std::vector<std::string> dc = doc_comment_;
+ EXPECT(kTokenIdentifier);
+ EXPECT(':');
+ Type type;
+ ECHECK(ParseType(type));
+
+ if (struct_def.fixed && !IsScalar(type.base_type) && !IsStruct(type) &&
+ !IsArray(type))
+ return Error("structs_ may contain only scalar or struct fields");
+
+ if (!struct_def.fixed && IsArray(type))
+ return Error("fixed-length array in table must be wrapped in struct");
+
+ if (IsArray(type) && !SupportsAdvancedArrayFeatures()) {
+ return Error(
+ "Arrays are not yet supported in all "
+ "the specified programming languages.");
+ }
+
+ FieldDef *typefield = nullptr;
+ if (type.base_type == BASE_TYPE_UNION) {
+ // For union fields, add a second auto-generated field to hold the type,
+ // with a special suffix.
+ ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
+ type.enum_def->underlying_type, &typefield));
+ } else if (type.base_type == BASE_TYPE_VECTOR &&
+ type.element == BASE_TYPE_UNION) {
+ // Only cpp, js and ts supports the union vector feature so far.
+ if (!SupportsAdvancedUnionFeatures()) {
+ return Error(
+ "Vectors of unions are not yet supported in all "
+ "the specified programming languages.");
+ }
+ // For vector of union fields, add a second auto-generated vector field to
+ // hold the types, with a special suffix.
+ Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def);
+ union_vector.element = BASE_TYPE_UTYPE;
+ ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector,
+ &typefield));
+ }
+
+ FieldDef *field;
+ ECHECK(AddField(struct_def, name, type, &field));
+
+ if (token_ == '=') {
+ NEXT();
+ ECHECK(ParseSingleValue(&field->name, field->value, true));
+ if (!IsScalar(type.base_type) ||
+ (struct_def.fixed && field->value.constant != "0"))
+ return Error(
+ "default values currently only supported for scalars in tables");
+ }
+ // Append .0 if the value has not it (skip hex and scientific floats).
+ // This suffix needed for generated C++ code.
+ if (IsFloat(type.base_type)) {
+ auto &text = field->value.constant;
+ FLATBUFFERS_ASSERT(false == text.empty());
+ auto s = text.c_str();
+ while(*s == ' ') s++;
+ if (*s == '-' || *s == '+') s++;
+ // 1) A float constants (nan, inf, pi, etc) is a kind of identifier.
+ // 2) A float number needn't ".0" at the end if it has exponent.
+ if ((false == IsIdentifierStart(*s)) &&
+ (std::string::npos == field->value.constant.find_first_of(".eEpP"))) {
+ field->value.constant += ".0";
+ }
+ }
+ if (type.enum_def) {
+ // The type.base_type can only be scalar, union, array or vector.
+ // Table, struct or string can't have enum_def.
+ // Default value of union and vector in NONE, NULL translated to "0".
+ FLATBUFFERS_ASSERT(IsInteger(type.base_type) ||
+ (type.base_type == BASE_TYPE_UNION) ||
+ (type.base_type == BASE_TYPE_VECTOR) ||
+ (type.base_type == BASE_TYPE_ARRAY));
+ if (type.base_type == BASE_TYPE_VECTOR) {
+ // Vector can't use initialization list.
+ FLATBUFFERS_ASSERT(field->value.constant == "0");
+ } else {
+ // All unions should have the NONE ("0") enum value.
+ auto in_enum = type.enum_def->attributes.Lookup("bit_flags") ||
+ type.enum_def->FindByValue(field->value.constant);
+ if (false == in_enum)
+ return Error("default value of " + field->value.constant +
+ " for field " + name + " is not part of enum " +
+ type.enum_def->name);
+ }
+ }
+
+ field->doc_comment = dc;
+ ECHECK(ParseMetaData(&field->attributes));
+ field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
+ auto hash_name = field->attributes.Lookup("hash");
+ if (hash_name) {
+ switch ((type.base_type == BASE_TYPE_VECTOR) ? type.element : type.base_type) {
+ case BASE_TYPE_SHORT:
+ case BASE_TYPE_USHORT: {
+ if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
+ return Error("Unknown hashing algorithm for 16 bit types: " +
+ hash_name->constant);
+ break;
+ }
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT: {
+ if (FindHashFunction32(hash_name->constant.c_str()) == nullptr)
+ return Error("Unknown hashing algorithm for 32 bit types: " +
+ hash_name->constant);
+ break;
+ }
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ if (FindHashFunction64(hash_name->constant.c_str()) == nullptr)
+ return Error("Unknown hashing algorithm for 64 bit types: " +
+ hash_name->constant);
+ break;
+ }
+ default:
+ return Error(
+ "only short, ushort, int, uint, long and ulong data types support hashing.");
+ }
+ }
+ auto cpp_type = field->attributes.Lookup("cpp_type");
+ if (cpp_type) {
+ if (!hash_name)
+ return Error("cpp_type can only be used with a hashed field");
+ /// forcing cpp_ptr_type to 'naked' if unset
+ auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type");
+ if (!cpp_ptr_type) {
+ auto val = new Value();
+ val->type = cpp_type->type;
+ val->constant = "naked";
+ field->attributes.Add("cpp_ptr_type", val);
+ }
+ }
+ if (field->deprecated && struct_def.fixed)
+ return Error("can't deprecate fields in a struct");
+ field->required = field->attributes.Lookup("required") != nullptr;
+ if (field->required &&
+ (struct_def.fixed || IsScalar(type.base_type)))
+ return Error("only non-scalar fields in tables may be 'required'");
+ field->key = field->attributes.Lookup("key") != nullptr;
+ if (field->key) {
+ if (struct_def.has_key) return Error("only one field may be set as 'key'");
+ struct_def.has_key = true;
+ if (!IsScalar(type.base_type)) {
+ field->required = true;
+ if (type.base_type != BASE_TYPE_STRING)
+ return Error("'key' field must be string or scalar type");
+ }
+ }
+ field->shared = field->attributes.Lookup("shared") != nullptr;
+ if (field->shared && field->value.type.base_type != BASE_TYPE_STRING)
+ return Error("shared can only be defined on strings");
+
+ auto field_native_custom_alloc =
+ field->attributes.Lookup("native_custom_alloc");
+ if (field_native_custom_alloc)
+ return Error(
+ "native_custom_alloc can only be used with a table or struct "
+ "definition");
+
+ field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
+ if (field->native_inline && !IsStruct(field->value.type))
+ return Error("native_inline can only be defined on structs");
+
+ auto nested = field->attributes.Lookup("nested_flatbuffer");
+ if (nested) {
+ if (nested->type.base_type != BASE_TYPE_STRING)
+ return Error(
+ "nested_flatbuffer attribute must be a string (the root type)");
+ if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR)
+ return Error(
+ "nested_flatbuffer attribute may only apply to a vector of ubyte");
+ // This will cause an error if the root type of the nested flatbuffer
+ // wasn't defined elsewhere.
+ field->nested_flatbuffer = LookupCreateStruct(nested->constant);
+ }
+
+ if (field->attributes.Lookup("flexbuffer")) {
+ field->flexbuffer = true;
+ uses_flexbuffers_ = true;
+ if (type.base_type != BASE_TYPE_VECTOR ||
+ type.element != BASE_TYPE_UCHAR)
+ return Error("flexbuffer attribute may only apply to a vector of ubyte");
+ }
+
+ if (typefield) {
+ if (!IsScalar(typefield->value.type.base_type)) {
+ // this is a union vector field
+ typefield->required = field->required;
+ }
+ // If this field is a union, and it has a manually assigned id,
+ // the automatically added type field should have an id as well (of N - 1).
+ auto attr = field->attributes.Lookup("id");
+ if (attr) {
+ auto id = atoi(attr->constant.c_str());
+ auto val = new Value();
+ val->type = attr->type;
+ val->constant = NumToString(id - 1);
+ typefield->attributes.Add("id", val);
+ }
+ }
+
+ EXPECT(';');
+ return NoError();
+}
+
+CheckedError Parser::ParseString(Value &val) {
+ auto s = attribute_;
+ EXPECT(kTokenStringConstant);
+ val.constant = NumToString(builder_.CreateString(s).o);
+ return NoError();
+}
+
+CheckedError Parser::ParseComma() {
+ if (!opts.protobuf_ascii_alike) EXPECT(',');
+ return NoError();
+}
+
+CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
+ size_t parent_fieldn,
+ const StructDef *parent_struct_def,
+ uoffset_t count,
+ bool inside_vector) {
+ switch (val.type.base_type) {
+ case BASE_TYPE_UNION: {
+ FLATBUFFERS_ASSERT(field);
+ std::string constant;
+ Vector<uint8_t> *vector_of_union_types = nullptr;
+ // Find corresponding type field we may have already parsed.
+ for (auto elem = field_stack_.rbegin() + count;
+ elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) {
+ auto &type = elem->second->value.type;
+ if (type.enum_def == val.type.enum_def) {
+ if (inside_vector) {
+ if (type.base_type == BASE_TYPE_VECTOR &&
+ type.element == BASE_TYPE_UTYPE) {
+ // Vector of union type field.
+ uoffset_t offset;
+ ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
+ vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>(
+ builder_.GetCurrentBufferPointer() +
+ builder_.GetSize() - offset);
+ break;
+ }
+ } else {
+ if (type.base_type == BASE_TYPE_UTYPE) {
+ // Union type field.
+ constant = elem->first.constant;
+ break;
+ }
+ }
+ }
+ }
+ if (constant.empty() && !inside_vector) {
+ // We haven't seen the type field yet. Sadly a lot of JSON writers
+ // output these in alphabetical order, meaning it comes after this
+ // value. So we scan past the value to find it, then come back here.
+ // We currently don't do this for vectors of unions because the
+ // scanning/serialization logic would get very complicated.
+ auto type_name = field->name + UnionTypeFieldSuffix();
+ FLATBUFFERS_ASSERT(parent_struct_def);
+ auto type_field = parent_struct_def->fields.Lookup(type_name);
+ FLATBUFFERS_ASSERT(type_field); // Guaranteed by ParseField().
+ // Remember where we are in the source file, so we can come back here.
+ auto backup = *static_cast<ParserState *>(this);
+ ECHECK(SkipAnyJsonValue()); // The table.
+ ECHECK(ParseComma());
+ auto next_name = attribute_;
+ if (Is(kTokenStringConstant)) {
+ NEXT();
+ } else {
+ EXPECT(kTokenIdentifier);
+ }
+ if (next_name == type_name) {
+ EXPECT(':');
+ Value type_val = type_field->value;
+ ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0));
+ constant = type_val.constant;
+ // Got the information we needed, now rewind:
+ *static_cast<ParserState *>(this) = backup;
+ }
+ }
+ if (constant.empty() && !vector_of_union_types) {
+ return Error("missing type field for this union value: " +
+ field->name);
+ }
+ uint8_t enum_idx;
+ if (vector_of_union_types) {
+ enum_idx = vector_of_union_types->Get(count);
+ } else {
+ ECHECK(atot(constant.c_str(), *this, &enum_idx));
+ }
+ auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true);
+ if (!enum_val) return Error("illegal type id for: " + field->name);
+ if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
+ ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
+ nullptr));
+ if (enum_val->union_type.struct_def->fixed) {
+ // All BASE_TYPE_UNION values are offsets, so turn this into one.
+ SerializeStruct(*enum_val->union_type.struct_def, val);
+ builder_.ClearOffsets();
+ val.constant = NumToString(builder_.GetSize());
+ }
+ } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
+ ECHECK(ParseString(val));
+ } else {
+ FLATBUFFERS_ASSERT(false);
+ }
+ break;
+ }
+ case BASE_TYPE_STRUCT:
+ ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
+ break;
+ case BASE_TYPE_STRING: {
+ ECHECK(ParseString(val));
+ break;
+ }
+ case BASE_TYPE_VECTOR: {
+ uoffset_t off;
+ ECHECK(ParseVector(val.type.VectorType(), &off, field, parent_fieldn));
+ val.constant = NumToString(off);
+ break;
+ }
+ case BASE_TYPE_ARRAY: {
+ ECHECK(ParseArray(val));
+ break;
+ }
+ case BASE_TYPE_INT:
+ case BASE_TYPE_UINT:
+ case BASE_TYPE_LONG:
+ case BASE_TYPE_ULONG: {
+ if (field && field->attributes.Lookup("hash") &&
+ (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
+ ECHECK(ParseHash(val, field));
+ } else {
+ ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
+ }
+ break;
+ }
+ default:
+ ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false));
+ break;
+ }
+ return NoError();
+}
+
+void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
+ SerializeStruct(builder_, struct_def, val);
+}
+
+void Parser::SerializeStruct(FlatBufferBuilder &builder,
+ const StructDef &struct_def, const Value &val) {
+ FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize);
+ builder.Align(struct_def.minalign);
+ builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()),
+ struct_def.bytesize);
+ builder.AddStructOffset(val.offset, builder.GetSize());
+}
+
+template <typename F>
+CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
+ const StructDef *struct_def,
+ F body) {
+ // We allow tables both as JSON object{ .. } with field names
+ // or vector[..] with all fields in order
+ char terminator = '}';
+ bool is_nested_vector = struct_def && Is('[');
+ if (is_nested_vector) {
+ NEXT();
+ terminator = ']';
+ } else {
+ EXPECT('{');
+ }
+ for (;;) {
+ if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
+ std::string name;
+ if (is_nested_vector) {
+ if (fieldn >= struct_def->fields.vec.size()) {
+ return Error("too many unnamed fields in nested array");
+ }
+ name = struct_def->fields.vec[fieldn]->name;
+ } else {
+ name = attribute_;
+ if (Is(kTokenStringConstant)) {
+ NEXT();
+ } else {
+ EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
+ }
+ if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
+ }
+ ECHECK(body(name, fieldn, struct_def));
+ if (Is(terminator)) break;
+ ECHECK(ParseComma());
+ }
+ NEXT();
+ if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
+ return Error("wrong number of unnamed fields in table vector");
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
+ uoffset_t *ovalue) {
+ size_t fieldn_outer = 0;
+ auto err = ParseTableDelimiters(
+ fieldn_outer, &struct_def,
+ [&](const std::string &name, size_t &fieldn,
+ const StructDef *struct_def_inner) -> CheckedError {
+ if (name == "$schema") {
+ ECHECK(Expect(kTokenStringConstant));
+ return NoError();
+ }
+ auto field = struct_def_inner->fields.Lookup(name);
+ if (!field) {
+ if (!opts.skip_unexpected_fields_in_json) {
+ return Error("unknown field: " + name);
+ } else {
+ ECHECK(SkipAnyJsonValue());
+ }
+ } else {
+ if (IsIdent("null") && !IsScalar(field->value.type.base_type)) {
+ ECHECK(Next()); // Ignore this field.
+ } else {
+ Value val = field->value;
+ if (field->flexbuffer) {
+ flexbuffers::Builder builder(1024,
+ flexbuffers::BUILDER_FLAG_SHARE_ALL);
+ ECHECK(ParseFlexBufferValue(&builder));
+ builder.Finish();
+ // Force alignment for nested flexbuffer
+ builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t),
+ sizeof(largest_scalar_t));
+ auto off = builder_.CreateVector(builder.GetBuffer());
+ val.constant = NumToString(off.o);
+ } else if (field->nested_flatbuffer) {
+ ECHECK(
+ ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
+ } else {
+ ECHECK(Recurse([&]() {
+ return ParseAnyValue(val, field, fieldn, struct_def_inner, 0);
+ }));
+ }
+ // Hardcoded insertion-sort with error-check.
+ // If fields are specified in order, then this loop exits
+ // immediately.
+ auto elem = field_stack_.rbegin();
+ for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
+ auto existing_field = elem->second;
+ if (existing_field == field)
+ return Error("field set more than once: " + field->name);
+ if (existing_field->value.offset < field->value.offset) break;
+ }
+ // Note: elem points to before the insertion point, thus .base()
+ // points to the correct spot.
+ field_stack_.insert(elem.base(), std::make_pair(val, field));
+ fieldn++;
+ }
+ }
+ return NoError();
+ });
+ ECHECK(err);
+
+ // Check if all required fields are parsed.
+ for (auto field_it = struct_def.fields.vec.begin();
+ field_it != struct_def.fields.vec.end(); ++field_it) {
+ auto required_field = *field_it;
+ if (!required_field->required) { continue; }
+ bool found = false;
+ for (auto pf_it = field_stack_.end() - fieldn_outer;
+ pf_it != field_stack_.end(); ++pf_it) {
+ auto parsed_field = pf_it->second;
+ if (parsed_field == required_field) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return Error("required field is missing: " + required_field->name +
+ " in " + struct_def.name);
+ }
+ }
+
+ if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
+ return Error("struct: wrong number of initializers: " + struct_def.name);
+
+ auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign)
+ : builder_.StartTable();
+
+ for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size;
+ size /= 2) {
+ // Go through elements in reverse, since we're building the data backwards.
+ for (auto it = field_stack_.rbegin();
+ it != field_stack_.rbegin() + fieldn_outer; ++it) {
+ auto &field_value = it->first;
+ auto field = it->second;
+ if (!struct_def.sortbysize ||
+ size == SizeOf(field_value.type.base_type)) {
+ switch (field_value.type.base_type) {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ builder_.Pad(field->padding); \
+ if (struct_def.fixed) { \
+ CTYPE val; \
+ ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+ builder_.PushElement(val); \
+ } else { \
+ CTYPE val, valdef; \
+ ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+ ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \
+ builder_.AddElement(field_value.offset, val, valdef); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+ #undef FLATBUFFERS_TD
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ builder_.Pad(field->padding); \
+ if (IsStruct(field->value.type)) { \
+ SerializeStruct(*field->value.type.struct_def, field_value); \
+ } else { \
+ CTYPE val; \
+ ECHECK(atot(field_value.constant.c_str(), *this, &val)); \
+ builder_.AddOffset(field_value.offset, val); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD);
+ #undef FLATBUFFERS_TD
+ case BASE_TYPE_ARRAY:
+ builder_.Pad(field->padding);
+ builder_.PushBytes(
+ reinterpret_cast<const uint8_t*>(field_value.constant.c_str()),
+ InlineSize(field_value.type));
+ break;
+ // clang-format on
+ }
+ }
+ }
+ }
+ for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
+
+ if (struct_def.fixed) {
+ builder_.ClearOffsets();
+ builder_.EndStruct();
+ FLATBUFFERS_ASSERT(value);
+ // Temporarily store this struct in the value string, since it is to
+ // be serialized in-place elsewhere.
+ value->assign(
+ reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()),
+ struct_def.bytesize);
+ builder_.PopBytes(struct_def.bytesize);
+ FLATBUFFERS_ASSERT(!ovalue);
+ } else {
+ auto val = builder_.EndTable(start);
+ if (ovalue) *ovalue = val;
+ if (value) *value = NumToString(val);
+ }
+ return NoError();
+}
+
+template <typename F>
+CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) {
+ EXPECT('[');
+ for (;;) {
+ if ((!opts.strict_json || !count) && Is(']')) break;
+ ECHECK(body(count));
+ count++;
+ if (Is(']')) break;
+ ECHECK(ParseComma());
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue,
+ FieldDef *field, size_t fieldn) {
+ uoffset_t count = 0;
+ auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ Value val;
+ val.type = type;
+ ECHECK(Recurse([&]() {
+ return ParseAnyValue(val, field, fieldn, nullptr, count, true);
+ }));
+ field_stack_.push_back(std::make_pair(val, nullptr));
+ return NoError();
+ });
+ ECHECK(err);
+
+ builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
+ InlineAlignment(type));
+ for (uoffset_t i = 0; i < count; i++) {
+ // start at the back, since we're building the data backwards.
+ auto &val = field_stack_.back().first;
+ switch (val.type.base_type) {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
+ else { \
+ CTYPE elem; \
+ ECHECK(atot(val.constant.c_str(), *this, &elem)); \
+ builder_.PushElement(elem); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ }
+ field_stack_.pop_back();
+ }
+
+ builder_.ClearOffsets();
+ *ovalue = builder_.EndVector(count);
+ return NoError();
+}
+
+CheckedError Parser::ParseArray(Value &array) {
+ std::vector<Value> stack;
+ FlatBufferBuilder builder;
+ const auto &type = array.type.VectorType();
+ auto length = array.type.fixed_length;
+ uoffset_t count = 0;
+ auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ vector_emplace_back(&stack, Value());
+ auto &val = stack.back();
+ val.type = type;
+ if (IsStruct(type)) {
+ ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
+ } else {
+ ECHECK(ParseSingleValue(nullptr, val, false));
+ }
+ return NoError();
+ });
+ ECHECK(err);
+ if (length != count) return Error("Fixed-length array size is incorrect.");
+
+ for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
+ auto &val = *it;
+ // clang-format off
+ switch (val.type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: \
+ if (IsStruct(val.type)) { \
+ SerializeStruct(builder, *val.type.struct_def, val); \
+ } else { \
+ CTYPE elem; \
+ ECHECK(atot(val.constant.c_str(), *this, &elem)); \
+ builder.PushElement(elem); \
+ } \
+ break;
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ // clang-format on
+ }
+
+ array.constant.assign(
+ reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()),
+ InlineSize(array.type));
+ return NoError();
+}
+
+CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
+ size_t fieldn,
+ const StructDef *parent_struct_def) {
+ if (token_ == '[') { // backwards compat for 'legacy' ubyte buffers
+ ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0));
+ } else {
+ auto cursor_at_value_begin = cursor_;
+ ECHECK(SkipAnyJsonValue());
+ std::string substring(cursor_at_value_begin - 1, cursor_ - 1);
+
+ // Create and initialize new parser
+ Parser nested_parser;
+ FLATBUFFERS_ASSERT(field->nested_flatbuffer);
+ nested_parser.root_struct_def_ = field->nested_flatbuffer;
+ nested_parser.enums_ = enums_;
+ nested_parser.opts = opts;
+ nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
+
+ // Parse JSON substring into new flatbuffer builder using nested_parser
+ bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr);
+
+ // Clean nested_parser to avoid deleting the elements in
+ // the SymbolTables on destruction
+ nested_parser.enums_.dict.clear();
+ nested_parser.enums_.vec.clear();
+
+ if (!ok) {
+ ECHECK(Error(nested_parser.error_));
+ }
+ // Force alignment for nested flatbuffer
+ builder_.ForceVectorAlignment(nested_parser.builder_.GetSize(), sizeof(uint8_t),
+ nested_parser.builder_.GetBufferMinAlignment());
+
+ auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(),
+ nested_parser.builder_.GetSize());
+ val.constant = NumToString(off.o);
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
+ if (Is('(')) {
+ NEXT();
+ for (;;) {
+ auto name = attribute_;
+ if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant)))
+ return Error("attribute name must be either identifier or string: " +
+ name);
+ if (known_attributes_.find(name) == known_attributes_.end())
+ return Error("user define attributes must be declared before use: " +
+ name);
+ NEXT();
+ auto e = new Value();
+ attributes->Add(name, e);
+ if (Is(':')) {
+ NEXT();
+ ECHECK(ParseSingleValue(&name, *e, true));
+ }
+ if (Is(')')) {
+ NEXT();
+ break;
+ }
+ EXPECT(',');
+ }
+ }
+ return NoError();
+}
+
+CheckedError Parser::TryTypedValue(const std::string *name, int dtoken,
+ bool check, Value &e, BaseType req,
+ bool *destmatch) {
+ bool match = dtoken == token_;
+ if (match) {
+ FLATBUFFERS_ASSERT(*destmatch == false);
+ *destmatch = true;
+ e.constant = attribute_;
+ // Check token match
+ if (!check) {
+ if (e.type.base_type == BASE_TYPE_NONE) {
+ e.type.base_type = req;
+ } else {
+ return Error(
+ std::string("type mismatch: expecting: ") +
+ kTypeNames[e.type.base_type] + ", found: " + kTypeNames[req] +
+ ", name: " + (name ? *name : "") + ", value: " + e.constant);
+ }
+ }
+ // The exponent suffix of hexadecimal float-point number is mandatory.
+ // A hex-integer constant is forbidden as an initializer of float number.
+ if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) {
+ const auto &s = e.constant;
+ const auto k = s.find_first_of("0123456789.");
+ if ((std::string::npos != k) && (s.length() > (k + 1)) &&
+ (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) &&
+ (std::string::npos == s.find_first_of("pP", k + 2))) {
+ return Error(
+ "invalid number, the exponent suffix of hexadecimal "
+ "floating-point literals is mandatory: \"" +
+ s + "\"");
+ }
+ }
+
+ NEXT();
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseEnumFromString(const Type &type,
+ std::string *result) {
+ const auto base_type =
+ type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type;
+ if (!IsInteger(base_type)) return Error("not a valid value for this field");
+ uint64_t u64 = 0;
+ for (size_t pos = 0; pos != std::string::npos;) {
+ const auto delim = attribute_.find_first_of(' ', pos);
+ const auto last = (std::string::npos == delim);
+ auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos);
+ pos = !last ? delim + 1 : std::string::npos;
+ const EnumVal *ev = nullptr;
+ if (type.enum_def) {
+ ev = type.enum_def->Lookup(word);
+ } else {
+ auto dot = word.find_first_of('.');
+ if (std::string::npos == dot)
+ return Error("enum values need to be qualified by an enum type");
+ auto enum_def_str = word.substr(0, dot);
+ const auto enum_def = LookupEnum(enum_def_str);
+ if (!enum_def) return Error("unknown enum: " + enum_def_str);
+ auto enum_val_str = word.substr(dot + 1);
+ ev = enum_def->Lookup(enum_val_str);
+ }
+ if (!ev) return Error("unknown enum value: " + word);
+ u64 |= ev->GetAsUInt64();
+ }
+ *result = IsUnsigned(base_type) ? NumToString(u64)
+ : NumToString(static_cast<int64_t>(u64));
+ return NoError();
+}
+
+CheckedError Parser::ParseHash(Value &e, FieldDef *field) {
+ FLATBUFFERS_ASSERT(field);
+ Value *hash_name = field->attributes.Lookup("hash");
+ switch (e.type.base_type) {
+ case BASE_TYPE_SHORT: {
+ auto hash = FindHashFunction16(hash_name->constant.c_str());
+ int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str()));
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_USHORT: {
+ auto hash = FindHashFunction16(hash_name->constant.c_str());
+ uint16_t hashed_value = hash(attribute_.c_str());
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_INT: {
+ auto hash = FindHashFunction32(hash_name->constant.c_str());
+ int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_UINT: {
+ auto hash = FindHashFunction32(hash_name->constant.c_str());
+ uint32_t hashed_value = hash(attribute_.c_str());
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_LONG: {
+ auto hash = FindHashFunction64(hash_name->constant.c_str());
+ int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ case BASE_TYPE_ULONG: {
+ auto hash = FindHashFunction64(hash_name->constant.c_str());
+ uint64_t hashed_value = hash(attribute_.c_str());
+ e.constant = NumToString(hashed_value);
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::TokenError() {
+ return Error("cannot parse value starting with: " + TokenToStringId(token_));
+}
+
+// Re-pack helper (ParseSingleValue) to normalize defaults of scalars.
+template<typename T> inline void SingleValueRepack(Value &e, T val) {
+ // Remove leading zeros.
+ if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); }
+}
+#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+// Normilaze defaults NaN to unsigned quiet-NaN(0).
+static inline void SingleValueRepack(Value& e, float val) {
+ if (val != val) e.constant = "nan";
+}
+static inline void SingleValueRepack(Value& e, double val) {
+ if (val != val) e.constant = "nan";
+}
+#endif
+
+CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
+ bool check_now) {
+ // First see if this could be a conversion function:
+ if (token_ == kTokenIdentifier && *cursor_ == '(') {
+ // todo: Extract processing of conversion functions to ParseFunction.
+ const auto functionname = attribute_;
+ if (!IsFloat(e.type.base_type)) {
+ return Error(functionname + ": type of argument mismatch, expecting: " +
+ kTypeNames[BASE_TYPE_DOUBLE] +
+ ", found: " + kTypeNames[e.type.base_type] +
+ ", name: " + (name ? *name : "") + ", value: " + e.constant);
+ }
+ NEXT();
+ EXPECT('(');
+ ECHECK(Recurse([&]() { return ParseSingleValue(name, e, false); }));
+ EXPECT(')');
+ // calculate with double precision
+ double x, y = 0.0;
+ ECHECK(atot(e.constant.c_str(), *this, &x));
+ auto func_match = false;
+ // clang-format off
+ #define FLATBUFFERS_FN_DOUBLE(name, op) \
+ if (!func_match && functionname == name) { y = op; func_match = true; }
+ FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
+ FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
+ FLATBUFFERS_FN_DOUBLE("sin", sin(x));
+ FLATBUFFERS_FN_DOUBLE("cos", cos(x));
+ FLATBUFFERS_FN_DOUBLE("tan", tan(x));
+ FLATBUFFERS_FN_DOUBLE("asin", asin(x));
+ FLATBUFFERS_FN_DOUBLE("acos", acos(x));
+ FLATBUFFERS_FN_DOUBLE("atan", atan(x));
+ // TODO(wvo): add more useful conversion functions here.
+ #undef FLATBUFFERS_FN_DOUBLE
+ // clang-format on
+ if (true != func_match) {
+ return Error(std::string("Unknown conversion function: ") + functionname +
+ ", field name: " + (name ? *name : "") +
+ ", value: " + e.constant);
+ }
+ e.constant = NumToString(y);
+ return NoError();
+ }
+
+ auto match = false;
+ const auto in_type = e.type.base_type;
+ // clang-format off
+ #define IF_ECHECK_(force, dtoken, check, req) \
+ if (!match && ((check) || IsConstTrue(force))) \
+ ECHECK(TryTypedValue(name, dtoken, check, e, req, &match))
+ #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req)
+ #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req)
+ // clang-format on
+
+ if (token_ == kTokenStringConstant || token_ == kTokenIdentifier) {
+ const auto kTokenStringOrIdent = token_;
+ // The string type is a most probable type, check it first.
+ TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
+ BASE_TYPE_STRING);
+
+ // avoid escaped and non-ascii in the string
+ if (!match && (token_ == kTokenStringConstant) && IsScalar(in_type) &&
+ !attr_is_trivial_ascii_string_) {
+ return Error(
+ std::string("type mismatch or invalid value, an initializer of "
+ "non-string field must be trivial ASCII string: type: ") +
+ kTypeNames[in_type] + ", name: " + (name ? *name : "") +
+ ", value: " + attribute_);
+ }
+
+ // A boolean as true/false. Boolean as Integer check below.
+ if (!match && IsBool(in_type)) {
+ auto is_true = attribute_ == "true";
+ if (is_true || attribute_ == "false") {
+ attribute_ = is_true ? "1" : "0";
+ // accepts both kTokenStringConstant and kTokenIdentifier
+ TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL);
+ }
+ }
+ // Check if this could be a string/identifier enum value.
+ // Enum can have only true integer base type.
+ if (!match && IsInteger(in_type) && !IsBool(in_type) &&
+ IsIdentifierStart(*attribute_.c_str())) {
+ ECHECK(ParseEnumFromString(e.type, &e.constant));
+ NEXT();
+ match = true;
+ }
+ // Parse a float/integer number from the string.
+ if (!match) check_now = true; // Re-pack if parsed from string literal.
+ if (!match && (token_ == kTokenStringConstant) && IsScalar(in_type)) {
+ // remove trailing whitespaces from attribute_
+ auto last = attribute_.find_last_not_of(' ');
+ if (std::string::npos != last) // has non-whitespace
+ attribute_.resize(last + 1);
+ }
+ // Float numbers or nan, inf, pi, etc.
+ TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT);
+ // An integer constant in string.
+ TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT);
+ // Unknown tokens will be interpreted as string type.
+ // An attribute value may be a scalar or string constant.
+ FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING,
+ BASE_TYPE_STRING);
+ } else {
+ // Try a float number.
+ TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
+ // Integer token can init any scalar (integer of float).
+ FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
+ }
+#undef FORCE_ECHECK
+#undef TRY_ECHECK
+#undef IF_ECHECK_
+
+ if (!match) {
+ std::string msg;
+ msg += "Cannot assign token starting with '" + TokenToStringId(token_) +
+ "' to value of <" + std::string(kTypeNames[in_type]) + "> type.";
+ return Error(msg);
+ }
+ const auto match_type = e.type.base_type; // may differ from in_type
+ // The check_now flag must be true when parse a fbs-schema.
+ // This flag forces to check default scalar values or metadata of field.
+ // For JSON parser the flag should be false.
+ // If it is set for JSON each value will be checked twice (see ParseTable).
+ if (check_now && IsScalar(match_type)) {
+ // clang-format off
+ switch (match_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_ ## ENUM: {\
+ CTYPE val; \
+ ECHECK(atot(e.constant.c_str(), *this, &val)); \
+ SingleValueRepack(e, val); \
+ break; }
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+ #undef FLATBUFFERS_TD
+ default: break;
+ }
+ // clang-format on
+ }
+ return NoError();
+}
+
+StructDef *Parser::LookupCreateStruct(const std::string &name,
+ bool create_if_new, bool definition) {
+ std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
+ // See if it exists pre-declared by an unqualified use.
+ auto struct_def = LookupStruct(name);
+ if (struct_def && struct_def->predecl) {
+ if (definition) {
+ // Make sure it has the current namespace, and is registered under its
+ // qualified name.
+ struct_def->defined_namespace = current_namespace_;
+ structs_.Move(name, qualified_name);
+ }
+ return struct_def;
+ }
+ // See if it exists pre-declared by an qualified use.
+ struct_def = LookupStruct(qualified_name);
+ if (struct_def && struct_def->predecl) {
+ if (definition) {
+ // Make sure it has the current namespace.
+ struct_def->defined_namespace = current_namespace_;
+ }
+ return struct_def;
+ }
+ if (!definition) {
+ // Search thru parent namespaces.
+ for (size_t components = current_namespace_->components.size();
+ components && !struct_def; components--) {
+ struct_def = LookupStruct(
+ current_namespace_->GetFullyQualifiedName(name, components - 1));
+ }
+ }
+ if (!struct_def && create_if_new) {
+ struct_def = new StructDef();
+ if (definition) {
+ structs_.Add(qualified_name, struct_def);
+ struct_def->name = name;
+ struct_def->defined_namespace = current_namespace_;
+ } else {
+ // Not a definition.
+ // Rather than failing, we create a "pre declared" StructDef, due to
+ // circular references, and check for errors at the end of parsing.
+ // It is defined in the current namespace, as the best guess what the
+ // final namespace will be.
+ structs_.Add(name, struct_def);
+ struct_def->name = name;
+ struct_def->defined_namespace = current_namespace_;
+ struct_def->original_location.reset(
+ new std::string(file_being_parsed_ + ":" + NumToString(line_)));
+ }
+ }
+ return struct_def;
+}
+
+const EnumVal *EnumDef::MinValue() const {
+ return vals.vec.empty() ? nullptr : vals.vec.front();
+}
+const EnumVal *EnumDef::MaxValue() const {
+ return vals.vec.empty() ? nullptr : vals.vec.back();
+}
+
+template<typename T> static uint64_t EnumDistanceImpl(T e1, T e2) {
+ if (e1 < e2) { std::swap(e1, e2); } // use std for scalars
+ // Signed overflow may occur, use unsigned calculation.
+ // The unsigned overflow is well-defined by C++ standard (modulo 2^n).
+ return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2);
+}
+
+uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const {
+ return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64())
+ : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64());
+}
+
+std::string EnumDef::AllFlags() const {
+ FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags"));
+ uint64_t u64 = 0;
+ for (auto it = Vals().begin(); it != Vals().end(); ++it) {
+ u64 |= (*it)->GetAsUInt64();
+ }
+ return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64));
+}
+
+EnumVal *EnumDef::ReverseLookup(int64_t enum_idx,
+ bool skip_union_default) const {
+ auto skip_first = static_cast<int>(is_union && skip_union_default);
+ for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) {
+ if ((*it)->GetAsInt64() == enum_idx) { return *it; }
+ }
+ return nullptr;
+}
+
+EnumVal *EnumDef::FindByValue(const std::string &constant) const {
+ int64_t i64;
+ auto done = false;
+ if (IsUInt64()) {
+ uint64_t u64; // avoid reinterpret_cast of pointers
+ done = StringToNumber(constant.c_str(), &u64);
+ i64 = static_cast<int64_t>(u64);
+ } else {
+ done = StringToNumber(constant.c_str(), &i64);
+ }
+ FLATBUFFERS_ASSERT(done);
+ if (!done) return nullptr;
+ return ReverseLookup(i64, false);
+}
+
+void EnumDef::SortByValue() {
+ auto &v = vals.vec;
+ if (IsUInt64())
+ std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+ return e1->GetAsUInt64() < e2->GetAsUInt64();
+ });
+ else
+ std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) {
+ return e1->GetAsInt64() < e2->GetAsInt64();
+ });
+}
+
+void EnumDef::RemoveDuplicates() {
+ // This method depends form SymbolTable implementation!
+ // 1) vals.vec - owner (raw pointer)
+ // 2) vals.dict - access map
+ auto first = vals.vec.begin();
+ auto last = vals.vec.end();
+ if (first == last) return;
+ auto result = first;
+ while (++first != last) {
+ if ((*result)->value != (*first)->value) {
+ *(++result) = *first;
+ } else {
+ auto ev = *first;
+ for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) {
+ if (it->second == ev) it->second = *result; // reassign
+ }
+ delete ev; // delete enum value
+ *first = nullptr;
+ }
+ }
+ vals.vec.erase(++result, last);
+}
+
+template<typename T> void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) {
+ ev->value = static_cast<int64_t>(new_value);
+}
+
+namespace EnumHelper {
+template<BaseType E> struct EnumValType { typedef int64_t type; };
+template<> struct EnumValType<BASE_TYPE_ULONG> { typedef uint64_t type; };
+} // namespace EnumHelper
+
+struct EnumValBuilder {
+ EnumVal *CreateEnumerator(const std::string &ev_name) {
+ FLATBUFFERS_ASSERT(!temp);
+ auto first = enum_def.vals.vec.empty();
+ user_value = first;
+ temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value);
+ return temp;
+ }
+
+ EnumVal *CreateEnumerator(const std::string &ev_name, int64_t val) {
+ FLATBUFFERS_ASSERT(!temp);
+ user_value = true;
+ temp = new EnumVal(ev_name, val);
+ return temp;
+ }
+
+ FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) {
+ FLATBUFFERS_ASSERT(temp);
+ ECHECK(ValidateValue(&temp->value, false == user_value));
+ FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) ||
+ (temp->union_type.enum_def == &enum_def));
+ auto not_unique = enum_def.vals.Add(name, temp);
+ temp = nullptr;
+ if (not_unique) return parser.Error("enum value already exists: " + name);
+ return NoError();
+ }
+
+ FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() {
+ return AcceptEnumerator(temp->name);
+ }
+
+ FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) {
+ user_value = true;
+ auto fit = false;
+ auto ascending = false;
+ if (enum_def.IsUInt64()) {
+ uint64_t u64;
+ fit = StringToNumber(value.c_str(), &u64);
+ ascending = u64 > temp->GetAsUInt64();
+ temp->value = static_cast<int64_t>(u64); // well-defined since C++20.
+ } else {
+ int64_t i64;
+ fit = StringToNumber(value.c_str(), &i64);
+ ascending = i64 > temp->GetAsInt64();
+ temp->value = i64;
+ }
+ if (!fit) return parser.Error("enum value does not fit, \"" + value + "\"");
+ if (!ascending && strict_ascending && !enum_def.vals.vec.empty())
+ return parser.Error("enum values must be specified in ascending order");
+ return NoError();
+ }
+
+ template<BaseType E, typename CTYPE>
+ inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) {
+ typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t
+ static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType");
+ const auto v = static_cast<T>(*ev);
+ auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)());
+ auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)());
+ if (v < dn || v > (up - m)) {
+ return parser.Error("enum value does not fit, \"" + NumToString(v) +
+ (m ? " + 1\"" : "\"") + " out of " +
+ TypeToIntervalString<CTYPE>());
+ }
+ *ev = static_cast<int64_t>(v + m); // well-defined since C++20.
+ return NoError();
+ }
+
+ FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) {
+ // clang-format off
+ switch (enum_def.underlying_type.base_type) {
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
+ PTYPE, RTYPE, KTYPE) \
+ case BASE_TYPE_##ENUM: { \
+ if (!IsInteger(BASE_TYPE_##ENUM)) break; \
+ return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \
+ }
+ FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
+ #undef FLATBUFFERS_TD
+ default: break;
+ }
+ // clang-format on
+ return parser.Error("fatal: invalid enum underlying type");
+ }
+
+ EnumValBuilder(Parser &_parser, EnumDef &_enum_def, bool strict_order = true)
+ : parser(_parser),
+ enum_def(_enum_def),
+ temp(nullptr),
+ strict_ascending(strict_order),
+ user_value(false) {}
+
+ ~EnumValBuilder() { delete temp; }
+
+ Parser &parser;
+ EnumDef &enum_def;
+ EnumVal *temp;
+ const bool strict_ascending;
+ bool user_value;
+};
+
+CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) {
+ std::vector<std::string> enum_comment = doc_comment_;
+ NEXT();
+ std::string enum_name = attribute_;
+ EXPECT(kTokenIdentifier);
+ EnumDef *enum_def;
+ ECHECK(StartEnum(enum_name, is_union, &enum_def));
+ enum_def->doc_comment = enum_comment;
+ if (!is_union && !opts.proto_mode) {
+ // Give specialized error message, since this type spec used to
+ // be optional in the first FlatBuffers release.
+ if (!Is(':')) {
+ return Error(
+ "must specify the underlying integer type for this"
+ " enum (e.g. \': short\', which was the default).");
+ } else {
+ NEXT();
+ }
+ // Specify the integer type underlying this enum.
+ ECHECK(ParseType(enum_def->underlying_type));
+ if (!IsInteger(enum_def->underlying_type.base_type) ||
+ IsBool(enum_def->underlying_type.base_type))
+ return Error("underlying enum type must be integral");
+ // Make this type refer back to the enum it was derived from.
+ enum_def->underlying_type.enum_def = enum_def;
+ }
+ ECHECK(ParseMetaData(&enum_def->attributes));
+ const auto underlying_type = enum_def->underlying_type.base_type;
+ if (enum_def->attributes.Lookup("bit_flags") &&
+ !IsUnsigned(underlying_type)) {
+ // todo: Convert to the Error in the future?
+ Warning("underlying type of bit_flags enum must be unsigned");
+ }
+ // Protobuf allows them to be specified in any order, so sort afterwards.
+ const auto strict_ascending = (false == opts.proto_mode);
+ EnumValBuilder evb(*this, *enum_def, strict_ascending);
+ EXPECT('{');
+ // A lot of code generatos expect that an enum is not-empty.
+ if ((is_union || Is('}')) && !opts.proto_mode) {
+ evb.CreateEnumerator("NONE");
+ ECHECK(evb.AcceptEnumerator());
+ }
+ std::set<std::pair<BaseType, StructDef *>> union_types;
+ while (!Is('}')) {
+ if (opts.proto_mode && attribute_ == "option") {
+ ECHECK(ParseProtoOption());
+ } else {
+ auto &ev = *evb.CreateEnumerator(attribute_);
+ auto full_name = ev.name;
+ ev.doc_comment = doc_comment_;
+ EXPECT(kTokenIdentifier);
+ if (is_union) {
+ ECHECK(ParseNamespacing(&full_name, &ev.name));
+ if (opts.union_value_namespacing) {
+ // Since we can't namespace the actual enum identifiers, turn
+ // namespace parts into part of the identifier.
+ ev.name = full_name;
+ std::replace(ev.name.begin(), ev.name.end(), '.', '_');
+ }
+ if (Is(':')) {
+ NEXT();
+ ECHECK(ParseType(ev.union_type));
+ if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
+ ev.union_type.base_type != BASE_TYPE_STRING)
+ return Error("union value type may only be table/struct/string");
+ } else {
+ ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
+ }
+ if (!enum_def->uses_multiple_type_instances) {
+ auto ins = union_types.insert(std::make_pair(
+ ev.union_type.base_type, ev.union_type.struct_def));
+ enum_def->uses_multiple_type_instances = (false == ins.second);
+ }
+ }
+
+ if (Is('=')) {
+ NEXT();
+ ECHECK(evb.AssignEnumeratorValue(attribute_));
+ EXPECT(kTokenIntegerConstant);
+ } else if (false == strict_ascending) {
+ // The opts.proto_mode flag is active.
+ return Error("Protobuf mode doesn't allow implicit enum values.");
+ }
+
+ ECHECK(evb.AcceptEnumerator());
+
+ if (opts.proto_mode && Is('[')) {
+ NEXT();
+ // ignore attributes on enums.
+ while (token_ != ']') NEXT();
+ NEXT();
+ }
+ }
+ if (!Is(opts.proto_mode ? ';' : ',')) break;
+ NEXT();
+ }
+ EXPECT('}');
+
+ // At this point, the enum can be empty if input is invalid proto-file.
+ if (!enum_def->size())
+ return Error("incomplete enum declaration, values not found");
+
+ if (enum_def->attributes.Lookup("bit_flags")) {
+ const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type));
+ for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
+ ++it) {
+ auto ev = *it;
+ const auto u = ev->GetAsUInt64();
+ // Stop manipulations with the sign.
+ if (!IsUnsigned(underlying_type) && u == (base_width - 1))
+ return Error("underlying type of bit_flags enum must be unsigned");
+ if (u >= base_width)
+ return Error("bit flag out of range of underlying integral type");
+ enum_def->ChangeEnumValue(ev, 1ULL << u);
+ }
+ }
+
+ if (false == strict_ascending)
+ enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue.
+
+ if (dest) *dest = enum_def;
+ types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name),
+ new Type(BASE_TYPE_UNION, nullptr, enum_def));
+ return NoError();
+}
+
+CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
+ auto &struct_def = *LookupCreateStruct(name, true, true);
+ if (!struct_def.predecl) return Error("datatype already exists: " + name);
+ struct_def.predecl = false;
+ struct_def.name = name;
+ struct_def.file = file_being_parsed_;
+ // Move this struct to the back of the vector just in case it was predeclared,
+ // to preserve declaration order.
+ *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) =
+ &struct_def;
+ *dest = &struct_def;
+ return NoError();
+}
+
+CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields,
+ StructDef *struct_def, const char *suffix,
+ BaseType basetype) {
+ auto len = strlen(suffix);
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ auto &fname = (*it)->name;
+ if (fname.length() > len &&
+ fname.compare(fname.length() - len, len, suffix) == 0 &&
+ (*it)->value.type.base_type != BASE_TYPE_UTYPE) {
+ auto field =
+ struct_def->fields.Lookup(fname.substr(0, fname.length() - len));
+ if (field && field->value.type.base_type == basetype)
+ return Error("Field " + fname +
+ " would clash with generated functions for field " +
+ field->name);
+ }
+ }
+ return NoError();
+}
+
+bool Parser::SupportsAdvancedUnionFeatures() const {
+ return opts.lang_to_generate != 0 &&
+ (opts.lang_to_generate & ~(IDLOptions::kCpp | IDLOptions::kJs |
+ IDLOptions::kTs | IDLOptions::kPhp |
+ IDLOptions::kJava | IDLOptions::kCSharp |
+ IDLOptions::kKotlin |
+ IDLOptions::kBinary)) == 0;
+}
+
+bool Parser::SupportsAdvancedArrayFeatures() const {
+ return (opts.lang_to_generate &
+ ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava |
+ IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson |
+ IDLOptions::kBinary)) == 0;
+}
+
+Namespace *Parser::UniqueNamespace(Namespace *ns) {
+ for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
+ if (ns->components == (*it)->components) {
+ delete ns;
+ return *it;
+ }
+ }
+ namespaces_.push_back(ns);
+ return ns;
+}
+
+std::string Parser::UnqualifiedName(const std::string &full_qualified_name) {
+ Namespace *ns = new Namespace();
+
+ std::size_t current, previous = 0;
+ current = full_qualified_name.find('.');
+ while (current != std::string::npos) {
+ ns->components.push_back(
+ full_qualified_name.substr(previous, current - previous));
+ previous = current + 1;
+ current = full_qualified_name.find('.', previous);
+ }
+ current_namespace_ = UniqueNamespace(ns);
+ return full_qualified_name.substr(previous, current - previous);
+}
+
+static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
+ auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
+ auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
+ return a_id < b_id;
+}
+
+CheckedError Parser::ParseDecl() {
+ std::vector<std::string> dc = doc_comment_;
+ bool fixed = IsIdent("struct");
+ if (!fixed && !IsIdent("table")) return Error("declaration expected");
+ NEXT();
+ std::string name = attribute_;
+ EXPECT(kTokenIdentifier);
+ StructDef *struct_def;
+ ECHECK(StartStruct(name, &struct_def));
+ struct_def->doc_comment = dc;
+ struct_def->fixed = fixed;
+ ECHECK(ParseMetaData(&struct_def->attributes));
+ struct_def->sortbysize =
+ struct_def->attributes.Lookup("original_order") == nullptr && !fixed;
+ EXPECT('{');
+ while (token_ != '}') ECHECK(ParseField(*struct_def));
+ auto force_align = struct_def->attributes.Lookup("force_align");
+ if (fixed) {
+ if (force_align) {
+ auto align = static_cast<size_t>(atoi(force_align->constant.c_str()));
+ if (force_align->type.base_type != BASE_TYPE_INT ||
+ align < struct_def->minalign || align > FLATBUFFERS_MAX_ALIGNMENT ||
+ align & (align - 1))
+ return Error(
+ "force_align must be a power of two integer ranging from the"
+ "struct\'s natural alignment to " +
+ NumToString(FLATBUFFERS_MAX_ALIGNMENT));
+ struct_def->minalign = align;
+ }
+ if (!struct_def->bytesize) return Error("size 0 structs not allowed");
+ }
+ struct_def->PadLastField(struct_def->minalign);
+ // Check if this is a table that has manual id assignments
+ auto &fields = struct_def->fields.vec;
+ if (!fixed && fields.size()) {
+ size_t num_id_fields = 0;
+ for (auto it = fields.begin(); it != fields.end(); ++it) {
+ if ((*it)->attributes.Lookup("id")) num_id_fields++;
+ }
+ // If any fields have ids..
+ if (num_id_fields) {
+ // Then all fields must have them.
+ if (num_id_fields != fields.size())
+ return Error(
+ "either all fields or no fields must have an 'id' attribute");
+ // Simply sort by id, then the fields are the same as if no ids had
+ // been specified.
+ std::sort(fields.begin(), fields.end(), compareFieldDefs);
+ // Verify we have a contiguous set, and reassign vtable offsets.
+ for (int i = 0; i < static_cast<int>(fields.size()); i++) {
+ if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
+ return Error("field id\'s must be consecutive from 0, id " +
+ NumToString(i) + " missing or set twice");
+ fields[i]->value.offset = FieldIndexToOffset(static_cast<voffset_t>(i));
+ }
+ }
+ }
+
+ ECHECK(
+ CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
+ ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
+ ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
+ ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
+ ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
+ EXPECT('}');
+ types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
+ new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
+ return NoError();
+}
+
+CheckedError Parser::ParseService() {
+ std::vector<std::string> service_comment = doc_comment_;
+ NEXT();
+ auto service_name = attribute_;
+ EXPECT(kTokenIdentifier);
+ auto &service_def = *new ServiceDef();
+ service_def.name = service_name;
+ service_def.file = file_being_parsed_;
+ service_def.doc_comment = service_comment;
+ service_def.defined_namespace = current_namespace_;
+ if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
+ &service_def))
+ return Error("service already exists: " + service_name);
+ ECHECK(ParseMetaData(&service_def.attributes));
+ EXPECT('{');
+ do {
+ std::vector<std::string> doc_comment = doc_comment_;
+ auto rpc_name = attribute_;
+ EXPECT(kTokenIdentifier);
+ EXPECT('(');
+ Type reqtype, resptype;
+ ECHECK(ParseTypeIdent(reqtype));
+ EXPECT(')');
+ EXPECT(':');
+ ECHECK(ParseTypeIdent(resptype));
+ if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed ||
+ resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed)
+ return Error("rpc request and response types must be tables");
+ auto &rpc = *new RPCCall();
+ rpc.name = rpc_name;
+ rpc.request = reqtype.struct_def;
+ rpc.response = resptype.struct_def;
+ rpc.doc_comment = doc_comment;
+ if (service_def.calls.Add(rpc_name, &rpc))
+ return Error("rpc already exists: " + rpc_name);
+ ECHECK(ParseMetaData(&rpc.attributes));
+ EXPECT(';');
+ } while (token_ != '}');
+ NEXT();
+ return NoError();
+}
+
+bool Parser::SetRootType(const char *name) {
+ root_struct_def_ = LookupStruct(name);
+ if (!root_struct_def_)
+ root_struct_def_ =
+ LookupStruct(current_namespace_->GetFullyQualifiedName(name));
+ return root_struct_def_ != nullptr;
+}
+
+void Parser::MarkGenerated() {
+ // This function marks all existing definitions as having already
+ // been generated, which signals no code for included files should be
+ // generated.
+ for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+ (*it)->generated = true;
+ }
+ for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
+ if (!(*it)->predecl) { (*it)->generated = true; }
+ }
+ for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
+ (*it)->generated = true;
+ }
+}
+
+CheckedError Parser::ParseNamespace() {
+ NEXT();
+ auto ns = new Namespace();
+ namespaces_.push_back(ns); // Store it here to not leak upon error.
+ if (token_ != ';') {
+ for (;;) {
+ ns->components.push_back(attribute_);
+ EXPECT(kTokenIdentifier);
+ if (Is('.')) NEXT() else break;
+ }
+ }
+ namespaces_.pop_back();
+ current_namespace_ = UniqueNamespace(ns);
+ EXPECT(';');
+ return NoError();
+}
+
+// Best effort parsing of .proto declarations, with the aim to turn them
+// in the closest corresponding FlatBuffer equivalent.
+// We parse everything as identifiers instead of keywords, since we don't
+// want protobuf keywords to become invalid identifiers in FlatBuffers.
+CheckedError Parser::ParseProtoDecl() {
+ bool isextend = IsIdent("extend");
+ if (IsIdent("package")) {
+ // These are identical in syntax to FlatBuffer's namespace decl.
+ ECHECK(ParseNamespace());
+ } else if (IsIdent("message") || isextend) {
+ std::vector<std::string> struct_comment = doc_comment_;
+ NEXT();
+ StructDef *struct_def = nullptr;
+ Namespace *parent_namespace = nullptr;
+ if (isextend) {
+ if (Is('.')) NEXT(); // qualified names may start with a . ?
+ auto id = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseNamespacing(&id, nullptr));
+ struct_def = LookupCreateStruct(id, false);
+ if (!struct_def)
+ return Error("cannot extend unknown message type: " + id);
+ } else {
+ std::string name = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(StartStruct(name, &struct_def));
+ // Since message definitions can be nested, we create a new namespace.
+ auto ns = new Namespace();
+ // Copy of current namespace.
+ *ns = *current_namespace_;
+ // But with current message name.
+ ns->components.push_back(name);
+ ns->from_table++;
+ parent_namespace = current_namespace_;
+ current_namespace_ = UniqueNamespace(ns);
+ }
+ struct_def->doc_comment = struct_comment;
+ ECHECK(ParseProtoFields(struct_def, isextend, false));
+ if (!isextend) { current_namespace_ = parent_namespace; }
+ if (Is(';')) NEXT();
+ } else if (IsIdent("enum")) {
+ // These are almost the same, just with different terminator:
+ EnumDef *enum_def;
+ ECHECK(ParseEnum(false, &enum_def));
+ if (Is(';')) NEXT();
+ // Temp: remove any duplicates, as .fbs files can't handle them.
+ enum_def->RemoveDuplicates();
+ } else if (IsIdent("syntax")) { // Skip these.
+ NEXT();
+ EXPECT('=');
+ EXPECT(kTokenStringConstant);
+ EXPECT(';');
+ } else if (IsIdent("option")) { // Skip these.
+ ECHECK(ParseProtoOption());
+ EXPECT(';');
+ } else if (IsIdent("service")) { // Skip these.
+ NEXT();
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseProtoCurliesOrIdent());
+ } else {
+ return Error("don\'t know how to parse .proto declaration starting with " +
+ TokenToStringId(token_));
+ }
+ return NoError();
+}
+
+CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union,
+ EnumDef **dest) {
+ auto &enum_def = *new EnumDef();
+ enum_def.name = enum_name;
+ enum_def.file = file_being_parsed_;
+ enum_def.doc_comment = doc_comment_;
+ enum_def.is_union = is_union;
+ enum_def.defined_namespace = current_namespace_;
+ if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
+ &enum_def))
+ return Error("enum already exists: " + enum_name);
+ enum_def.underlying_type.base_type = is_union ? BASE_TYPE_UTYPE
+ : BASE_TYPE_INT;
+ enum_def.underlying_type.enum_def = &enum_def;
+ if (dest) *dest = &enum_def;
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend,
+ bool inside_oneof) {
+ EXPECT('{');
+ while (token_ != '}') {
+ if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
+ // Nested declarations.
+ ECHECK(ParseProtoDecl());
+ } else if (IsIdent("extensions")) { // Skip these.
+ NEXT();
+ EXPECT(kTokenIntegerConstant);
+ if (Is(kTokenIdentifier)) {
+ NEXT(); // to
+ NEXT(); // num
+ }
+ EXPECT(';');
+ } else if (IsIdent("option")) { // Skip these.
+ ECHECK(ParseProtoOption());
+ EXPECT(';');
+ } else if (IsIdent("reserved")) { // Skip these.
+ NEXT();
+ while (!Is(';')) { NEXT(); } // A variety of formats, just skip.
+ NEXT();
+ } else {
+ std::vector<std::string> field_comment = doc_comment_;
+ // Parse the qualifier.
+ bool required = false;
+ bool repeated = false;
+ bool oneof = false;
+ if (!inside_oneof) {
+ if (IsIdent("optional")) {
+ // This is the default.
+ NEXT();
+ } else if (IsIdent("required")) {
+ required = true;
+ NEXT();
+ } else if (IsIdent("repeated")) {
+ repeated = true;
+ NEXT();
+ } else if (IsIdent("oneof")) {
+ oneof = true;
+ NEXT();
+ } else {
+ // can't error, proto3 allows decls without any of the above.
+ }
+ }
+ StructDef *anonymous_struct = nullptr;
+ EnumDef *oneof_union = nullptr;
+ Type type;
+ if (IsIdent("group") || oneof) {
+ if (!oneof) NEXT();
+ if (oneof && opts.proto_oneof_union) {
+ auto name = MakeCamel(attribute_, true) + "Union";
+ ECHECK(StartEnum(name, true, &oneof_union));
+ type = Type(BASE_TYPE_UNION, nullptr, oneof_union);
+ } else {
+ auto name = "Anonymous" + NumToString(anonymous_counter++);
+ ECHECK(StartStruct(name, &anonymous_struct));
+ type = Type(BASE_TYPE_STRUCT, anonymous_struct);
+ }
+ } else {
+ ECHECK(ParseTypeFromProtoType(&type));
+ }
+ // Repeated elements get mapped to a vector.
+ if (repeated) {
+ type.element = type.base_type;
+ type.base_type = BASE_TYPE_VECTOR;
+ if (type.element == BASE_TYPE_VECTOR) {
+ // We have a vector or vectors, which FlatBuffers doesn't support.
+ // For now make it a vector of string (since the source is likely
+ // "repeated bytes").
+ // TODO(wvo): A better solution would be to wrap this in a table.
+ type.element = BASE_TYPE_STRING;
+ }
+ }
+ std::string name = attribute_;
+ EXPECT(kTokenIdentifier);
+ if (!oneof) {
+ // Parse the field id. Since we're just translating schemas, not
+ // any kind of binary compatibility, we can safely ignore these, and
+ // assign our own.
+ EXPECT('=');
+ EXPECT(kTokenIntegerConstant);
+ }
+ FieldDef *field = nullptr;
+ if (isextend) {
+ // We allow a field to be re-defined when extending.
+ // TODO: are there situations where that is problematic?
+ field = struct_def->fields.Lookup(name);
+ }
+ if (!field) ECHECK(AddField(*struct_def, name, type, &field));
+ field->doc_comment = field_comment;
+ if (!IsScalar(type.base_type)) field->required = required;
+ // See if there's a default specified.
+ if (Is('[')) {
+ NEXT();
+ for (;;) {
+ auto key = attribute_;
+ ECHECK(ParseProtoKey());
+ EXPECT('=');
+ auto val = attribute_;
+ ECHECK(ParseProtoCurliesOrIdent());
+ if (key == "default") {
+ // Temp: skip non-numeric defaults (enums).
+ auto numeric = strpbrk(val.c_str(), "0123456789-+.");
+ if (IsScalar(type.base_type) && numeric == val.c_str())
+ field->value.constant = val;
+ } else if (key == "deprecated") {
+ field->deprecated = val == "true";
+ }
+ if (!Is(',')) break;
+ NEXT();
+ }
+ EXPECT(']');
+ }
+ if (anonymous_struct) {
+ ECHECK(ParseProtoFields(anonymous_struct, false, oneof));
+ if (Is(';')) NEXT();
+ } else if (oneof_union) {
+ // Parse into a temporary StructDef, then transfer fields into an
+ // EnumDef describing the oneof as a union.
+ StructDef oneof_struct;
+ ECHECK(ParseProtoFields(&oneof_struct, false, oneof));
+ if (Is(';')) NEXT();
+ for (auto field_it = oneof_struct.fields.vec.begin();
+ field_it != oneof_struct.fields.vec.end(); ++field_it) {
+ const auto &oneof_field = **field_it;
+ const auto &oneof_type = oneof_field.value.type;
+ if (oneof_type.base_type != BASE_TYPE_STRUCT ||
+ !oneof_type.struct_def || oneof_type.struct_def->fixed)
+ return Error("oneof '" + name +
+ "' cannot be mapped to a union because member '" +
+ oneof_field.name + "' is not a table type.");
+ EnumValBuilder evb(*this, *oneof_union);
+ auto ev = evb.CreateEnumerator(oneof_type.struct_def->name);
+ ev->union_type = oneof_type;
+ ev->doc_comment = oneof_field.doc_comment;
+ ECHECK(evb.AcceptEnumerator(oneof_field.name));
+ }
+ } else {
+ EXPECT(';');
+ }
+ }
+ }
+ NEXT();
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoKey() {
+ if (token_ == '(') {
+ NEXT();
+ // Skip "(a.b)" style custom attributes.
+ while (token_ == '.' || token_ == kTokenIdentifier) NEXT();
+ EXPECT(')');
+ while (Is('.')) {
+ NEXT();
+ EXPECT(kTokenIdentifier);
+ }
+ } else {
+ EXPECT(kTokenIdentifier);
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoCurliesOrIdent() {
+ if (Is('{')) {
+ NEXT();
+ for (int nesting = 1; nesting;) {
+ if (token_ == '{')
+ nesting++;
+ else if (token_ == '}')
+ nesting--;
+ NEXT();
+ }
+ } else {
+ NEXT(); // Any single token.
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseProtoOption() {
+ NEXT();
+ ECHECK(ParseProtoKey());
+ EXPECT('=');
+ ECHECK(ParseProtoCurliesOrIdent());
+ return NoError();
+}
+
+// Parse a protobuf type, and map it to the corresponding FlatBuffer one.
+CheckedError Parser::ParseTypeFromProtoType(Type *type) {
+ struct type_lookup {
+ const char *proto_type;
+ BaseType fb_type, element;
+ };
+ static type_lookup lookup[] = {
+ { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
+ { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
+ { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
+ { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+ { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+ { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+ { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
+ { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+ { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+ { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+ { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
+ { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+ { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
+ { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
+ { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
+ { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
+ };
+ for (auto tl = lookup; tl->proto_type; tl++) {
+ if (attribute_ == tl->proto_type) {
+ type->base_type = tl->fb_type;
+ type->element = tl->element;
+ NEXT();
+ return NoError();
+ }
+ }
+ if (Is('.')) NEXT(); // qualified names may start with a . ?
+ ECHECK(ParseTypeIdent(*type));
+ return NoError();
+}
+
+CheckedError Parser::SkipAnyJsonValue() {
+ switch (token_) {
+ case '{': {
+ size_t fieldn_outer = 0;
+ return ParseTableDelimiters(
+ fieldn_outer, nullptr,
+ [&](const std::string &, size_t &fieldn,
+ const StructDef *) -> CheckedError {
+ ECHECK(Recurse([&]() { return SkipAnyJsonValue(); }));
+ fieldn++;
+ return NoError();
+ });
+ }
+ case '[': {
+ uoffset_t count = 0;
+ return ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ return Recurse([&]() { return SkipAnyJsonValue(); });
+ });
+ }
+ case kTokenStringConstant:
+ case kTokenIntegerConstant:
+ case kTokenFloatConstant: NEXT(); break;
+ default:
+ if (IsIdent("true") || IsIdent("false") || IsIdent("null")) {
+ NEXT();
+ } else
+ return TokenError();
+ }
+ return NoError();
+}
+
+CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
+ switch (token_) {
+ case '{': {
+ auto start = builder->StartMap();
+ size_t fieldn_outer = 0;
+ auto err =
+ ParseTableDelimiters(fieldn_outer, nullptr,
+ [&](const std::string &name, size_t &fieldn,
+ const StructDef *) -> CheckedError {
+ builder->Key(name);
+ ECHECK(ParseFlexBufferValue(builder));
+ fieldn++;
+ return NoError();
+ });
+ ECHECK(err);
+ builder->EndMap(start);
+ break;
+ }
+ case '[': {
+ auto start = builder->StartVector();
+ uoffset_t count = 0;
+ ECHECK(ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError {
+ return ParseFlexBufferValue(builder);
+ }));
+ builder->EndVector(start, false, false);
+ break;
+ }
+ case kTokenStringConstant:
+ builder->String(attribute_);
+ EXPECT(kTokenStringConstant);
+ break;
+ case kTokenIntegerConstant:
+ builder->Int(StringToInt(attribute_.c_str()));
+ EXPECT(kTokenIntegerConstant);
+ break;
+ case kTokenFloatConstant:
+ builder->Double(strtod(attribute_.c_str(), nullptr));
+ EXPECT(kTokenFloatConstant);
+ break;
+ default:
+ if (IsIdent("true")) {
+ builder->Bool(true);
+ NEXT();
+ } else if (IsIdent("false")) {
+ builder->Bool(false);
+ NEXT();
+ } else if (IsIdent("null")) {
+ builder->Null();
+ NEXT();
+ } else
+ return TokenError();
+ }
+ return NoError();
+}
+
+bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
+ flexbuffers::Builder *builder) {
+ auto ok = !StartParseFile(source, source_filename).Check() &&
+ !ParseFlexBufferValue(builder).Check();
+ if (ok) builder->Finish();
+ return ok;
+}
+
+bool Parser::Parse(const char *source, const char **include_paths,
+ const char *source_filename) {
+ FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+ auto r = !ParseRoot(source, include_paths, source_filename).Check();
+ FLATBUFFERS_ASSERT(0 == recurse_protection_counter);
+ return r;
+}
+
+CheckedError Parser::StartParseFile(const char *source,
+ const char *source_filename) {
+ file_being_parsed_ = source_filename ? source_filename : "";
+ source_ = source;
+ ResetState(source_);
+ error_.clear();
+ ECHECK(SkipByteOrderMark());
+ NEXT();
+ if (Is(kTokenEof)) return Error("input file is empty");
+ return NoError();
+}
+
+CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
+ const char *source_filename) {
+ ECHECK(DoParse(source, include_paths, source_filename, nullptr));
+
+ // Check that all types were defined.
+ for (auto it = structs_.vec.begin(); it != structs_.vec.end();) {
+ auto &struct_def = **it;
+ if (struct_def.predecl) {
+ if (opts.proto_mode) {
+ // Protos allow enums to be used before declaration, so check if that
+ // is the case here.
+ EnumDef *enum_def = nullptr;
+ for (size_t components =
+ struct_def.defined_namespace->components.size() + 1;
+ components && !enum_def; components--) {
+ auto qualified_name =
+ struct_def.defined_namespace->GetFullyQualifiedName(
+ struct_def.name, components - 1);
+ enum_def = LookupEnum(qualified_name);
+ }
+ if (enum_def) {
+ // This is pretty slow, but a simple solution for now.
+ auto initial_count = struct_def.refcount;
+ for (auto struct_it = structs_.vec.begin();
+ struct_it != structs_.vec.end(); ++struct_it) {
+ auto &sd = **struct_it;
+ for (auto field_it = sd.fields.vec.begin();
+ field_it != sd.fields.vec.end(); ++field_it) {
+ auto &field = **field_it;
+ if (field.value.type.struct_def == &struct_def) {
+ field.value.type.struct_def = nullptr;
+ field.value.type.enum_def = enum_def;
+ auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR
+ ? field.value.type.element
+ : field.value.type.base_type;
+ FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT);
+ bt = enum_def->underlying_type.base_type;
+ struct_def.refcount--;
+ enum_def->refcount++;
+ }
+ }
+ }
+ if (struct_def.refcount)
+ return Error("internal: " + NumToString(struct_def.refcount) + "/" +
+ NumToString(initial_count) +
+ " use(s) of pre-declaration enum not accounted for: " +
+ enum_def->name);
+ structs_.dict.erase(structs_.dict.find(struct_def.name));
+ it = structs_.vec.erase(it);
+ delete &struct_def;
+ continue; // Skip error.
+ }
+ }
+ auto err = "type referenced but not defined (check namespace): " +
+ struct_def.name;
+ if (struct_def.original_location)
+ err += ", originally at: " + *struct_def.original_location;
+ return Error(err);
+ }
+ ++it;
+ }
+
+ // This check has to happen here and not earlier, because only now do we
+ // know for sure what the type of these are.
+ for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+ auto &enum_def = **it;
+ if (enum_def.is_union) {
+ for (auto val_it = enum_def.Vals().begin();
+ val_it != enum_def.Vals().end(); ++val_it) {
+ auto &val = **val_it;
+ if (!SupportsAdvancedUnionFeatures() && val.union_type.struct_def &&
+ val.union_type.struct_def->fixed)
+ return Error(
+ "only tables can be union elements in the generated language: " +
+ val.name);
+ }
+ }
+ }
+ return NoError();
+}
+
+CheckedError Parser::DoParse(const char *source, const char **include_paths,
+ const char *source_filename,
+ const char *include_filename) {
+ if (source_filename) {
+ if (included_files_.find(source_filename) == included_files_.end()) {
+ included_files_[source_filename] =
+ include_filename ? include_filename : "";
+ files_included_per_file_[source_filename] = std::set<std::string>();
+ } else {
+ return NoError();
+ }
+ }
+ if (!include_paths) {
+ static const char *current_directory[] = { "", nullptr };
+ include_paths = current_directory;
+ }
+ field_stack_.clear();
+ builder_.Clear();
+ // Start with a blank namespace just in case this file doesn't have one.
+ current_namespace_ = empty_namespace_;
+
+ ECHECK(StartParseFile(source, source_filename));
+
+ // Includes must come before type declarations:
+ for (;;) {
+ // Parse pre-include proto statements if any:
+ if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" ||
+ attribute_ == "package")) {
+ ECHECK(ParseProtoDecl());
+ } else if (IsIdent("native_include")) {
+ NEXT();
+ vector_emplace_back(&native_included_files_, attribute_);
+ EXPECT(kTokenStringConstant);
+ EXPECT(';');
+ } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
+ NEXT();
+ if (opts.proto_mode && attribute_ == "public") NEXT();
+ auto name = flatbuffers::PosixPath(attribute_.c_str());
+ EXPECT(kTokenStringConstant);
+ // Look for the file in include_paths.
+ std::string filepath;
+ for (auto paths = include_paths; paths && *paths; paths++) {
+ filepath = flatbuffers::ConCatPathFileName(*paths, name);
+ if (FileExists(filepath.c_str())) break;
+ }
+ if (filepath.empty())
+ return Error("unable to locate include file: " + name);
+ if (source_filename)
+ files_included_per_file_[source_filename].insert(filepath);
+ if (included_files_.find(filepath) == included_files_.end()) {
+ // We found an include file that we have not parsed yet.
+ // Load it and parse it.
+ std::string contents;
+ if (!LoadFile(filepath.c_str(), true, &contents))
+ return Error("unable to load include file: " + name);
+ ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
+ name.c_str()));
+ // We generally do not want to output code for any included files:
+ if (!opts.generate_all) MarkGenerated();
+ // Reset these just in case the included file had them, and the
+ // parent doesn't.
+ root_struct_def_ = nullptr;
+ file_identifier_.clear();
+ file_extension_.clear();
+ // This is the easiest way to continue this file after an include:
+ // instead of saving and restoring all the state, we simply start the
+ // file anew. This will cause it to encounter the same include
+ // statement again, but this time it will skip it, because it was
+ // entered into included_files_.
+ // This is recursive, but only go as deep as the number of include
+ // statements.
+ if (source_filename) {
+ included_files_.erase(source_filename);
+ }
+ return DoParse(source, include_paths, source_filename,
+ include_filename);
+ }
+ EXPECT(';');
+ } else {
+ break;
+ }
+ }
+ // Now parse all other kinds of declarations:
+ while (token_ != kTokenEof) {
+ if (opts.proto_mode) {
+ ECHECK(ParseProtoDecl());
+ } else if (IsIdent("namespace")) {
+ ECHECK(ParseNamespace());
+ } else if (token_ == '{') {
+ if (!root_struct_def_)
+ return Error("no root type set to parse json with");
+ if (builder_.GetSize()) {
+ return Error("cannot have more than one json object in a file");
+ }
+ uoffset_t toff;
+ ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
+ if (opts.size_prefixed) {
+ builder_.FinishSizePrefixed(Offset<Table>(toff), file_identifier_.length()
+ ? file_identifier_.c_str()
+ : nullptr);
+ } else {
+ builder_.Finish(Offset<Table>(toff), file_identifier_.length()
+ ? file_identifier_.c_str()
+ : nullptr);
+ }
+ // Check that JSON file doesn't contain more objects or IDL directives.
+ // Comments after JSON are allowed.
+ EXPECT(kTokenEof);
+ } else if (IsIdent("enum")) {
+ ECHECK(ParseEnum(false, nullptr));
+ } else if (IsIdent("union")) {
+ ECHECK(ParseEnum(true, nullptr));
+ } else if (IsIdent("root_type")) {
+ NEXT();
+ auto root_type = attribute_;
+ EXPECT(kTokenIdentifier);
+ ECHECK(ParseNamespacing(&root_type, nullptr));
+ if (opts.root_type.empty()) {
+ if (!SetRootType(root_type.c_str()))
+ return Error("unknown root type: " + root_type);
+ if (root_struct_def_->fixed)
+ return Error("root type must be a table");
+ }
+ EXPECT(';');
+ } else if (IsIdent("file_identifier")) {
+ NEXT();
+ file_identifier_ = attribute_;
+ EXPECT(kTokenStringConstant);
+ if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength)
+ return Error("file_identifier must be exactly " +
+ NumToString(FlatBufferBuilder::kFileIdentifierLength) +
+ " characters");
+ EXPECT(';');
+ } else if (IsIdent("file_extension")) {
+ NEXT();
+ file_extension_ = attribute_;
+ EXPECT(kTokenStringConstant);
+ EXPECT(';');
+ } else if (IsIdent("include")) {
+ return Error("includes must come before declarations");
+ } else if (IsIdent("attribute")) {
+ NEXT();
+ auto name = attribute_;
+ if (Is(kTokenIdentifier)) {
+ NEXT();
+ } else {
+ EXPECT(kTokenStringConstant);
+ }
+ EXPECT(';');
+ known_attributes_[name] = false;
+ } else if (IsIdent("rpc_service")) {
+ ECHECK(ParseService());
+ } else {
+ ECHECK(ParseDecl());
+ }
+ }
+ return NoError();
+}
+
+std::set<std::string> Parser::GetIncludedFilesRecursive(
+ const std::string &file_name) const {
+ std::set<std::string> included_files;
+ std::list<std::string> to_process;
+
+ if (file_name.empty()) return included_files;
+ to_process.push_back(file_name);
+
+ while (!to_process.empty()) {
+ std::string current = to_process.front();
+ to_process.pop_front();
+ included_files.insert(current);
+
+ // Workaround the lack of const accessor in C++98 maps.
+ auto &new_files =
+ (*const_cast<std::map<std::string, std::set<std::string>> *>(
+ &files_included_per_file_))[current];
+ for (auto it = new_files.begin(); it != new_files.end(); ++it) {
+ if (included_files.find(*it) == included_files.end())
+ to_process.push_back(*it);
+ }
+ }
+
+ return included_files;
+}
+
+// Schema serialization functionality:
+
+template<typename T> bool compareName(const T *a, const T *b) {
+ return a->defined_namespace->GetFullyQualifiedName(a->name) <
+ b->defined_namespace->GetFullyQualifiedName(b->name);
+}
+
+template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
+ // Pre-sort these vectors, such that we can set the correct indices for them.
+ auto vec = defvec;
+ std::sort(vec.begin(), vec.end(), compareName<T>);
+ for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
+}
+
+void Parser::Serialize() {
+ builder_.Clear();
+ AssignIndices(structs_.vec);
+ AssignIndices(enums_.vec);
+ std::vector<Offset<reflection::Object>> object_offsets;
+ for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
+ auto offset = (*it)->Serialize(&builder_, *this);
+ object_offsets.push_back(offset);
+ (*it)->serialized_location = offset.o;
+ }
+ std::vector<Offset<reflection::Enum>> enum_offsets;
+ for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+ auto offset = (*it)->Serialize(&builder_, *this);
+ enum_offsets.push_back(offset);
+ (*it)->serialized_location = offset.o;
+ }
+ std::vector<Offset<reflection::Service>> service_offsets;
+ for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) {
+ auto offset = (*it)->Serialize(&builder_, *this);
+ service_offsets.push_back(offset);
+ (*it)->serialized_location = offset.o;
+ }
+ auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets);
+ auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets);
+ auto fiid__ = builder_.CreateString(file_identifier_);
+ auto fext__ = builder_.CreateString(file_extension_);
+ auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets);
+ auto schema_offset =
+ reflection::CreateSchema(builder_, objs__, enum__, fiid__, fext__,
+ (root_struct_def_ ? root_struct_def_->serialized_location : 0),
+ serv__);
+ if (opts.size_prefixed) {
+ builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier());
+ } else {
+ builder_.Finish(schema_offset, reflection::SchemaIdentifier());
+ }
+}
+
+static Namespace *GetNamespace(
+ const std::string &qualified_name, std::vector<Namespace *> &namespaces,
+ std::map<std::string, Namespace *> &namespaces_index) {
+ size_t dot = qualified_name.find_last_of('.');
+ std::string namespace_name = (dot != std::string::npos)
+ ? std::string(qualified_name.c_str(), dot)
+ : "";
+ Namespace *&ns = namespaces_index[namespace_name];
+
+ if (!ns) {
+ ns = new Namespace();
+ namespaces.push_back(ns);
+
+ size_t pos = 0;
+
+ for (;;) {
+ dot = qualified_name.find('.', pos);
+ if (dot == std::string::npos) { break; }
+ ns->components.push_back(qualified_name.substr(pos, dot - pos));
+ pos = dot + 1;
+ }
+ }
+
+ return ns;
+}
+
+Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<Offset<reflection::Field>> field_offsets;
+ for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) {
+ field_offsets.push_back((*it)->Serialize(
+ builder, static_cast<uint16_t>(it - fields.vec.begin()), parser));
+ }
+ auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+ auto name__ = builder->CreateString(qualified_name);
+ auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateObject(*builder, name__, flds__, fixed,
+ static_cast<int>(minalign),
+ static_cast<int>(bytesize),
+ attr__, docs__);
+}
+
+bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) {
+ if (!DeserializeAttributes(parser, object->attributes()))
+ return false;
+ DeserializeDoc(doc_comment, object->documentation());
+ name = parser.UnqualifiedName(object->name()->str());
+ predecl = false;
+ sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
+ const auto& of = *(object->fields());
+ auto indexes = std::vector<uoffset_t>(of.size());
+ for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i;
+ size_t tmp_struct_size = 0;
+ for (size_t i = 0; i < indexes.size(); i++) {
+ auto field = of.Get(indexes[i]);
+ auto field_def = new FieldDef();
+ if (!field_def->Deserialize(parser, field) ||
+ fields.Add(field_def->name, field_def)) {
+ delete field_def;
+ return false;
+ }
+ if (fixed) {
+ // Recompute padding since that's currently not serialized.
+ auto size = InlineSize(field_def->value.type);
+ auto next_field =
+ i + 1 < indexes.size()
+ ? of.Get(indexes[i+1])
+ : nullptr;
+ tmp_struct_size += size;
+ field_def->padding =
+ next_field ? (next_field->offset() - field_def->value.offset) - size
+ : PaddingBytes(tmp_struct_size, minalign);
+ tmp_struct_size += field_def->padding;
+ }
+ }
+ FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize());
+ return true;
+}
+
+Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
+ uint16_t id,
+ const Parser &parser) const {
+ auto name__ = builder->CreateString(name);
+ auto type__ = value.type.Serialize(builder);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateField(*builder, name__, type__, id, value.offset,
+ // Is uint64>max(int64) tested?
+ IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0,
+ // result may be platform-dependent if underlying is float (not double)
+ IsFloat(value.type.base_type) ? strtod(value.constant.c_str(), nullptr)
+ : 0.0,
+ deprecated, required, key, attr__, docs__);
+ // TODO: value.constant is almost always "0", we could save quite a bit of
+ // space by sharing it. Same for common values of value.type.
+}
+
+bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) {
+ name = field->name()->str();
+ defined_namespace = parser.current_namespace_;
+ if (!value.type.Deserialize(parser, field->type()))
+ return false;
+ value.offset = field->offset();
+ if (IsInteger(value.type.base_type)) {
+ value.constant = NumToString(field->default_integer());
+ } else if (IsFloat(value.type.base_type)) {
+ value.constant = FloatToString(field->default_real(), 16);
+ size_t last_zero = value.constant.find_last_not_of('0');
+ if (last_zero != std::string::npos && last_zero != 0) {
+ value.constant.erase(last_zero, std::string::npos);
+ }
+ }
+ deprecated = field->deprecated();
+ required = field->required();
+ key = field->key();
+ if (!DeserializeAttributes(parser, field->attributes()))
+ return false;
+ // TODO: this should probably be handled by a separate attribute
+ if (attributes.Lookup("flexbuffer")) {
+ flexbuffer = true;
+ parser.uses_flexbuffers_ = true;
+ if (value.type.base_type != BASE_TYPE_VECTOR ||
+ value.type.element != BASE_TYPE_UCHAR)
+ return false;
+ }
+ if (auto nested = attributes.Lookup("nested_flatbuffer")) {
+ auto nested_qualified_name =
+ parser.current_namespace_->GetFullyQualifiedName(nested->constant);
+ nested_flatbuffer = parser.LookupStruct(nested_qualified_name);
+ if (!nested_flatbuffer) return false;
+ }
+ DeserializeDoc(doc_comment, field->documentation());
+ return true;
+}
+
+Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ auto name__ = builder->CreateString(name);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateRPCCall(*builder, name__,
+ request->serialized_location,
+ response->serialized_location,
+ attr__, docs__);
+}
+
+bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) {
+ name = call->name()->str();
+ if (!DeserializeAttributes(parser, call->attributes()))
+ return false;
+ DeserializeDoc(doc_comment, call->documentation());
+ request = parser.structs_.Lookup(call->request()->name()->str());
+ response = parser.structs_.Lookup(call->response()->name()->str());
+ if (!request || !response) { return false; }
+ return true;
+}
+
+Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<Offset<reflection::RPCCall>> servicecall_offsets;
+ for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) {
+ servicecall_offsets.push_back((*it)->Serialize(builder, parser));
+ }
+ auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+ auto name__ = builder->CreateString(qualified_name);
+ auto call__ = builder->CreateVector(servicecall_offsets);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateService(*builder, name__, call__, attr__, docs__);
+}
+
+bool ServiceDef::Deserialize(Parser &parser,
+ const reflection::Service *service) {
+ name = parser.UnqualifiedName(service->name()->str());
+ if (service->calls()) {
+ for (uoffset_t i = 0; i < service->calls()->size(); ++i) {
+ auto call = new RPCCall();
+ if (!call->Deserialize(parser, service->calls()->Get(i)) ||
+ calls.Add(call->name, call)) {
+ delete call;
+ return false;
+ }
+ }
+ }
+ if (!DeserializeAttributes(parser, service->attributes()))
+ return false;
+ DeserializeDoc(doc_comment, service->documentation());
+ return true;
+}
+
+Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<Offset<reflection::EnumVal>> enumval_offsets;
+ for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) {
+ enumval_offsets.push_back((*it)->Serialize(builder, parser));
+ }
+ auto qualified_name = defined_namespace->GetFullyQualifiedName(name);
+ auto name__ = builder->CreateString(qualified_name);
+ auto vals__ = builder->CreateVector(enumval_offsets);
+ auto type__ = underlying_type.Serialize(builder);
+ auto attr__ = SerializeAttributes(builder, parser);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateEnum(*builder, name__, vals__, is_union, type__,
+ attr__, docs__);
+}
+
+bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) {
+ name = parser.UnqualifiedName(_enum->name()->str());
+ for (uoffset_t i = 0; i < _enum->values()->size(); ++i) {
+ auto val = new EnumVal();
+ if (!val->Deserialize(parser, _enum->values()->Get(i)) ||
+ vals.Add(val->name, val)) {
+ delete val;
+ return false;
+ }
+ }
+ is_union = _enum->is_union();
+ if (!underlying_type.Deserialize(parser, _enum->underlying_type())) {
+ return false;
+ }
+ if (!DeserializeAttributes(parser, _enum->attributes()))
+ return false;
+ DeserializeDoc(doc_comment, _enum->documentation());
+ return true;
+}
+
+Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ auto name__ = builder->CreateString(name);
+ auto type__ = union_type.Serialize(builder);
+ auto docs__ = parser.opts.binary_schema_comments
+ ? builder->CreateVectorOfStrings(doc_comment)
+ : 0;
+ return reflection::CreateEnumVal(*builder, name__, value,
+ union_type.struct_def ? union_type.struct_def->serialized_location : 0,
+ type__, docs__);
+}
+
+bool EnumVal::Deserialize(const Parser &parser,
+ const reflection::EnumVal *val) {
+ name = val->name()->str();
+ value = val->value();
+ if (!union_type.Deserialize(parser, val->union_type()))
+ return false;
+ DeserializeDoc(doc_comment, val->documentation());
+ return true;
+}
+
+Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
+ return reflection::CreateType(
+ *builder, static_cast<reflection::BaseType>(base_type),
+ static_cast<reflection::BaseType>(element),
+ struct_def ? struct_def->index : (enum_def ? enum_def->index : -1),
+ fixed_length);
+}
+
+bool Type::Deserialize(const Parser &parser, const reflection::Type *type) {
+ if (type == nullptr) return true;
+ base_type = static_cast<BaseType>(type->base_type());
+ element = static_cast<BaseType>(type->element());
+ fixed_length = type->fixed_length();
+ if (type->index() >= 0) {
+ bool is_series = type->base_type() == reflection::Vector ||
+ type->base_type() == reflection::Array;
+ if (type->base_type() == reflection::Obj ||
+ (is_series &&
+ type->element() == reflection::Obj)) {
+ if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) {
+ struct_def = parser.structs_.vec[type->index()];
+ struct_def->refcount++;
+ } else {
+ return false;
+ }
+ } else {
+ if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) {
+ enum_def = parser.enums_.vec[type->index()];
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+flatbuffers::Offset<
+ flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>>
+Definition::SerializeAttributes(FlatBufferBuilder *builder,
+ const Parser &parser) const {
+ std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs;
+ for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) {
+ auto it = parser.known_attributes_.find(kv->first);
+ FLATBUFFERS_ASSERT(it != parser.known_attributes_.end());
+ if (parser.opts.binary_schema_builtins || !it->second) {
+ auto key = builder->CreateString(kv->first);
+ auto val = builder->CreateString(kv->second->constant);
+ attrs.push_back(reflection::CreateKeyValue(*builder, key, val));
+ }
+ }
+ if (attrs.size()) {
+ return builder->CreateVectorOfSortedTables(&attrs);
+ } else {
+ return 0;
+ }
+}
+
+bool Definition::DeserializeAttributes(
+ Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) {
+ if (attrs == nullptr)
+ return true;
+ for (uoffset_t i = 0; i < attrs->size(); ++i) {
+ auto kv = attrs->Get(i);
+ auto value = new Value();
+ if (kv->value()) { value->constant = kv->value()->str(); }
+ if (attributes.Add(kv->key()->str(), value)) {
+ delete value;
+ return false;
+ }
+ parser.known_attributes_[kv->key()->str()];
+ }
+ return true;
+}
+
+/************************************************************************/
+/* DESERIALIZATION */
+/************************************************************************/
+bool Parser::Deserialize(const uint8_t *buf, const size_t size) {
+ flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size);
+ bool size_prefixed = false;
+ if(!reflection::SchemaBufferHasIdentifier(buf)) {
+ if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(),
+ true))
+ return false;
+ else
+ size_prefixed = true;
+ }
+ auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer
+ : &reflection::VerifySchemaBuffer;
+ if (!verify_fn(verifier)) {
+ return false;
+ }
+ auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf)
+ : reflection::GetSchema(buf);
+ return Deserialize(schema);
+}
+
+bool Parser::Deserialize(const reflection::Schema *schema) {
+ file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : "";
+ file_extension_ = schema->file_ext() ? schema->file_ext()->str() : "";
+ std::map<std::string, Namespace *> namespaces_index;
+
+ // Create defs without deserializing so references from fields to structs and
+ // enums can be resolved.
+ for (auto it = schema->objects()->begin(); it != schema->objects()->end();
+ ++it) {
+ auto struct_def = new StructDef();
+ struct_def->bytesize = it->bytesize();
+ struct_def->fixed = it->is_struct();
+ struct_def->minalign = it->minalign();
+ if (structs_.Add(it->name()->str(), struct_def)) {
+ delete struct_def;
+ return false;
+ }
+ auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr);
+ if (types_.Add(it->name()->str(), type)) {
+ delete type;
+ return false;
+ }
+ }
+ for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
+ auto enum_def = new EnumDef();
+ if (enums_.Add(it->name()->str(), enum_def)) {
+ delete enum_def;
+ return false;
+ }
+ auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def);
+ if (types_.Add(it->name()->str(), type)) {
+ delete type;
+ return false;
+ }
+ }
+
+ // Now fields can refer to structs and enums by index.
+ for (auto it = schema->objects()->begin(); it != schema->objects()->end();
+ ++it) {
+ std::string qualified_name = it->name()->str();
+ auto struct_def = structs_.Lookup(qualified_name);
+ struct_def->defined_namespace =
+ GetNamespace(qualified_name, namespaces_, namespaces_index);
+ if (!struct_def->Deserialize(*this, * it)) { return false; }
+ if (schema->root_table() == *it) { root_struct_def_ = struct_def; }
+ }
+ for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) {
+ std::string qualified_name = it->name()->str();
+ auto enum_def = enums_.Lookup(qualified_name);
+ enum_def->defined_namespace =
+ GetNamespace(qualified_name, namespaces_, namespaces_index);
+ if (!enum_def->Deserialize(*this, *it)) { return false; }
+ }
+
+ if (schema->services()) {
+ for (auto it = schema->services()->begin(); it != schema->services()->end();
+ ++it) {
+ std::string qualified_name = it->name()->str();
+ auto service_def = new ServiceDef();
+ service_def->defined_namespace =
+ GetNamespace(qualified_name, namespaces_, namespaces_index);
+ if (!service_def->Deserialize(*this, *it) ||
+ services_.Add(qualified_name, service_def)) {
+ delete service_def;
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+std::string Parser::ConformTo(const Parser &base) {
+ for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) {
+ auto &struct_def = **sit;
+ auto qualified_name =
+ struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
+ auto struct_def_base = base.LookupStruct(qualified_name);
+ if (!struct_def_base) continue;
+ for (auto fit = struct_def.fields.vec.begin();
+ fit != struct_def.fields.vec.end(); ++fit) {
+ auto &field = **fit;
+ auto field_base = struct_def_base->fields.Lookup(field.name);
+ if (field_base) {
+ if (field.value.offset != field_base->value.offset)
+ return "offsets differ for field: " + field.name;
+ if (field.value.constant != field_base->value.constant)
+ return "defaults differ for field: " + field.name;
+ if (!EqualByName(field.value.type, field_base->value.type))
+ return "types differ for field: " + field.name;
+ } else {
+ // Doesn't have to exist, deleting fields is fine.
+ // But we should check if there is a field that has the same offset
+ // but is incompatible (in the case of field renaming).
+ for (auto fbit = struct_def_base->fields.vec.begin();
+ fbit != struct_def_base->fields.vec.end(); ++fbit) {
+ field_base = *fbit;
+ if (field.value.offset == field_base->value.offset) {
+ if (!EqualByName(field.value.type, field_base->value.type))
+ return "field renamed to different type: " + field.name;
+ break;
+ }
+ }
+ }
+ }
+ }
+ for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) {
+ auto &enum_def = **eit;
+ auto qualified_name =
+ enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name);
+ auto enum_def_base = base.enums_.Lookup(qualified_name);
+ if (!enum_def_base) continue;
+ for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end();
+ ++evit) {
+ auto &enum_val = **evit;
+ auto enum_val_base = enum_def_base->Lookup(enum_val.name);
+ if (enum_val_base) {
+ if (enum_val != *enum_val_base)
+ return "values differ for enum: " + enum_val.name;
+ }
+ }
+ }
+ return "";
+}
+
+} // namespace flatbuffers
diff --git a/src/reflection.cpp b/src/reflection.cpp
new file mode 100644
index 0000000..89ce783
--- /dev/null
+++ b/src/reflection.cpp
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "flatbuffers/reflection.h"
+#include "flatbuffers/util.h"
+
+// Helper functionality for reflection.
+
+namespace flatbuffers {
+
+int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) {
+ // clang-format off
+ #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data))
+ switch (type) {
+ case reflection::UType:
+ case reflection::Bool:
+ case reflection::UByte: return FLATBUFFERS_GET(uint8_t);
+ case reflection::Byte: return FLATBUFFERS_GET(int8_t);
+ case reflection::Short: return FLATBUFFERS_GET(int16_t);
+ case reflection::UShort: return FLATBUFFERS_GET(uint16_t);
+ case reflection::Int: return FLATBUFFERS_GET(int32_t);
+ case reflection::UInt: return FLATBUFFERS_GET(uint32_t);
+ case reflection::Long: return FLATBUFFERS_GET(int64_t);
+ case reflection::ULong: return FLATBUFFERS_GET(uint64_t);
+ case reflection::Float: return FLATBUFFERS_GET(float);
+ case reflection::Double: return FLATBUFFERS_GET(double);
+ case reflection::String: {
+ auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) +
+ data);
+ return s ? StringToInt(s->c_str()) : 0;
+ }
+ default: return 0; // Tables & vectors do not make sense.
+ }
+ #undef FLATBUFFERS_GET
+ // clang-format on
+}
+
+double GetAnyValueF(reflection::BaseType type, const uint8_t *data) {
+ switch (type) {
+ case reflection::Float: return static_cast<double>(ReadScalar<float>(data));
+ case reflection::Double: return ReadScalar<double>(data);
+ case reflection::String: {
+ auto s =
+ reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
+ return s ? strtod(s->c_str(), nullptr) : 0.0;
+ }
+ default: return static_cast<double>(GetAnyValueI(type, data));
+ }
+}
+
+std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
+ const reflection::Schema *schema, int type_index) {
+ switch (type) {
+ case reflection::Float:
+ case reflection::Double: return NumToString(GetAnyValueF(type, data));
+ case reflection::String: {
+ auto s =
+ reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data);
+ return s ? s->c_str() : "";
+ }
+ case reflection::Obj:
+ if (schema) {
+ // Convert the table to a string. This is mostly for debugging purposes,
+ // and does NOT promise to be JSON compliant.
+ // Also prefixes the type.
+ auto &objectdef = *schema->objects()->Get(type_index);
+ auto s = objectdef.name()->str();
+ if (objectdef.is_struct()) {
+ s += "(struct)"; // TODO: implement this as well.
+ } else {
+ auto table_field = reinterpret_cast<const Table *>(
+ ReadScalar<uoffset_t>(data) + data);
+ s += " { ";
+ auto fielddefs = objectdef.fields();
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ if (!table_field->CheckField(fielddef.offset())) continue;
+ auto val = GetAnyFieldS(*table_field, fielddef, schema);
+ if (fielddef.type()->base_type() == reflection::String) {
+ std::string esc;
+ flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true,
+ false);
+ val = esc;
+ }
+ s += fielddef.name()->str();
+ s += ": ";
+ s += val;
+ s += ", ";
+ }
+ s += "}";
+ }
+ return s;
+ } else {
+ return "(table)";
+ }
+ case reflection::Vector:
+ return "[(elements)]"; // TODO: implement this as well.
+ case reflection::Union: return "(union)"; // TODO: implement this as well.
+ default: return NumToString(GetAnyValueI(type, data));
+ }
+}
+
+void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) {
+ // clang-format off
+ #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val))
+ switch (type) {
+ case reflection::UType:
+ case reflection::Bool:
+ case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break;
+ case reflection::Byte: FLATBUFFERS_SET(int8_t ); break;
+ case reflection::Short: FLATBUFFERS_SET(int16_t ); break;
+ case reflection::UShort: FLATBUFFERS_SET(uint16_t); break;
+ case reflection::Int: FLATBUFFERS_SET(int32_t ); break;
+ case reflection::UInt: FLATBUFFERS_SET(uint32_t); break;
+ case reflection::Long: FLATBUFFERS_SET(int64_t ); break;
+ case reflection::ULong: FLATBUFFERS_SET(uint64_t); break;
+ case reflection::Float: FLATBUFFERS_SET(float ); break;
+ case reflection::Double: FLATBUFFERS_SET(double ); break;
+ // TODO: support strings
+ default: break;
+ }
+ #undef FLATBUFFERS_SET
+ // clang-format on
+}
+
+void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) {
+ switch (type) {
+ case reflection::Float: WriteScalar(data, static_cast<float>(val)); break;
+ case reflection::Double: WriteScalar(data, val); break;
+ // TODO: support strings.
+ default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break;
+ }
+}
+
+void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) {
+ switch (type) {
+ case reflection::Float:
+ case reflection::Double:
+ SetAnyValueF(type, data, strtod(val, nullptr));
+ break;
+ // TODO: support strings.
+ default: SetAnyValueI(type, data, StringToInt(val)); break;
+ }
+}
+
+// Resize a FlatBuffer in-place by iterating through all offsets in the buffer
+// and adjusting them by "delta" if they straddle the start offset.
+// Once that is done, bytes can now be inserted/deleted safely.
+// "delta" may be negative (shrinking).
+// Unless "delta" is a multiple of the largest alignment, you'll create a small
+// amount of garbage space in the buffer (usually 0..7 bytes).
+// If your FlatBuffer's root table is not the schema's root table, you should
+// pass in your root_table type as well.
+class ResizeContext {
+ public:
+ ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
+ std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table = nullptr)
+ : schema_(schema),
+ startptr_(vector_data(*flatbuf) + start),
+ delta_(delta),
+ buf_(*flatbuf),
+ dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
+ auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
+ delta_ = (delta_ + mask) & ~mask;
+ if (!delta_) return; // We can't shrink by less than largest_scalar_t.
+ // Now change all the offsets by delta_.
+ auto root = GetAnyRoot(vector_data(buf_));
+ Straddle<uoffset_t, 1>(vector_data(buf_), root, vector_data(buf_));
+ ResizeTable(root_table ? *root_table : *schema.root_table(), root);
+ // We can now add or remove bytes at start.
+ if (delta_ > 0)
+ buf_.insert(buf_.begin() + start, delta_, 0);
+ else
+ buf_.erase(buf_.begin() + start, buf_.begin() + start - delta_);
+ }
+
+ // Check if the range between first (lower address) and second straddles
+ // the insertion point. If it does, change the offset at offsetloc (of
+ // type T, with direction D).
+ template<typename T, int D>
+ void Straddle(const void *first, const void *second, void *offsetloc) {
+ if (first <= startptr_ && second >= startptr_) {
+ WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D);
+ DagCheck(offsetloc) = true;
+ }
+ }
+
+ // This returns a boolean that records if the corresponding offset location
+ // has been modified already. If so, we can't even read the corresponding
+ // offset, since it is pointing to a location that is illegal until the
+ // resize actually happens.
+ // This must be checked for every offset, since we can't know which offsets
+ // will straddle and which won't.
+ uint8_t &DagCheck(const void *offsetloc) {
+ auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
+ reinterpret_cast<const uoffset_t *>(vector_data(buf_));
+ return dag_check_[dag_idx];
+ }
+
+ void ResizeTable(const reflection::Object &objectdef, Table *table) {
+ if (DagCheck(table)) return; // Table already visited.
+ auto vtable = table->GetVTable();
+ // Early out: since all fields inside the table must point forwards in
+ // memory, if the insertion point is before the table we can stop here.
+ auto tableloc = reinterpret_cast<uint8_t *>(table);
+ if (startptr_ <= tableloc) {
+ // Check if insertion point is between the table and a vtable that
+ // precedes it. This can't happen in current construction code, but check
+ // just in case we ever change the way flatbuffers are built.
+ Straddle<soffset_t, -1>(vtable, table, table);
+ } else {
+ // Check each field.
+ auto fielddefs = objectdef.fields();
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ auto base_type = fielddef.type()->base_type();
+ // Ignore scalars.
+ if (base_type <= reflection::Double) continue;
+ // Ignore fields that are not stored.
+ auto offset = table->GetOptionalFieldOffset(fielddef.offset());
+ if (!offset) continue;
+ // Ignore structs.
+ auto subobjectdef =
+ base_type == reflection::Obj
+ ? schema_.objects()->Get(fielddef.type()->index())
+ : nullptr;
+ if (subobjectdef && subobjectdef->is_struct()) continue;
+ // Get this fields' offset, and read it if safe.
+ auto offsetloc = tableloc + offset;
+ if (DagCheck(offsetloc)) continue; // This offset already visited.
+ auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc);
+ Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc);
+ // Recurse.
+ switch (base_type) {
+ case reflection::Obj: {
+ ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref));
+ break;
+ }
+ case reflection::Vector: {
+ auto elem_type = fielddef.type()->element();
+ if (elem_type != reflection::Obj && elem_type != reflection::String)
+ break;
+ auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref);
+ auto elemobjectdef =
+ elem_type == reflection::Obj
+ ? schema_.objects()->Get(fielddef.type()->index())
+ : nullptr;
+ if (elemobjectdef && elemobjectdef->is_struct()) break;
+ for (uoffset_t i = 0; i < vec->size(); i++) {
+ auto loc = vec->Data() + i * sizeof(uoffset_t);
+ if (DagCheck(loc)) continue; // This offset already visited.
+ auto dest = loc + vec->Get(i);
+ Straddle<uoffset_t, 1>(loc, dest, loc);
+ if (elemobjectdef)
+ ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest));
+ }
+ break;
+ }
+ case reflection::Union: {
+ ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table),
+ reinterpret_cast<Table *>(ref));
+ break;
+ }
+ case reflection::String: break;
+ default: FLATBUFFERS_ASSERT(false);
+ }
+ }
+ // Check if the vtable offset points beyond the insertion point.
+ // Must do this last, since GetOptionalFieldOffset above still reads
+ // this value.
+ Straddle<soffset_t, -1>(table, vtable, table);
+ }
+ }
+
+ void operator=(const ResizeContext &rc);
+
+ private:
+ const reflection::Schema &schema_;
+ uint8_t *startptr_;
+ int delta_;
+ std::vector<uint8_t> &buf_;
+ std::vector<uint8_t> dag_check_;
+};
+
+void SetString(const reflection::Schema &schema, const std::string &val,
+ const String *str, std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table) {
+ auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size());
+ auto str_start = static_cast<uoffset_t>(
+ reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf));
+ auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
+ if (delta) {
+ // Clear the old string, since we don't want parts of it remaining.
+ memset(vector_data(*flatbuf) + start, 0, str->size());
+ // Different size, we must expand (or contract).
+ ResizeContext(schema, start, delta, flatbuf, root_table);
+ // Set the new length.
+ WriteScalar(vector_data(*flatbuf) + str_start,
+ static_cast<uoffset_t>(val.size()));
+ }
+ // Copy new data. Safe because we created the right amount of space.
+ memcpy(vector_data(*flatbuf) + start, val.c_str(), val.size() + 1);
+}
+
+uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
+ const VectorOfAny *vec, uoffset_t num_elems,
+ uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
+ const reflection::Object *root_table) {
+ auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
+ auto delta_bytes = delta_elem * static_cast<int>(elem_size);
+ auto vec_start =
+ reinterpret_cast<const uint8_t *>(vec) - vector_data(*flatbuf);
+ auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
+ elem_size * num_elems);
+ if (delta_bytes) {
+ if (delta_elem < 0) {
+ // Clear elements we're throwing away, since some might remain in the
+ // buffer.
+ auto size_clear = -delta_elem * elem_size;
+ memset(vector_data(*flatbuf) + start - size_clear, 0, size_clear);
+ }
+ ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
+ WriteScalar(vector_data(*flatbuf) + vec_start, newsize); // Length field.
+ // Set new elements to 0.. this can be overwritten by the caller.
+ if (delta_elem > 0) {
+ memset(vector_data(*flatbuf) + start, 0, delta_elem * elem_size);
+ }
+ }
+ return vector_data(*flatbuf) + start;
+}
+
+const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
+ const uint8_t *newbuf, size_t newlen) {
+ // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
+ // going to chop off the root offset.
+ while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
+ !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
+ flatbuf.push_back(0);
+ }
+ auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
+ // Insert the entire FlatBuffer minus the root pointer.
+ flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
+ auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
+ return vector_data(flatbuf) + insertion_point + root_offset;
+}
+
+void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
+ const Table &table, size_t align, size_t size) {
+ fbb.Align(align);
+ fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size);
+ fbb.TrackField(fielddef.offset(), fbb.GetSize());
+}
+
+Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
+ const reflection::Schema &schema,
+ const reflection::Object &objectdef,
+ const Table &table, bool use_string_pooling) {
+ // Before we can construct the table, we have to first generate any
+ // subobjects, and collect their offsets.
+ std::vector<uoffset_t> offsets;
+ auto fielddefs = objectdef.fields();
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ // Skip if field is not present in the source.
+ if (!table.CheckField(fielddef.offset())) continue;
+ uoffset_t offset = 0;
+ switch (fielddef.type()->base_type()) {
+ case reflection::String: {
+ offset = use_string_pooling
+ ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o
+ : fbb.CreateString(GetFieldS(table, fielddef)).o;
+ break;
+ }
+ case reflection::Obj: {
+ auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+ if (!subobjectdef.is_struct()) {
+ offset =
+ CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef))
+ .o;
+ }
+ break;
+ }
+ case reflection::Union: {
+ auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table);
+ offset =
+ CopyTable(fbb, schema, subobjectdef, *GetFieldT(table, fielddef)).o;
+ break;
+ }
+ case reflection::Vector: {
+ auto vec =
+ table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset());
+ auto element_base_type = fielddef.type()->element();
+ auto elemobjectdef =
+ element_base_type == reflection::Obj
+ ? schema.objects()->Get(fielddef.type()->index())
+ : nullptr;
+ switch (element_base_type) {
+ case reflection::String: {
+ std::vector<Offset<const String *>> elements(vec->size());
+ auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec);
+ for (uoffset_t i = 0; i < vec_s->size(); i++) {
+ elements[i] = use_string_pooling
+ ? fbb.CreateSharedString(vec_s->Get(i)).o
+ : fbb.CreateString(vec_s->Get(i)).o;
+ }
+ offset = fbb.CreateVector(elements).o;
+ break;
+ }
+ case reflection::Obj: {
+ if (!elemobjectdef->is_struct()) {
+ std::vector<Offset<const Table *>> elements(vec->size());
+ for (uoffset_t i = 0; i < vec->size(); i++) {
+ elements[i] =
+ CopyTable(fbb, schema, *elemobjectdef, *vec->Get(i));
+ }
+ offset = fbb.CreateVector(elements).o;
+ break;
+ }
+ }
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ default: { // Scalars and structs.
+ auto element_size = GetTypeSize(element_base_type);
+ if (elemobjectdef && elemobjectdef->is_struct())
+ element_size = elemobjectdef->bytesize();
+ fbb.StartVector(vec->size(), element_size);
+ fbb.PushBytes(vec->Data(), element_size * vec->size());
+ offset = fbb.EndVector(vec->size());
+ break;
+ }
+ }
+ break;
+ }
+ default: // Scalars.
+ break;
+ }
+ if (offset) { offsets.push_back(offset); }
+ }
+ // Now we can build the actual table from either offsets or scalar data.
+ auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign())
+ : fbb.StartTable();
+ size_t offset_idx = 0;
+ for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) {
+ auto &fielddef = **it;
+ if (!table.CheckField(fielddef.offset())) continue;
+ auto base_type = fielddef.type()->base_type();
+ switch (base_type) {
+ case reflection::Obj: {
+ auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index());
+ if (subobjectdef.is_struct()) {
+ CopyInline(fbb, fielddef, table, subobjectdef.minalign(),
+ subobjectdef.bytesize());
+ break;
+ }
+ }
+ FLATBUFFERS_FALLTHROUGH(); // fall thru
+ case reflection::Union:
+ case reflection::String:
+ case reflection::Vector:
+ fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++]));
+ break;
+ default: { // Scalars.
+ auto size = GetTypeSize(base_type);
+ CopyInline(fbb, fielddef, table, size, size);
+ break;
+ }
+ }
+ }
+ FLATBUFFERS_ASSERT(offset_idx == offsets.size());
+ if (objectdef.is_struct()) {
+ fbb.ClearOffsets();
+ return fbb.EndStruct();
+ } else {
+ return fbb.EndTable(start);
+ }
+}
+
+bool VerifyStruct(flatbuffers::Verifier &v,
+ const flatbuffers::Table &parent_table,
+ voffset_t field_offset, const reflection::Object &obj,
+ bool required) {
+ auto offset = parent_table.GetOptionalFieldOffset(field_offset);
+ if (required && !offset) { return false; }
+
+ return !offset ||
+ v.Verify(reinterpret_cast<const uint8_t *>(&parent_table), offset,
+ obj.bytesize());
+}
+
+bool VerifyVectorOfStructs(flatbuffers::Verifier &v,
+ const flatbuffers::Table &parent_table,
+ voffset_t field_offset,
+ const reflection::Object &obj, bool required) {
+ auto p = parent_table.GetPointer<const uint8_t *>(field_offset);
+ if (required && !p) { return false; }
+
+ return !p || v.VerifyVectorOrString(p, obj.bytesize());
+}
+
+// forward declare to resolve cyclic deps between VerifyObject and VerifyVector
+bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ const reflection::Object &obj,
+ const flatbuffers::Table *table, bool required);
+
+bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ const flatbuffers::Table &table,
+ const reflection::Field &vec_field) {
+ FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector);
+ if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false;
+
+ switch (vec_field.type()->element()) {
+ case reflection::None: FLATBUFFERS_ASSERT(false); break;
+ case reflection::UType:
+ return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field));
+ case reflection::Bool:
+ case reflection::Byte:
+ case reflection::UByte:
+ return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field));
+ case reflection::Short:
+ case reflection::UShort:
+ return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field));
+ case reflection::Int:
+ case reflection::UInt:
+ return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field));
+ case reflection::Long:
+ case reflection::ULong:
+ return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field));
+ case reflection::Float:
+ return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field));
+ case reflection::Double:
+ return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field));
+ case reflection::String: {
+ auto vec_string =
+ flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
+ table, vec_field);
+ if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ case reflection::Vector: FLATBUFFERS_ASSERT(false); break;
+ case reflection::Obj: {
+ auto obj = schema.objects()->Get(vec_field.type()->index());
+ if (obj->is_struct()) {
+ if (!VerifyVectorOfStructs(v, table, vec_field.offset(), *obj,
+ vec_field.required())) {
+ return false;
+ }
+ } else {
+ auto vec =
+ flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>(
+ table, vec_field);
+ if (!v.VerifyVector(vec)) return false;
+ if (vec) {
+ for (uoffset_t j = 0; j < vec->size(); j++) {
+ if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+ case reflection::Union: FLATBUFFERS_ASSERT(false); break;
+ default: FLATBUFFERS_ASSERT(false); break;
+ }
+
+ return false;
+}
+
+bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema,
+ const reflection::Object &obj,
+ const flatbuffers::Table *table, bool required) {
+ if (!table) {
+ if (!required)
+ return true;
+ else
+ return false;
+ }
+
+ if (!table->VerifyTableStart(v)) return false;
+
+ for (uoffset_t i = 0; i < obj.fields()->size(); i++) {
+ auto field_def = obj.fields()->Get(i);
+ switch (field_def->type()->base_type()) {
+ case reflection::None: FLATBUFFERS_ASSERT(false); break;
+ case reflection::UType:
+ if (!table->VerifyField<uint8_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Bool:
+ case reflection::Byte:
+ case reflection::UByte:
+ if (!table->VerifyField<int8_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Short:
+ case reflection::UShort:
+ if (!table->VerifyField<int16_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Int:
+ case reflection::UInt:
+ if (!table->VerifyField<int32_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Long:
+ case reflection::ULong:
+ if (!table->VerifyField<int64_t>(v, field_def->offset())) return false;
+ break;
+ case reflection::Float:
+ if (!table->VerifyField<float>(v, field_def->offset())) return false;
+ break;
+ case reflection::Double:
+ if (!table->VerifyField<double>(v, field_def->offset())) return false;
+ break;
+ case reflection::String:
+ if (!table->VerifyField<uoffset_t>(v, field_def->offset()) ||
+ !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) {
+ return false;
+ }
+ break;
+ case reflection::Vector:
+ if (!VerifyVector(v, schema, *table, *field_def)) return false;
+ break;
+ case reflection::Obj: {
+ auto child_obj = schema.objects()->Get(field_def->type()->index());
+ if (child_obj->is_struct()) {
+ if (!VerifyStruct(v, *table, field_def->offset(), *child_obj,
+ field_def->required())) {
+ return false;
+ }
+ } else {
+ if (!VerifyObject(v, schema, *child_obj,
+ flatbuffers::GetFieldT(*table, *field_def),
+ field_def->required())) {
+ return false;
+ }
+ }
+ break;
+ }
+ case reflection::Union: {
+ // get union type from the prev field
+ voffset_t utype_offset = field_def->offset() - sizeof(voffset_t);
+ auto utype = table->GetField<uint8_t>(utype_offset, 0);
+ if (utype != 0) {
+ // Means we have this union field present
+ auto fb_enum = schema.enums()->Get(field_def->type()->index());
+ auto child_obj = fb_enum->values()->Get(utype)->object();
+ if (!VerifyObject(v, schema, *child_obj,
+ flatbuffers::GetFieldT(*table, *field_def),
+ field_def->required())) {
+ return false;
+ }
+ }
+ break;
+ }
+ default: FLATBUFFERS_ASSERT(false); break;
+ }
+ }
+
+ if (!v.EndTable()) return false;
+
+ return true;
+}
+
+bool Verify(const reflection::Schema &schema, const reflection::Object &root,
+ const uint8_t *buf, size_t length) {
+ Verifier v(buf, length);
+ return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true);
+}
+
+} // namespace flatbuffers
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 0000000..5483cee
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// clang-format off
+// Dont't remove `format off`, it prevent reordering of win-includes.
+#ifdef _WIN32
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# ifndef NOMINMAX
+# define NOMINMAX
+# endif
+# ifdef _MSC_VER
+# include <crtdbg.h>
+# endif
+# include <windows.h> // Must be included before <direct.h>
+# include <direct.h>
+# include <winbase.h>
+# undef interface // This is also important because of reasons
+#else
+# include <limits.h>
+#endif
+// clang-format on
+
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+#include <sys/stat.h>
+#include <clocale>
+#include <fstream>
+
+namespace flatbuffers {
+
+bool FileExistsRaw(const char *name) {
+ std::ifstream ifs(name);
+ return ifs.good();
+}
+
+bool LoadFileRaw(const char *name, bool binary, std::string *buf) {
+ if (DirExists(name)) return false;
+ std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in);
+ if (!ifs.is_open()) return false;
+ if (binary) {
+ // The fastest way to read a file into a string.
+ ifs.seekg(0, std::ios::end);
+ auto size = ifs.tellg();
+ (*buf).resize(static_cast<size_t>(size));
+ ifs.seekg(0, std::ios::beg);
+ ifs.read(&(*buf)[0], (*buf).size());
+ } else {
+ // This is slower, but works correctly on all platforms for text files.
+ std::ostringstream oss;
+ oss << ifs.rdbuf();
+ *buf = oss.str();
+ }
+ return !ifs.bad();
+}
+
+static LoadFileFunction g_load_file_function = LoadFileRaw;
+static FileExistsFunction g_file_exists_function = FileExistsRaw;
+
+bool LoadFile(const char *name, bool binary, std::string *buf) {
+ FLATBUFFERS_ASSERT(g_load_file_function);
+ return g_load_file_function(name, binary, buf);
+}
+
+bool FileExists(const char *name) {
+ FLATBUFFERS_ASSERT(g_file_exists_function);
+ return g_file_exists_function(name);
+}
+
+bool DirExists(const char *name) {
+ // clang-format off
+
+ #ifdef _WIN32
+ #define flatbuffers_stat _stat
+ #define FLATBUFFERS_S_IFDIR _S_IFDIR
+ #else
+ #define flatbuffers_stat stat
+ #define FLATBUFFERS_S_IFDIR S_IFDIR
+ #endif
+ // clang-format on
+ struct flatbuffers_stat file_info;
+ if (flatbuffers_stat(name, &file_info) != 0) return false;
+ return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0;
+}
+
+LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) {
+ LoadFileFunction previous_function = g_load_file_function;
+ g_load_file_function = load_file_function ? load_file_function : LoadFileRaw;
+ return previous_function;
+}
+
+FileExistsFunction SetFileExistsFunction(
+ FileExistsFunction file_exists_function) {
+ FileExistsFunction previous_function = g_file_exists_function;
+ g_file_exists_function =
+ file_exists_function ? file_exists_function : FileExistsRaw;
+ return previous_function;
+}
+
+bool SaveFile(const char *name, const char *buf, size_t len, bool binary) {
+ std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out);
+ if (!ofs.is_open()) return false;
+ ofs.write(buf, len);
+ return !ofs.bad();
+}
+
+// We internally store paths in posix format ('/'). Paths supplied
+// by the user should go through PosixPath to ensure correct behavior
+// on Windows when paths are string-compared.
+
+static const char kPathSeparatorWindows = '\\';
+static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
+
+std::string StripExtension(const std::string &filepath) {
+ size_t i = filepath.find_last_of('.');
+ return i != std::string::npos ? filepath.substr(0, i) : filepath;
+}
+
+std::string GetExtension(const std::string &filepath) {
+ size_t i = filepath.find_last_of('.');
+ return i != std::string::npos ? filepath.substr(i + 1) : "";
+}
+
+std::string StripPath(const std::string &filepath) {
+ size_t i = filepath.find_last_of(PathSeparatorSet);
+ return i != std::string::npos ? filepath.substr(i + 1) : filepath;
+}
+
+std::string StripFileName(const std::string &filepath) {
+ size_t i = filepath.find_last_of(PathSeparatorSet);
+ return i != std::string::npos ? filepath.substr(0, i) : "";
+}
+
+std::string ConCatPathFileName(const std::string &path,
+ const std::string &filename) {
+ std::string filepath = path;
+ if (filepath.length()) {
+ char &filepath_last_character = string_back(filepath);
+ if (filepath_last_character == kPathSeparatorWindows) {
+ filepath_last_character = kPathSeparator;
+ } else if (filepath_last_character != kPathSeparator) {
+ filepath += kPathSeparator;
+ }
+ }
+ filepath += filename;
+ // Ignore './' at the start of filepath.
+ if (filepath[0] == '.' && filepath[1] == kPathSeparator) {
+ filepath.erase(0, 2);
+ }
+ return filepath;
+}
+
+std::string PosixPath(const char *path) {
+ std::string p = path;
+ std::replace(p.begin(), p.end(), '\\', '/');
+ return p;
+}
+
+void EnsureDirExists(const std::string &filepath) {
+ auto parent = StripFileName(filepath);
+ if (parent.length()) EnsureDirExists(parent);
+ // clang-format off
+
+ #ifdef _WIN32
+ (void)_mkdir(filepath.c_str());
+ #else
+ mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP);
+ #endif
+ // clang-format on
+}
+
+std::string AbsolutePath(const std::string &filepath) {
+ // clang-format off
+
+ #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+ return filepath;
+ #else
+ #ifdef _WIN32
+ char abs_path[MAX_PATH];
+ return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr)
+ #else
+ char abs_path[PATH_MAX];
+ return realpath(filepath.c_str(), abs_path)
+ #endif
+ ? abs_path
+ : filepath;
+ #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION
+ // clang-format on
+}
+
+// Locale-independent code.
+#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \
+ (FLATBUFFERS_LOCALE_INDEPENDENT > 0)
+
+// clang-format off
+// Allocate locale instance at startup of application.
+ClassicLocale ClassicLocale::instance_;
+
+#ifdef _MSC_VER
+ ClassicLocale::ClassicLocale()
+ : locale_(_create_locale(LC_ALL, "C")) {}
+ ClassicLocale::~ClassicLocale() { _free_locale(locale_); }
+#else
+ ClassicLocale::ClassicLocale()
+ : locale_(newlocale(LC_ALL, "C", nullptr)) {}
+ ClassicLocale::~ClassicLocale() { freelocale(locale_); }
+#endif
+// clang-format on
+
+#endif // !FLATBUFFERS_LOCALE_INDEPENDENT
+
+std::string RemoveStringQuotes(const std::string &s) {
+ auto ch = *s.c_str();
+ return ((s.size() >= 2) && (ch == '\"' || ch == '\'') &&
+ (ch == string_back(s)))
+ ? s.substr(1, s.length() - 2)
+ : s;
+}
+
+bool SetGlobalTestLocale(const char *locale_name, std::string *_value) {
+ const auto the_locale = setlocale(LC_ALL, locale_name);
+ if (!the_locale) return false;
+ if (_value) *_value = std::string(the_locale);
+ return true;
+}
+
+bool ReadEnvironmentVariable(const char *var_name, std::string *_value) {
+ #ifdef _MSC_VER
+ __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS
+ #endif
+ auto env_str = std::getenv(var_name);
+ if (!env_str) return false;
+ if (_value) *_value = std::string(env_str);
+ return true;
+}
+
+void SetupDefaultCRTReportMode() {
+ // clang-format off
+
+ #ifdef _MSC_VER
+ // By default, send all reports to STDOUT to prevent CI hangs.
+ // Enable assert report box [Abort|Retry|Ignore] if a debugger is present.
+ const int dbg_mode = (_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG) |
+ (IsDebuggerPresent() ? _CRTDBG_MODE_WNDW : 0);
+ (void)dbg_mode; // release mode fix
+ // CrtDebug reports to _CRT_WARN channel.
+ _CrtSetReportMode(_CRT_WARN, dbg_mode);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
+ // The assert from <assert.h> reports to _CRT_ERROR channel
+ _CrtSetReportMode(_CRT_ERROR, dbg_mode);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
+ // Internal CRT assert channel?
+ _CrtSetReportMode(_CRT_ASSERT, dbg_mode);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
+ #endif
+
+ // clang-format on
+}
+
+} // namespace flatbuffers
diff --git a/tests/DartTest.sh b/tests/DartTest.sh
new file mode 100755
index 0000000..6ce72cc
--- /dev/null
+++ b/tests/DartTest.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+
+command -v pub >/dev/null 2>&1 || { echo >&2 "Dart tests require `pub` but it's not installed. Aborting."; exit 1; }
+command -v dart >/dev/null 2>&1 || { echo >&2 "Dart tests require dart to be in path but it's not installed. Aborting."; exit 1; }
+# output required files to the dart folder so that pub will be able to
+# distribute them and more people can more easily run the dart tests
+../flatc --dart -I include_test -o ../dart/test monster_test.fbs
+cp monsterdata_test.mon ../dart/test
+
+cd ../dart
+
+# update packages
+pub get
+# Execute the sample.
+dart test/flat_buffers_test.dart
+
+# cleanup
+rm ../dart/test/monsterdata_test.mon
diff --git a/tests/FlatBuffers.Benchmarks/FlatBufferBuilderBenchmark.cs b/tests/FlatBuffers.Benchmarks/FlatBufferBuilderBenchmark.cs
new file mode 100644
index 0000000..1df5ac3
--- /dev/null
+++ b/tests/FlatBuffers.Benchmarks/FlatBufferBuilderBenchmark.cs
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using BenchmarkDotNet.Attributes;
+using MyGame.Example;
+
+namespace FlatBuffers.Benchmarks
+{
+ //[EtwProfiler] - needs elevated privileges
+ [MemoryDiagnoser]
+ public class FlatBufferBuilderBenchmark
+ {
+ private const int NumberOfRows = 10_000;
+
+ [Benchmark]
+ public void BuildNestedMonster()
+ {
+ const string nestedMonsterName = "NestedMonsterName";
+ const short nestedMonsterHp = 600;
+ const short nestedMonsterMana = 1024;
+
+ for (int i = 0; i < NumberOfRows; i++)
+ {
+ // Create nested buffer as a Monster type
+ var fbb1 = new FlatBufferBuilder(16);
+ var str1 = fbb1.CreateString(nestedMonsterName);
+ Monster.StartMonster(fbb1);
+ Monster.AddName(fbb1, str1);
+ Monster.AddHp(fbb1, nestedMonsterHp);
+ Monster.AddMana(fbb1, nestedMonsterMana);
+ var monster1 = Monster.EndMonster(fbb1);
+ Monster.FinishMonsterBuffer(fbb1, monster1);
+ var fbb1Bytes = fbb1.SizedByteArray();
+ fbb1 = null;
+
+ // Create a Monster which has the first buffer as a nested buffer
+ var fbb2 = new FlatBufferBuilder(16);
+ var str2 = fbb2.CreateString("My Monster");
+ var nestedBuffer = Monster.CreateTestnestedflatbufferVector(fbb2, fbb1Bytes);
+ Monster.StartMonster(fbb2);
+ Monster.AddName(fbb2, str2);
+ Monster.AddHp(fbb2, 50);
+ Monster.AddMana(fbb2, 32);
+ Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer);
+ var monster = Monster.EndMonster(fbb2);
+ Monster.FinishMonsterBuffer(fbb2, monster);
+ }
+ }
+
+ [Benchmark]
+ public void BuildMonster()
+ {
+ for (int i = 0; i < NumberOfRows; i++)
+ {
+ var builder = new FlatBufferBuilder(16);
+ var str1 = builder.CreateString("MonsterName");
+ Monster.StartMonster(builder);
+ Monster.AddName(builder, str1);
+ Monster.AddHp(builder, 600);
+ Monster.AddMana(builder, 1024);
+ Monster.AddColor(builder, Color.Blue);
+ Monster.AddTestbool(builder, true);
+ Monster.AddTestf(builder, 0.3f);
+ Monster.AddTestf2(builder, 0.2f);
+ Monster.AddTestf3(builder, 0.1f);
+
+ var monster1 = Monster.EndMonster(builder);
+ Monster.FinishMonsterBuffer(builder, monster1);
+ }
+ }
+
+ [Benchmark]
+ public void TestTables()
+ {
+ FlatBufferBuilder builder = new FlatBufferBuilder(1024 * 1024 * 32);
+ for (int x = 0; x < 500000; ++x)
+ {
+ var offset = builder.CreateString("T");
+ builder.StartObject(4);
+ builder.AddDouble(3.2);
+ builder.AddDouble(4.2);
+ builder.AddDouble(5.2);
+ builder.AddOffset(offset.Value);
+ builder.EndObject();
+ }
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Benchmarks/FlatBuffers.Benchmarks.csproj b/tests/FlatBuffers.Benchmarks/FlatBuffers.Benchmarks.csproj
new file mode 100644
index 0000000..b900384
--- /dev/null
+++ b/tests/FlatBuffers.Benchmarks/FlatBuffers.Benchmarks.csproj
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>netcoreapp2.1</TargetFramework>
+ <LangVersion>latest</LangVersion>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>$(DefineConstants);UNSAFE_BYTEBUFFER;BYTEBUFFER_NO_BOUNDS_CHECK;ENABLE_SPAN_T</DefineConstants>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="BenchmarkDotNet" Version="0.11.3" />
+ <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.11.3" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <Compile Include="..\..\net\FlatBuffers\*.cs" Link="FlatBuffers\%(FileName).cs" />
+ <Compile Include="..\MyGame\**\*.cs" Link="MyGame\Example\%(FileName).cs" />
+ </ItemGroup>
+
+</Project>
diff --git a/tests/FlatBuffers.Benchmarks/Program.cs b/tests/FlatBuffers.Benchmarks/Program.cs
new file mode 100644
index 0000000..9e63b4b
--- /dev/null
+++ b/tests/FlatBuffers.Benchmarks/Program.cs
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using BenchmarkDotNet.Running;
+
+namespace FlatBuffers.Benchmarks
+{
+ public static class Program
+ {
+ public static void Main(string[] args)
+ {
+ BenchmarkSwitcher
+ .FromAssembly(typeof(Program).Assembly)
+ .Run(args);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlatBuffers.Test/Assert.cs b/tests/FlatBuffers.Test/Assert.cs
new file mode 100644
index 0000000..488c338
--- /dev/null
+++ b/tests/FlatBuffers.Test/Assert.cs
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace FlatBuffers.Test
+{
+
+ public class AssertFailedException : Exception
+ {
+ private readonly object _expected;
+ private readonly object _actual;
+
+ public AssertFailedException(object expected, object actual)
+ {
+ _expected = expected;
+ _actual = actual;
+ }
+
+ public override string Message
+ {
+ get { return string.Format("Expected {0} but saw {1}", _expected, _actual); }
+ }
+ }
+
+ public class AssertArrayFailedException : Exception
+ {
+ private readonly int _index;
+ private readonly object _expected;
+ private readonly object _actual;
+
+ public AssertArrayFailedException(int index, object expected, object actual)
+ {
+ _index = index;
+ _expected = expected;
+ _actual = actual;
+ }
+
+ public override string Message
+ {
+ get { return string.Format("Expected {0} at index {1} but saw {2}", _expected, _index, _actual); }
+ }
+ }
+
+ public class AssertUnexpectedThrowException : Exception
+ {
+ private readonly object _expected;
+
+ public AssertUnexpectedThrowException(object expected)
+ {
+ _expected = expected;
+ }
+
+ public override string Message
+ {
+ get { return string.Format("Expected exception of type {0}", _expected); }
+ }
+ }
+
+ public static class Assert
+ {
+ public static void AreEqual<T>(T expected, T actual)
+ {
+ if (!expected.Equals(actual))
+ {
+ throw new AssertFailedException(expected, actual);
+ }
+ }
+
+ public static void ArrayEqual<T>(T[] expected, T[] actual)
+ {
+ if (expected.Length != actual.Length)
+ {
+ throw new AssertFailedException(expected, actual);
+ }
+
+ for(var i = 0; i < expected.Length; ++i)
+ {
+ if (!expected[i].Equals(actual[i]))
+ {
+ throw new AssertArrayFailedException(i, expected, actual);
+ }
+ }
+ }
+
+ public static void IsTrue(bool value)
+ {
+ if (!value)
+ {
+ throw new AssertFailedException(true, value);
+ }
+ }
+
+ public static void IsFalse(bool value)
+ {
+ if (value)
+ {
+ throw new AssertFailedException(false, value);
+ }
+ }
+
+ public static void Throws<T>(Action action) where T : Exception
+ {
+ var caught = false;
+ try
+ {
+ action();
+ }
+ catch (T)
+ {
+ caught = true;
+ }
+
+ if (!caught)
+ {
+ throw new AssertUnexpectedThrowException(typeof (T));
+ }
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/ByteBufferTests.cs b/tests/FlatBuffers.Test/ByteBufferTests.cs
new file mode 100644
index 0000000..1c33a2f
--- /dev/null
+++ b/tests/FlatBuffers.Test/ByteBufferTests.cs
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace FlatBuffers.Test
+{
+ [FlatBuffersTestClass]
+ public class ByteBufferTests
+ {
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Length_MatchesBufferLength()
+ {
+ var buffer = new byte[1000];
+ var uut = new ByteBuffer(buffer);
+ Assert.AreEqual(buffer.Length, uut.Length);
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutBytePopulatesBufferAtZeroOffset()
+ {
+ var buffer = new byte[1];
+ var uut = new ByteBuffer(buffer);
+ uut.PutByte(0, (byte)99);
+
+ Assert.AreEqual((byte)99, buffer[0]);
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutByteCannotPutAtOffsetPastLength()
+ {
+ var uut = new ByteBuffer(1);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutByte(1, 99));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutShortPopulatesBufferCorrectly()
+ {
+ var buffer = new byte[2];
+ var uut = new ByteBuffer(buffer);
+ uut.PutShort(0, (short)1);
+
+ // Ensure Endianness was written correctly
+ Assert.AreEqual((byte)1, buffer[0]);
+ Assert.AreEqual((byte)0, buffer[1]);
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutShortCannotPutAtOffsetPastLength()
+ {
+ var uut = new ByteBuffer(2);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(2, 99));
+ }
+#endif
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutShortChecksLength()
+ {
+ var uut = new ByteBuffer(1);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(0, 99));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutShortChecksLengthAndOffset()
+ {
+ var uut = new ByteBuffer(2);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutShort(1, 99));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutIntPopulatesBufferCorrectly()
+ {
+ var buffer = new byte[4];
+ var uut = new ByteBuffer(buffer);
+ uut.PutInt(0, 0x0A0B0C0D);
+
+ // Ensure Endianness was written correctly
+ Assert.AreEqual(0x0D, buffer[0]);
+ Assert.AreEqual(0x0C, buffer[1]);
+ Assert.AreEqual(0x0B, buffer[2]);
+ Assert.AreEqual(0x0A, buffer[3]);
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutIntCannotPutAtOffsetPastLength()
+ {
+ var uut = new ByteBuffer(4);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutIntChecksLength()
+ {
+ var uut = new ByteBuffer(1);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(0, 0x0A0B0C0D));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutIntChecksLengthAndOffset()
+ {
+ var uut = new ByteBuffer(4);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutInt(2, 0x0A0B0C0D));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutLongPopulatesBufferCorrectly()
+ {
+ var buffer = new byte[8];
+ var uut = new ByteBuffer(buffer);
+ uut.PutLong(0, 0x010203040A0B0C0D);
+
+ // Ensure Endianness was written correctly
+ Assert.AreEqual(0x0D, buffer[0]);
+ Assert.AreEqual(0x0C, buffer[1]);
+ Assert.AreEqual(0x0B, buffer[2]);
+ Assert.AreEqual(0x0A, buffer[3]);
+ Assert.AreEqual(0x04, buffer[4]);
+ Assert.AreEqual(0x03, buffer[5]);
+ Assert.AreEqual(0x02, buffer[6]);
+ Assert.AreEqual(0x01, buffer[7]);
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutLongCannotPutAtOffsetPastLength()
+ {
+ var uut = new ByteBuffer(8);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutLongChecksLength()
+ {
+ var uut = new ByteBuffer(1);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(0, 0x010203040A0B0C0D));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_PutLongChecksLengthAndOffset()
+ {
+ var uut = new ByteBuffer(8);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.PutLong(2, 0x010203040A0B0C0D));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetByteReturnsCorrectData()
+ {
+ var buffer = new byte[1];
+ buffer[0] = 99;
+ var uut = new ByteBuffer(buffer);
+ Assert.AreEqual((byte)99, uut.Get(0));
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetByteChecksOffset()
+ {
+ var uut = new ByteBuffer(1);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.Get(1));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetShortReturnsCorrectData()
+ {
+ var buffer = new byte[2];
+ buffer[0] = 1;
+ buffer[1] = 0;
+ var uut = new ByteBuffer(buffer);
+ Assert.AreEqual(1, uut.GetShort(0));
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetShortChecksOffset()
+ {
+ var uut = new ByteBuffer(2);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(2));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetShortChecksLength()
+ {
+ var uut = new ByteBuffer(2);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetShort(1));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetIntReturnsCorrectData()
+ {
+ var buffer = new byte[4];
+ buffer[0] = 0x0D;
+ buffer[1] = 0x0C;
+ buffer[2] = 0x0B;
+ buffer[3] = 0x0A;
+ var uut = new ByteBuffer(buffer);
+ Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0));
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetIntChecksOffset()
+ {
+ var uut = new ByteBuffer(4);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(4));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetIntChecksLength()
+ {
+ var uut = new ByteBuffer(2);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetInt(0));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetLongReturnsCorrectData()
+ {
+ var buffer = new byte[8];
+ buffer[0] = 0x0D;
+ buffer[1] = 0x0C;
+ buffer[2] = 0x0B;
+ buffer[3] = 0x0A;
+ buffer[4] = 0x04;
+ buffer[5] = 0x03;
+ buffer[6] = 0x02;
+ buffer[7] = 0x01;
+ var uut = new ByteBuffer(buffer);
+ Assert.AreEqual(0x010203040A0B0C0D, uut.GetLong(0));
+ }
+
+#if !BYTEBUFFER_NO_BOUNDS_CHECK
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetLongChecksOffset()
+ {
+ var uut = new ByteBuffer(8);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(8));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_GetLongChecksLength()
+ {
+ var uut = new ByteBuffer(7);
+ Assert.Throws<ArgumentOutOfRangeException>(() => uut.GetLong(0));
+ }
+#endif
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_ReverseBytesUshort()
+ {
+ const ushort original = (ushort)0x1234U;
+ var reverse = ByteBuffer.ReverseBytes(original);
+ Assert.AreEqual(0x3412U, reverse);
+
+ var rereverse = ByteBuffer.ReverseBytes(reverse);
+ Assert.AreEqual(original, rereverse);
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_ReverseBytesUint()
+ {
+ const uint original = 0x12345678;
+ var reverse = ByteBuffer.ReverseBytes(original);
+ Assert.AreEqual(0x78563412U, reverse);
+
+ var rereverse = ByteBuffer.ReverseBytes(reverse);
+ Assert.AreEqual(original, rereverse);
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_ReverseBytesUlong()
+ {
+ const ulong original = 0x1234567890ABCDEFUL;
+ var reverse = ByteBuffer.ReverseBytes(original);
+ Assert.AreEqual(0xEFCDAB9078563412UL, reverse);
+
+ var rereverse = ByteBuffer.ReverseBytes(reverse);
+ Assert.AreEqual(original, rereverse);
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_ToFullArray_MatchesBuffer()
+ {
+ var buffer = new byte[4];
+ buffer[0] = 0x0D;
+ buffer[1] = 0x0C;
+ buffer[2] = 0x0B;
+ buffer[3] = 0x0A;
+ var uut = new ByteBuffer(buffer);
+ Assert.ArrayEqual(buffer, uut.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_ToSizedArray_MatchesBuffer()
+ {
+ var buffer = new byte[4];
+ buffer[0] = 0x0D;
+ buffer[1] = 0x0C;
+ buffer[2] = 0x0B;
+ buffer[3] = 0x0A;
+ var uut = new ByteBuffer(buffer);
+ Assert.ArrayEqual(buffer, uut.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Duplicate_MatchesBuffer()
+ {
+ var buffer = new byte[4];
+ buffer[0] = 0x0D;
+ buffer[1] = 0x0C;
+ buffer[2] = 0x0B;
+ buffer[3] = 0x0A;
+ var uut = new ByteBuffer(buffer);
+ Assert.AreEqual(0x0A0B0C0D, uut.GetInt(0));
+
+ // Advance by two bytes
+ uut.Position = 2; uut = uut.Duplicate();
+ Assert.AreEqual(0x0A0B, uut.GetShort(2));
+
+ // Advance by one more byte
+ uut.Position = 1; uut = uut.Duplicate();
+ Assert.AreEqual(0x0A, uut.Get(3));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_To_Array_Float()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var fData = new float[len];
+ fData[0] = 1.0079F;
+ fData[1] = 4.0026F;
+ fData[2] = 6.941F;
+ fData[3] = 9.0122F;
+ fData[4] = 10.811F;
+ fData[5] = 12.0107F;
+ fData[6] = 14.0067F;
+ fData[7] = 15.9994F;
+ fData[8] = 18.9984F;
+
+ // Tranfer it to a byte array
+ var buffer = new byte[sizeof(float) * fData.Length];
+ Buffer.BlockCopy(fData, 0, buffer, 0, buffer.Length);
+
+ // Create the Byte Buffer from byte array
+ var uut = new ByteBuffer(buffer);
+
+ // Get the full array back out and ensure they are equivalent
+ var bbArray = uut.ToArray<float>(0, len);
+ Assert.ArrayEqual(fData, bbArray);
+
+ // Get a portion of the full array back out and ensure the
+ // subrange agrees
+ var bbArray2 = uut.ToArray<float>(4, len - 1);
+ Assert.AreEqual(bbArray2.Length, len - 1);
+ for (int i = 1; i < len - 1; i++)
+ {
+ Assert.AreEqual(fData[i], bbArray2[i - 1]);
+ }
+
+ // Get a sub portion of the full array back out and ensure the
+ // subrange agrees
+ var bbArray3 = uut.ToArray<float>(8, len - 4);
+ Assert.AreEqual(bbArray3.Length, len - 4);
+ for (int i = 2; i < len - 4; i++)
+ {
+ Assert.AreEqual(fData[i], bbArray3[i - 2]);
+ }
+ }
+
+ public void ByteBuffer_Put_Array_Helper<T>(T[] data, int typeSize)
+ where T : struct
+ {
+ // Create the Byte Buffer
+ var uut = new ByteBuffer(1024);
+
+ // Put the data into the buffer and make sure the offset is
+ // calculated correctly
+ int nOffset = uut.Put(1024, data);
+ Assert.AreEqual(1024 - typeSize * data.Length, nOffset);
+
+ // Get the full array back out and ensure they are equivalent
+ var bbArray = uut.ToArray<T>(nOffset, data.Length);
+ Assert.ArrayEqual(data, bbArray);
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Float()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new float[len];
+ data[0] = 1.0079F;
+ data[1] = 4.0026F;
+ data[2] = 6.941F;
+ data[3] = 9.0122F;
+ data[4] = 10.811F;
+ data[5] = 12.0107F;
+ data[6] = 14.0067F;
+ data[7] = 15.9994F;
+ data[8] = 18.9984F;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(float));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Double()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new double[len];
+ data[0] = 1.0079;
+ data[1] = 4.0026;
+ data[2] = 6.941;
+ data[3] = 9.0122;
+ data[4] = 10.811;
+ data[5] = 12.0107;
+ data[6] = 14.0067;
+ data[7] = 15.9994;
+ data[8] = 18.9984;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(double));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Int()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new int[len];
+ data[0] = 1;
+ data[1] = 4;
+ data[2] = 6;
+ data[3] = 9;
+ data[4] = 10;
+ data[5] = 12;
+ data[6] = 14;
+ data[7] = 15;
+ data[8] = 18;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(int));
+ }
+
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_UInt()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new uint[len];
+ data[0] = 1;
+ data[1] = 4;
+ data[2] = 6;
+ data[3] = 9;
+ data[4] = 10;
+ data[5] = 12;
+ data[6] = 14;
+ data[7] = 15;
+ data[8] = 18;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(uint));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Bool()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new bool[len];
+ data[0] = true;
+ data[1] = true;
+ data[2] = false;
+ data[3] = true;
+ data[4] = false;
+ data[5] = true;
+ data[6] = true;
+ data[7] = true;
+ data[8] = false;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(bool));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Long()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new long[len];
+ data[0] = 1;
+ data[1] = 4;
+ data[2] = 6;
+ data[3] = 9;
+ data[4] = 10;
+ data[5] = 12;
+ data[6] = 14;
+ data[7] = 15;
+ data[8] = 18;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(long));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Byte()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new byte[len];
+ data[0] = 1;
+ data[1] = 4;
+ data[2] = 6;
+ data[3] = 9;
+ data[4] = 10;
+ data[5] = 12;
+ data[6] = 14;
+ data[7] = 15;
+ data[8] = 18;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(byte));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_SByte()
+ {
+ const int len = 9;
+
+ // Construct the data array
+ var data = new sbyte[len];
+ data[0] = 1;
+ data[1] = 4;
+ data[2] = 6;
+ data[3] = 9;
+ data[4] = 10;
+ data[5] = 12;
+ data[6] = 14;
+ data[7] = 15;
+ data[8] = 18;
+
+ ByteBuffer_Put_Array_Helper(data, sizeof(sbyte));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Null_Throws()
+ {
+ // Create the Byte Buffer
+ var uut = new ByteBuffer(1024);
+
+ // create a null array and try to put it into the buffer
+ float[] data = null;
+ Assert.Throws<ArgumentNullException>(() => uut.Put(1024, data));
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_Empty_Throws()
+ {
+ // Create the Byte Buffer
+ var uut = new ByteBuffer(1024);
+
+ // create an array of length == 0, and try to put it into the buffer
+ float[] data = new float[0];
+ Assert.Throws<ArgumentException>(() => uut.Put(1024, data));
+ }
+
+ private struct dummyStruct
+ {
+ int a;
+ float b;
+ }
+
+ [FlatBuffersTestMethod]
+ public void ByteBuffer_Put_Array_IncorrectType_Throws()
+ {
+ // Create the Byte Buffer
+ var uut = new ByteBuffer(1024);
+
+ // Create an array of dummy structures that shouldn't be
+ // able to be put into the buffer
+ var data = new dummyStruct[10];
+ Assert.Throws<ArgumentException>(() => uut.Put(1024, data));
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs b/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs
new file mode 100644
index 0000000..d2f49f7
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBufferBuilderTests.cs
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace FlatBuffers.Test
+{
+ [FlatBuffersTestClass]
+ public class FlatBufferBuilderTests
+ {
+ private FlatBufferBuilder CreateBuffer(bool forceDefaults = true)
+ {
+ var fbb = new FlatBufferBuilder(16) {ForceDefaults = forceDefaults};
+ fbb.StartTable(1);
+ return fbb;
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddBool_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddBool(0, false, false);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(bool), endOffset-storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddSByte_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddSbyte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(sbyte), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddByte_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddByte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(byte), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddShort_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddShort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(short), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddUShort_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddUshort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(ushort), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddInt_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddInt(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(int), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddUInt_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddUint(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(uint), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddLong_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddLong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(long), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddULong_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddUlong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(ulong), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddFloat_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddFloat(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(float), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WithForceDefaults_WhenAddDouble_AndDefaultValue_OffsetIncreasesBySize()
+ {
+ var fbb = CreateBuffer();
+ var storedOffset = fbb.Offset;
+ fbb.AddDouble(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(sizeof(double), endOffset - storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddBool_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddBool(0, false, false);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddSByte_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddSbyte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddByte_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddByte(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddShort_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddShort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddUShort_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddUshort(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddInt_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddInt(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddUInt_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddUint(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddLong_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddLong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddULong_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddUlong(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddFloat_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddFloat(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_WhenAddDouble_AndDefaultValue_OffsetIsUnchanged()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+ fbb.AddDouble(0, 0, 0);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_Add_Array_Float()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+
+ const int len = 9;
+
+ // Construct the data array
+ var data = new float[len];
+ data[0] = 1.0079F;
+ data[1] = 4.0026F;
+ data[2] = 6.941F;
+ data[3] = 9.0122F;
+ data[4] = 10.811F;
+ data[5] = 12.0107F;
+ data[6] = 14.0067F;
+ data[7] = 15.9994F;
+ data[8] = 18.9984F;
+
+ fbb.Add(data);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset + sizeof(float) * data.Length);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_Add_Array_Bool()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+
+ const int len = 9;
+
+ // Construct the data array
+ var data = new bool[len];
+ data[0] = true;
+ data[1] = true;
+ data[2] = false;
+ data[3] = true;
+ data[4] = false;
+ data[5] = true;
+ data[6] = true;
+ data[7] = true;
+ data[8] = false;
+
+ fbb.Add(data);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset + sizeof(bool) * data.Length);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_Add_Array_Double()
+ {
+ var fbb = CreateBuffer(false);
+ var storedOffset = fbb.Offset;
+
+ const int len = 9;
+
+ // Construct the data array
+ var data = new double[len];
+ data[0] = 1.0079;
+ data[1] = 4.0026;
+ data[2] = 6.941;
+ data[3] = 9.0122;
+ data[4] = 10.811;
+ data[5] = 12.0107;
+ data[6] = 14.0067;
+ data[7] = 15.9994;
+ data[8] = 18.9984;
+
+ fbb.Add(data);
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset + sizeof(double) * data.Length);
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_Add_Array_Null_Throws()
+ {
+ var fbb = CreateBuffer(false);
+
+ // Construct the data array
+ float[] data = null;
+
+ Assert.Throws<ArgumentNullException>(() => fbb.Add(data));
+ }
+
+ [FlatBuffersTestMethod]
+ public void FlatBufferBuilder_Add_Array_Empty_Noop()
+ {
+ var fbb = CreateBuffer(false);
+
+ var storedOffset = fbb.Offset;
+
+ // Construct an empty data array
+ float[] data = new float[0];
+ fbb.Add(data);
+
+ // Make sure the offset didn't change since nothing
+ // was really added
+ var endOffset = fbb.Offset;
+ Assert.AreEqual(endOffset, storedOffset);
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
new file mode 100644
index 0000000..d698d20
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{9DB0B5E7-757E-4BD1-A5F6-279390331254}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>FlatBuffers.Test</RootNamespace>
+ <AssemblyName>FlatBuffers.Test</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <StartupObject />
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(UnsafeByteBuffer)' == 'true'">
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <DefineConstants>$(DefineConstants);UNSAFE_BYTEBUFFER</DefineConstants>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\..\net\FlatBuffers\ByteBuffer.cs">
+ <Link>FlatBuffers\ByteBuffer.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\ByteBufferUtil.cs">
+ <Link>FlatBuffers\ByteBufferUtil.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\IFlatbufferObject.cs">
+ <Link>FlatBuffers\IFlatbufferObject.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\Offset.cs">
+ <Link>FlatBuffers\Offset.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\FlatBufferBuilder.cs">
+ <Link>FlatBuffers\FlatBufferBuilder.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\FlatBufferConstants.cs">
+ <Link>FlatBuffers\FlatBufferConstants.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\Struct.cs">
+ <Link>FlatBuffers\Struct.cs</Link>
+ </Compile>
+ <Compile Include="..\..\net\FlatBuffers\Table.cs">
+ <Link>FlatBuffers\Table.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Any.cs">
+ <Link>MyGame\Example\Any.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\AnyAmbiguousAliases.cs">
+ <Link>MyGame\Example\AnyAmbiguousAliases.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\AnyUniqueAliases.cs">
+ <Link>MyGame\Example\AnyUniqueAliases.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Color.cs">
+ <Link>MyGame\Example\Color.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Monster.cs">
+ <Link>MyGame\Example\Monster.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Referrable.cs">
+ <Link>MyGame\Example\Referrable.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Stat.cs">
+ <Link>MyGame\Example\Stat.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Test.cs">
+ <Link>MyGame\Example\Test.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\TestSimpleTableWithEnum.cs">
+ <Link>MyGame\Example\TestSimpleTableWithEnum.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Vec3.cs">
+ <Link>MyGame\Example\Vec3.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\Ability.cs">
+ <Link>MyGame\Example\Ability.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\ArrayTable.cs">
+ <Link>MyGame\Example\ArrayTable.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\ArrayStruct.cs">
+ <Link>MyGame\Example\ArrayStruct.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\NestedStruct.cs">
+ <Link>MyGame\Example\NestedStruct.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\Example\TestEnum.cs">
+ <Link>MyGame\Example\TestEnum.cs</Link>
+ </Compile>
+ <Compile Include="..\MyGame\InParentNamespace.cs">
+ <Link>MyGame\InParentNamespace.cs</Link>
+ </Compile>
+ <Compile Include="..\namespace_test\NamespaceA\NamespaceB\EnumInNestedNS.cs">
+ <Link>NamespaceA\NamespaceB\EnumInNestedNS.cs</Link>
+ </Compile>
+ <Compile Include="..\namespace_test\NamespaceA\NamespaceB\StructInNestedNS.cs">
+ <Link>NamespaceA\NamespaceB\StructInNestedNS.cs</Link>
+ </Compile>
+ <Compile Include="..\namespace_test\NamespaceA\NamespaceB\TableInNestedNS.cs">
+ <Link>NamespaceA\NamespaceB\TableInNestedNS.cs</Link>
+ </Compile>
+ <Compile Include="..\namespace_test\NamespaceA\TableInFirstNS.cs">
+ <Link>NamespaceA\TableInFirstNS.cs</Link>
+ </Compile>
+ <Compile Include="Assert.cs" />
+ <Compile Include="ByteBufferTests.cs" />
+ <Compile Include="FlatBufferBuilderTests.cs" />
+ <Compile Include="FlatBuffersFuzzTests.cs" />
+ <Compile Include="FlatBuffersTestClassAttribute.cs" />
+ <Compile Include="FlatBuffersTestMethodAttribute.cs" />
+ <Compile Include="FuzzTestData.cs" />
+ <Compile Include="Lcg.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="FlatBuffersExampleTests.cs" />
+ <Compile Include="TestTable.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="..\monsterdata_test.mon">
+ <Link>Resources\monsterdata_test.mon</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
new file mode 100644
index 0000000..b09119c
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.IO;
+using System.Text;
+using MyGame.Example;
+
+namespace FlatBuffers.Test
+{
+ [FlatBuffersTestClass]
+ public class FlatBuffersExampleTests
+ {
+ public void RunTests()
+ {
+ CanCreateNewFlatBufferFromScratch();
+ CanReadCppGeneratedWireFile();
+ TestEnums();
+ }
+
+ [FlatBuffersTestMethod]
+ public void CanCreateNewFlatBufferFromScratch()
+ {
+ CanCreateNewFlatBufferFromScratch(true);
+ CanCreateNewFlatBufferFromScratch(false);
+ }
+
+ private void CanCreateNewFlatBufferFromScratch(bool sizePrefix)
+ {
+ // Second, let's create a FlatBuffer from scratch in C#, and test it also.
+ // We use an initial size of 1 to exercise the reallocation algorithm,
+ // normally a size larger than the typical FlatBuffer you generate would be
+ // better for performance.
+ var fbb = new FlatBufferBuilder(1);
+
+ StringOffset[] names = { fbb.CreateString("Frodo"), fbb.CreateString("Barney"), fbb.CreateString("Wilma") };
+ Offset<Monster>[] off = new Offset<Monster>[3];
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, names[0]);
+ off[0] = Monster.EndMonster(fbb);
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, names[1]);
+ off[1] = Monster.EndMonster(fbb);
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, names[2]);
+ off[2] = Monster.EndMonster(fbb);
+ var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off);
+
+ // We set up the same values as monsterdata.json:
+
+ var str = fbb.CreateString("MyMonster");
+ var test1 = fbb.CreateString("test1");
+ var test2 = fbb.CreateString("test2");
+
+
+ Monster.StartInventoryVector(fbb, 5);
+ for (int i = 4; i >= 0; i--)
+ {
+ fbb.AddByte((byte)i);
+ }
+ var inv = fbb.EndVector();
+
+ var fred = fbb.CreateString("Fred");
+ Monster.StartMonster(fbb);
+ Monster.AddName(fbb, fred);
+ var mon2 = Monster.EndMonster(fbb);
+
+ Monster.StartTest4Vector(fbb, 2);
+ MyGame.Example.Test.CreateTest(fbb, (short)10, (sbyte)20);
+ MyGame.Example.Test.CreateTest(fbb, (short)30, (sbyte)40);
+ var test4 = fbb.EndVector();
+
+ Monster.StartTestarrayofstringVector(fbb, 2);
+ fbb.AddOffset(test2.Value);
+ fbb.AddOffset(test1.Value);
+ var testArrayOfString = fbb.EndVector();
+
+ Monster.StartMonster(fbb);
+ Monster.AddPos(fbb, Vec3.CreateVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
+ Color.Green, (short)5, (sbyte)6));
+ Monster.AddHp(fbb, (short)80);
+ Monster.AddName(fbb, str);
+ Monster.AddInventory(fbb, inv);
+ Monster.AddTestType(fbb, Any.Monster);
+ Monster.AddTest(fbb, mon2.Value);
+ Monster.AddTest4(fbb, test4);
+ Monster.AddTestarrayofstring(fbb, testArrayOfString);
+ Monster.AddTestbool(fbb, true);
+ Monster.AddTestarrayoftables(fbb, sortMons);
+ var mon = Monster.EndMonster(fbb);
+
+ if (sizePrefix)
+ {
+ Monster.FinishSizePrefixedMonsterBuffer(fbb, mon);
+ }
+ else
+ {
+ Monster.FinishMonsterBuffer(fbb, mon);
+ }
+
+ // Dump to output directory so we can inspect later, if needed
+#if ENABLE_SPAN_T
+ var data = fbb.DataBuffer.ToSizedArray();
+ string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon";
+ File.WriteAllBytes(filename, data);
+#else
+ using (var ms = fbb.DataBuffer.ToMemoryStream(fbb.DataBuffer.Position, fbb.Offset))
+ {
+ var data = ms.ToArray();
+ string filename = @"Resources/monsterdata_cstest" + (sizePrefix ? "_sp" : "") + ".mon";
+ File.WriteAllBytes(filename, data);
+ }
+#endif
+
+ // Remove the size prefix if necessary for further testing
+ ByteBuffer dataBuffer = fbb.DataBuffer;
+ if (sizePrefix)
+ {
+ Assert.AreEqual(ByteBufferUtil.GetSizePrefix(dataBuffer) + FlatBufferConstants.SizePrefixLength,
+ dataBuffer.Length - dataBuffer.Position);
+ dataBuffer = ByteBufferUtil.RemoveSizePrefix(dataBuffer);
+ }
+
+ // Now assert the buffer
+ TestBuffer(dataBuffer);
+
+ //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
+ // revert to original values after testing
+ Monster monster = Monster.GetRootAsMonster(dataBuffer);
+
+
+ // mana is optional and does not exist in the buffer so the mutation should fail
+ // the mana field should retain its default value
+ Assert.AreEqual(monster.MutateMana((short)10), false);
+ Assert.AreEqual(monster.Mana, (short)150);
+
+ // Accessing a vector of sorted by the key tables
+ Assert.AreEqual(monster.Testarrayoftables(0).Value.Name, "Barney");
+ Assert.AreEqual(monster.Testarrayoftables(1).Value.Name, "Frodo");
+ Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
+
+ // Example of searching for a table by the key
+ Assert.IsTrue(monster.TestarrayoftablesByKey("Frodo") != null);
+ Assert.IsTrue(monster.TestarrayoftablesByKey("Barney") != null);
+ Assert.IsTrue(monster.TestarrayoftablesByKey("Wilma") != null);
+
+ // testType is an existing field and mutating it should succeed
+ Assert.AreEqual(monster.TestType, Any.Monster);
+ Assert.AreEqual(monster.MutateTestType(Any.NONE), true);
+ Assert.AreEqual(monster.TestType, Any.NONE);
+ Assert.AreEqual(monster.MutateTestType(Any.Monster), true);
+ Assert.AreEqual(monster.TestType, Any.Monster);
+
+ //mutate the inventory vector
+ Assert.AreEqual(monster.MutateInventory(0, 1), true);
+ Assert.AreEqual(monster.MutateInventory(1, 2), true);
+ Assert.AreEqual(monster.MutateInventory(2, 3), true);
+ Assert.AreEqual(monster.MutateInventory(3, 4), true);
+ Assert.AreEqual(monster.MutateInventory(4, 5), true);
+
+ for (int i = 0; i < monster.InventoryLength; i++)
+ {
+ Assert.AreEqual(monster.Inventory(i), i + 1);
+ }
+
+ //reverse mutation
+ Assert.AreEqual(monster.MutateInventory(0, 0), true);
+ Assert.AreEqual(monster.MutateInventory(1, 1), true);
+ Assert.AreEqual(monster.MutateInventory(2, 2), true);
+ Assert.AreEqual(monster.MutateInventory(3, 3), true);
+ Assert.AreEqual(monster.MutateInventory(4, 4), true);
+
+ // get a struct field and edit one of its fields
+ Vec3 pos = (Vec3)monster.Pos;
+ Assert.AreEqual(pos.X, 1.0f);
+ pos.MutateX(55.0f);
+ Assert.AreEqual(pos.X, 55.0f);
+ pos.MutateX(1.0f);
+ Assert.AreEqual(pos.X, 1.0f);
+
+ TestBuffer(dataBuffer);
+ }
+
+ private void TestBuffer(ByteBuffer bb)
+ {
+ Monster monster = Monster.GetRootAsMonster(bb);
+
+ Assert.AreEqual(80, monster.Hp);
+ Assert.AreEqual(150, monster.Mana);
+ Assert.AreEqual("MyMonster", monster.Name);
+
+ var pos = monster.Pos.Value;
+ Assert.AreEqual(1.0f, pos.X);
+ Assert.AreEqual(2.0f, pos.Y);
+ Assert.AreEqual(3.0f, pos.Z);
+
+ Assert.AreEqual(3.0f, pos.Test1);
+ Assert.AreEqual(Color.Green, pos.Test2);
+ var t = (MyGame.Example.Test)pos.Test3;
+ Assert.AreEqual((short)5, t.A);
+ Assert.AreEqual((sbyte)6, t.B);
+
+ Assert.AreEqual(Any.Monster, monster.TestType);
+
+ var monster2 = monster.Test<Monster>().Value;
+ Assert.AreEqual("Fred", monster2.Name);
+
+
+ Assert.AreEqual(5, monster.InventoryLength);
+ var invsum = 0;
+ for (var i = 0; i < monster.InventoryLength; i++)
+ {
+ invsum += monster.Inventory(i);
+ }
+ Assert.AreEqual(10, invsum);
+
+ // Get the inventory as an array and subtract the
+ // sum to get it back to 0
+ var inventoryArray = monster.GetInventoryArray();
+ Assert.AreEqual(5, inventoryArray.Length);
+ foreach(var inv in inventoryArray)
+ {
+ invsum -= inv;
+ }
+ Assert.AreEqual(0, invsum);
+
+ var test0 = monster.Test4(0).Value;
+ var test1 = monster.Test4(1).Value;
+ Assert.AreEqual(2, monster.Test4Length);
+
+ Assert.AreEqual(100, test0.A + test0.B + test1.A + test1.B);
+
+ Assert.AreEqual(2, monster.TestarrayofstringLength);
+ Assert.AreEqual("test1", monster.Testarrayofstring(0));
+ Assert.AreEqual("test2", monster.Testarrayofstring(1));
+
+ Assert.AreEqual(true, monster.Testbool);
+
+#if ENABLE_SPAN_T
+ var nameBytes = monster.GetNameBytes();
+ Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.ToArray(), 0, nameBytes.Length));
+
+ if (0 == monster.TestarrayofboolsLength)
+ {
+ Assert.IsFalse(monster.GetTestarrayofboolsBytes().Length != 0);
+ }
+ else
+ {
+ Assert.IsTrue(monster.GetTestarrayofboolsBytes().Length != 0);
+ }
+#else
+ var nameBytes = monster.GetNameBytes().Value;
+ Assert.AreEqual("MyMonster", Encoding.UTF8.GetString(nameBytes.Array, nameBytes.Offset, nameBytes.Count));
+
+ if (0 == monster.TestarrayofboolsLength)
+ {
+ Assert.IsFalse(monster.GetTestarrayofboolsBytes().HasValue);
+ }
+ else
+ {
+ Assert.IsTrue(monster.GetTestarrayofboolsBytes().HasValue);
+ }
+#endif
+ }
+
+ [FlatBuffersTestMethod]
+ public void CanReadCppGeneratedWireFile()
+ {
+ var data = File.ReadAllBytes(@"Resources/monsterdata_test.mon");
+ var bb = new ByteBuffer(data);
+ TestBuffer(bb);
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestEnums()
+ {
+ Assert.AreEqual("Red", Color.Red.ToString());
+ Assert.AreEqual("Blue", Color.Blue.ToString());
+ Assert.AreEqual("NONE", Any.NONE.ToString());
+ Assert.AreEqual("Monster", Any.Monster.ToString());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestNestedFlatBuffer()
+ {
+ const string nestedMonsterName = "NestedMonsterName";
+ const short nestedMonsterHp = 600;
+ const short nestedMonsterMana = 1024;
+ // Create nested buffer as a Monster type
+ var fbb1 = new FlatBufferBuilder(16);
+ var str1 = fbb1.CreateString(nestedMonsterName);
+ Monster.StartMonster(fbb1);
+ Monster.AddName(fbb1, str1);
+ Monster.AddHp(fbb1, nestedMonsterHp);
+ Monster.AddMana(fbb1, nestedMonsterMana);
+ var monster1 = Monster.EndMonster(fbb1);
+ Monster.FinishMonsterBuffer(fbb1, monster1);
+ var fbb1Bytes = fbb1.SizedByteArray();
+ fbb1 = null;
+
+ // Create a Monster which has the first buffer as a nested buffer
+ var fbb2 = new FlatBufferBuilder(16);
+ var str2 = fbb2.CreateString("My Monster");
+ var nestedBuffer = Monster.CreateTestnestedflatbufferVector(fbb2, fbb1Bytes);
+ Monster.StartMonster(fbb2);
+ Monster.AddName(fbb2, str2);
+ Monster.AddHp(fbb2, 50);
+ Monster.AddMana(fbb2, 32);
+ Monster.AddTestnestedflatbuffer(fbb2, nestedBuffer);
+ var monster = Monster.EndMonster(fbb2);
+ Monster.FinishMonsterBuffer(fbb2, monster);
+
+ // Now test the data extracted from the nested buffer
+ var mons = Monster.GetRootAsMonster(fbb2.DataBuffer);
+ var nestedMonster = mons.GetTestnestedflatbufferAsMonster().Value;
+
+ Assert.AreEqual(nestedMonsterMana, nestedMonster.Mana);
+ Assert.AreEqual(nestedMonsterHp, nestedMonster.Hp);
+ Assert.AreEqual(nestedMonsterName, nestedMonster.Name);
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestFixedLenghtArrays()
+ {
+ FlatBufferBuilder builder = new FlatBufferBuilder(100);
+
+ float a;
+ int[] b = new int[15];
+ sbyte c;
+ int[,] d_a = new int[2, 2];
+ TestEnum[] d_b = new TestEnum[2];
+ TestEnum[,] d_c = new TestEnum[2, 2];
+
+ a = 0.5f;
+ for (int i = 0; i < 15; i++) b[i] = i;
+ c = 1;
+ d_a[0, 0] = 1;
+ d_a[0, 1] = 2;
+ d_a[1, 0] = 3;
+ d_a[1, 1] = 4;
+ d_b[0] = TestEnum.B;
+ d_b[1] = TestEnum.C;
+ d_c[0, 0] = TestEnum.A;
+ d_c[0, 1] = TestEnum.B;
+ d_c[1, 0] = TestEnum.C;
+ d_c[1, 1] = TestEnum.B;
+
+ Offset<ArrayStruct> arrayOffset = ArrayStruct.CreateArrayStruct(
+ builder, a, b, c, d_a, d_b, d_c);
+
+ // Create a table with the ArrayStruct.
+ ArrayTable.StartArrayTable(builder);
+ ArrayTable.AddA(builder, arrayOffset);
+ Offset<ArrayTable> tableOffset = ArrayTable.EndArrayTable(builder);
+
+ ArrayTable.FinishArrayTableBuffer(builder, tableOffset);
+
+ ArrayTable table = ArrayTable.GetRootAsArrayTable(builder.DataBuffer);
+
+ Assert.AreEqual(table.A?.A, 0.5f);
+ for (int i = 0; i < 15; i++) Assert.AreEqual(table.A?.B(i), i);
+ Assert.AreEqual(table.A?.C, (sbyte)1);
+ Assert.AreEqual(table.A?.D(0).A(0), 1);
+ Assert.AreEqual(table.A?.D(0).A(1), 2);
+ Assert.AreEqual(table.A?.D(1).A(0), 3);
+ Assert.AreEqual(table.A?.D(1).A(1), 4);
+ Assert.AreEqual(table.A?.D(0).B, TestEnum.B);
+ Assert.AreEqual(table.A?.D(1).B, TestEnum.C);
+ Assert.AreEqual(table.A?.D(0).C(0), TestEnum.A);
+ Assert.AreEqual(table.A?.D(0).C(1), TestEnum.B);
+ Assert.AreEqual(table.A?.D(1).C(0), TestEnum.C);
+ Assert.AreEqual(table.A?.D(1).C(1), TestEnum.B);
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs b/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
new file mode 100644
index 0000000..b6c60ea
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
@@ -0,0 +1,811 @@
+/*
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace FlatBuffers.Test
+{
+ [FlatBuffersTestClass]
+ public class FlatBuffersFuzzTests
+ {
+ private readonly Lcg _lcg = new Lcg();
+
+ [FlatBuffersTestMethod]
+ public void TestObjects()
+ {
+ CheckObjects(11, 100);
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestNumbers()
+ {
+ var builder = new FlatBufferBuilder(1);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddBool(true);
+ Assert.ArrayEqual(new byte[] { 1 }, builder.DataBuffer.ToFullArray());
+ builder.AddSbyte(-127);
+ Assert.ArrayEqual(new byte[] { 129, 1 }, builder.DataBuffer.ToFullArray());
+ builder.AddByte(255);
+ Assert.ArrayEqual(new byte[] { 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // First pad
+ builder.AddShort(-32222);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // Second pad
+ builder.AddUshort(0xFEEE);
+ Assert.ArrayEqual(new byte[] { 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // no pad
+ builder.AddInt(-53687092);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // third pad
+ builder.AddUint(0x98765432);
+ Assert.ArrayEqual(new byte[] { 0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1 }, builder.DataBuffer.ToFullArray()); // no pad
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestNumbers64()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.AddUlong(0x1122334455667788);
+ Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.ToFullArray());
+
+ builder = new FlatBufferBuilder(1);
+ builder.AddLong(0x1122334455667788);
+ Assert.ArrayEqual(new byte[] { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVector_1xUInt8()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(byte), 1, 1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddByte(1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.EndVector();
+ Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVector_2xUint8()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(byte), 2, 1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddByte(1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddByte(2);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.EndVector();
+ Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 2, 1, 0, 0 }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVector_1xUInt16()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(ushort), 1, 1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddUshort(1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.EndVector();
+ Assert.ArrayEqual(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVector_2xUInt16()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(ushort), 2, 1);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddUshort(0xABCD);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0, 0, 0xCD, 0xAB }, builder.DataBuffer.ToFullArray());
+ builder.AddUshort(0xDCBA);
+ Assert.ArrayEqual(new byte[] { 0, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.ToFullArray());
+ builder.EndVector();
+ Assert.ArrayEqual(new byte[] { 2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestCreateAsciiString()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.CreateString("foo");
+ Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.ToFullArray());
+
+ builder.CreateString("moop");
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // Padding to 32 bytes
+ 4, 0, 0, 0,
+ (byte)'m', (byte)'o', (byte)'o', (byte)'p',
+ 0, 0, 0, 0, // zero terminator with 3 byte pad
+ 3, 0, 0, 0,
+ (byte)'f', (byte)'o', (byte)'o', 0
+ }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestCreateSharedAsciiString()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.CreateSharedString("foo");
+ Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.ToFullArray());
+
+ builder.CreateSharedString("foo");
+ Assert.ArrayEqual(new byte[] { 3, 0, 0, 0, (byte)'f', (byte)'o', (byte)'o', 0 }, builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestCreateArbitarytring()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.CreateString("\x01\x02\x03");
+ Assert.ArrayEqual(new byte[]
+ {
+ 3, 0, 0, 0,
+ 0x01, 0x02, 0x03, 0
+ }, builder.DataBuffer.ToFullArray()); // No padding
+ builder.CreateString("\x04\x05\x06\x07");
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // Padding to 32 bytes
+ 4, 0, 0, 0,
+ 0x04, 0x05, 0x06, 0x07,
+ 0, 0, 0, 0, // zero terminator with 3 byte pad
+ 3, 0, 0, 0,
+ 0x01, 0x02, 0x03, 0
+ }, builder.DataBuffer.ToFullArray()); // No padding
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestEmptyVTable()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(0);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 4, 0, 4, 0,
+ 4, 0, 0, 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithOneBool()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(1);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddBool(0, true, false);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, // padding to 16 bytes
+ 6, 0, // vtable bytes
+ 8, 0, // object length inc vtable offset
+ 7, 0, // start of bool value
+ 6, 0, 0, 0, // int32 offset for start of vtable
+ 0, 0, 0, // padding
+ 1, // value 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithOneBool_DefaultValue()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(1);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddBool(0, false, false);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ // No padding.
+ 4, 0, // vtable bytes
+ 4, 0, // end of object from here
+ // entry 0 is not stored (trimmed end of vtable)
+ 4, 0, 0, 0, // int32 offset for start of vtable
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithOneInt16()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(1);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddShort(0, 0x789A, 0);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, // padding to 16 bytes
+ 6, 0, // vtable bytes
+ 8, 0, // object length inc vtable offset
+ 6, 0, // start of int16 value
+ 6, 0, 0, 0, // int32 offset for start of vtable
+ 0, 0, // padding
+ 0x9A, 0x78, //value 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithTwoInt16()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(2);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddShort(0, 0x3456, 0);
+ builder.AddShort(1, 0x789A, 0);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 8, 0, // vtable bytes
+ 8, 0, // object length inc vtable offset
+ 6, 0, // start of int16 value 0
+ 4, 0, // start of int16 value 1
+ 8, 0, 0, 0, // int32 offset for start of vtable
+ 0x9A, 0x78, // value 1
+ 0x56, 0x34, // value 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithInt16AndBool()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(2);
+ Assert.ArrayEqual(new byte[] { 0 }, builder.DataBuffer.ToFullArray());
+ builder.AddShort(0, 0x3456, 0);
+ builder.AddBool(1, true, false);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 8, 0, // vtable bytes
+ 8, 0, // object length inc vtable offset
+ 6, 0, // start of int16 value 0
+ 5, 0, // start of bool value 1
+ 8, 0, 0, 0, // int32 offset for start of vtable
+ 0, 1, // padding + value 1
+ 0x56, 0x34, // value 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithEmptyVector()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(byte), 0, 1);
+ var vecEnd = builder.EndVector();
+
+ builder.StartTable(1);
+
+ builder.AddOffset(0, vecEnd.Value, 0);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, // Padding to 32 bytes
+ 6, 0, // vtable bytes
+ 8, 0, // object length inc vtable offset
+ 4, 0, // start of vector offset value 0
+ 6, 0, 0, 0, // int32 offset for start of vtable
+ 4, 0, 0, 0,
+ 0, 0, 0, 0,
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithEmptyVectorAndScalars()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(byte), 0, 1);
+ var vecEnd = builder.EndVector();
+
+ builder.StartTable(2);
+ builder.AddShort(0, 55, 0);
+ builder.AddOffset(1, vecEnd.Value, 0);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // Padding to 32 bytes
+ 8, 0, // vtable bytes
+ 12, 0, // object length inc vtable offset
+ 10, 0, // offset to int16 value 0
+ 4, 0, // start of vector offset value 1
+ 8, 0, 0, 0, // int32 offset for start of vtable
+ 8, 0, 0, 0, // value 1
+ 0, 0, 55, 0, // value 0
+ 0, 0, 0, 0, // length of vector (not in sctruc)
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWith_1xInt16_and_Vector_or_2xInt16()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(short), 2, 1);
+ builder.AddShort(0x1234);
+ builder.AddShort(0x5678);
+ var vecEnd = builder.EndVector();
+
+ builder.StartTable(2);
+ builder.AddOffset(1, vecEnd.Value, 0);
+ builder.AddShort(0, 55, 0);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0, // Padding to 32 bytes
+ 8, 0, // vtable bytes
+ 12, 0, // object length
+ 6, 0, // start of value 0 from end of vtable
+ 8, 0, // start of value 1 from end of buffer
+ 8, 0, 0, 0, // int32 offset for start of vtable
+ 0, 0, 55, 0, // padding + value 0
+ 4, 0, 0, 0, // position of vector from here
+ 2, 0, 0, 0, // length of vector
+ 0x78, 0x56, // vector value 0
+ 0x34, 0x12, // vector value 1
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithAStruct_of_int8_int16_int32()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(1);
+ builder.Prep(4+4+4, 0);
+ builder.AddSbyte(55);
+ builder.Pad(3);
+ builder.AddShort(0x1234);
+ builder.Pad(2);
+ builder.AddInt(0x12345678);
+ var structStart = builder.Offset;
+ builder.AddStruct(0, structStart, 0);
+ builder.EndTable();
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, // Padding to 32 bytes
+ 6, 0, // vtable bytes
+ 16, 0, // object length
+ 4, 0, // start of struct from here
+ 6, 0, 0, 0, // int32 offset for start of vtable
+ 0x78, 0x56, 0x34, 0x12, // struct value 2
+ 0x00, 0x00, 0x34, 0x12, // struct value 1
+ 0x00, 0x00, 0x00, 55, // struct value 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithAVectorOf_2xStructOf_2xInt8()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartVector(sizeof(byte)*2, 2, 1);
+ builder.AddByte(33);
+ builder.AddByte(44);
+ builder.AddByte(55);
+ builder.AddByte(66);
+ var vecEnd = builder.EndVector();
+
+ builder.StartTable(1);
+ builder.AddOffset(0, vecEnd.Value, 0);
+ builder.EndTable();
+
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, // Padding to 32 bytes
+ 6, 0, // vtable bytes
+ 8, 0, // object length
+ 4, 0, // offset of vector offset
+ 6, 0, 0, 0, // int32 offset for start of vtable
+ 4, 0, 0, 0, // Vector start offset
+ 2, 0, 0, 0, // Vector len
+ 66, // vector 1, 1
+ 55, // vector 1, 0
+ 44, // vector 0, 1
+ 33, // vector 0, 0
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestVTableWithSomeElements()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(2);
+ builder.AddByte(0, 33, 0);
+ builder.AddShort(1, 66, 0);
+ var off = builder.EndTable();
+ builder.Finish(off);
+
+ byte[] padded = new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, //Padding to 32 bytes
+ 12, 0, 0, 0, // root of table, pointing to vtable offset
+ 8, 0, // vtable bytes
+ 8, 0, // object length
+ 7, 0, // start of value 0
+ 4, 0, // start of value 1
+ 8, 0, 0, 0, // int32 offset for start of vtable
+ 66, 0, // value 1
+ 0, 33, // value 0
+
+ };
+ Assert.ArrayEqual(padded, builder.DataBuffer.ToFullArray());
+
+ // no padding in sized array
+ byte[] unpadded = new byte[padded.Length - 12];
+ Buffer.BlockCopy(padded, 12, unpadded, 0, unpadded.Length);
+ Assert.ArrayEqual(unpadded, builder.DataBuffer.ToSizedArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestTwoFinishTable()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(2);
+ builder.AddByte(0, 33, 0);
+ builder.AddByte(1, 44, 0);
+ var off0 = builder.EndTable();
+ builder.Finish(off0);
+
+ builder.StartTable(3);
+ builder.AddByte(0, 55, 0);
+ builder.AddByte(1, 66, 0);
+ builder.AddByte(2, 77, 0);
+ var off1 = builder.EndTable();
+ builder.Finish(off1);
+
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // padding to 64 bytes
+ 16, 0, 0, 0, // root of table, pointing to vtable offset (obj1)
+ 0, 0, // padding
+
+ 10, 0, // vtable bytes
+ 8, 0, // object length
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 5, 0, // start of value 2
+ 10, 0, 0, 0, // int32 offset for start of vtable
+ 0, // pad
+ 77, // values 2, 1, 0
+ 66,
+ 55,
+
+ 12, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
+ 8, 0, // vtable bytes
+ 8, 0, // object length
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 8, 0, 0, 0, // int32 offset for start of vtable
+ 0, 0, // pad
+ 44, // value 1, 0
+ 33,
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestBunchOfBools()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(8);
+ for (var i = 0; i < 8; i++)
+ {
+ builder.AddBool(i, true, false);
+ }
+ var off = builder.EndTable();
+ builder.Finish(off);
+
+ byte[] padded = new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // padding to 64 bytes
+
+ 24, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
+ 20, 0, // vtable bytes
+ 12, 0, // object length
+ 11, 0, // start of value 0
+ 10, 0, // start of value 1
+ 9, 0, // start of value 2
+ 8, 0, // start of value 3
+ 7, 0, // start of value 4
+ 6, 0, // start of value 5
+ 5, 0, // start of value 6
+ 4, 0, // start of value 7
+
+ 20, 0, 0, 0, // int32 offset for start of vtable
+
+ 1, 1, 1, 1, // values
+ 1, 1, 1, 1,
+
+ };
+ Assert.ArrayEqual(padded, builder.DataBuffer.ToFullArray());
+
+ // no padding in sized array
+ byte[] unpadded = new byte[padded.Length - 28];
+ Buffer.BlockCopy(padded, 28, unpadded, 0, unpadded.Length);
+ Assert.ArrayEqual(unpadded, builder.DataBuffer.ToSizedArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestBunchOfBoolsSizePrefixed()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(8);
+ for (var i = 0; i < 8; i++)
+ {
+ builder.AddBool(i, true, false);
+ }
+ var off = builder.EndTable();
+ builder.FinishSizePrefixed(off);
+
+ byte[] padded = new byte[]
+ {
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, // padding to 64 bytes
+
+ 36, 0, 0, 0, // size prefix
+ 24, 0, 0, 0, // root of table, pointing to vtable offset (obj0)
+ 20, 0, // vtable bytes
+ 12, 0, // object length
+ 11, 0, // start of value 0
+ 10, 0, // start of value 1
+ 9, 0, // start of value 2
+ 8, 0, // start of value 3
+ 7, 0, // start of value 4
+ 6, 0, // start of value 5
+ 5, 0, // start of value 6
+ 4, 0, // start of value 7
+
+ 20, 0, 0, 0, // int32 offset for start of vtable
+
+ 1, 1, 1, 1, // values
+ 1, 1, 1, 1,
+
+ };
+ Assert.ArrayEqual(padded, builder.DataBuffer.ToFullArray());
+
+ // no padding in sized array
+ byte[] unpadded = new byte[padded.Length - 24];
+ Buffer.BlockCopy(padded, 24, unpadded, 0, unpadded.Length);
+ Assert.ArrayEqual(unpadded, builder.DataBuffer.ToSizedArray());
+ }
+
+ [FlatBuffersTestMethod]
+ public void TestWithFloat()
+ {
+ var builder = new FlatBufferBuilder(1);
+ builder.StartTable(1);
+ builder.AddFloat(0, 1, 0);
+ builder.EndTable();
+
+
+ Assert.ArrayEqual(new byte[]
+ {
+ 0, 0,
+ 6, 0, // vtable bytes
+ 8, 0, // object length
+ 4, 0, // start of value 0
+ 6, 0, 0, 0, // int32 offset for start of vtable
+ 0, 0, 128, 63, // value
+
+ },
+ builder.DataBuffer.ToFullArray());
+ }
+
+ private void CheckObjects(int fieldCount, int objectCount)
+ {
+ _lcg.Reset();
+
+ const int testValuesMax = 11;
+
+ var builder = new FlatBufferBuilder(1);
+
+ var objects = new int[objectCount];
+
+ for (var i = 0; i < objectCount; ++i)
+ {
+ builder.StartTable(fieldCount);
+
+ for (var j = 0; j < fieldCount; ++j)
+ {
+ var fieldType = _lcg.Next()%testValuesMax;
+
+ switch (fieldType)
+ {
+ case 0:
+ {
+ builder.AddBool(j, FuzzTestData.BoolValue, false);
+ break;
+ }
+ case 1:
+ {
+ builder.AddSbyte(j, FuzzTestData.Int8Value, 0);
+ break;
+ }
+ case 2:
+ {
+ builder.AddByte(j, FuzzTestData.UInt8Value, 0);
+ break;
+ }
+ case 3:
+ {
+ builder.AddShort(j, FuzzTestData.Int16Value, 0);
+ break;
+ }
+ case 4:
+ {
+ builder.AddUshort(j, FuzzTestData.UInt16Value, 0);
+ break;
+ }
+ case 5:
+ {
+ builder.AddInt(j, FuzzTestData.Int32Value, 0);
+ break;
+ }
+ case 6:
+ {
+ builder.AddUint(j, FuzzTestData.UInt32Value, 0);
+ break;
+ }
+ case 7:
+ {
+ builder.AddLong(j, FuzzTestData.Int64Value, 0);
+ break;
+ }
+ case 8:
+ {
+ builder.AddUlong(j, FuzzTestData.UInt64Value, 0);
+ break;
+ }
+ case 9:
+ {
+ builder.AddFloat(j, FuzzTestData.Float32Value, 0);
+ break;
+ }
+ case 10:
+ {
+ builder.AddDouble(j, FuzzTestData.Float64Value, 0);
+ break;
+ }
+ default:
+ throw new Exception("Unreachable");
+ }
+
+ }
+
+ var offset = builder.EndTable();
+
+ // Store the object offset
+ objects[i] = offset;
+ }
+
+ _lcg.Reset();
+
+ // Test all objects are readable and return expected values...
+ for (var i = 0; i < objectCount; ++i)
+ {
+ var table = new TestTable(builder.DataBuffer, builder.DataBuffer.Length - objects[i]);
+
+ for (var j = 0; j < fieldCount; ++j)
+ {
+ var fieldType = _lcg.Next() % testValuesMax;
+ var fc = 2 + j; // 2 == VtableMetadataFields
+ var f = fc * 2;
+
+ switch (fieldType)
+ {
+ case 0:
+ {
+ Assert.AreEqual(FuzzTestData.BoolValue, table.GetSlot(f, false));
+ break;
+ }
+ case 1:
+ {
+ Assert.AreEqual(FuzzTestData.Int8Value, table.GetSlot(f, (sbyte)0));
+ break;
+ }
+ case 2:
+ {
+ Assert.AreEqual(FuzzTestData.UInt8Value, table.GetSlot(f, (byte)0));
+ break;
+ }
+ case 3:
+ {
+ Assert.AreEqual(FuzzTestData.Int16Value, table.GetSlot(f, (short)0));
+ break;
+ }
+ case 4:
+ {
+ Assert.AreEqual(FuzzTestData.UInt16Value, table.GetSlot(f, (ushort)0));
+ break;
+ }
+ case 5:
+ {
+ Assert.AreEqual(FuzzTestData.Int32Value, table.GetSlot(f, (int)0));
+ break;
+ }
+ case 6:
+ {
+ Assert.AreEqual(FuzzTestData.UInt32Value, table.GetSlot(f, (uint)0));
+ break;
+ }
+ case 7:
+ {
+ Assert.AreEqual(FuzzTestData.Int64Value, table.GetSlot(f, (long)0));
+ break;
+ }
+ case 8:
+ {
+ Assert.AreEqual(FuzzTestData.UInt64Value, table.GetSlot(f, (ulong)0));
+ break;
+ }
+ case 9:
+ {
+ Assert.AreEqual(FuzzTestData.Float32Value, table.GetSlot(f, (float)0));
+ break;
+ }
+ case 10:
+ {
+ Assert.AreEqual(FuzzTestData.Float64Value, table.GetSlot(f, (double)0));
+ break;
+ }
+ default:
+ throw new Exception("Unreachable");
+ }
+
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/FlatBuffersTestClassAttribute.cs b/tests/FlatBuffers.Test/FlatBuffersTestClassAttribute.cs
new file mode 100644
index 0000000..f31e38b
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBuffersTestClassAttribute.cs
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace FlatBuffers.Test
+{
+ [AttributeUsage(AttributeTargets.Class)]
+ public class FlatBuffersTestClassAttribute : Attribute
+ {
+ }
+}
diff --git a/tests/FlatBuffers.Test/FlatBuffersTestMethodAttribute.cs b/tests/FlatBuffers.Test/FlatBuffersTestMethodAttribute.cs
new file mode 100644
index 0000000..989dae5
--- /dev/null
+++ b/tests/FlatBuffers.Test/FlatBuffersTestMethodAttribute.cs
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ using System;
+
+namespace FlatBuffers.Test
+{
+ [AttributeUsage(AttributeTargets.Method)]
+ public class FlatBuffersTestMethodAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/tests/FlatBuffers.Test/FuzzTestData.cs b/tests/FlatBuffers.Test/FuzzTestData.cs
new file mode 100644
index 0000000..119e44e
--- /dev/null
+++ b/tests/FlatBuffers.Test/FuzzTestData.cs
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+
+namespace FlatBuffers.Test
+{
+ internal static class FuzzTestData
+ {
+ private static readonly byte[] _overflowInt32 = new byte[] {0x83, 0x33, 0x33, 0x33};
+ private static readonly byte[] _overflowInt64 = new byte[] { 0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 };
+
+ public static readonly bool BoolValue = true;
+ public static readonly sbyte Int8Value = -127; // 0x81
+ public static readonly byte UInt8Value = 255; // 0xFF
+ public static readonly short Int16Value = -32222; // 0x8222;
+ public static readonly ushort UInt16Value = 65262; // 0xFEEE
+ public static readonly int Int32Value = BitConverter.ToInt32(_overflowInt32, 0);
+ public static readonly uint UInt32Value = 0xFDDDDDDD;
+ public static readonly long Int64Value = BitConverter.ToInt64(_overflowInt64, 0);
+ public static readonly ulong UInt64Value = 0xFCCCCCCCCCCCCCCC;
+ public static readonly float Float32Value = 3.14159f;
+ public static readonly double Float64Value = 3.14159265359;
+ }
+}
\ No newline at end of file
diff --git a/tests/FlatBuffers.Test/Lcg.cs b/tests/FlatBuffers.Test/Lcg.cs
new file mode 100644
index 0000000..c329ed8
--- /dev/null
+++ b/tests/FlatBuffers.Test/Lcg.cs
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers.Test
+{
+ /// <summary>
+ /// Lcg Pseudo RNG
+ /// </summary>
+ internal sealed class Lcg
+ {
+ private const uint InitialValue = 10000;
+ private uint _state;
+
+ public Lcg()
+ {
+ _state = InitialValue;
+ }
+
+ public uint Next()
+ {
+ return (_state = 69069 * _state + 362437);
+ }
+
+ public void Reset()
+ {
+ _state = InitialValue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlatBuffers.Test/NetTest.sh b/tests/FlatBuffers.Test/NetTest.sh
new file mode 100644
index 0000000..3822b49
--- /dev/null
+++ b/tests/FlatBuffers.Test/NetTest.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# Testing C# on Linux using Mono.
+
+mcs -debug -out:./fbnettest.exe \
+ ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs ../MyGame/*.cs ../union_vector/*.cs \
+ FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs
+mono --debug ./fbnettest.exe
+rm fbnettest.exe
+rm Resources/monsterdata_cstest.mon
+rm Resources/monsterdata_cstest_sp.mon
+
+# Repeat with unsafe versions
+
+mcs -debug -out:./fbnettest.exe \
+ -unsafe -d:UNSAFE_BYTEBUFFER \
+ ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs ../MyGame/*.cs ../union_vector/*.cs\
+ FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs
+mono --debug ./fbnettest.exe
+rm fbnettest.exe
+rm Resources/monsterdata_cstest.mon
+rm Resources/monsterdata_cstest_sp.mon
+
diff --git a/tests/FlatBuffers.Test/Program.cs b/tests/FlatBuffers.Test/Program.cs
new file mode 100644
index 0000000..f8cec4e
--- /dev/null
+++ b/tests/FlatBuffers.Test/Program.cs
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace FlatBuffers.Test
+{
+ static class Program
+ {
+ public static int Main(string[] args)
+ {
+ var testResults = new List<bool>();
+
+ var testClasses = Assembly.GetExecutingAssembly().GetExportedTypes()
+ .Where(t => t.IsClass && t.GetCustomAttributes(typeof (FlatBuffersTestClassAttribute), false).Length > 0);
+
+ foreach (var testClass in testClasses)
+ {
+ var methods = testClass.GetMethods(BindingFlags.Public |
+ BindingFlags.Instance)
+ .Where(m => m.GetCustomAttributes(typeof(FlatBuffersTestMethodAttribute), false).Length > 0);
+
+ var inst = Activator.CreateInstance(testClass);
+
+ foreach (var method in methods)
+ {
+ try
+ {
+ method.Invoke(inst, new object[] { });
+ testResults.Add(true);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("{0}: FAILED when invoking {1} with error {2}",
+ testClass.Name ,method.Name, ex.GetBaseException());
+ testResults.Add(false);
+ }
+ }
+ }
+
+ var failedCount = testResults.Count(i => i == false);
+
+ Console.WriteLine("{0} tests run, {1} failed", testResults.Count, failedCount);
+
+ if (failedCount > 0)
+ {
+ return -1;
+ }
+ return 0;
+ }
+ }
+}
diff --git a/tests/FlatBuffers.Test/Properties/AssemblyInfo.cs b/tests/FlatBuffers.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2e33f08
--- /dev/null
+++ b/tests/FlatBuffers.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FlatBuffers.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FlatBuffers.Test")]
+[assembly: AssemblyCopyright("Copyright (c) 2014 Google Inc")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a1d58a51-3e74-4ae9-aac7-5a399c9eed1a")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/tests/FlatBuffers.Test/Resources/monsterdata_test.mon b/tests/FlatBuffers.Test/Resources/monsterdata_test.mon
new file mode 100644
index 0000000..3f83972
--- /dev/null
+++ b/tests/FlatBuffers.Test/Resources/monsterdata_test.mon
Binary files differ
diff --git a/tests/FlatBuffers.Test/TestTable.cs b/tests/FlatBuffers.Test/TestTable.cs
new file mode 100644
index 0000000..4f663f0
--- /dev/null
+++ b/tests/FlatBuffers.Test/TestTable.cs
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2016 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace FlatBuffers.Test
+{
+ /// <summary>
+ /// A test Table object that gives easy access to the slot data
+ /// </summary>
+ internal struct TestTable
+ {
+ Table t;
+
+ public TestTable(ByteBuffer bb, int pos)
+ {
+ t = new Table(pos, bb);
+ }
+
+ public bool GetSlot(int slot, bool def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetSbyte(t.bb_pos + off) != 0;
+ }
+
+ public sbyte GetSlot(int slot, sbyte def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetSbyte(t.bb_pos + off);
+ }
+
+ public byte GetSlot(int slot, byte def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.Get(t.bb_pos + off);
+ }
+
+ public short GetSlot(int slot, short def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetShort(t.bb_pos + off);
+ }
+
+ public ushort GetSlot(int slot, ushort def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetUshort(t.bb_pos + off);
+ }
+
+ public int GetSlot(int slot, int def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetInt(t.bb_pos + off);
+ }
+
+ public uint GetSlot(int slot, uint def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetUint(t.bb_pos + off);
+ }
+
+ public long GetSlot(int slot, long def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetLong(t.bb_pos + off);
+ }
+
+ public ulong GetSlot(int slot, ulong def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetUlong(t.bb_pos + off);
+ }
+
+ public float GetSlot(int slot, float def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetFloat(t.bb_pos + off);
+ }
+
+ public double GetSlot(int slot, double def)
+ {
+ var off = t.__offset(slot);
+
+ if (off == 0)
+ {
+ return def;
+ }
+ return t.bb.GetDouble(t.bb_pos + off);
+ }
+ }
+}
diff --git a/tests/GoTest.sh b/tests/GoTest.sh
new file mode 100755
index 0000000..e69f0d8
--- /dev/null
+++ b/tests/GoTest.sh
@@ -0,0 +1,75 @@
+#!/bin/bash -eu
+#
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+test_dir="$(pwd)"
+go_path=${test_dir}/go_gen
+go_src=${go_path}/src
+
+# Emit Go code for the example schema in the test dir:
+../flatc -g -I include_test monster_test.fbs
+
+# Go requires a particular layout of files in order to link multiple packages.
+# Copy flatbuffer Go files to their own package directories to compile the
+# test binary:
+mkdir -p ${go_src}/MyGame/Example
+mkdir -p ${go_src}/MyGame/Example2
+mkdir -p ${go_src}/github.com/google/flatbuffers/go
+mkdir -p ${go_src}/flatbuffers_test
+
+cp -a MyGame/*.go ./go_gen/src/MyGame/
+cp -a MyGame/Example/*.go ./go_gen/src/MyGame/Example/
+cp -a MyGame/Example2/*.go ./go_gen/src/MyGame/Example2/
+# do not compile the gRPC generated files, which are not tested by go_test.go
+# below, but have their own test.
+rm ./go_gen/src/MyGame/Example/*_grpc.go
+cp -a ../go/* ./go_gen/src/github.com/google/flatbuffers/go
+cp -a ./go_test.go ./go_gen/src/flatbuffers_test/
+
+# Run tests with necessary flags.
+# Developers may wish to see more detail by appending the verbosity flag
+# -test.v to arguments for this command, as in:
+# go -test -test.v ...
+# Developers may also wish to run benchmarks, which may be achieved with the
+# flag -test.bench and the wildcard regexp ".":
+# go -test -test.bench=. ...
+GOPATH=${go_path} go test flatbuffers_test \
+ --test.coverpkg=github.com/google/flatbuffers/go \
+ --cpp_data=${test_dir}/monsterdata_test.mon \
+ --out_data=${test_dir}/monsterdata_go_wire.mon \
+ --test.bench=. \
+ --test.benchtime=3s \
+ --fuzz=true \
+ --fuzz_fields=4 \
+ --fuzz_objects=10000
+
+GO_TEST_RESULT=$?
+rm -rf ${go_path}/{pkg,src}
+if [[ $GO_TEST_RESULT == 0 ]]; then
+ echo "OK: Go tests passed."
+else
+ echo "KO: Go tests failed."
+ exit 1
+fi
+
+NOT_FMT_FILES=$(gofmt -l MyGame)
+if [[ ${NOT_FMT_FILES} != "" ]]; then
+ echo "These files are not well gofmt'ed:"
+ echo
+ echo "${NOT_FMT_FILES}"
+ # enable this when enums are properly formated
+ # exit 1
+fi
diff --git a/tests/JavaScriptTest.js b/tests/JavaScriptTest.js
new file mode 100644
index 0000000..7116daa
--- /dev/null
+++ b/tests/JavaScriptTest.js
@@ -0,0 +1,369 @@
+// Run this using JavaScriptTest.sh
+var assert = require('assert');
+var fs = require('fs');
+
+var flatbuffers = require('../js/flatbuffers').flatbuffers;
+var MyGame = require(process.argv[2]).MyGame;
+
+function main() {
+
+ // First, let's test reading a FlatBuffer generated by C++ code:
+ // This file was generated from monsterdata_test.json
+ var data = new Uint8Array(fs.readFileSync('monsterdata_test.mon'));
+
+ // Now test it:
+
+ var bb = new flatbuffers.ByteBuffer(data);
+ testBuffer(bb);
+
+ // Second, let's create a FlatBuffer from scratch in JavaScript, and test it also.
+ // We use an initial size of 1 to exercise the reallocation algorithm,
+ // normally a size larger than the typical FlatBuffer you generate would be
+ // better for performance.
+ var fbb = new flatbuffers.Builder(1);
+ createMonster(fbb);
+ serializeAndTest(fbb);
+
+ // clear the builder, repeat tests
+ var clearIterations = 100;
+ var startingCapacity = fbb.bb.capacity();
+ for (var i = 0; i < clearIterations; i++) {
+ fbb.clear();
+ createMonster(fbb);
+ serializeAndTest(fbb);
+ }
+ // the capacity of our buffer shouldn't increase with the same size payload
+ assert.strictEqual(fbb.bb.capacity(), startingCapacity);
+
+ test64bit();
+ testUnicode();
+ fuzzTest1();
+
+ console.log('FlatBuffers test: completed successfully');
+}
+
+function createMonster(fbb) {
+ // We set up the same values as monsterdata.json:
+
+ var str = fbb.createString('MyMonster');
+
+ var inv = MyGame.Example.Monster.createInventoryVector(fbb, [0, 1, 2, 3, 4]);
+
+ var fred = fbb.createString('Fred');
+ MyGame.Example.Monster.startMonster(fbb);
+ MyGame.Example.Monster.addName(fbb, fred);
+ var mon2 = MyGame.Example.Monster.endMonster(fbb);
+
+ MyGame.Example.Monster.startTest4Vector(fbb, 2);
+ MyGame.Example.Test.createTest(fbb, 10, 20);
+ MyGame.Example.Test.createTest(fbb, 30, 40);
+ var test4 = fbb.endVector();
+
+ var testArrayOfString = MyGame.Example.Monster.createTestarrayofstringVector(fbb, [
+ fbb.createString('test1'),
+ fbb.createString('test2')
+ ]);
+
+ MyGame.Example.Monster.startMonster(fbb);
+ MyGame.Example.Monster.addPos(fbb, MyGame.Example.Vec3.createVec3(fbb, 1, 2, 3, 3, MyGame.Example.Color.Green, 5, 6));
+ MyGame.Example.Monster.addHp(fbb, 80);
+ MyGame.Example.Monster.addName(fbb, str);
+ MyGame.Example.Monster.addInventory(fbb, inv);
+ MyGame.Example.Monster.addTestType(fbb, MyGame.Example.Any.Monster);
+ MyGame.Example.Monster.addTest(fbb, mon2);
+ MyGame.Example.Monster.addTest4(fbb, test4);
+ MyGame.Example.Monster.addTestarrayofstring(fbb, testArrayOfString);
+ MyGame.Example.Monster.addTestbool(fbb, true);
+ var mon = MyGame.Example.Monster.endMonster(fbb);
+
+ MyGame.Example.Monster.finishMonsterBuffer(fbb, mon);
+}
+
+function serializeAndTest(fbb) {
+ // Write the result to a file for debugging purposes:
+ // Note that the binaries are not necessarily identical, since the JSON
+ // parser may serialize in a slightly different order than the above
+ // JavaScript code. They are functionally equivalent though.
+
+ fs.writeFileSync('monsterdata_javascript_wire.mon', new Buffer(fbb.asUint8Array()));
+
+ // Tests mutation first. This will verify that we did not trample any other
+ // part of the byte buffer.
+ testMutation(fbb.dataBuffer());
+
+ testBuffer(fbb.dataBuffer());
+}
+
+function testMutation(bb) {
+ var monster = MyGame.Example.Monster.getRootAsMonster(bb);
+
+ monster.mutate_hp(120);
+ assert.strictEqual(monster.hp(), 120);
+
+ monster.mutate_hp(80);
+ assert.strictEqual(monster.hp(), 80);
+
+ var manaRes = monster.mutate_mana(10);
+ assert.strictEqual(manaRes, false); // Field was NOT present, because default value.
+
+ // TODO: There is not the availability to mutate structs or vectors.
+}
+
+function testBuffer(bb) {
+ assert.ok(MyGame.Example.Monster.bufferHasIdentifier(bb));
+
+ var monster = MyGame.Example.Monster.getRootAsMonster(bb);
+
+ assert.strictEqual(monster.hp(), 80);
+ assert.strictEqual(monster.mana(), 150); // default
+
+ assert.strictEqual(monster.name(), 'MyMonster');
+
+ var pos = monster.pos();
+ assert.strictEqual(pos.x(), 1);
+ assert.strictEqual(pos.y(), 2);
+ assert.strictEqual(pos.z(), 3);
+ assert.strictEqual(pos.test1(), 3);
+ assert.strictEqual(pos.test2(), MyGame.Example.Color.Green);
+ var t = pos.test3();
+ assert.strictEqual(t.a(), 5);
+ assert.strictEqual(t.b(), 6);
+
+ assert.strictEqual(monster.testType(), MyGame.Example.Any.Monster);
+ var monster2 = new MyGame.Example.Monster();
+ assert.strictEqual(monster.test(monster2) != null, true);
+ assert.strictEqual(monster2.name(), 'Fred');
+
+ assert.strictEqual(monster.inventoryLength(), 5);
+ var invsum = 0;
+ for (var i = 0; i < monster.inventoryLength(); i++) {
+ invsum += monster.inventory(i);
+ }
+ assert.strictEqual(invsum, 10);
+
+ var invsum2 = 0;
+ var invArr = monster.inventoryArray();
+ for (var i = 0; i < invArr.length; i++) {
+ invsum2 += invArr[i];
+ }
+ assert.strictEqual(invsum2, 10);
+
+ var test_0 = monster.test4(0);
+ var test_1 = monster.test4(1);
+ assert.strictEqual(monster.test4Length(), 2);
+ assert.strictEqual(test_0.a() + test_0.b() + test_1.a() + test_1.b(), 100);
+
+ assert.strictEqual(monster.testarrayofstringLength(), 2);
+ assert.strictEqual(monster.testarrayofstring(0), 'test1');
+ assert.strictEqual(monster.testarrayofstring(1), 'test2');
+
+ assert.strictEqual(monster.testbool(), true);
+}
+
+function test64bit() {
+ var fbb = new flatbuffers.Builder();
+ var required = fbb.createString('required');
+
+ MyGame.Example.Stat.startStat(fbb);
+ var stat2 = MyGame.Example.Stat.endStat(fbb);
+
+ MyGame.Example.Monster.startMonster(fbb);
+ MyGame.Example.Monster.addName(fbb, required);
+ MyGame.Example.Monster.addTestempty(fbb, stat2);
+ var mon2 = MyGame.Example.Monster.endMonster(fbb);
+
+ MyGame.Example.Stat.startStat(fbb);
+ // 2541551405100253985 = 0x87654321(low part) + 0x23456789 * 0x100000000(high part);
+ MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x87654321, 0x23456789)); // the low part is Uint32
+ var stat = MyGame.Example.Stat.endStat(fbb);
+
+ MyGame.Example.Monster.startMonster(fbb);
+ MyGame.Example.Monster.addName(fbb, required);
+ MyGame.Example.Monster.addEnemy(fbb, mon2);
+ MyGame.Example.Monster.addTestempty(fbb, stat);
+ var mon = MyGame.Example.Monster.endMonster(fbb);
+
+ MyGame.Example.Monster.finishMonsterBuffer(fbb, mon);
+ var bytes = fbb.asUint8Array();
+
+ ////////////////////////////////////////////////////////////////
+
+ var bb = new flatbuffers.ByteBuffer(bytes);
+ assert.ok(MyGame.Example.Monster.bufferHasIdentifier(bb));
+ var mon = MyGame.Example.Monster.getRootAsMonster(bb);
+
+ var stat = mon.testempty();
+ assert.strictEqual(stat != null, true);
+ assert.strictEqual(stat.val() != null, true);
+ assert.strictEqual(stat.val().toFloat64(), 2541551405100253985);
+
+ var mon2 = mon.enemy();
+ assert.strictEqual(mon2 != null, true);
+ stat = mon2.testempty();
+ assert.strictEqual(stat != null, true);
+ assert.strictEqual(stat.val() != null, true);
+ assert.strictEqual(stat.val().low, 0); // default value
+ assert.strictEqual(stat.val().high, 0);
+}
+
+function testUnicode() {
+ var correct = fs.readFileSync('unicode_test.mon');
+ var json = JSON.parse(fs.readFileSync('unicode_test.json', 'utf8'));
+
+ // Test reading
+ function testReadingUnicode(bb) {
+ var monster = MyGame.Example.Monster.getRootAsMonster(bb);
+ assert.strictEqual(monster.name(), json.name);
+ assert.deepEqual(new Buffer(monster.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(json.name));
+ assert.strictEqual(monster.testarrayoftablesLength(), json.testarrayoftables.length);
+ json.testarrayoftables.forEach(function(table, i) {
+ var value = monster.testarrayoftables(i);
+ assert.strictEqual(value.name(), table.name);
+ assert.deepEqual(new Buffer(value.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(table.name));
+ });
+ assert.strictEqual(monster.testarrayofstringLength(), json.testarrayofstring.length);
+ json.testarrayofstring.forEach(function(string, i) {
+ assert.strictEqual(monster.testarrayofstring(i), string);
+ assert.deepEqual(new Buffer(monster.testarrayofstring(i, flatbuffers.Encoding.UTF8_BYTES)), new Buffer(string));
+ });
+ }
+ testReadingUnicode(new flatbuffers.ByteBuffer(new Uint8Array(correct)));
+
+ // Test writing
+ var fbb = new flatbuffers.Builder();
+ var name = fbb.createString(json.name);
+ var testarrayoftablesOffsets = json.testarrayoftables.map(function(table) {
+ var name = fbb.createString(new Uint8Array(new Buffer(table.name)));
+ MyGame.Example.Monster.startMonster(fbb);
+ MyGame.Example.Monster.addName(fbb, name);
+ return MyGame.Example.Monster.endMonster(fbb);
+ });
+ var testarrayoftablesOffset = MyGame.Example.Monster.createTestarrayoftablesVector(fbb,
+ testarrayoftablesOffsets);
+ var testarrayofstringOffset = MyGame.Example.Monster.createTestarrayofstringVector(fbb,
+ json.testarrayofstring.map(function(string) { return fbb.createString(string); }));
+ MyGame.Example.Monster.startMonster(fbb);
+ MyGame.Example.Monster.addTestarrayofstring(fbb, testarrayofstringOffset);
+ MyGame.Example.Monster.addTestarrayoftables(fbb, testarrayoftablesOffset);
+ MyGame.Example.Monster.addName(fbb, name);
+ MyGame.Example.Monster.finishSizePrefixedMonsterBuffer(fbb, MyGame.Example.Monster.endMonster(fbb));
+ var bb = new flatbuffers.ByteBuffer(fbb.asUint8Array())
+ bb.setPosition(4);
+ testReadingUnicode(bb);
+}
+
+var __imul = Math.imul ? Math.imul : function(a, b) {
+ var ah = a >> 16 & 65535;
+ var bh = b >> 16 & 65535;
+ var al = a & 65535;
+ var bl = b & 65535;
+ return al * bl + (ah * bl + al * bh << 16) | 0;
+};
+
+// Include simple random number generator to ensure results will be the
+// same cross platform.
+// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
+var lcg_seed = 48271;
+
+function lcg_rand() {
+ return lcg_seed = (__imul(lcg_seed, 279470273) >>> 0) % 4294967291;
+}
+
+function lcg_reset() {
+ lcg_seed = 48271;
+}
+
+// Converts a Field ID to a virtual table offset.
+function fieldIndexToOffset(field_id) {
+ // Should correspond to what EndTable() below builds up.
+ var fixed_fields = 2; // Vtable size and Object Size.
+ return (field_id + fixed_fields) * 2;
+}
+
+// Low level stress/fuzz test: serialize/deserialize a variety of
+// different kinds of data in different combinations
+function fuzzTest1() {
+
+ // Values we're testing against: chosen to ensure no bits get chopped
+ // off anywhere, and also be different from eachother.
+ var bool_val = true;
+ var char_val = -127; // 0x81
+ var uchar_val = 0xFF;
+ var short_val = -32222; // 0x8222;
+ var ushort_val = 0xFEEE;
+ var int_val = 0x83333333 | 0;
+ var uint_val = 0xFDDDDDDD;
+ var long_val = new flatbuffers.Long(0x44444444, 0x84444444);
+ var ulong_val = new flatbuffers.Long(0xCCCCCCCC, 0xFCCCCCCC);
+ var float_val = new Float32Array([3.14159])[0];
+ var double_val = 3.14159265359;
+
+ var test_values_max = 11;
+ var fields_per_object = 4;
+ var num_fuzz_objects = 10000; // The higher, the more thorough :)
+
+ var builder = new flatbuffers.Builder();
+
+ lcg_reset(); // Keep it deterministic.
+
+ var objects = [];
+
+ // Generate num_fuzz_objects random objects each consisting of
+ // fields_per_object fields, each of a random type.
+ for (var i = 0; i < num_fuzz_objects; i++) {
+ builder.startObject(fields_per_object);
+ for (var f = 0; f < fields_per_object; f++) {
+ var choice = lcg_rand() % test_values_max;
+ switch (choice) {
+ case 0: builder.addFieldInt8(f, bool_val, 0); break;
+ case 1: builder.addFieldInt8(f, char_val, 0); break;
+ case 2: builder.addFieldInt8(f, uchar_val, 0); break;
+ case 3: builder.addFieldInt16(f, short_val, 0); break;
+ case 4: builder.addFieldInt16(f, ushort_val, 0); break;
+ case 5: builder.addFieldInt32(f, int_val, 0); break;
+ case 6: builder.addFieldInt32(f, uint_val, 0); break;
+ case 7: builder.addFieldInt64(f, long_val, flatbuffers.Long.ZERO); break;
+ case 8: builder.addFieldInt64(f, ulong_val, flatbuffers.Long.ZERO); break;
+ case 9: builder.addFieldFloat32(f, float_val, 0); break;
+ case 10: builder.addFieldFloat64(f, double_val, 0); break;
+ }
+ }
+ objects.push(builder.endObject());
+ }
+ builder.prep(8, 0); // Align whole buffer.
+
+ lcg_reset(); // Reset.
+
+ builder.finish(objects[objects.length - 1]);
+ var bytes = new Uint8Array(builder.asUint8Array());
+ var view = new DataView(bytes.buffer);
+
+ // Test that all objects we generated are readable and return the
+ // expected values. We generate random objects in the same order
+ // so this is deterministic.
+ for (var i = 0; i < num_fuzz_objects; i++) {
+ var offset = bytes.length - objects[i];
+ for (var f = 0; f < fields_per_object; f++) {
+ var choice = lcg_rand() % test_values_max;
+ var vtable_offset = fieldIndexToOffset(f);
+ var vtable = offset - view.getInt32(offset, true);
+ assert.ok(vtable_offset < view.getInt16(vtable, true));
+ var field_offset = offset + view.getInt16(vtable + vtable_offset, true);
+ switch (choice) {
+ case 0: assert.strictEqual(!!view.getInt8(field_offset), bool_val); break;
+ case 1: assert.strictEqual(view.getInt8(field_offset), char_val); break;
+ case 2: assert.strictEqual(view.getUint8(field_offset), uchar_val); break;
+ case 3: assert.strictEqual(view.getInt16(field_offset, true), short_val); break;
+ case 4: assert.strictEqual(view.getUint16(field_offset, true), ushort_val); break;
+ case 5: assert.strictEqual(view.getInt32(field_offset, true), int_val); break;
+ case 6: assert.strictEqual(view.getUint32(field_offset, true), uint_val); break;
+ case 7: assert.strictEqual(view.getInt32(field_offset, true), long_val.low); assert.strictEqual(view.getInt32(field_offset + 4, true), long_val.high); break;
+ case 8: assert.strictEqual(view.getInt32(field_offset, true), ulong_val.low); assert.strictEqual(view.getInt32(field_offset + 4, true), ulong_val.high); break;
+ case 9: assert.strictEqual(view.getFloat32(field_offset, true), float_val); break;
+ case 10: assert.strictEqual(view.getFloat64(field_offset, true), double_val); break;
+ }
+ }
+ }
+}
+
+main();
diff --git a/tests/JavaScriptTest.sh b/tests/JavaScriptTest.sh
new file mode 100755
index 0000000..c0286a0
--- /dev/null
+++ b/tests/JavaScriptTest.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+../flatc -b -I include_test monster_test.fbs unicode_test.json
+node JavaScriptTest ./monster_test_generated
diff --git a/tests/JavaScriptUnionVectorTest.js b/tests/JavaScriptUnionVectorTest.js
new file mode 100644
index 0000000..d79669f
--- /dev/null
+++ b/tests/JavaScriptUnionVectorTest.js
@@ -0,0 +1,57 @@
+var assert = require('assert');
+
+var flatbuffers = require('../js/flatbuffers').flatbuffers;
+var Test = require(process.argv[2]);
+
+function main() {
+ var fbb = new flatbuffers.Builder();
+
+ var charTypes = [
+ Test.Character.Belle,
+ Test.Character.MuLan,
+ Test.Character.BookFan,
+ ];
+
+ Test.Attacker.startAttacker(fbb);
+ Test.Attacker.addSwordAttackDamage(fbb, 5);
+ var attackerOffset = Test.Attacker.endAttacker(fbb);
+
+ var charTypesOffset = Test.Movie.createCharactersTypeVector(fbb, charTypes);
+ var charsOffset = Test.Movie.createCharactersVector(
+ fbb,
+ [
+ Test.BookReader.createBookReader(fbb, 7),
+ attackerOffset,
+ Test.BookReader.createBookReader(fbb, 2),
+ ]
+ );
+
+ Test.Movie.startMovie(fbb);
+ Test.Movie.addCharactersType(fbb, charTypesOffset);
+ Test.Movie.addCharacters(fbb, charsOffset);
+ Test.Movie.finishMovieBuffer(fbb, Test.Movie.endMovie(fbb));
+
+ var buf = new flatbuffers.ByteBuffer(fbb.asUint8Array());
+
+ var movie = Test.Movie.getRootAsMovie(buf);
+
+ assert.strictEqual(movie.charactersTypeLength(), charTypes.length);
+ assert.strictEqual(movie.charactersLength(), movie.charactersTypeLength());
+
+ for (var i = 0; i < charTypes.length; ++i) {
+ assert.strictEqual(movie.charactersType(i), charTypes[i]);
+ }
+
+ var bookReader7 = movie.characters(0, new Test.BookReader());
+ assert.strictEqual(bookReader7.booksRead(), 7);
+
+ var attacker = movie.characters(1, new Test.Attacker());
+ assert.strictEqual(attacker.swordAttackDamage(), 5);
+
+ var bookReader2 = movie.characters(2, new Test.BookReader());
+ assert.strictEqual(bookReader2.booksRead(), 2);
+
+ console.log('FlatBuffers union vector test: completed successfully');
+}
+
+main();
diff --git a/tests/JavaTest.bat b/tests/JavaTest.bat
new file mode 100644
index 0000000..921815a
--- /dev/null
+++ b/tests/JavaTest.bat
@@ -0,0 +1,21 @@
+@echo off
+rem Copyright 2014 Google Inc. All rights reserved.
+rem
+rem Licensed under the Apache License, Version 2.0 (the "License");
+rem you may not use this file except in compliance with the License.
+rem You may obtain a copy of the License at
+rem
+rem http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing, software
+rem distributed under the License is distributed on an "AS IS" BASIS,
+rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem See the License for the specific language governing permissions and
+rem limitations under the License.
+
+rem Compile then run the Java test.
+
+set batch_file_dir=%~d0%~p0
+
+javac -g -classpath %batch_file_dir%\..\java;%batch_file_dir%;%batch_file_dir%\namespace_test;%batch_file_dir%\union_vector JavaTest.java
+java -classpath %batch_file_dir%\..\java;%batch_file_dir%;%batch_file_dir%\namespace_test;%batch_file_dir%\union_vector JavaTest
diff --git a/tests/JavaTest.java b/tests/JavaTest.java
new file mode 100644
index 0000000..6505767
--- /dev/null
+++ b/tests/JavaTest.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import MyGame.Example.*;
+import NamespaceA.*;
+import NamespaceA.NamespaceB.*;
+import com.google.flatbuffers.ByteBufferUtil;
+import static com.google.flatbuffers.Constants.*;
+import com.google.flatbuffers.FlatBufferBuilder;
+import MyGame.MonsterExtra;
+
+class JavaTest {
+ public static void main(String[] args) {
+
+ // First, let's test reading a FlatBuffer generated by C++ code:
+ // This file was generated from monsterdata_test.json
+
+ byte[] data = null;
+ File file = new File("monsterdata_test.mon");
+ RandomAccessFile f = null;
+ try {
+ f = new RandomAccessFile(file, "r");
+ data = new byte[(int)f.length()];
+ f.readFully(data);
+ f.close();
+ } catch(java.io.IOException e) {
+ System.out.println("FlatBuffers test: couldn't read file");
+ return;
+ }
+
+ // Now test it:
+
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ TestBuffer(bb);
+
+ // Second, let's create a FlatBuffer from scratch in Java, and test it also.
+ // We use an initial size of 1 to exercise the reallocation algorithm,
+ // normally a size larger than the typical FlatBuffer you generate would be
+ // better for performance.
+ FlatBufferBuilder fbb = new FlatBufferBuilder(1);
+
+ TestBuilderBasics(fbb, true);
+ TestBuilderBasics(fbb, false);
+
+ TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
+
+ TestNamespaceNesting();
+
+ TestNestedFlatBuffer();
+
+ TestCreateByteVector();
+
+ TestCreateUninitializedVector();
+
+ TestByteBufferFactory();
+
+ TestSizedInputStream();
+
+ TestVectorOfUnions();
+
+ TestFixedLengthArrays();
+
+ System.out.println("FlatBuffers test: completed successfully");
+ }
+
+ static void TestEnums() {
+ TestEq(Color.name(Color.Red), "Red");
+ TestEq(Color.name(Color.Blue), "Blue");
+ TestEq(Any.name(Any.NONE), "NONE");
+ TestEq(Any.name(Any.Monster), "Monster");
+ }
+
+ static void TestBuffer(ByteBuffer bb) {
+ TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
+
+ Monster monster = Monster.getRootAsMonster(bb);
+
+ TestEq(monster.hp(), (short)80);
+ TestEq(monster.mana(), (short)150); // default
+
+ TestEq(monster.name(), "MyMonster");
+ // monster.friendly() // can't access, deprecated
+
+ Vec3 pos = monster.pos();
+ TestEq(pos.x(), 1.0f);
+ TestEq(pos.y(), 2.0f);
+ TestEq(pos.z(), 3.0f);
+ TestEq(pos.test1(), 3.0);
+ // issue: int != byte
+ TestEq(pos.test2(), (int) Color.Green);
+ Test t = pos.test3();
+ TestEq(t.a(), (short)5);
+ TestEq(t.b(), (byte)6);
+
+ TestEq(monster.testType(), (byte)Any.Monster);
+ Monster monster2 = new Monster();
+ TestEq(monster.test(monster2) != null, true);
+ TestEq(monster2.name(), "Fred");
+
+ TestEq(monster.inventoryLength(), 5);
+ int invsum = 0;
+ for (int i = 0; i < monster.inventoryLength(); i++)
+ invsum += monster.inventory(i);
+ TestEq(invsum, 10);
+
+ // Alternative way of accessing a vector:
+ ByteBuffer ibb = monster.inventoryAsByteBuffer();
+ invsum = 0;
+ while (ibb.position() < ibb.limit())
+ invsum += ibb.get();
+ TestEq(invsum, 10);
+
+ Test test_0 = monster.test4(0);
+ Test test_1 = monster.test4(1);
+ TestEq(monster.test4Length(), 2);
+ TestEq(test_0.a() + test_0.b() + test_1.a() + test_1.b(), 100);
+
+ TestEq(monster.testarrayofstringLength(), 2);
+ TestEq(monster.testarrayofstring(0),"test1");
+ TestEq(monster.testarrayofstring(1),"test2");
+
+ TestEq(monster.testbool(), true);
+ }
+
+ // this method checks additional fields not present in the binary buffer read from file
+ // these new tests are performed on top of the regular tests
+ static void TestExtendedBuffer(ByteBuffer bb) {
+ TestBuffer(bb);
+
+ Monster monster = Monster.getRootAsMonster(bb);
+
+ TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
+ }
+
+ static void TestNamespaceNesting() {
+ // reference / manipulate these to verify compilation
+ FlatBufferBuilder fbb = new FlatBufferBuilder(1);
+
+ TableInNestedNS.startTableInNestedNS(fbb);
+ TableInNestedNS.addFoo(fbb, 1234);
+ int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb);
+
+ TableInFirstNS.startTableInFirstNS(fbb);
+ TableInFirstNS.addFooTable(fbb, nestedTableOff);
+ int off = TableInFirstNS.endTableInFirstNS(fbb);
+ }
+
+ static void TestNestedFlatBuffer() {
+ final String nestedMonsterName = "NestedMonsterName";
+ final short nestedMonsterHp = 600;
+ final short nestedMonsterMana = 1024;
+
+ FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
+ int str1 = fbb1.createString(nestedMonsterName);
+ Monster.startMonster(fbb1);
+ Monster.addName(fbb1, str1);
+ Monster.addHp(fbb1, nestedMonsterHp);
+ Monster.addMana(fbb1, nestedMonsterMana);
+ int monster1 = Monster.endMonster(fbb1);
+ Monster.finishMonsterBuffer(fbb1, monster1);
+ byte[] fbb1Bytes = fbb1.sizedByteArray();
+ fbb1 = null;
+
+ FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
+ int str2 = fbb2.createString("My Monster");
+ int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
+ Monster.startMonster(fbb2);
+ Monster.addName(fbb2, str2);
+ Monster.addHp(fbb2, (short)50);
+ Monster.addMana(fbb2, (short)32);
+ Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
+ int monster = Monster.endMonster(fbb2);
+ Monster.finishMonsterBuffer(fbb2, monster);
+
+ // Now test the data extracted from the nested buffer
+ Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
+ Monster nestedMonster = mons.testnestedflatbufferAsMonster();
+
+ TestEq(nestedMonsterMana, nestedMonster.mana());
+ TestEq(nestedMonsterHp, nestedMonster.hp());
+ TestEq(nestedMonsterName, nestedMonster.name());
+ }
+
+ static void TestCreateByteVector() {
+ FlatBufferBuilder fbb = new FlatBufferBuilder(16);
+ int str = fbb.createString("MyMonster");
+ byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
+ int vec = fbb.createByteVector(inventory);
+ Monster.startMonster(fbb);
+ Monster.addInventory(fbb, vec);
+ Monster.addName(fbb, str);
+ int monster1 = Monster.endMonster(fbb);
+ Monster.finishMonsterBuffer(fbb, monster1);
+ Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
+
+ TestEq(monsterObject.inventory(1), (int)inventory[1]);
+ TestEq(monsterObject.inventoryLength(), inventory.length);
+ TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
+ }
+
+ static void TestCreateUninitializedVector() {
+ FlatBufferBuilder fbb = new FlatBufferBuilder(16);
+ int str = fbb.createString("MyMonster");
+ byte[] inventory = new byte[] { 0, 1, 2, 3, 4 };
+ ByteBuffer bb = fbb.createUnintializedVector(1, inventory.length, 1);
+ for (byte i:inventory) {
+ bb.put(i);
+ }
+ int vec = fbb.endVector();
+ Monster.startMonster(fbb);
+ Monster.addInventory(fbb, vec);
+ Monster.addName(fbb, str);
+ int monster1 = Monster.endMonster(fbb);
+ Monster.finishMonsterBuffer(fbb, monster1);
+ Monster monsterObject = Monster.getRootAsMonster(fbb.dataBuffer());
+
+ TestEq(monsterObject.inventory(1), (int)inventory[1]);
+ TestEq(monsterObject.inventoryLength(), inventory.length);
+ TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
+ }
+
+ static void TestByteBufferFactory() {
+ final class MappedByteBufferFactory extends FlatBufferBuilder.ByteBufferFactory {
+ @Override
+ public ByteBuffer newByteBuffer(int capacity) {
+ ByteBuffer bb;
+ try {
+ bb = new RandomAccessFile("javatest.bin", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, capacity).order(ByteOrder.LITTLE_ENDIAN);
+ } catch(Throwable e) {
+ System.out.println("FlatBuffers test: couldn't map ByteBuffer to a file");
+ bb = null;
+ }
+ return bb;
+ }
+ }
+
+ FlatBufferBuilder fbb = new FlatBufferBuilder(1, new MappedByteBufferFactory());
+
+ TestBuilderBasics(fbb, false);
+ }
+
+ static void TestSizedInputStream() {
+ // Test on default FlatBufferBuilder that uses HeapByteBuffer
+ FlatBufferBuilder fbb = new FlatBufferBuilder(1);
+
+ TestBuilderBasics(fbb, false);
+
+ InputStream in = fbb.sizedInputStream();
+ byte[] array = fbb.sizedByteArray();
+ int count = 0;
+ int currentVal = 0;
+
+ while (currentVal != -1 && count < array.length) {
+ try {
+ currentVal = in.read();
+ } catch(java.io.IOException e) {
+ System.out.println("FlatBuffers test: couldn't read from InputStream");
+ return;
+ }
+ TestEq((byte)currentVal, array[count]);
+ count++;
+ }
+ TestEq(count, array.length);
+ }
+
+ static void TestBuilderBasics(FlatBufferBuilder fbb, boolean sizePrefix) {
+ int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
+ int[] off = new int[3];
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, names[0]);
+ off[0] = Monster.endMonster(fbb);
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, names[1]);
+ off[1] = Monster.endMonster(fbb);
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, names[2]);
+ off[2] = Monster.endMonster(fbb);
+ int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
+
+ // We set up the same values as monsterdata.json:
+
+ int str = fbb.createString("MyMonster");
+
+ int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
+
+ int fred = fbb.createString("Fred");
+ Monster.startMonster(fbb);
+ Monster.addName(fbb, fred);
+ int mon2 = Monster.endMonster(fbb);
+
+ Monster.startTest4Vector(fbb, 2);
+ Test.createTest(fbb, (short)10, (byte)20);
+ Test.createTest(fbb, (short)30, (byte)40);
+ int test4 = fbb.endVector();
+
+ int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
+ fbb.createString("test1"),
+ fbb.createString("test2")
+ });
+
+ Monster.startMonster(fbb);
+ Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
+ Color.Green, (short)5, (byte)6));
+ Monster.addHp(fbb, (short)80);
+ Monster.addName(fbb, str);
+ Monster.addInventory(fbb, inv);
+ Monster.addTestType(fbb, (byte)Any.Monster);
+ Monster.addTest(fbb, mon2);
+ Monster.addTest4(fbb, test4);
+ Monster.addTestarrayofstring(fbb, testArrayOfString);
+ Monster.addTestbool(fbb, true);
+ Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
+ Monster.addTestarrayoftables(fbb, sortMons);
+ int mon = Monster.endMonster(fbb);
+
+ if (sizePrefix) {
+ Monster.finishSizePrefixedMonsterBuffer(fbb, mon);
+ } else {
+ Monster.finishMonsterBuffer(fbb, mon);
+ }
+
+ // Write the result to a file for debugging purposes:
+ // Note that the binaries are not necessarily identical, since the JSON
+ // parser may serialize in a slightly different order than the above
+ // Java code. They are functionally equivalent though.
+
+ try {
+ String filename = "monsterdata_java_wire" + (sizePrefix ? "_sp" : "") + ".mon";
+ FileChannel fc = new FileOutputStream(filename).getChannel();
+ fc.write(fbb.dataBuffer().duplicate());
+ fc.close();
+ } catch(java.io.IOException e) {
+ System.out.println("FlatBuffers test: couldn't write file");
+ return;
+ }
+
+ // Test it:
+ ByteBuffer dataBuffer = fbb.dataBuffer();
+ if (sizePrefix) {
+ TestEq(ByteBufferUtil.getSizePrefix(dataBuffer) + SIZE_PREFIX_LENGTH,
+ dataBuffer.remaining());
+ dataBuffer = ByteBufferUtil.removeSizePrefix(dataBuffer);
+ }
+ TestExtendedBuffer(dataBuffer);
+
+ // Make sure it also works with read only ByteBuffers. This is slower,
+ // since creating strings incurs an additional copy
+ // (see Table.__string).
+ TestExtendedBuffer(dataBuffer.asReadOnlyBuffer());
+
+ TestEnums();
+
+ //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
+ // revert to original values after testing
+ Monster monster = Monster.getRootAsMonster(dataBuffer);
+
+ // mana is optional and does not exist in the buffer so the mutation should fail
+ // the mana field should retain its default value
+ TestEq(monster.mutateMana((short)10), false);
+ TestEq(monster.mana(), (short)150);
+
+ // Accessing a vector of sorted by the key tables
+ TestEq(monster.testarrayoftables(0).name(), "Barney");
+ TestEq(monster.testarrayoftables(1).name(), "Frodo");
+ TestEq(monster.testarrayoftables(2).name(), "Wilma");
+
+ // Example of searching for a table by the key
+ TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
+ TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
+ TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
+
+ // testType is an existing field and mutating it should succeed
+ TestEq(monster.testType(), (byte)Any.Monster);
+ TestEq(monster.mutateTestType(Any.NONE), true);
+ TestEq(monster.testType(), (byte)Any.NONE);
+ TestEq(monster.mutateTestType(Any.Monster), true);
+ TestEq(monster.testType(), (byte)Any.Monster);
+
+ //mutate the inventory vector
+ TestEq(monster.mutateInventory(0, 1), true);
+ TestEq(monster.mutateInventory(1, 2), true);
+ TestEq(monster.mutateInventory(2, 3), true);
+ TestEq(monster.mutateInventory(3, 4), true);
+ TestEq(monster.mutateInventory(4, 5), true);
+
+ for (int i = 0; i < monster.inventoryLength(); i++) {
+ TestEq(monster.inventory(i), i + 1);
+ }
+
+ //reverse mutation
+ TestEq(monster.mutateInventory(0, 0), true);
+ TestEq(monster.mutateInventory(1, 1), true);
+ TestEq(monster.mutateInventory(2, 2), true);
+ TestEq(monster.mutateInventory(3, 3), true);
+ TestEq(monster.mutateInventory(4, 4), true);
+
+ // get a struct field and edit one of its fields
+ Vec3 pos = monster.pos();
+ TestEq(pos.x(), 1.0f);
+ pos.mutateX(55.0f);
+ TestEq(pos.x(), 55.0f);
+ pos.mutateX(1.0f);
+ TestEq(pos.x(), 1.0f);
+ }
+
+ static void TestVectorOfUnions() {
+ final FlatBufferBuilder fbb = new FlatBufferBuilder();
+
+ final int swordAttackDamage = 1;
+
+ final int[] characterVector = new int[] {
+ Attacker.createAttacker(fbb, swordAttackDamage),
+ };
+
+ final byte[] characterTypeVector = new byte[]{
+ Character.MuLan,
+ };
+
+ Movie.finishMovieBuffer(
+ fbb,
+ Movie.createMovie(
+ fbb,
+ (byte)0,
+ (byte)0,
+ Movie.createCharactersTypeVector(fbb, characterTypeVector),
+ Movie.createCharactersVector(fbb, characterVector)
+ )
+ );
+
+ final Movie movie = Movie.getRootAsMovie(fbb.dataBuffer());
+
+ TestEq(movie.charactersTypeLength(), characterTypeVector.length);
+ TestEq(movie.charactersLength(), characterVector.length);
+
+ TestEq(movie.charactersType(0), characterTypeVector[0]);
+
+ TestEq(((Attacker)movie.characters(new Attacker(), 0)).swordAttackDamage(), swordAttackDamage);
+ }
+
+ static void TestFixedLengthArrays() {
+ FlatBufferBuilder builder = new FlatBufferBuilder(0);
+
+ float a;
+ int[] b = new int[15];
+ byte c;
+ int[][] d_a = new int[2][2];
+ byte[] d_b = new byte[2];
+ byte[][] d_c = new byte[2][2];
+
+ a = 0.5f;
+ for (int i = 0; i < 15; i++) b[i] = i;
+ c = 1;
+ d_a[0][0] = 1;
+ d_a[0][1] = 2;
+ d_a[1][0] = 3;
+ d_a[1][1] = 4;
+ d_b[0] = TestEnum.B;
+ d_b[1] = TestEnum.C;
+ d_c[0][0] = TestEnum.A;
+ d_c[0][1] = TestEnum.B;
+ d_c[1][0] = TestEnum.C;
+ d_c[1][1] = TestEnum.B;
+
+ int arrayOffset = ArrayStruct.createArrayStruct(builder,
+ a, b, c, d_a, d_b, d_c);
+
+ // Create a table with the ArrayStruct.
+ ArrayTable.startArrayTable(builder);
+ ArrayTable.addA(builder, arrayOffset);
+ int tableOffset = ArrayTable.endArrayTable(builder);
+
+ ArrayTable.finishArrayTableBuffer(builder, tableOffset);
+
+ ArrayTable table = ArrayTable.getRootAsArrayTable(builder.dataBuffer());
+ NestedStruct nested = new NestedStruct();
+
+ TestEq(table.a().a(), 0.5f);
+ for (int i = 0; i < 15; i++) TestEq(table.a().b(i), i);
+ TestEq(table.a().c(), (byte)1);
+ TestEq(table.a().d(nested, 0).a(0), 1);
+ TestEq(table.a().d(nested, 0).a(1), 2);
+ TestEq(table.a().d(nested, 1).a(0), 3);
+ TestEq(table.a().d(nested, 1).a(1), 4);
+ TestEq(table.a().d(nested, 0).b(), TestEnum.B);
+ TestEq(table.a().d(nested, 1).b(), TestEnum.C);
+ TestEq(table.a().d(nested, 0).c(0), TestEnum.A);
+ TestEq(table.a().d(nested, 0).c(1), TestEnum.B);
+ TestEq(table.a().d(nested, 1).c(0), TestEnum.C);
+ TestEq(table.a().d(nested, 1).c(1), TestEnum.B);
+ }
+
+ static <T> void TestEq(T a, T b) {
+ if (!a.equals(b)) {
+ System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
+ System.out.println("FlatBuffers test FAILED: \'" + a + "\' != \'" + b + "\'");
+ assert false;
+ System.exit(1);
+ }
+ }
+}
diff --git a/tests/JavaTest.sh b/tests/JavaTest.sh
new file mode 100755
index 0000000..58d8442
--- /dev/null
+++ b/tests/JavaTest.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -o errexit
+
+echo Compile then run the Java test.
+
+java -version
+
+testdir="$(readlink -fn "$(dirname "$0")")"
+
+targetdir="${testdir}/target"
+
+if [[ -e "${targetdir}" ]]; then
+ echo "cleaning target"
+ rm -rf "${targetdir}"
+fi
+
+mkdir -v "${targetdir}"
+
+if ! find "${testdir}/../java" -type f -name "*.class" -delete; then
+ echo "failed to clean .class files from java directory" >&2
+ exit 1
+fi
+
+javac -d "${targetdir}" -classpath "${testdir}/../java:${testdir}:${testdir}/namespace_test:${testdir}/union_vector" "${testdir}/JavaTest.java"
+
+(cd "${testdir}" && java -classpath "${targetdir}" JavaTest )
+
+rm -rf "${targetdir}"
diff --git a/tests/KotlinTest.kt b/tests/KotlinTest.kt
new file mode 100644
index 0000000..07f0465
--- /dev/null
+++ b/tests/KotlinTest.kt
@@ -0,0 +1,460 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import MyGame.Example.*
+import com.google.flatbuffers.ByteBufferUtil
+import com.google.flatbuffers.FlatBufferBuilder
+import NamespaceA.*
+import NamespaceA.NamespaceB.*
+import NamespaceA.NamespaceB.TableInNestedNS
+import java.io.File
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.io.RandomAccessFile
+import java.nio.ByteBuffer
+import java.nio.ByteOrder
+import java.nio.channels.FileChannel
+
+import com.google.flatbuffers.Constants.SIZE_PREFIX_LENGTH
+
+@kotlin.ExperimentalUnsignedTypes
+class KotlinTest {
+
+ companion object {
+ @JvmStatic
+ fun main(args: Array<String>) {
+
+ // First, let's test reading a FlatBuffer generated by C++ code:
+ // This file was generated from monsterdata_test.json
+
+ val data = RandomAccessFile(File("monsterdata_test.mon"), "r").use {
+ val temp = ByteArray(it.length().toInt())
+ it.readFully(temp)
+ temp
+ }
+
+ // Now test it:
+
+ val bb = ByteBuffer.wrap(data)
+ TestBuffer(bb)
+
+ // Second, let's create a FlatBuffer from scratch in Java, and test it also.
+ // We use an initial size of 1 to exercise the reallocation algorithm,
+ // normally a size larger than the typical FlatBuffer you generate would be
+ // better for performance.
+ val fbb = FlatBufferBuilder(1)
+
+ TestBuilderBasics(fbb, true)
+ TestBuilderBasics(fbb, false)
+
+ TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer())
+
+ TestNamespaceNesting()
+
+ TestNestedFlatBuffer()
+
+ TestCreateByteVector()
+
+ TestCreateUninitializedVector()
+
+ TestByteBufferFactory()
+
+ TestSizedInputStream()
+
+ TestVectorOfUnions()
+
+ println("FlatBuffers test: completed successfully")
+ }
+
+ fun TestEnums() {
+ assert(Color.name(Color.Red.toInt()) == "Red")
+ assert(Color.name(Color.Blue.toInt()) == "Blue")
+ assert(Any_.name(Any_.NONE.toInt()) == "NONE")
+ assert(Any_.name(Any_.Monster.toInt()) == "Monster")
+ }
+
+ fun TestBuffer(bb: ByteBuffer) {
+ assert(Monster.MonsterBufferHasIdentifier(bb) == true)
+
+ val monster = Monster.getRootAsMonster(bb)
+
+ assert(monster.hp == 80.toShort())
+ assert(monster.mana == 150.toShort()) // default
+
+ assert(monster.name == "MyMonster")
+ // monster.friendly() // can't access, deprecated
+
+ val pos = monster.pos!!
+ assert(pos.x == 1.0f)
+ assert(pos.y == 2.0f)
+ assert(pos.z == 3.0f)
+ assert(pos.test1 == 3.0)
+ // issue: int != byte
+ assert(pos.test2 == Color.Green)
+ val t = pos.test3!!
+ assert(t.a == 5.toShort())
+ assert(t.b == 6.toByte())
+
+ assert(monster.testType == Any_.Monster)
+ val monster2 = Monster()
+ assert(monster.test(monster2) != null == true)
+ assert(monster2.name == "Fred")
+
+ assert(monster.inventoryLength == 5)
+ var invsum = 0u
+ for (i in 0 until monster.inventoryLength)
+ invsum += monster.inventory(i)
+ assert(invsum == 10u)
+
+ // Alternative way of accessing a vector:
+ val ibb = monster.inventoryAsByteBuffer
+ invsum = 0u
+ while (ibb.position() < ibb.limit())
+ invsum += ibb.get().toUInt()
+ assert(invsum == 10u)
+
+
+ val test_0 = monster.test4(0)!!
+ val test_1 = monster.test4(1)!!
+ assert(monster.test4Length == 2)
+ assert(test_0.a + test_0.b + test_1.a + test_1.b == 100)
+
+ assert(monster.testarrayofstringLength == 2)
+ assert(monster.testarrayofstring(0) == "test1")
+ assert(monster.testarrayofstring(1) == "test2")
+
+ assert(monster.testbool == true)
+ }
+
+ // this method checks additional fields not present in the binary buffer read from file
+ // these new tests are performed on top of the regular tests
+ fun TestExtendedBuffer(bb: ByteBuffer) {
+ TestBuffer(bb)
+
+ val monster = Monster.getRootAsMonster(bb)
+
+ assert(monster.testhashu32Fnv1 == (1u + Integer.MAX_VALUE.toUInt()))
+ }
+
+ fun TestNamespaceNesting() {
+ // reference / manipulate these to verify compilation
+ val fbb = FlatBufferBuilder(1)
+
+ TableInNestedNS.startTableInNestedNS(fbb)
+ TableInNestedNS.addFoo(fbb, 1234)
+ val nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb)
+
+ TableInFirstNS.startTableInFirstNS(fbb)
+ TableInFirstNS.addFooTable(fbb, nestedTableOff)
+ }
+
+ fun TestNestedFlatBuffer() {
+ val nestedMonsterName = "NestedMonsterName"
+ val nestedMonsterHp: Short = 600
+ val nestedMonsterMana: Short = 1024
+
+ var fbb1: FlatBufferBuilder? = FlatBufferBuilder(16)
+ val str1 = fbb1!!.createString(nestedMonsterName)
+ Monster.startMonster(fbb1)
+ Monster.addName(fbb1, str1)
+ Monster.addHp(fbb1, nestedMonsterHp)
+ Monster.addMana(fbb1, nestedMonsterMana)
+ val monster1 = Monster.endMonster(fbb1)
+ Monster.finishMonsterBuffer(fbb1, monster1)
+ val fbb1Bytes = fbb1.sizedByteArray()
+
+ val fbb2 = FlatBufferBuilder(16)
+ val str2 = fbb2.createString("My Monster")
+ val nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes.asUByteArray())
+ Monster.startMonster(fbb2)
+ Monster.addName(fbb2, str2)
+ Monster.addHp(fbb2, 50.toShort())
+ Monster.addMana(fbb2, 32.toShort())
+ Monster.addTestnestedflatbuffer(fbb2, nestedBuffer)
+ val monster = Monster.endMonster(fbb2)
+ Monster.finishMonsterBuffer(fbb2, monster)
+
+ // Now test the data extracted from the nested buffer
+ val mons = Monster.getRootAsMonster(fbb2.dataBuffer())
+ val nestedMonster = mons.testnestedflatbufferAsMonster!!
+
+ assert(nestedMonsterMana == nestedMonster.mana)
+ assert(nestedMonsterHp == nestedMonster.hp)
+ assert(nestedMonsterName == nestedMonster.name)
+ }
+
+ fun TestCreateByteVector() {
+ val fbb = FlatBufferBuilder(16)
+ val str = fbb.createString("MyMonster")
+ val inventory = byteArrayOf(0, 1, 2, 3, 4)
+ val vec = fbb.createByteVector(inventory)
+ Monster.startMonster(fbb)
+ Monster.addInventory(fbb, vec)
+ Monster.addName(fbb, str)
+ val monster1 = Monster.endMonster(fbb)
+ Monster.finishMonsterBuffer(fbb, monster1)
+ val monsterObject = Monster.getRootAsMonster(fbb.dataBuffer())
+
+ assert(monsterObject.inventory(1) == inventory[1].toUByte())
+ assert(monsterObject.inventoryLength == inventory.size)
+ assert(ByteBuffer.wrap(inventory) == monsterObject.inventoryAsByteBuffer)
+ }
+
+ fun TestCreateUninitializedVector() {
+ val fbb = FlatBufferBuilder(16)
+ val str = fbb.createString("MyMonster")
+ val inventory = byteArrayOf(0, 1, 2, 3, 4)
+ val bb = fbb.createUnintializedVector(1, inventory.size, 1)
+ for (i in inventory) {
+ bb.put(i)
+ }
+ val vec = fbb.endVector()
+ Monster.startMonster(fbb)
+ Monster.addInventory(fbb, vec)
+ Monster.addName(fbb, str)
+ val monster1 = Monster.endMonster(fbb)
+ Monster.finishMonsterBuffer(fbb, monster1)
+ val monsterObject = Monster.getRootAsMonster(fbb.dataBuffer())
+
+ assert(monsterObject.inventory(1) == inventory[1].toUByte())
+ assert(monsterObject.inventoryLength == inventory.size)
+ assert(ByteBuffer.wrap(inventory) == monsterObject.inventoryAsByteBuffer)
+ }
+
+ fun TestByteBufferFactory() {
+ class MappedByteBufferFactory : FlatBufferBuilder.ByteBufferFactory() {
+ override fun newByteBuffer(capacity: Int): ByteBuffer? {
+ var bb: ByteBuffer?
+ try {
+ bb = RandomAccessFile("javatest.bin", "rw").channel.map(
+ FileChannel.MapMode.READ_WRITE,
+ 0,
+ capacity.toLong()
+ ).order(ByteOrder.LITTLE_ENDIAN)
+ } catch (e: Throwable) {
+ println("FlatBuffers test: couldn't map ByteBuffer to a file")
+ bb = null
+ }
+
+ return bb
+ }
+ }
+
+ val fbb = FlatBufferBuilder(1, MappedByteBufferFactory())
+
+ TestBuilderBasics(fbb, false)
+ }
+
+ fun TestSizedInputStream() {
+ // Test on default FlatBufferBuilder that uses HeapByteBuffer
+ val fbb = FlatBufferBuilder(1)
+
+ TestBuilderBasics(fbb, false)
+
+ val `in` = fbb.sizedInputStream()
+ val array = fbb.sizedByteArray()
+ var count = 0
+ var currentVal = 0
+
+ while (currentVal != -1 && count < array.size) {
+ try {
+ currentVal = `in`.read()
+ } catch (e: java.io.IOException) {
+ println("FlatBuffers test: couldn't read from InputStream")
+ return
+ }
+
+ assert(currentVal.toByte() == array[count])
+ count++
+ }
+ assert(count == array.size)
+ }
+
+ fun TestBuilderBasics(fbb: FlatBufferBuilder, sizePrefix: Boolean) {
+ val names = intArrayOf(fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma"))
+ val off = IntArray(3)
+ Monster.startMonster(fbb)
+ Monster.addName(fbb, names[0])
+ off[0] = Monster.endMonster(fbb)
+ Monster.startMonster(fbb)
+ Monster.addName(fbb, names[1])
+ off[1] = Monster.endMonster(fbb)
+ Monster.startMonster(fbb)
+ Monster.addName(fbb, names[2])
+ off[2] = Monster.endMonster(fbb)
+ val sortMons = fbb.createSortedVectorOfTables(Monster(), off)
+
+ // We set up the same values as monsterdata.json:
+
+ val str = fbb.createString("MyMonster")
+
+ val inv = Monster.createInventoryVector(fbb, byteArrayOf(0, 1, 2, 3, 4).asUByteArray())
+
+ val fred = fbb.createString("Fred")
+ Monster.startMonster(fbb)
+ Monster.addName(fbb, fred)
+ val mon2 = Monster.endMonster(fbb)
+
+ Monster.startTest4Vector(fbb, 2)
+ Test.createTest(fbb, 10.toShort(), 20.toByte())
+ Test.createTest(fbb, 30.toShort(), 40.toByte())
+ val test4 = fbb.endVector()
+
+ val testArrayOfString =
+ Monster.createTestarrayofstringVector(fbb, intArrayOf(fbb.createString("test1"), fbb.createString("test2")))
+
+ Monster.startMonster(fbb)
+ Monster.addPos(
+ fbb, Vec3.createVec3(
+ fbb, 1.0f, 2.0f, 3.0f, 3.0,
+ Color.Green, 5.toShort(), 6.toByte()
+ )
+ )
+ Monster.addHp(fbb, 80.toShort())
+ Monster.addName(fbb, str)
+ Monster.addInventory(fbb, inv)
+ Monster.addTestType(fbb, Any_.Monster)
+ Monster.addTest(fbb, mon2)
+ Monster.addTest4(fbb, test4)
+ Monster.addTestarrayofstring(fbb, testArrayOfString)
+ Monster.addTestbool(fbb, true)
+ Monster.addTesthashu32Fnv1(fbb, UInt.MAX_VALUE + 1u)
+ Monster.addTestarrayoftables(fbb, sortMons)
+ val mon = Monster.endMonster(fbb)
+
+ if (sizePrefix) {
+ Monster.finishSizePrefixedMonsterBuffer(fbb, mon)
+ } else {
+ Monster.finishMonsterBuffer(fbb, mon)
+ }
+
+ // Write the result to a file for debugging purposes:
+ // Note that the binaries are not necessarily identical, since the JSON
+ // parser may serialize in a slightly different order than the above
+ // Java code. They are functionally equivalent though.
+
+ try {
+ val filename = "monsterdata_java_wire" + (if (sizePrefix) "_sp" else "") + ".mon"
+ val fc = FileOutputStream(filename).channel
+ fc.write(fbb.dataBuffer().duplicate())
+ fc.close()
+ } catch (e: java.io.IOException) {
+ println("FlatBuffers test: couldn't write file")
+ return
+ }
+
+ // Test it:
+ var dataBuffer = fbb.dataBuffer()
+ if (sizePrefix) {
+ assert(
+ ByteBufferUtil.getSizePrefix(dataBuffer) + SIZE_PREFIX_LENGTH ==
+ dataBuffer.remaining()
+ )
+ dataBuffer = ByteBufferUtil.removeSizePrefix(dataBuffer)
+ }
+ TestExtendedBuffer(dataBuffer)
+
+ // Make sure it also works with read only ByteBuffers. This is slower,
+ // since creating strings incurs an additional copy
+ // (see Table.__string).
+ TestExtendedBuffer(dataBuffer.asReadOnlyBuffer())
+
+ TestEnums()
+
+ //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
+ // revert to original values after testing
+ val monster = Monster.getRootAsMonster(dataBuffer)
+
+ // mana is optional and does not exist in the buffer so the mutation should fail
+ // the mana field should retain its default value
+ assert(monster.mutateMana(10.toShort()) == false)
+ assert(monster.mana == 150.toShort())
+
+ // Accessing a vector of sorted by the key tables
+ assert(monster.testarrayoftables(0)!!.name == "Barney")
+ assert(monster.testarrayoftables(1)!!.name == "Frodo")
+ assert(monster.testarrayoftables(2)!!.name == "Wilma")
+
+ // Example of searching for a table by the key
+ assert(monster.testarrayoftablesByKey("Frodo")!!.name == "Frodo")
+ assert(monster.testarrayoftablesByKey("Barney")!!.name == "Barney")
+ assert(monster.testarrayoftablesByKey("Wilma")!!.name == "Wilma")
+
+ // testType is an existing field and mutating it should succeed
+ assert(monster.testType == Any_.Monster)
+ assert(monster.mutateTestType(Any_.NONE) == true)
+ assert(monster.testType == Any_.NONE)
+ assert(monster.mutateTestType(Any_.Monster) == true)
+ assert(monster.testType == Any_.Monster)
+
+ //mutate the inventory vector
+ assert(monster.mutateInventory(0, 1u) == true)
+ assert(monster.mutateInventory(1, 2u) == true)
+ assert(monster.mutateInventory(2, 3u) == true)
+ assert(monster.mutateInventory(3, 4u) == true)
+ assert(monster.mutateInventory(4, 5u) == true)
+
+ for (i in 0 until monster.inventoryLength) {
+ assert(monster.inventory(i) == (i.toUByte() + 1u).toUByte())
+ }
+
+ //reverse mutation
+ assert(monster.mutateInventory(0, 0u) == true)
+ assert(monster.mutateInventory(1, 1u) == true)
+ assert(monster.mutateInventory(2, 2u) == true)
+ assert(monster.mutateInventory(3, 3u) == true)
+ assert(monster.mutateInventory(4, 4u) == true)
+
+ // get a struct field and edit one of its fields
+ val pos = monster.pos!!
+ assert(pos.x == 1.0f)
+ pos.mutateX(55.0f)
+ assert(pos.x == 55.0f)
+ pos.mutateX(1.0f)
+ assert(pos.x == 1.0f)
+ }
+
+ fun TestVectorOfUnions() {
+ val fbb = FlatBufferBuilder()
+
+ val swordAttackDamage = 1
+
+ val characterVector = intArrayOf(Attacker.createAttacker(fbb, swordAttackDamage))
+
+ val characterTypeVector = ubyteArrayOf(Character_.MuLan)
+
+ Movie.finishMovieBuffer(
+ fbb,
+ Movie.createMovie(
+ fbb,
+ 0u,
+ 0,
+ Movie.createCharactersTypeVector(fbb, characterTypeVector),
+ Movie.createCharactersVector(fbb, characterVector)
+ )
+ )
+
+ val movie = Movie.getRootAsMovie(fbb.dataBuffer())
+
+ assert(movie.charactersTypeLength == characterTypeVector.size)
+ assert(movie.charactersLength == characterVector.size)
+
+ assert(movie.charactersType(0) == characterTypeVector[0])
+
+ assert((movie.characters(Attacker(), 0) as Attacker).swordAttackDamage == swordAttackDamage)
+ }
+}
+ }
diff --git a/tests/KotlinTest.sh b/tests/KotlinTest.sh
new file mode 100755
index 0000000..709e68c
--- /dev/null
+++ b/tests/KotlinTest.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+echo Compile then run the Kotlin test.
+
+testdir=$(dirname $0)
+targetdir="${testdir}/kotlin"
+
+if [[ -e "${targetdir}" ]]; then
+ echo "cleaning target"
+ rm -rf "${targetdir}"
+fi
+
+mkdir -v "${targetdir}"
+
+if ! find "${testdir}/../java" -type f -name "*.class" -delete; then
+ echo "failed to clean .class files from java directory" >&2
+ exit 1
+fi
+
+all_kt_files=`find . -name "*.kt" -print`
+
+# Compile java FlatBuffer library
+javac ${testdir}/../java/com/google/flatbuffers/*.java -d $targetdir
+# Compile Kotlin files
+kotlinc $all_kt_files -classpath $targetdir -include-runtime -d $targetdir
+# Make jar
+jar cvf ${testdir}/kotlin_test.jar -C $targetdir . > /dev/null
+# Run test
+kotlin -cp ${testdir}/kotlin_test.jar KotlinTest
+# clean up
+rm -rf $targetdir
+rm ${testdir}/kotlin_test.jar
diff --git a/tests/LuaTest.bat b/tests/LuaTest.bat
new file mode 100644
index 0000000..2bbf1d0
--- /dev/null
+++ b/tests/LuaTest.bat
@@ -0,0 +1,6 @@
+set buildtype=Release
+if "%1"=="-b" set buildtype=%2
+
+..\%buildtype%\flatc.exe --lua -I include_test monster_test.fbs
+
+lua53.exe luatest.lua
\ No newline at end of file
diff --git a/tests/LuaTest.sh b/tests/LuaTest.sh
new file mode 100755
index 0000000..eb70e8a
--- /dev/null
+++ b/tests/LuaTest.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -eu
+#
+# Copyright 2019 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+test_dir="$(pwd)"
+
+${test_dir}/../flatc --lua -I include_test monster_test.fbs
+
+lua5.3 luatest.lua
diff --git a/tests/MyGame/Example/Ability.cs b/tests/MyGame/Example/Ability.cs
new file mode 100644
index 0000000..8315985
--- /dev/null
+++ b/tests/MyGame/Example/Ability.cs
@@ -0,0 +1,32 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Ability : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public uint Id { get { return __p.bb.GetUint(__p.bb_pos + 0); } }
+ public void MutateId(uint id) { __p.bb.PutUint(__p.bb_pos + 0, id); }
+ public uint Distance { get { return __p.bb.GetUint(__p.bb_pos + 4); } }
+ public void MutateDistance(uint distance) { __p.bb.PutUint(__p.bb_pos + 4, distance); }
+
+ public static Offset<MyGame.Example.Ability> CreateAbility(FlatBufferBuilder builder, uint Id, uint Distance) {
+ builder.Prep(4, 8);
+ builder.PutUint(Distance);
+ builder.PutUint(Id);
+ return new Offset<MyGame.Example.Ability>(builder.Offset);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Ability.go b/tests/MyGame/Example/Ability.go
new file mode 100644
index 0000000..a56b445
--- /dev/null
+++ b/tests/MyGame/Example/Ability.go
@@ -0,0 +1,41 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Ability struct {
+ _tab flatbuffers.Struct
+}
+
+func (rcv *Ability) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Ability) Table() flatbuffers.Table {
+ return rcv._tab.Table
+}
+
+func (rcv *Ability) Id() uint32 {
+ return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
+}
+func (rcv *Ability) MutateId(n uint32) bool {
+ return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
+}
+
+func (rcv *Ability) Distance() uint32 {
+ return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
+}
+func (rcv *Ability) MutateDistance(n uint32) bool {
+ return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
+}
+
+func CreateAbility(builder *flatbuffers.Builder, id uint32, distance uint32) flatbuffers.UOffsetT {
+ builder.Prep(4, 8)
+ builder.PrependUint32(distance)
+ builder.PrependUint32(id)
+ return builder.Offset()
+}
diff --git a/tests/MyGame/Example/Ability.java b/tests/MyGame/Example/Ability.java
new file mode 100644
index 0000000..1a8ef03
--- /dev/null
+++ b/tests/MyGame/Example/Ability.java
@@ -0,0 +1,27 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Ability extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public long id() { return (long)bb.getInt(bb_pos + 0) & 0xFFFFFFFFL; }
+ public void mutateId(long id) { bb.putInt(bb_pos + 0, (int)id); }
+ public long distance() { return (long)bb.getInt(bb_pos + 4) & 0xFFFFFFFFL; }
+ public void mutateDistance(long distance) { bb.putInt(bb_pos + 4, (int)distance); }
+
+ public static int createAbility(FlatBufferBuilder builder, long id, long distance) {
+ builder.prep(4, 8);
+ builder.putInt((int)distance);
+ builder.putInt((int)id);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/MyGame/Example/Ability.kt b/tests/MyGame/Example/Ability.kt
new file mode 100644
index 0000000..1b644d6
--- /dev/null
+++ b/tests/MyGame/Example/Ability.kt
@@ -0,0 +1,32 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Ability : Struct() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Ability {
+ __init(_i, _bb)
+ return this
+ }
+ val id : UInt get() = bb.getInt(bb_pos + 0).toUInt()
+ fun mutateId(id: UInt) : ByteBuffer = bb.putInt(bb_pos + 0, id.toInt())
+ val distance : UInt get() = bb.getInt(bb_pos + 4).toUInt()
+ fun mutateDistance(distance: UInt) : ByteBuffer = bb.putInt(bb_pos + 4, distance.toInt())
+ companion object {
+ fun createAbility(builder: FlatBufferBuilder, id: UInt, distance: UInt) : Int {
+ builder.prep(4, 8)
+ builder.putInt(distance.toInt())
+ builder.putInt(id.toInt())
+ return builder.offset()
+ }
+ }
+}
diff --git a/tests/MyGame/Example/Ability.lua b/tests/MyGame/Example/Ability.lua
new file mode 100644
index 0000000..7fb664a
--- /dev/null
+++ b/tests/MyGame/Example/Ability.lua
@@ -0,0 +1,31 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Ability = {} -- the module
+local Ability_mt = {} -- the class metatable
+
+function Ability.New()
+ local o = {}
+ setmetatable(o, {__index = Ability_mt})
+ return o
+end
+function Ability_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Ability_mt:Id()
+ return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 0)
+end
+function Ability_mt:Distance()
+ return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 4)
+end
+function Ability.CreateAbility(builder, id, distance)
+ builder:Prep(4, 8)
+ builder:PrependUint32(distance)
+ builder:PrependUint32(id)
+ return builder:Offset()
+end
+
+return Ability -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Ability.php b/tests/MyGame/Example/Ability.php
new file mode 100644
index 0000000..c09eca3
--- /dev/null
+++ b/tests/MyGame/Example/Ability.php
@@ -0,0 +1,52 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Ability extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Ability
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return uint
+ */
+ public function GetId()
+ {
+ return $this->bb->getUint($this->bb_pos + 0);
+ }
+
+ /**
+ * @return uint
+ */
+ public function GetDistance()
+ {
+ return $this->bb->getUint($this->bb_pos + 4);
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createAbility(FlatBufferBuilder $builder, $id, $distance)
+ {
+ $builder->prep(4, 8);
+ $builder->putUint($distance);
+ $builder->putUint($id);
+ return $builder->offset();
+ }
+}
diff --git a/tests/MyGame/Example/Ability.py b/tests/MyGame/Example/Ability.py
new file mode 100644
index 0000000..3c4776e
--- /dev/null
+++ b/tests/MyGame/Example/Ability.py
@@ -0,0 +1,23 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class Ability(object):
+ __slots__ = ['_tab']
+
+ # Ability
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # Ability
+ def Id(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
+ # Ability
+ def Distance(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
+
+def CreateAbility(builder, id, distance):
+ builder.Prep(4, 8)
+ builder.PrependUint32(distance)
+ builder.PrependUint32(id)
+ return builder.Offset()
diff --git a/tests/MyGame/Example/Any.cs b/tests/MyGame/Example/Any.cs
new file mode 100644
index 0000000..f95c6bc
--- /dev/null
+++ b/tests/MyGame/Example/Any.cs
@@ -0,0 +1,17 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+public enum Any : byte
+{
+ NONE = 0,
+ Monster = 1,
+ TestSimpleTableWithEnum = 2,
+ MyGame_Example2_Monster = 3,
+};
+
+
+}
diff --git a/tests/MyGame/Example/Any.go b/tests/MyGame/Example/Any.go
new file mode 100644
index 0000000..8d9067e
--- /dev/null
+++ b/tests/MyGame/Example/Any.go
@@ -0,0 +1,35 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import "strconv"
+
+type Any byte
+
+const (
+ AnyNONE Any = 0
+ AnyMonster Any = 1
+ AnyTestSimpleTableWithEnum Any = 2
+ AnyMyGame_Example2_Monster Any = 3
+)
+
+var EnumNamesAny = map[Any]string{
+ AnyNONE: "NONE",
+ AnyMonster: "Monster",
+ AnyTestSimpleTableWithEnum: "TestSimpleTableWithEnum",
+ AnyMyGame_Example2_Monster: "MyGame_Example2_Monster",
+}
+
+var EnumValuesAny = map[string]Any{
+ "NONE": AnyNONE,
+ "Monster": AnyMonster,
+ "TestSimpleTableWithEnum": AnyTestSimpleTableWithEnum,
+ "MyGame_Example2_Monster": AnyMyGame_Example2_Monster,
+}
+
+func (v Any) String() string {
+ if s, ok := EnumNamesAny[v]; ok {
+ return s
+ }
+ return "Any(" + strconv.FormatInt(int64(v), 10) + ")"
+}
diff --git a/tests/MyGame/Example/Any.java b/tests/MyGame/Example/Any.java
new file mode 100644
index 0000000..6e4fb76
--- /dev/null
+++ b/tests/MyGame/Example/Any.java
@@ -0,0 +1,16 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+public final class Any {
+ private Any() { }
+ public static final byte NONE = 0;
+ public static final byte Monster = 1;
+ public static final byte TestSimpleTableWithEnum = 2;
+ public static final byte MyGame_Example2_Monster = 3;
+
+ public static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", };
+
+ public static String name(int e) { return names[e]; }
+}
+
diff --git a/tests/MyGame/Example/Any.kt b/tests/MyGame/Example/Any.kt
new file mode 100644
index 0000000..f1a4dfe
--- /dev/null
+++ b/tests/MyGame/Example/Any.kt
@@ -0,0 +1,16 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Any_ private constructor() {
+ companion object {
+ const val NONE: UByte = 0u
+ const val Monster: UByte = 1u
+ const val TestSimpleTableWithEnum: UByte = 2u
+ const val MyGameExample2Monster: UByte = 3u
+ val names : Array<String> = arrayOf("NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster")
+ fun name(e: Int) : String = names[e]
+ }
+}
diff --git a/tests/MyGame/Example/Any.lua b/tests/MyGame/Example/Any.lua
new file mode 100644
index 0000000..03225ba
--- /dev/null
+++ b/tests/MyGame/Example/Any.lua
@@ -0,0 +1,12 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local Any = {
+ NONE = 0,
+ Monster = 1,
+ TestSimpleTableWithEnum = 2,
+ MyGame_Example2_Monster = 3,
+}
+
+return Any -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Any.php b/tests/MyGame/Example/Any.php
new file mode 100644
index 0000000..929caaf
--- /dev/null
+++ b/tests/MyGame/Example/Any.php
@@ -0,0 +1,27 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+class Any
+{
+ const NONE = 0;
+ const Monster = 1;
+ const TestSimpleTableWithEnum = 2;
+ const MyGame_Example2_Monster = 3;
+
+ private static $names = array(
+ Any::NONE=>"NONE",
+ Any::Monster=>"Monster",
+ Any::TestSimpleTableWithEnum=>"TestSimpleTableWithEnum",
+ Any::MyGame_Example2_Monster=>"MyGame_Example2_Monster",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/MyGame/Example/Any.py b/tests/MyGame/Example/Any.py
new file mode 100644
index 0000000..f1b8d51
--- /dev/null
+++ b/tests/MyGame/Example/Any.py
@@ -0,0 +1,10 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+class Any(object):
+ NONE = 0
+ Monster = 1
+ TestSimpleTableWithEnum = 2
+ MyGame_Example2_Monster = 3
+
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.cs b/tests/MyGame/Example/AnyAmbiguousAliases.cs
new file mode 100644
index 0000000..c727b88
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.cs
@@ -0,0 +1,17 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+public enum AnyAmbiguousAliases : byte
+{
+ NONE = 0,
+ M1 = 1,
+ M2 = 2,
+ M3 = 3,
+};
+
+
+}
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.go b/tests/MyGame/Example/AnyAmbiguousAliases.go
new file mode 100644
index 0000000..b9c3793
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.go
@@ -0,0 +1,35 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import "strconv"
+
+type AnyAmbiguousAliases byte
+
+const (
+ AnyAmbiguousAliasesNONE AnyAmbiguousAliases = 0
+ AnyAmbiguousAliasesM1 AnyAmbiguousAliases = 1
+ AnyAmbiguousAliasesM2 AnyAmbiguousAliases = 2
+ AnyAmbiguousAliasesM3 AnyAmbiguousAliases = 3
+)
+
+var EnumNamesAnyAmbiguousAliases = map[AnyAmbiguousAliases]string{
+ AnyAmbiguousAliasesNONE: "NONE",
+ AnyAmbiguousAliasesM1: "M1",
+ AnyAmbiguousAliasesM2: "M2",
+ AnyAmbiguousAliasesM3: "M3",
+}
+
+var EnumValuesAnyAmbiguousAliases = map[string]AnyAmbiguousAliases{
+ "NONE": AnyAmbiguousAliasesNONE,
+ "M1": AnyAmbiguousAliasesM1,
+ "M2": AnyAmbiguousAliasesM2,
+ "M3": AnyAmbiguousAliasesM3,
+}
+
+func (v AnyAmbiguousAliases) String() string {
+ if s, ok := EnumNamesAnyAmbiguousAliases[v]; ok {
+ return s
+ }
+ return "AnyAmbiguousAliases(" + strconv.FormatInt(int64(v), 10) + ")"
+}
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.java b/tests/MyGame/Example/AnyAmbiguousAliases.java
new file mode 100644
index 0000000..b8a6870
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.java
@@ -0,0 +1,16 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+public final class AnyAmbiguousAliases {
+ private AnyAmbiguousAliases() { }
+ public static final byte NONE = 0;
+ public static final byte M1 = 1;
+ public static final byte M2 = 2;
+ public static final byte M3 = 3;
+
+ public static final String[] names = { "NONE", "M1", "M2", "M3", };
+
+ public static String name(int e) { return names[e]; }
+}
+
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.kt b/tests/MyGame/Example/AnyAmbiguousAliases.kt
new file mode 100644
index 0000000..cee13c5
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.kt
@@ -0,0 +1,16 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class AnyAmbiguousAliases private constructor() {
+ companion object {
+ const val NONE: UByte = 0u
+ const val M1: UByte = 1u
+ const val M2: UByte = 2u
+ const val M3: UByte = 3u
+ val names : Array<String> = arrayOf("NONE", "M1", "M2", "M3")
+ fun name(e: Int) : String = names[e]
+ }
+}
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.lua b/tests/MyGame/Example/AnyAmbiguousAliases.lua
new file mode 100644
index 0000000..dbe474b
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.lua
@@ -0,0 +1,12 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local AnyAmbiguousAliases = {
+ NONE = 0,
+ M1 = 1,
+ M2 = 2,
+ M3 = 3,
+}
+
+return AnyAmbiguousAliases -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.php b/tests/MyGame/Example/AnyAmbiguousAliases.php
new file mode 100644
index 0000000..13d318a
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.php
@@ -0,0 +1,27 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+class AnyAmbiguousAliases
+{
+ const NONE = 0;
+ const M1 = 1;
+ const M2 = 2;
+ const M3 = 3;
+
+ private static $names = array(
+ AnyAmbiguousAliases::NONE=>"NONE",
+ AnyAmbiguousAliases::M1=>"M1",
+ AnyAmbiguousAliases::M2=>"M2",
+ AnyAmbiguousAliases::M3=>"M3",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/MyGame/Example/AnyAmbiguousAliases.py b/tests/MyGame/Example/AnyAmbiguousAliases.py
new file mode 100644
index 0000000..de6e9d0
--- /dev/null
+++ b/tests/MyGame/Example/AnyAmbiguousAliases.py
@@ -0,0 +1,10 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+class AnyAmbiguousAliases(object):
+ NONE = 0
+ M1 = 1
+ M2 = 2
+ M3 = 3
+
diff --git a/tests/MyGame/Example/AnyUniqueAliases.cs b/tests/MyGame/Example/AnyUniqueAliases.cs
new file mode 100644
index 0000000..42a3e0b
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.cs
@@ -0,0 +1,17 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+public enum AnyUniqueAliases : byte
+{
+ NONE = 0,
+ M = 1,
+ TS = 2,
+ M2 = 3,
+};
+
+
+}
diff --git a/tests/MyGame/Example/AnyUniqueAliases.go b/tests/MyGame/Example/AnyUniqueAliases.go
new file mode 100644
index 0000000..23d8649
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.go
@@ -0,0 +1,35 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import "strconv"
+
+type AnyUniqueAliases byte
+
+const (
+ AnyUniqueAliasesNONE AnyUniqueAliases = 0
+ AnyUniqueAliasesM AnyUniqueAliases = 1
+ AnyUniqueAliasesTS AnyUniqueAliases = 2
+ AnyUniqueAliasesM2 AnyUniqueAliases = 3
+)
+
+var EnumNamesAnyUniqueAliases = map[AnyUniqueAliases]string{
+ AnyUniqueAliasesNONE: "NONE",
+ AnyUniqueAliasesM: "M",
+ AnyUniqueAliasesTS: "TS",
+ AnyUniqueAliasesM2: "M2",
+}
+
+var EnumValuesAnyUniqueAliases = map[string]AnyUniqueAliases{
+ "NONE": AnyUniqueAliasesNONE,
+ "M": AnyUniqueAliasesM,
+ "TS": AnyUniqueAliasesTS,
+ "M2": AnyUniqueAliasesM2,
+}
+
+func (v AnyUniqueAliases) String() string {
+ if s, ok := EnumNamesAnyUniqueAliases[v]; ok {
+ return s
+ }
+ return "AnyUniqueAliases(" + strconv.FormatInt(int64(v), 10) + ")"
+}
diff --git a/tests/MyGame/Example/AnyUniqueAliases.java b/tests/MyGame/Example/AnyUniqueAliases.java
new file mode 100644
index 0000000..1f32945
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.java
@@ -0,0 +1,16 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+public final class AnyUniqueAliases {
+ private AnyUniqueAliases() { }
+ public static final byte NONE = 0;
+ public static final byte M = 1;
+ public static final byte TS = 2;
+ public static final byte M2 = 3;
+
+ public static final String[] names = { "NONE", "M", "TS", "M2", };
+
+ public static String name(int e) { return names[e]; }
+}
+
diff --git a/tests/MyGame/Example/AnyUniqueAliases.kt b/tests/MyGame/Example/AnyUniqueAliases.kt
new file mode 100644
index 0000000..1902d5d
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.kt
@@ -0,0 +1,16 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class AnyUniqueAliases private constructor() {
+ companion object {
+ const val NONE: UByte = 0u
+ const val M: UByte = 1u
+ const val TS: UByte = 2u
+ const val M2: UByte = 3u
+ val names : Array<String> = arrayOf("NONE", "M", "TS", "M2")
+ fun name(e: Int) : String = names[e]
+ }
+}
diff --git a/tests/MyGame/Example/AnyUniqueAliases.lua b/tests/MyGame/Example/AnyUniqueAliases.lua
new file mode 100644
index 0000000..9bfeb80
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.lua
@@ -0,0 +1,12 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local AnyUniqueAliases = {
+ NONE = 0,
+ M = 1,
+ TS = 2,
+ M2 = 3,
+}
+
+return AnyUniqueAliases -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/AnyUniqueAliases.php b/tests/MyGame/Example/AnyUniqueAliases.php
new file mode 100644
index 0000000..830d8b5
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.php
@@ -0,0 +1,27 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+class AnyUniqueAliases
+{
+ const NONE = 0;
+ const M = 1;
+ const TS = 2;
+ const M2 = 3;
+
+ private static $names = array(
+ AnyUniqueAliases::NONE=>"NONE",
+ AnyUniqueAliases::M=>"M",
+ AnyUniqueAliases::TS=>"TS",
+ AnyUniqueAliases::M2=>"M2",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/MyGame/Example/AnyUniqueAliases.py b/tests/MyGame/Example/AnyUniqueAliases.py
new file mode 100644
index 0000000..a6da355
--- /dev/null
+++ b/tests/MyGame/Example/AnyUniqueAliases.py
@@ -0,0 +1,10 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+class AnyUniqueAliases(object):
+ NONE = 0
+ M = 1
+ TS = 2
+ M2 = 3
+
diff --git a/tests/MyGame/Example/ArrayStruct.cs b/tests/MyGame/Example/ArrayStruct.cs
new file mode 100644
index 0000000..28815e7
--- /dev/null
+++ b/tests/MyGame/Example/ArrayStruct.cs
@@ -0,0 +1,50 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct ArrayStruct : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public ArrayStruct __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public float A { get { return __p.bb.GetFloat(__p.bb_pos + 0); } }
+ public void MutateA(float a) { __p.bb.PutFloat(__p.bb_pos + 0, a); }
+ public int B(int j) { return __p.bb.GetInt(__p.bb_pos + 4 + j * 4); }
+ public void MutateB(int j, int b) { __p.bb.PutInt(__p.bb_pos + 4 + j * 4, b); }
+ public sbyte C { get { return __p.bb.GetSbyte(__p.bb_pos + 64); } }
+ public void MutateC(sbyte c) { __p.bb.PutSbyte(__p.bb_pos + 64, c); }
+ public MyGame.Example.NestedStruct D(int j) { return (new MyGame.Example.NestedStruct()).__assign(__p.bb_pos + 68 + j * 12, __p.bb); }
+
+ public static Offset<MyGame.Example.ArrayStruct> CreateArrayStruct(FlatBufferBuilder builder, float A, int[] B, sbyte C, int[,] d_A, MyGame.Example.TestEnum[] d_B, MyGame.Example.TestEnum[,] d_C) {
+ builder.Prep(4, 92);
+ for (int _idx0 = 2; _idx0 > 0; _idx0--) {
+ builder.Prep(4, 12);
+ builder.Pad(1);
+ for (int _idx1 = 2; _idx1 > 0; _idx1--) {
+ builder.PutSbyte((sbyte)d_C[_idx0-1,_idx1-1]);
+ }
+ builder.PutSbyte((sbyte)d_B[_idx0-1]);
+ for (int _idx1 = 2; _idx1 > 0; _idx1--) {
+ builder.PutInt(d_A[_idx0-1,_idx1-1]);
+ }
+ }
+ builder.Pad(3);
+ builder.PutSbyte(C);
+ for (int _idx0 = 15; _idx0 > 0; _idx0--) {
+ builder.PutInt(B[_idx0-1]);
+ }
+ builder.PutFloat(A);
+ return new Offset<MyGame.Example.ArrayStruct>(builder.Offset);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/ArrayStruct.java b/tests/MyGame/Example/ArrayStruct.java
new file mode 100644
index 0000000..0098c55
--- /dev/null
+++ b/tests/MyGame/Example/ArrayStruct.java
@@ -0,0 +1,45 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class ArrayStruct extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public ArrayStruct __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public float a() { return bb.getFloat(bb_pos + 0); }
+ public void mutateA(float a) { bb.putFloat(bb_pos + 0, a); }
+ public int b(int j) { return bb.getInt(bb_pos + 4 + j * 4); }
+ public void mutateB(int j, int b) { bb.putInt(bb_pos + 4 + j * 4, b); }
+ public byte c() { return bb.get(bb_pos + 64); }
+ public void mutateC(byte c) { bb.put(bb_pos + 64, c); }
+ public MyGame.Example.NestedStruct d(MyGame.Example.NestedStruct obj, int j) { return obj.__assign(bb_pos + 68 + j * 12, bb); }
+
+ public static int createArrayStruct(FlatBufferBuilder builder, float a, int[] b, byte c, int[][] d_a, byte[] d_b, byte[][] d_c) {
+ builder.prep(4, 92);
+ for (int _idx0 = 2; _idx0 > 0; _idx0--) {
+ builder.prep(4, 12);
+ builder.pad(1);
+ for (int _idx1 = 2; _idx1 > 0; _idx1--) {
+ builder.putByte(d_c[_idx0-1][_idx1-1]);
+ }
+ builder.putByte(d_b[_idx0-1]);
+ for (int _idx1 = 2; _idx1 > 0; _idx1--) {
+ builder.putInt(d_a[_idx0-1][_idx1-1]);
+ }
+ }
+ builder.pad(3);
+ builder.putByte(c);
+ for (int _idx0 = 15; _idx0 > 0; _idx0--) {
+ builder.putInt(b[_idx0-1]);
+ }
+ builder.putFloat(a);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/MyGame/Example/ArrayStruct.py b/tests/MyGame/Example/ArrayStruct.py
new file mode 100644
index 0000000..79dda31
--- /dev/null
+++ b/tests/MyGame/Example/ArrayStruct.py
@@ -0,0 +1,41 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class ArrayStruct(object):
+ __slots__ = ['_tab']
+
+ # ArrayStruct
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # ArrayStruct
+ def A(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
+ # ArrayStruct
+ def B(self): return [self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4 + i * 4)) for i in range(15)]
+ # ArrayStruct
+ def C(self): return self._tab.Get(flatbuffers.number_types.Int8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(64))
+ # ArrayStruct
+ def D(self, obj, i):
+ obj.Init(self._tab.Bytes, self._tab.Pos + 68 + i * 12)
+ return obj
+
+
+def CreateArrayStruct(builder, a, b, c, d_a, d_b, d_c):
+ builder.Prep(4, 92)
+ for _idx0 in range(2 , 0, -1):
+ builder.Prep(4, 12)
+ builder.Pad(1)
+ for _idx1 in range(2 , 0, -1):
+ builder.PrependInt8(d_c[_idx0-1][_idx1-1])
+ builder.PrependInt8(d_b[_idx0-1])
+ for _idx1 in range(2 , 0, -1):
+ builder.PrependInt32(d_a[_idx0-1][_idx1-1])
+ builder.Pad(3)
+ builder.PrependInt8(c)
+ for _idx0 in range(15 , 0, -1):
+ builder.PrependInt32(b[_idx0-1])
+ builder.PrependFloat32(a)
+ return builder.Offset()
diff --git a/tests/MyGame/Example/ArrayTable.cs b/tests/MyGame/Example/ArrayTable.cs
new file mode 100644
index 0000000..e303211
--- /dev/null
+++ b/tests/MyGame/Example/ArrayTable.cs
@@ -0,0 +1,35 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct ArrayTable : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static ArrayTable GetRootAsArrayTable(ByteBuffer _bb) { return GetRootAsArrayTable(_bb, new ArrayTable()); }
+ public static ArrayTable GetRootAsArrayTable(ByteBuffer _bb, ArrayTable obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool ArrayTableBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "ARRT"); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public ArrayTable __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public MyGame.Example.ArrayStruct? A { get { int o = __p.__offset(4); return o != 0 ? (MyGame.Example.ArrayStruct?)(new MyGame.Example.ArrayStruct()).__assign(o + __p.bb_pos, __p.bb) : null; } }
+
+ public static void StartArrayTable(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddA(FlatBufferBuilder builder, Offset<MyGame.Example.ArrayStruct> aOffset) { builder.AddStruct(0, aOffset.Value, 0); }
+ public static Offset<MyGame.Example.ArrayTable> EndArrayTable(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.Example.ArrayTable>(o);
+ }
+ public static void FinishArrayTableBuffer(FlatBufferBuilder builder, Offset<MyGame.Example.ArrayTable> offset) { builder.Finish(offset.Value, "ARRT"); }
+ public static void FinishSizePrefixedArrayTableBuffer(FlatBufferBuilder builder, Offset<MyGame.Example.ArrayTable> offset) { builder.FinishSizePrefixed(offset.Value, "ARRT"); }
+};
+
+
+}
diff --git a/tests/MyGame/Example/ArrayTable.java b/tests/MyGame/Example/ArrayTable.java
new file mode 100644
index 0000000..74ce86a
--- /dev/null
+++ b/tests/MyGame/Example/ArrayTable.java
@@ -0,0 +1,31 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class ArrayTable extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static ArrayTable getRootAsArrayTable(ByteBuffer _bb) { return getRootAsArrayTable(_bb, new ArrayTable()); }
+ public static ArrayTable getRootAsArrayTable(ByteBuffer _bb, ArrayTable obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public static boolean ArrayTableBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "ARRT"); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public ArrayTable __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public MyGame.Example.ArrayStruct a() { return a(new MyGame.Example.ArrayStruct()); }
+ public MyGame.Example.ArrayStruct a(MyGame.Example.ArrayStruct obj) { int o = __offset(4); return o != 0 ? obj.__assign(o + bb_pos, bb) : null; }
+
+ public static void startArrayTable(FlatBufferBuilder builder) { builder.startTable(1); }
+ public static void addA(FlatBufferBuilder builder, int aOffset) { builder.addStruct(0, aOffset, 0); }
+ public static int endArrayTable(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+ public static void finishArrayTableBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "ARRT"); }
+ public static void finishSizePrefixedArrayTableBuffer(FlatBufferBuilder builder, int offset) { builder.finishSizePrefixed(offset, "ARRT"); }
+}
+
diff --git a/tests/MyGame/Example/ArrayTable.py b/tests/MyGame/Example/ArrayTable.py
new file mode 100644
index 0000000..6d583f9
--- /dev/null
+++ b/tests/MyGame/Example/ArrayTable.py
@@ -0,0 +1,38 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class ArrayTable(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsArrayTable(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = ArrayTable()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def ArrayTableBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x41\x52\x52\x54", size_prefixed=size_prefixed)
+
+ # ArrayTable
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # ArrayTable
+ def A(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = o + self._tab.Pos
+ from .ArrayStruct import ArrayStruct
+ obj = ArrayStruct()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def ArrayTableStart(builder): builder.StartObject(1)
+def ArrayTableAddA(builder, a): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(a), 0)
+def ArrayTableEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Color.cs b/tests/MyGame/Example/Color.cs
new file mode 100644
index 0000000..5981cf8
--- /dev/null
+++ b/tests/MyGame/Example/Color.cs
@@ -0,0 +1,21 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+/// Composite components of Monster color.
+[System.FlagsAttribute]
+public enum Color : byte
+{
+ Red = 1,
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ Green = 2,
+ /// \brief color Blue (1u << 3)
+ Blue = 8,
+};
+
+
+}
diff --git a/tests/MyGame/Example/Color.go b/tests/MyGame/Example/Color.go
new file mode 100644
index 0000000..9570ae4
--- /dev/null
+++ b/tests/MyGame/Example/Color.go
@@ -0,0 +1,36 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import "strconv"
+
+/// Composite components of Monster color.
+type Color byte
+
+const (
+ ColorRed Color = 1
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ ColorGreen Color = 2
+ /// \brief color Blue (1u << 3)
+ ColorBlue Color = 8
+)
+
+var EnumNamesColor = map[Color]string{
+ ColorRed: "Red",
+ ColorGreen: "Green",
+ ColorBlue: "Blue",
+}
+
+var EnumValuesColor = map[string]Color{
+ "Red": ColorRed,
+ "Green": ColorGreen,
+ "Blue": ColorBlue,
+}
+
+func (v Color) String() string {
+ if s, ok := EnumNamesColor[v]; ok {
+ return s
+ }
+ return "Color(" + strconv.FormatInt(int64(v), 10) + ")"
+}
diff --git a/tests/MyGame/Example/Color.java b/tests/MyGame/Example/Color.java
new file mode 100644
index 0000000..0563c0a
--- /dev/null
+++ b/tests/MyGame/Example/Color.java
@@ -0,0 +1,25 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+/**
+ * Composite components of Monster color.
+ */
+public final class Color {
+ private Color() { }
+ public static final byte Red = 1;
+ /**
+ * \brief color Green
+ * Green is bit_flag with value (1u << 1)
+ */
+ public static final byte Green = 2;
+ /**
+ * \brief color Blue (1u << 3)
+ */
+ public static final byte Blue = 8;
+
+ public static final String[] names = { "Red", "Green", "", "", "", "", "", "Blue", };
+
+ public static String name(int e) { return names[e - Red]; }
+}
+
diff --git a/tests/MyGame/Example/Color.kt b/tests/MyGame/Example/Color.kt
new file mode 100644
index 0000000..4c27ba3
--- /dev/null
+++ b/tests/MyGame/Example/Color.kt
@@ -0,0 +1,25 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+/**
+ * Composite components of Monster color.
+ */
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Color private constructor() {
+ companion object {
+ const val Red: UByte = 1u
+ /**
+ * \brief color Green
+ * Green is bit_flag with value (1u << 1)
+ */
+ const val Green: UByte = 2u
+ /**
+ * \brief color Blue (1u << 3)
+ */
+ const val Blue: UByte = 8u
+ val names : Array<String> = arrayOf("Red", "Green", "", "", "", "", "", "Blue")
+ fun name(e: Int) : String = names[e - Red.toInt()]
+ }
+}
diff --git a/tests/MyGame/Example/Color.lua b/tests/MyGame/Example/Color.lua
new file mode 100644
index 0000000..d4d2cbc
--- /dev/null
+++ b/tests/MyGame/Example/Color.lua
@@ -0,0 +1,15 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+-- Composite components of Monster color.
+local Color = {
+ Red = 1,
+ -- \brief color Green
+ -- Green is bit_flag with value (1u << 1)
+ Green = 2,
+ -- \brief color Blue (1u << 3)
+ Blue = 8,
+}
+
+return Color -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Color.php b/tests/MyGame/Example/Color.php
new file mode 100644
index 0000000..8c32922
--- /dev/null
+++ b/tests/MyGame/Example/Color.php
@@ -0,0 +1,29 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+/// Composite components of Monster color.
+class Color
+{
+ const Red = 1;
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ const Green = 2;
+ /// \brief color Blue (1u << 3)
+ const Blue = 8;
+
+ private static $names = array(
+ Color::Red=>"Red",
+ Color::Green=>"Green",
+ Color::Blue=>"Blue",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/MyGame/Example/Color.py b/tests/MyGame/Example/Color.py
new file mode 100644
index 0000000..55aa821
--- /dev/null
+++ b/tests/MyGame/Example/Color.py
@@ -0,0 +1,13 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+# Composite components of Monster color.
+class Color(object):
+ Red = 1
+ # \brief color Green
+ # Green is bit_flag with value (1u << 1)
+ Green = 2
+ # \brief color Blue (1u << 3)
+ Blue = 8
+
diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs
new file mode 100644
index 0000000..5dc669e
--- /dev/null
+++ b/tests/MyGame/Example/Monster.cs
@@ -0,0 +1,324 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+/// an example documentation comment: monster object
+public struct Monster : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
+ public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool MonsterBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "MONS"); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public MyGame.Example.Vec3? Pos { get { int o = __p.__offset(4); return o != 0 ? (MyGame.Example.Vec3?)(new MyGame.Example.Vec3()).__assign(o + __p.bb_pos, __p.bb) : null; } }
+ public short Mana { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)150; } }
+ public bool MutateMana(short mana) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, mana); return true; } else { return false; } }
+ public short Hp { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)100; } }
+ public bool MutateHp(short hp) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, hp); return true; } else { return false; } }
+ public string Name { get { int o = __p.__offset(10); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetNameBytes() { return __p.__vector_as_span(10); }
+#else
+ public ArraySegment<byte>? GetNameBytes() { return __p.__vector_as_arraysegment(10); }
+#endif
+ public byte[] GetNameArray() { return __p.__vector_as_array<byte>(10); }
+ public byte Inventory(int j) { int o = __p.__offset(14); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int InventoryLength { get { int o = __p.__offset(14); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetInventoryBytes() { return __p.__vector_as_span(14); }
+#else
+ public ArraySegment<byte>? GetInventoryBytes() { return __p.__vector_as_arraysegment(14); }
+#endif
+ public byte[] GetInventoryArray() { return __p.__vector_as_array<byte>(14); }
+ public bool MutateInventory(int j, byte inventory) { int o = __p.__offset(14); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, inventory); return true; } else { return false; } }
+ public MyGame.Example.Color Color { get { int o = __p.__offset(16); return o != 0 ? (MyGame.Example.Color)__p.bb.Get(o + __p.bb_pos) : MyGame.Example.Color.Blue; } }
+ public bool MutateColor(MyGame.Example.Color color) { int o = __p.__offset(16); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)color); return true; } else { return false; } }
+ public MyGame.Example.Any TestType { get { int o = __p.__offset(18); return o != 0 ? (MyGame.Example.Any)__p.bb.Get(o + __p.bb_pos) : MyGame.Example.Any.NONE; } }
+ public bool MutateTestType(MyGame.Example.Any test_type) { int o = __p.__offset(18); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)test_type); return true; } else { return false; } }
+ public TTable? Test<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(20); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
+ public MyGame.Example.Test? Test4(int j) { int o = __p.__offset(22); return o != 0 ? (MyGame.Example.Test?)(new MyGame.Example.Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
+ public int Test4Length { get { int o = __p.__offset(22); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public string Testarrayofstring(int j) { int o = __p.__offset(24); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
+ public int TestarrayofstringLength { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } }
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ public MyGame.Example.Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (MyGame.Example.Monster?)(new MyGame.Example.Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
+ public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public MyGame.Example.Monster? TestarrayoftablesByKey(string key) { int o = __p.__offset(26); return o != 0 ? MyGame.Example.Monster.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
+ public MyGame.Example.Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (MyGame.Example.Monster?)(new MyGame.Example.Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetTestnestedflatbufferBytes() { return __p.__vector_as_span(30); }
+#else
+ public ArraySegment<byte>? GetTestnestedflatbufferBytes() { return __p.__vector_as_arraysegment(30); }
+#endif
+ public byte[] GetTestnestedflatbufferArray() { return __p.__vector_as_array<byte>(30); }
+ public MyGame.Example.Monster? GetTestnestedflatbufferAsMonster() { int o = __p.__offset(30); return o != 0 ? (MyGame.Example.Monster?)(new MyGame.Example.Monster()).__assign(__p.__indirect(__p.__vector(o)), __p.bb) : null; }
+ public bool MutateTestnestedflatbuffer(int j, byte testnestedflatbuffer) { int o = __p.__offset(30); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, testnestedflatbuffer); return true; } else { return false; } }
+ public MyGame.Example.Stat? Testempty { get { int o = __p.__offset(32); return o != 0 ? (MyGame.Example.Stat?)(new MyGame.Example.Stat()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public bool Testbool { get { int o = __p.__offset(34); return o != 0 ? 0!=__p.bb.Get(o + __p.bb_pos) : (bool)false; } }
+ public bool MutateTestbool(bool testbool) { int o = __p.__offset(34); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
+ public int Testhashs32Fnv1 { get { int o = __p.__offset(36); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __p.__offset(36); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, testhashs32_fnv1); return true; } else { return false; } }
+ public uint Testhashu32Fnv1 { get { int o = __p.__offset(38); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
+ public bool MutateTesthashu32Fnv1(uint testhashu32_fnv1) { int o = __p.__offset(38); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, testhashu32_fnv1); return true; } else { return false; } }
+ public long Testhashs64Fnv1 { get { int o = __p.__offset(40); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __p.__offset(40); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, testhashs64_fnv1); return true; } else { return false; } }
+ public ulong Testhashu64Fnv1 { get { int o = __p.__offset(42); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateTesthashu64Fnv1(ulong testhashu64_fnv1) { int o = __p.__offset(42); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1); return true; } else { return false; } }
+ public int Testhashs32Fnv1a { get { int o = __p.__offset(44); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __p.__offset(44); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
+ public uint Testhashu32Fnv1a { get { int o = __p.__offset(46); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
+ public bool MutateTesthashu32Fnv1a(uint testhashu32_fnv1a) { int o = __p.__offset(46); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, testhashu32_fnv1a); return true; } else { return false; } }
+ public long Testhashs64Fnv1a { get { int o = __p.__offset(48); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __p.__offset(48); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
+ public ulong Testhashu64Fnv1a { get { int o = __p.__offset(50); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateTesthashu64Fnv1a(ulong testhashu64_fnv1a) { int o = __p.__offset(50); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
+ public bool Testarrayofbools(int j) { int o = __p.__offset(52); return o != 0 ? 0!=__p.bb.Get(__p.__vector(o) + j * 1) : false; }
+ public int TestarrayofboolsLength { get { int o = __p.__offset(52); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetTestarrayofboolsBytes() { return __p.__vector_as_span(52); }
+#else
+ public ArraySegment<byte>? GetTestarrayofboolsBytes() { return __p.__vector_as_arraysegment(52); }
+#endif
+ public bool[] GetTestarrayofboolsArray() { return __p.__vector_as_array<bool>(52); }
+ public bool MutateTestarrayofbools(int j, bool testarrayofbools) { int o = __p.__offset(52); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
+ public float Testf { get { int o = __p.__offset(54); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.14159f; } }
+ public bool MutateTestf(float testf) { int o = __p.__offset(54); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf); return true; } else { return false; } }
+ public float Testf2 { get { int o = __p.__offset(56); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)3.0f; } }
+ public bool MutateTestf2(float testf2) { int o = __p.__offset(56); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf2); return true; } else { return false; } }
+ public float Testf3 { get { int o = __p.__offset(58); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } }
+ public bool MutateTestf3(float testf3) { int o = __p.__offset(58); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf3); return true; } else { return false; } }
+ public string Testarrayofstring2(int j) { int o = __p.__offset(60); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
+ public int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public MyGame.Example.Ability? Testarrayofsortedstruct(int j) { int o = __p.__offset(62); return o != 0 ? (MyGame.Example.Ability?)(new MyGame.Example.Ability()).__assign(__p.__vector(o) + j * 8, __p.bb) : null; }
+ public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+ public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetFlexBytes() { return __p.__vector_as_span(64); }
+#else
+ public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(64); }
+#endif
+ public byte[] GetFlexArray() { return __p.__vector_as_array<byte>(64); }
+ public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } }
+ public MyGame.Example.Test? Test5(int j) { int o = __p.__offset(66); return o != 0 ? (MyGame.Example.Test?)(new MyGame.Example.Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
+ public int Test5Length { get { int o = __p.__offset(66); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public long VectorOfLongs(int j) { int o = __p.__offset(68); return o != 0 ? __p.bb.GetLong(__p.__vector(o) + j * 8) : (long)0; }
+ public int VectorOfLongsLength { get { int o = __p.__offset(68); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVectorOfLongsBytes() { return __p.__vector_as_span(68); }
+#else
+ public ArraySegment<byte>? GetVectorOfLongsBytes() { return __p.__vector_as_arraysegment(68); }
+#endif
+ public long[] GetVectorOfLongsArray() { return __p.__vector_as_array<long>(68); }
+ public bool MutateVectorOfLongs(int j, long vector_of_longs) { int o = __p.__offset(68); if (o != 0) { __p.bb.PutLong(__p.__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
+ public double VectorOfDoubles(int j) { int o = __p.__offset(70); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
+ public int VectorOfDoublesLength { get { int o = __p.__offset(70); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVectorOfDoublesBytes() { return __p.__vector_as_span(70); }
+#else
+ public ArraySegment<byte>? GetVectorOfDoublesBytes() { return __p.__vector_as_arraysegment(70); }
+#endif
+ public double[] GetVectorOfDoublesArray() { return __p.__vector_as_array<double>(70); }
+ public bool MutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __p.__offset(70); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
+ public MyGame.InParentNamespace? ParentNamespaceTest { get { int o = __p.__offset(72); return o != 0 ? (MyGame.InParentNamespace?)(new MyGame.InParentNamespace()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public MyGame.Example.Referrable? VectorOfReferrables(int j) { int o = __p.__offset(74); return o != 0 ? (MyGame.Example.Referrable?)(new MyGame.Example.Referrable()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
+ public int VectorOfReferrablesLength { get { int o = __p.__offset(74); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public MyGame.Example.Referrable? VectorOfReferrablesByKey(ulong key) { int o = __p.__offset(74); return o != 0 ? MyGame.Example.Referrable.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
+ public ulong SingleWeakReference { get { int o = __p.__offset(76); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateSingleWeakReference(ulong single_weak_reference) { int o = __p.__offset(76); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, single_weak_reference); return true; } else { return false; } }
+ public ulong VectorOfWeakReferences(int j) { int o = __p.__offset(78); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; }
+ public int VectorOfWeakReferencesLength { get { int o = __p.__offset(78); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVectorOfWeakReferencesBytes() { return __p.__vector_as_span(78); }
+#else
+ public ArraySegment<byte>? GetVectorOfWeakReferencesBytes() { return __p.__vector_as_arraysegment(78); }
+#endif
+ public ulong[] GetVectorOfWeakReferencesArray() { return __p.__vector_as_array<ulong>(78); }
+ public bool MutateVectorOfWeakReferences(int j, ulong vector_of_weak_references) { int o = __p.__offset(78); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_weak_references); return true; } else { return false; } }
+ public MyGame.Example.Referrable? VectorOfStrongReferrables(int j) { int o = __p.__offset(80); return o != 0 ? (MyGame.Example.Referrable?)(new MyGame.Example.Referrable()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
+ public int VectorOfStrongReferrablesLength { get { int o = __p.__offset(80); return o != 0 ? __p.__vector_len(o) : 0; } }
+ public MyGame.Example.Referrable? VectorOfStrongReferrablesByKey(ulong key) { int o = __p.__offset(80); return o != 0 ? MyGame.Example.Referrable.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
+ public ulong CoOwningReference { get { int o = __p.__offset(82); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateCoOwningReference(ulong co_owning_reference) { int o = __p.__offset(82); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, co_owning_reference); return true; } else { return false; } }
+ public ulong VectorOfCoOwningReferences(int j) { int o = __p.__offset(84); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; }
+ public int VectorOfCoOwningReferencesLength { get { int o = __p.__offset(84); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVectorOfCoOwningReferencesBytes() { return __p.__vector_as_span(84); }
+#else
+ public ArraySegment<byte>? GetVectorOfCoOwningReferencesBytes() { return __p.__vector_as_arraysegment(84); }
+#endif
+ public ulong[] GetVectorOfCoOwningReferencesArray() { return __p.__vector_as_array<ulong>(84); }
+ public bool MutateVectorOfCoOwningReferences(int j, ulong vector_of_co_owning_references) { int o = __p.__offset(84); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_co_owning_references); return true; } else { return false; } }
+ public ulong NonOwningReference { get { int o = __p.__offset(86); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateNonOwningReference(ulong non_owning_reference) { int o = __p.__offset(86); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, non_owning_reference); return true; } else { return false; } }
+ public ulong VectorOfNonOwningReferences(int j) { int o = __p.__offset(88); return o != 0 ? __p.bb.GetUlong(__p.__vector(o) + j * 8) : (ulong)0; }
+ public int VectorOfNonOwningReferencesLength { get { int o = __p.__offset(88); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVectorOfNonOwningReferencesBytes() { return __p.__vector_as_span(88); }
+#else
+ public ArraySegment<byte>? GetVectorOfNonOwningReferencesBytes() { return __p.__vector_as_arraysegment(88); }
+#endif
+ public ulong[] GetVectorOfNonOwningReferencesArray() { return __p.__vector_as_array<ulong>(88); }
+ public bool MutateVectorOfNonOwningReferences(int j, ulong vector_of_non_owning_references) { int o = __p.__offset(88); if (o != 0) { __p.bb.PutUlong(__p.__vector(o) + j * 8, vector_of_non_owning_references); return true; } else { return false; } }
+ public MyGame.Example.AnyUniqueAliases AnyUniqueType { get { int o = __p.__offset(90); return o != 0 ? (MyGame.Example.AnyUniqueAliases)__p.bb.Get(o + __p.bb_pos) : MyGame.Example.AnyUniqueAliases.NONE; } }
+ public bool MutateAnyUniqueType(MyGame.Example.AnyUniqueAliases any_unique_type) { int o = __p.__offset(90); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)any_unique_type); return true; } else { return false; } }
+ public TTable? AnyUnique<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(92); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
+ public MyGame.Example.AnyAmbiguousAliases AnyAmbiguousType { get { int o = __p.__offset(94); return o != 0 ? (MyGame.Example.AnyAmbiguousAliases)__p.bb.Get(o + __p.bb_pos) : MyGame.Example.AnyAmbiguousAliases.NONE; } }
+ public bool MutateAnyAmbiguousType(MyGame.Example.AnyAmbiguousAliases any_ambiguous_type) { int o = __p.__offset(94); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)any_ambiguous_type); return true; } else { return false; } }
+ public TTable? AnyAmbiguous<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(96); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
+ public MyGame.Example.Color VectorOfEnums(int j) { int o = __p.__offset(98); return o != 0 ? (MyGame.Example.Color)__p.bb.Get(__p.__vector(o) + j * 1) : (MyGame.Example.Color)0; }
+ public int VectorOfEnumsLength { get { int o = __p.__offset(98); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVectorOfEnumsBytes() { return __p.__vector_as_span(98); }
+#else
+ public ArraySegment<byte>? GetVectorOfEnumsBytes() { return __p.__vector_as_arraysegment(98); }
+#endif
+ public MyGame.Example.Color[] GetVectorOfEnumsArray() { return __p.__vector_as_array<MyGame.Example.Color>(98); }
+ public bool MutateVectorOfEnums(int j, MyGame.Example.Color vector_of_enums) { int o = __p.__offset(98); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)vector_of_enums); return true; } else { return false; } }
+
+ public static void StartMonster(FlatBufferBuilder builder) { builder.StartTable(48); }
+ public static void AddPos(FlatBufferBuilder builder, Offset<MyGame.Example.Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
+ public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
+ public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
+ public static void AddName(FlatBufferBuilder builder, StringOffset nameOffset) { builder.AddOffset(3, nameOffset.Value, 0); }
+ public static void AddInventory(FlatBufferBuilder builder, VectorOffset inventoryOffset) { builder.AddOffset(5, inventoryOffset.Value, 0); }
+ public static VectorOffset CreateInventoryVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateInventoryVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartInventoryVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddColor(FlatBufferBuilder builder, MyGame.Example.Color color) { builder.AddByte(6, (byte)color, 8); }
+ public static void AddTestType(FlatBufferBuilder builder, MyGame.Example.Any testType) { builder.AddByte(7, (byte)testType, 0); }
+ public static void AddTest(FlatBufferBuilder builder, int testOffset) { builder.AddOffset(8, testOffset, 0); }
+ public static void AddTest4(FlatBufferBuilder builder, VectorOffset test4Offset) { builder.AddOffset(9, test4Offset.Value, 0); }
+ public static void StartTest4Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 2); }
+ public static void AddTestarrayofstring(FlatBufferBuilder builder, VectorOffset testarrayofstringOffset) { builder.AddOffset(10, testarrayofstringOffset.Value, 0); }
+ public static VectorOffset CreateTestarrayofstringVector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
+ public static VectorOffset CreateTestarrayofstringVectorBlock(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartTestarrayofstringVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static void AddTestarrayoftables(FlatBufferBuilder builder, VectorOffset testarrayoftablesOffset) { builder.AddOffset(11, testarrayoftablesOffset.Value, 0); }
+ public static VectorOffset CreateTestarrayoftablesVector(FlatBufferBuilder builder, Offset<MyGame.Example.Monster>[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
+ public static VectorOffset CreateTestarrayoftablesVectorBlock(FlatBufferBuilder builder, Offset<MyGame.Example.Monster>[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static void AddEnemy(FlatBufferBuilder builder, Offset<MyGame.Example.Monster> enemyOffset) { builder.AddOffset(12, enemyOffset.Value, 0); }
+ public static void AddTestnestedflatbuffer(FlatBufferBuilder builder, VectorOffset testnestedflatbufferOffset) { builder.AddOffset(13, testnestedflatbufferOffset.Value, 0); }
+ public static VectorOffset CreateTestnestedflatbufferVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateTestnestedflatbufferVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddTestempty(FlatBufferBuilder builder, Offset<MyGame.Example.Stat> testemptyOffset) { builder.AddOffset(14, testemptyOffset.Value, 0); }
+ public static void AddTestbool(FlatBufferBuilder builder, bool testbool) { builder.AddBool(15, testbool, false); }
+ public static void AddTesthashs32Fnv1(FlatBufferBuilder builder, int testhashs32Fnv1) { builder.AddInt(16, testhashs32Fnv1, 0); }
+ public static void AddTesthashu32Fnv1(FlatBufferBuilder builder, uint testhashu32Fnv1) { builder.AddUint(17, testhashu32Fnv1, 0); }
+ public static void AddTesthashs64Fnv1(FlatBufferBuilder builder, long testhashs64Fnv1) { builder.AddLong(18, testhashs64Fnv1, 0); }
+ public static void AddTesthashu64Fnv1(FlatBufferBuilder builder, ulong testhashu64Fnv1) { builder.AddUlong(19, testhashu64Fnv1, 0); }
+ public static void AddTesthashs32Fnv1a(FlatBufferBuilder builder, int testhashs32Fnv1a) { builder.AddInt(20, testhashs32Fnv1a, 0); }
+ public static void AddTesthashu32Fnv1a(FlatBufferBuilder builder, uint testhashu32Fnv1a) { builder.AddUint(21, testhashu32Fnv1a, 0); }
+ public static void AddTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.AddLong(22, testhashs64Fnv1a, 0); }
+ public static void AddTesthashu64Fnv1a(FlatBufferBuilder builder, ulong testhashu64Fnv1a) { builder.AddUlong(23, testhashu64Fnv1a, 0); }
+ public static void AddTestarrayofbools(FlatBufferBuilder builder, VectorOffset testarrayofboolsOffset) { builder.AddOffset(24, testarrayofboolsOffset.Value, 0); }
+ public static VectorOffset CreateTestarrayofboolsVector(FlatBufferBuilder builder, bool[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddBool(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateTestarrayofboolsVectorBlock(FlatBufferBuilder builder, bool[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartTestarrayofboolsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddTestf(FlatBufferBuilder builder, float testf) { builder.AddFloat(25, testf, 3.14159f); }
+ public static void AddTestf2(FlatBufferBuilder builder, float testf2) { builder.AddFloat(26, testf2, 3.0f); }
+ public static void AddTestf3(FlatBufferBuilder builder, float testf3) { builder.AddFloat(27, testf3, 0.0f); }
+ public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); }
+ public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
+ public static VectorOffset CreateTestarrayofstring2VectorBlock(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static void AddTestarrayofsortedstruct(FlatBufferBuilder builder, VectorOffset testarrayofsortedstructOffset) { builder.AddOffset(29, testarrayofsortedstructOffset.Value, 0); }
+ public static void StartTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 4); }
+ public static void AddFlex(FlatBufferBuilder builder, VectorOffset flexOffset) { builder.AddOffset(30, flexOffset.Value, 0); }
+ public static VectorOffset CreateFlexVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateFlexVectorBlock(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddTest5(FlatBufferBuilder builder, VectorOffset test5Offset) { builder.AddOffset(31, test5Offset.Value, 0); }
+ public static void StartTest5Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 2); }
+ public static void AddVectorOfLongs(FlatBufferBuilder builder, VectorOffset vectorOfLongsOffset) { builder.AddOffset(32, vectorOfLongsOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfLongsVector(FlatBufferBuilder builder, long[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddLong(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfLongsVectorBlock(FlatBufferBuilder builder, long[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfLongsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static void AddVectorOfDoubles(FlatBufferBuilder builder, VectorOffset vectorOfDoublesOffset) { builder.AddOffset(33, vectorOfDoublesOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfDoublesVector(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddDouble(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfDoublesVectorBlock(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfDoublesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static void AddParentNamespaceTest(FlatBufferBuilder builder, Offset<MyGame.InParentNamespace> parentNamespaceTestOffset) { builder.AddOffset(34, parentNamespaceTestOffset.Value, 0); }
+ public static void AddVectorOfReferrables(FlatBufferBuilder builder, VectorOffset vectorOfReferrablesOffset) { builder.AddOffset(35, vectorOfReferrablesOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfReferrablesVector(FlatBufferBuilder builder, Offset<MyGame.Example.Referrable>[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfReferrablesVectorBlock(FlatBufferBuilder builder, Offset<MyGame.Example.Referrable>[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfReferrablesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static void AddSingleWeakReference(FlatBufferBuilder builder, ulong singleWeakReference) { builder.AddUlong(36, singleWeakReference, 0); }
+ public static void AddVectorOfWeakReferences(FlatBufferBuilder builder, VectorOffset vectorOfWeakReferencesOffset) { builder.AddOffset(37, vectorOfWeakReferencesOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfWeakReferencesVector(FlatBufferBuilder builder, ulong[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddUlong(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfWeakReferencesVectorBlock(FlatBufferBuilder builder, ulong[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfWeakReferencesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static void AddVectorOfStrongReferrables(FlatBufferBuilder builder, VectorOffset vectorOfStrongReferrablesOffset) { builder.AddOffset(38, vectorOfStrongReferrablesOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfStrongReferrablesVector(FlatBufferBuilder builder, Offset<MyGame.Example.Referrable>[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfStrongReferrablesVectorBlock(FlatBufferBuilder builder, Offset<MyGame.Example.Referrable>[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfStrongReferrablesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static void AddCoOwningReference(FlatBufferBuilder builder, ulong coOwningReference) { builder.AddUlong(39, coOwningReference, 0); }
+ public static void AddVectorOfCoOwningReferences(FlatBufferBuilder builder, VectorOffset vectorOfCoOwningReferencesOffset) { builder.AddOffset(40, vectorOfCoOwningReferencesOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfCoOwningReferencesVector(FlatBufferBuilder builder, ulong[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddUlong(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfCoOwningReferencesVectorBlock(FlatBufferBuilder builder, ulong[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfCoOwningReferencesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static void AddNonOwningReference(FlatBufferBuilder builder, ulong nonOwningReference) { builder.AddUlong(41, nonOwningReference, 0); }
+ public static void AddVectorOfNonOwningReferences(FlatBufferBuilder builder, VectorOffset vectorOfNonOwningReferencesOffset) { builder.AddOffset(42, vectorOfNonOwningReferencesOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfNonOwningReferencesVector(FlatBufferBuilder builder, ulong[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddUlong(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfNonOwningReferencesVectorBlock(FlatBufferBuilder builder, ulong[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfNonOwningReferencesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static void AddAnyUniqueType(FlatBufferBuilder builder, MyGame.Example.AnyUniqueAliases anyUniqueType) { builder.AddByte(43, (byte)anyUniqueType, 0); }
+ public static void AddAnyUnique(FlatBufferBuilder builder, int anyUniqueOffset) { builder.AddOffset(44, anyUniqueOffset, 0); }
+ public static void AddAnyAmbiguousType(FlatBufferBuilder builder, MyGame.Example.AnyAmbiguousAliases anyAmbiguousType) { builder.AddByte(45, (byte)anyAmbiguousType, 0); }
+ public static void AddAnyAmbiguous(FlatBufferBuilder builder, int anyAmbiguousOffset) { builder.AddOffset(46, anyAmbiguousOffset, 0); }
+ public static void AddVectorOfEnums(FlatBufferBuilder builder, VectorOffset vectorOfEnumsOffset) { builder.AddOffset(47, vectorOfEnumsOffset.Value, 0); }
+ public static VectorOffset CreateVectorOfEnumsVector(FlatBufferBuilder builder, MyGame.Example.Color[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte((byte)data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVectorOfEnumsVectorBlock(FlatBufferBuilder builder, MyGame.Example.Color[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartVectorOfEnumsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static Offset<MyGame.Example.Monster> EndMonster(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ builder.Required(o, 10); // name
+ return new Offset<MyGame.Example.Monster>(o);
+ }
+ public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<MyGame.Example.Monster> offset) { builder.Finish(offset.Value, "MONS"); }
+ public static void FinishSizePrefixedMonsterBuffer(FlatBufferBuilder builder, Offset<MyGame.Example.Monster> offset) { builder.FinishSizePrefixed(offset.Value, "MONS"); }
+
+ public static VectorOffset CreateSortedVectorOfMonster(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
+ Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer));
+ return builder.CreateVectorOfTables(offsets);
+ }
+
+ public static Monster? __lookup_by_key(int vectorLocation, string key, ByteBuffer bb) {
+ byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
+ int span = bb.GetInt(vectorLocation - 4);
+ int start = 0;
+ while (span != 0) {
+ int middle = span / 2;
+ int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
+ int comp = Table.CompareStrings(Table.__offset(10, bb.Length - tableOffset, bb), byteKey, bb);
+ if (comp > 0) {
+ span = middle;
+ } else if (comp < 0) {
+ middle++;
+ start += middle;
+ span -= middle;
+ } else {
+ return new Monster().__assign(tableOffset, bb);
+ }
+ }
+ return null;
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go
new file mode 100644
index 0000000..dabb596
--- /dev/null
+++ b/tests/MyGame/Example/Monster.go
@@ -0,0 +1,1018 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+
+ MyGame "MyGame"
+)
+
+/// an example documentation comment: monster object
+type Monster struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsMonster(buf []byte, offset flatbuffers.UOffsetT) *Monster {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &Monster{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Monster) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *Monster) Pos(obj *Vec3) *Vec3 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := o + rcv._tab.Pos
+ if obj == nil {
+ obj = new(Vec3)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *Monster) Mana() int16 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ return rcv._tab.GetInt16(o + rcv._tab.Pos)
+ }
+ return 150
+}
+
+func (rcv *Monster) MutateMana(n int16) bool {
+ return rcv._tab.MutateInt16Slot(6, n)
+}
+
+func (rcv *Monster) Hp() int16 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
+ if o != 0 {
+ return rcv._tab.GetInt16(o + rcv._tab.Pos)
+ }
+ return 100
+}
+
+func (rcv *Monster) MutateHp(n int16) bool {
+ return rcv._tab.MutateInt16Slot(8, n)
+}
+
+func (rcv *Monster) Name() []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
+ if o != 0 {
+ return rcv._tab.ByteVector(o + rcv._tab.Pos)
+ }
+ return nil
+}
+
+func (rcv *Monster) Inventory(j int) byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1))
+ }
+ return 0
+}
+
+func (rcv *Monster) InventoryLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) InventoryBytes() []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
+ if o != 0 {
+ return rcv._tab.ByteVector(o + rcv._tab.Pos)
+ }
+ return nil
+}
+
+func (rcv *Monster) MutateInventory(j int, n byte) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateByte(a+flatbuffers.UOffsetT(j*1), n)
+ }
+ return false
+}
+
+func (rcv *Monster) Color() Color {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
+ if o != 0 {
+ return Color(rcv._tab.GetByte(o + rcv._tab.Pos))
+ }
+ return 8
+}
+
+func (rcv *Monster) MutateColor(n Color) bool {
+ return rcv._tab.MutateByteSlot(16, byte(n))
+}
+
+func (rcv *Monster) TestType() Any {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
+ if o != 0 {
+ return Any(rcv._tab.GetByte(o + rcv._tab.Pos))
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTestType(n Any) bool {
+ return rcv._tab.MutateByteSlot(18, byte(n))
+}
+
+func (rcv *Monster) Test(obj *flatbuffers.Table) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(20))
+ if o != 0 {
+ rcv._tab.Union(obj, o)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) Test4(obj *Test, j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(22))
+ if o != 0 {
+ x := rcv._tab.Vector(o)
+ x += flatbuffers.UOffsetT(j) * 4
+ obj.Init(rcv._tab.Bytes, x)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) Test4Length() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(22))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) Testarrayofstring(j int) []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j*4))
+ }
+ return nil
+}
+
+func (rcv *Monster) TestarrayofstringLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+/// an example documentation comment: this will end up in the generated code
+/// multiline too
+func (rcv *Monster) Testarrayoftables(obj *Monster, j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+ if o != 0 {
+ x := rcv._tab.Vector(o)
+ x += flatbuffers.UOffsetT(j) * 4
+ x = rcv._tab.Indirect(x)
+ obj.Init(rcv._tab.Bytes, x)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) TestarrayoftablesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+/// an example documentation comment: this will end up in the generated code
+/// multiline too
+func (rcv *Monster) Enemy(obj *Monster) *Monster {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(28))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(Monster)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *Monster) Testnestedflatbuffer(j int) byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1))
+ }
+ return 0
+}
+
+func (rcv *Monster) TestnestedflatbufferLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) TestnestedflatbufferBytes() []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
+ if o != 0 {
+ return rcv._tab.ByteVector(o + rcv._tab.Pos)
+ }
+ return nil
+}
+
+func (rcv *Monster) MutateTestnestedflatbuffer(j int, n byte) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(30))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateByte(a+flatbuffers.UOffsetT(j*1), n)
+ }
+ return false
+}
+
+func (rcv *Monster) Testempty(obj *Stat) *Stat {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(32))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(Stat)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *Monster) Testbool() bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(34))
+ if o != 0 {
+ return rcv._tab.GetBool(o + rcv._tab.Pos)
+ }
+ return false
+}
+
+func (rcv *Monster) MutateTestbool(n bool) bool {
+ return rcv._tab.MutateBoolSlot(34, n)
+}
+
+func (rcv *Monster) Testhashs32Fnv1() int32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(36))
+ if o != 0 {
+ return rcv._tab.GetInt32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashs32Fnv1(n int32) bool {
+ return rcv._tab.MutateInt32Slot(36, n)
+}
+
+func (rcv *Monster) Testhashu32Fnv1() uint32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(38))
+ if o != 0 {
+ return rcv._tab.GetUint32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashu32Fnv1(n uint32) bool {
+ return rcv._tab.MutateUint32Slot(38, n)
+}
+
+func (rcv *Monster) Testhashs64Fnv1() int64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(40))
+ if o != 0 {
+ return rcv._tab.GetInt64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashs64Fnv1(n int64) bool {
+ return rcv._tab.MutateInt64Slot(40, n)
+}
+
+func (rcv *Monster) Testhashu64Fnv1() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(42))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashu64Fnv1(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(42, n)
+}
+
+func (rcv *Monster) Testhashs32Fnv1a() int32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(44))
+ if o != 0 {
+ return rcv._tab.GetInt32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashs32Fnv1a(n int32) bool {
+ return rcv._tab.MutateInt32Slot(44, n)
+}
+
+func (rcv *Monster) Testhashu32Fnv1a() uint32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(46))
+ if o != 0 {
+ return rcv._tab.GetUint32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashu32Fnv1a(n uint32) bool {
+ return rcv._tab.MutateUint32Slot(46, n)
+}
+
+func (rcv *Monster) Testhashs64Fnv1a() int64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(48))
+ if o != 0 {
+ return rcv._tab.GetInt64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashs64Fnv1a(n int64) bool {
+ return rcv._tab.MutateInt64Slot(48, n)
+}
+
+func (rcv *Monster) Testhashu64Fnv1a() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(50))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTesthashu64Fnv1a(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(50, n)
+}
+
+func (rcv *Monster) Testarrayofbools(j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(52))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetBool(a + flatbuffers.UOffsetT(j*1))
+ }
+ return false
+}
+
+func (rcv *Monster) TestarrayofboolsLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(52))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateTestarrayofbools(j int, n bool) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(52))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateBool(a+flatbuffers.UOffsetT(j*1), n)
+ }
+ return false
+}
+
+func (rcv *Monster) Testf() float32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(54))
+ if o != 0 {
+ return rcv._tab.GetFloat32(o + rcv._tab.Pos)
+ }
+ return 3.14159
+}
+
+func (rcv *Monster) MutateTestf(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(54, n)
+}
+
+func (rcv *Monster) Testf2() float32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(56))
+ if o != 0 {
+ return rcv._tab.GetFloat32(o + rcv._tab.Pos)
+ }
+ return 3.0
+}
+
+func (rcv *Monster) MutateTestf2(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(56, n)
+}
+
+func (rcv *Monster) Testf3() float32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(58))
+ if o != 0 {
+ return rcv._tab.GetFloat32(o + rcv._tab.Pos)
+ }
+ return 0.0
+}
+
+func (rcv *Monster) MutateTestf3(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(58, n)
+}
+
+func (rcv *Monster) Testarrayofstring2(j int) []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(60))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j*4))
+ }
+ return nil
+}
+
+func (rcv *Monster) Testarrayofstring2Length() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(60))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) Testarrayofsortedstruct(obj *Ability, j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
+ if o != 0 {
+ x := rcv._tab.Vector(o)
+ x += flatbuffers.UOffsetT(j) * 8
+ obj.Init(rcv._tab.Bytes, x)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) TestarrayofsortedstructLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) Flex(j int) byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1))
+ }
+ return 0
+}
+
+func (rcv *Monster) FlexLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) FlexBytes() []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+ if o != 0 {
+ return rcv._tab.ByteVector(o + rcv._tab.Pos)
+ }
+ return nil
+}
+
+func (rcv *Monster) MutateFlex(j int, n byte) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateByte(a+flatbuffers.UOffsetT(j*1), n)
+ }
+ return false
+}
+
+func (rcv *Monster) Test5(obj *Test, j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(66))
+ if o != 0 {
+ x := rcv._tab.Vector(o)
+ x += flatbuffers.UOffsetT(j) * 4
+ obj.Init(rcv._tab.Bytes, x)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) Test5Length() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(66))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfLongs(j int) int64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetInt64(a + flatbuffers.UOffsetT(j*8))
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfLongsLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateVectorOfLongs(j int, n int64) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateInt64(a+flatbuffers.UOffsetT(j*8), n)
+ }
+ return false
+}
+
+func (rcv *Monster) VectorOfDoubles(j int) float64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetFloat64(a + flatbuffers.UOffsetT(j*8))
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfDoublesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateVectorOfDoubles(j int, n float64) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateFloat64(a+flatbuffers.UOffsetT(j*8), n)
+ }
+ return false
+}
+
+func (rcv *Monster) ParentNamespaceTest(obj *MyGame.InParentNamespace) *MyGame.InParentNamespace {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(72))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(MyGame.InParentNamespace)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *Monster) VectorOfReferrables(obj *Referrable, j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(74))
+ if o != 0 {
+ x := rcv._tab.Vector(o)
+ x += flatbuffers.UOffsetT(j) * 4
+ x = rcv._tab.Indirect(x)
+ obj.Init(rcv._tab.Bytes, x)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) VectorOfReferrablesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(74))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) SingleWeakReference() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(76))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateSingleWeakReference(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(76, n)
+}
+
+func (rcv *Monster) VectorOfWeakReferences(j int) uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(78))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetUint64(a + flatbuffers.UOffsetT(j*8))
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfWeakReferencesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(78))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateVectorOfWeakReferences(j int, n uint64) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(78))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateUint64(a+flatbuffers.UOffsetT(j*8), n)
+ }
+ return false
+}
+
+func (rcv *Monster) VectorOfStrongReferrables(obj *Referrable, j int) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(80))
+ if o != 0 {
+ x := rcv._tab.Vector(o)
+ x += flatbuffers.UOffsetT(j) * 4
+ x = rcv._tab.Indirect(x)
+ obj.Init(rcv._tab.Bytes, x)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) VectorOfStrongReferrablesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(80))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) CoOwningReference() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(82))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateCoOwningReference(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(82, n)
+}
+
+func (rcv *Monster) VectorOfCoOwningReferences(j int) uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(84))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetUint64(a + flatbuffers.UOffsetT(j*8))
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfCoOwningReferencesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(84))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateVectorOfCoOwningReferences(j int, n uint64) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(84))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateUint64(a+flatbuffers.UOffsetT(j*8), n)
+ }
+ return false
+}
+
+func (rcv *Monster) NonOwningReference() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(86))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateNonOwningReference(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(86, n)
+}
+
+func (rcv *Monster) VectorOfNonOwningReferences(j int) uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(88))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetUint64(a + flatbuffers.UOffsetT(j*8))
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfNonOwningReferencesLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(88))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateVectorOfNonOwningReferences(j int, n uint64) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(88))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateUint64(a+flatbuffers.UOffsetT(j*8), n)
+ }
+ return false
+}
+
+func (rcv *Monster) AnyUniqueType() AnyUniqueAliases {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(90))
+ if o != 0 {
+ return AnyUniqueAliases(rcv._tab.GetByte(o + rcv._tab.Pos))
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateAnyUniqueType(n AnyUniqueAliases) bool {
+ return rcv._tab.MutateByteSlot(90, byte(n))
+}
+
+func (rcv *Monster) AnyUnique(obj *flatbuffers.Table) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(92))
+ if o != 0 {
+ rcv._tab.Union(obj, o)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) AnyAmbiguousType() AnyAmbiguousAliases {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(94))
+ if o != 0 {
+ return AnyAmbiguousAliases(rcv._tab.GetByte(o + rcv._tab.Pos))
+ }
+ return 0
+}
+
+func (rcv *Monster) MutateAnyAmbiguousType(n AnyAmbiguousAliases) bool {
+ return rcv._tab.MutateByteSlot(94, byte(n))
+}
+
+func (rcv *Monster) AnyAmbiguous(obj *flatbuffers.Table) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(96))
+ if o != 0 {
+ rcv._tab.Union(obj, o)
+ return true
+ }
+ return false
+}
+
+func (rcv *Monster) VectorOfEnums(j int) Color {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(98))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return Color(rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1)))
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfEnumsLength() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(98))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *Monster) VectorOfEnumsBytes() []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(98))
+ if o != 0 {
+ return rcv._tab.ByteVector(o + rcv._tab.Pos)
+ }
+ return nil
+}
+
+func (rcv *Monster) MutateVectorOfEnums(j int, n Color) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(98))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateByte(a+flatbuffers.UOffsetT(j*1), byte(n))
+ }
+ return false
+}
+
+func MonsterStart(builder *flatbuffers.Builder) {
+ builder.StartObject(48)
+}
+func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
+ builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0)
+}
+func MonsterAddMana(builder *flatbuffers.Builder, mana int16) {
+ builder.PrependInt16Slot(1, mana, 150)
+}
+func MonsterAddHp(builder *flatbuffers.Builder, hp int16) {
+ builder.PrependInt16Slot(2, hp, 100)
+}
+func MonsterAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(name), 0)
+}
+func MonsterAddInventory(builder *flatbuffers.Builder, inventory flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(5, flatbuffers.UOffsetT(inventory), 0)
+}
+func MonsterStartInventoryVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(1, numElems, 1)
+}
+func MonsterAddColor(builder *flatbuffers.Builder, color Color) {
+ builder.PrependByteSlot(6, byte(color), 8)
+}
+func MonsterAddTestType(builder *flatbuffers.Builder, testType Any) {
+ builder.PrependByteSlot(7, byte(testType), 0)
+}
+func MonsterAddTest(builder *flatbuffers.Builder, test flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(8, flatbuffers.UOffsetT(test), 0)
+}
+func MonsterAddTest4(builder *flatbuffers.Builder, test4 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(9, flatbuffers.UOffsetT(test4), 0)
+}
+func MonsterStartTest4Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 2)
+}
+func MonsterAddTestarrayofstring(builder *flatbuffers.Builder, testarrayofstring flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(10, flatbuffers.UOffsetT(testarrayofstring), 0)
+}
+func MonsterStartTestarrayofstringVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 4)
+}
+func MonsterAddTestarrayoftables(builder *flatbuffers.Builder, testarrayoftables flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(11, flatbuffers.UOffsetT(testarrayoftables), 0)
+}
+func MonsterStartTestarrayoftablesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 4)
+}
+func MonsterAddEnemy(builder *flatbuffers.Builder, enemy flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(12, flatbuffers.UOffsetT(enemy), 0)
+}
+func MonsterAddTestnestedflatbuffer(builder *flatbuffers.Builder, testnestedflatbuffer flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(13, flatbuffers.UOffsetT(testnestedflatbuffer), 0)
+}
+func MonsterStartTestnestedflatbufferVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(1, numElems, 1)
+}
+func MonsterAddTestempty(builder *flatbuffers.Builder, testempty flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(14, flatbuffers.UOffsetT(testempty), 0)
+}
+func MonsterAddTestbool(builder *flatbuffers.Builder, testbool bool) {
+ builder.PrependBoolSlot(15, testbool, false)
+}
+func MonsterAddTesthashs32Fnv1(builder *flatbuffers.Builder, testhashs32Fnv1 int32) {
+ builder.PrependInt32Slot(16, testhashs32Fnv1, 0)
+}
+func MonsterAddTesthashu32Fnv1(builder *flatbuffers.Builder, testhashu32Fnv1 uint32) {
+ builder.PrependUint32Slot(17, testhashu32Fnv1, 0)
+}
+func MonsterAddTesthashs64Fnv1(builder *flatbuffers.Builder, testhashs64Fnv1 int64) {
+ builder.PrependInt64Slot(18, testhashs64Fnv1, 0)
+}
+func MonsterAddTesthashu64Fnv1(builder *flatbuffers.Builder, testhashu64Fnv1 uint64) {
+ builder.PrependUint64Slot(19, testhashu64Fnv1, 0)
+}
+func MonsterAddTesthashs32Fnv1a(builder *flatbuffers.Builder, testhashs32Fnv1a int32) {
+ builder.PrependInt32Slot(20, testhashs32Fnv1a, 0)
+}
+func MonsterAddTesthashu32Fnv1a(builder *flatbuffers.Builder, testhashu32Fnv1a uint32) {
+ builder.PrependUint32Slot(21, testhashu32Fnv1a, 0)
+}
+func MonsterAddTesthashs64Fnv1a(builder *flatbuffers.Builder, testhashs64Fnv1a int64) {
+ builder.PrependInt64Slot(22, testhashs64Fnv1a, 0)
+}
+func MonsterAddTesthashu64Fnv1a(builder *flatbuffers.Builder, testhashu64Fnv1a uint64) {
+ builder.PrependUint64Slot(23, testhashu64Fnv1a, 0)
+}
+func MonsterAddTestarrayofbools(builder *flatbuffers.Builder, testarrayofbools flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(24, flatbuffers.UOffsetT(testarrayofbools), 0)
+}
+func MonsterStartTestarrayofboolsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(1, numElems, 1)
+}
+func MonsterAddTestf(builder *flatbuffers.Builder, testf float32) {
+ builder.PrependFloat32Slot(25, testf, 3.14159)
+}
+func MonsterAddTestf2(builder *flatbuffers.Builder, testf2 float32) {
+ builder.PrependFloat32Slot(26, testf2, 3.0)
+}
+func MonsterAddTestf3(builder *flatbuffers.Builder, testf3 float32) {
+ builder.PrependFloat32Slot(27, testf3, 0.0)
+}
+func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstring2 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(28, flatbuffers.UOffsetT(testarrayofstring2), 0)
+}
+func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 4)
+}
+func MonsterAddTestarrayofsortedstruct(builder *flatbuffers.Builder, testarrayofsortedstruct flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(29, flatbuffers.UOffsetT(testarrayofsortedstruct), 0)
+}
+func MonsterStartTestarrayofsortedstructVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 4)
+}
+func MonsterAddFlex(builder *flatbuffers.Builder, flex flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(30, flatbuffers.UOffsetT(flex), 0)
+}
+func MonsterStartFlexVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(1, numElems, 1)
+}
+func MonsterAddTest5(builder *flatbuffers.Builder, test5 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(31, flatbuffers.UOffsetT(test5), 0)
+}
+func MonsterStartTest5Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 2)
+}
+func MonsterAddVectorOfLongs(builder *flatbuffers.Builder, vectorOfLongs flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(32, flatbuffers.UOffsetT(vectorOfLongs), 0)
+}
+func MonsterStartVectorOfLongsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddVectorOfDoubles(builder *flatbuffers.Builder, vectorOfDoubles flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(33, flatbuffers.UOffsetT(vectorOfDoubles), 0)
+}
+func MonsterStartVectorOfDoublesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddParentNamespaceTest(builder *flatbuffers.Builder, parentNamespaceTest flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(34, flatbuffers.UOffsetT(parentNamespaceTest), 0)
+}
+func MonsterAddVectorOfReferrables(builder *flatbuffers.Builder, vectorOfReferrables flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(35, flatbuffers.UOffsetT(vectorOfReferrables), 0)
+}
+func MonsterStartVectorOfReferrablesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 4)
+}
+func MonsterAddSingleWeakReference(builder *flatbuffers.Builder, singleWeakReference uint64) {
+ builder.PrependUint64Slot(36, singleWeakReference, 0)
+}
+func MonsterAddVectorOfWeakReferences(builder *flatbuffers.Builder, vectorOfWeakReferences flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(37, flatbuffers.UOffsetT(vectorOfWeakReferences), 0)
+}
+func MonsterStartVectorOfWeakReferencesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddVectorOfStrongReferrables(builder *flatbuffers.Builder, vectorOfStrongReferrables flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(38, flatbuffers.UOffsetT(vectorOfStrongReferrables), 0)
+}
+func MonsterStartVectorOfStrongReferrablesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(4, numElems, 4)
+}
+func MonsterAddCoOwningReference(builder *flatbuffers.Builder, coOwningReference uint64) {
+ builder.PrependUint64Slot(39, coOwningReference, 0)
+}
+func MonsterAddVectorOfCoOwningReferences(builder *flatbuffers.Builder, vectorOfCoOwningReferences flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(40, flatbuffers.UOffsetT(vectorOfCoOwningReferences), 0)
+}
+func MonsterStartVectorOfCoOwningReferencesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddNonOwningReference(builder *flatbuffers.Builder, nonOwningReference uint64) {
+ builder.PrependUint64Slot(41, nonOwningReference, 0)
+}
+func MonsterAddVectorOfNonOwningReferences(builder *flatbuffers.Builder, vectorOfNonOwningReferences flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(42, flatbuffers.UOffsetT(vectorOfNonOwningReferences), 0)
+}
+func MonsterStartVectorOfNonOwningReferencesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddAnyUniqueType(builder *flatbuffers.Builder, anyUniqueType AnyUniqueAliases) {
+ builder.PrependByteSlot(43, byte(anyUniqueType), 0)
+}
+func MonsterAddAnyUnique(builder *flatbuffers.Builder, anyUnique flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(44, flatbuffers.UOffsetT(anyUnique), 0)
+}
+func MonsterAddAnyAmbiguousType(builder *flatbuffers.Builder, anyAmbiguousType AnyAmbiguousAliases) {
+ builder.PrependByteSlot(45, byte(anyAmbiguousType), 0)
+}
+func MonsterAddAnyAmbiguous(builder *flatbuffers.Builder, anyAmbiguous flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(46, flatbuffers.UOffsetT(anyAmbiguous), 0)
+}
+func MonsterAddVectorOfEnums(builder *flatbuffers.Builder, vectorOfEnums flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(47, flatbuffers.UOffsetT(vectorOfEnums), 0)
+}
+func MonsterStartVectorOfEnumsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(1, numElems, 1)
+}
+func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
new file mode 100644
index 0000000..34d7983
--- /dev/null
+++ b/tests/MyGame/Example/Monster.java
@@ -0,0 +1,276 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+/**
+ * an example documentation comment: monster object
+ */
+public final class Monster extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
+ public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public static boolean MonsterBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MONS"); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public MyGame.Example.Vec3 pos() { return pos(new MyGame.Example.Vec3()); }
+ public MyGame.Example.Vec3 pos(MyGame.Example.Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__assign(o + bb_pos, bb) : null; }
+ public short mana() { int o = __offset(6); return o != 0 ? bb.getShort(o + bb_pos) : 150; }
+ public boolean mutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.putShort(o + bb_pos, mana); return true; } else { return false; } }
+ public short hp() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 100; }
+ public boolean mutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, hp); return true; } else { return false; } }
+ public String name() { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; }
+ public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(10, 1); }
+ public ByteBuffer nameInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 10, 1); }
+ public int inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+ public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer inventoryAsByteBuffer() { return __vector_as_bytebuffer(14, 1); }
+ public ByteBuffer inventoryInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 14, 1); }
+ public boolean mutateInventory(int j, int inventory) { int o = __offset(14); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)inventory); return true; } else { return false; } }
+ public int color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 8; }
+ public boolean mutateColor(int color) { int o = __offset(16); if (o != 0) { bb.put(o + bb_pos, (byte)color); return true; } else { return false; } }
+ public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; }
+ public boolean mutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.put(o + bb_pos, test_type); return true; } else { return false; } }
+ public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; }
+ public MyGame.Example.Test test4(int j) { return test4(new MyGame.Example.Test(), j); }
+ public MyGame.Example.Test test4(MyGame.Example.Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__assign(__vector(o) + j * 4, bb) : null; }
+ public int test4Length() { int o = __offset(22); return o != 0 ? __vector_len(o) : 0; }
+ public String testarrayofstring(int j) { int o = __offset(24); return o != 0 ? __string(__vector(o) + j * 4) : null; }
+ public int testarrayofstringLength() { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; }
+ /**
+ * an example documentation comment: this will end up in the generated code
+ * multiline too
+ */
+ public MyGame.Example.Monster testarrayoftables(int j) { return testarrayoftables(new MyGame.Example.Monster(), j); }
+ public MyGame.Example.Monster testarrayoftables(MyGame.Example.Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; }
+ public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
+ public MyGame.Example.Monster testarrayoftablesByKey(String key) { int o = __offset(26); return o != 0 ? MyGame.Example.Monster.__lookup_by_key(null, __vector(o), key, bb) : null; }
+ public MyGame.Example.Monster testarrayoftablesByKey(MyGame.Example.Monster obj, String key) { int o = __offset(26); return o != 0 ? MyGame.Example.Monster.__lookup_by_key(obj, __vector(o), key, bb) : null; }
+ public MyGame.Example.Monster enemy() { return enemy(new MyGame.Example.Monster()); }
+ public MyGame.Example.Monster enemy(MyGame.Example.Monster obj) { int o = __offset(28); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+ public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+ public int testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer testnestedflatbufferAsByteBuffer() { return __vector_as_bytebuffer(30, 1); }
+ public ByteBuffer testnestedflatbufferInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 30, 1); }
+ public MyGame.Example.Monster testnestedflatbufferAsMonster() { return testnestedflatbufferAsMonster(new MyGame.Example.Monster()); }
+ public MyGame.Example.Monster testnestedflatbufferAsMonster(MyGame.Example.Monster obj) { int o = __offset(30); return o != 0 ? obj.__assign(__indirect(__vector(o)), bb) : null; }
+ public boolean mutateTestnestedflatbuffer(int j, int testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)testnestedflatbuffer); return true; } else { return false; } }
+ public MyGame.Example.Stat testempty() { return testempty(new MyGame.Example.Stat()); }
+ public MyGame.Example.Stat testempty(MyGame.Example.Stat obj) { int o = __offset(32); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+ public boolean testbool() { int o = __offset(34); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
+ public boolean mutateTestbool(boolean testbool) { int o = __offset(34); if (o != 0) { bb.put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
+ public int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+ public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } }
+ public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
+ public boolean mutateTesthashu32Fnv1(long testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1); return true; } else { return false; } }
+ public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } }
+ public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateTesthashu64Fnv1(long testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } }
+ public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+ public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
+ public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
+ public boolean mutateTesthashu32Fnv1a(long testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1a); return true; } else { return false; } }
+ public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
+ public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateTesthashu64Fnv1a(long testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
+ public boolean testarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.get(__vector(o) + j * 1) : false; }
+ public int testarrayofboolsLength() { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer testarrayofboolsAsByteBuffer() { return __vector_as_bytebuffer(52, 1); }
+ public ByteBuffer testarrayofboolsInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 52, 1); }
+ public boolean mutateTestarrayofbools(int j, boolean testarrayofbools) { int o = __offset(52); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
+ public float testf() { int o = __offset(54); return o != 0 ? bb.getFloat(o + bb_pos) : 3.14159f; }
+ public boolean mutateTestf(float testf) { int o = __offset(54); if (o != 0) { bb.putFloat(o + bb_pos, testf); return true; } else { return false; } }
+ public float testf2() { int o = __offset(56); return o != 0 ? bb.getFloat(o + bb_pos) : 3.0f; }
+ public boolean mutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.putFloat(o + bb_pos, testf2); return true; } else { return false; } }
+ public float testf3() { int o = __offset(58); return o != 0 ? bb.getFloat(o + bb_pos) : 0.0f; }
+ public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } }
+ public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
+ public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; }
+ public MyGame.Example.Ability testarrayofsortedstruct(int j) { return testarrayofsortedstruct(new MyGame.Example.Ability(), j); }
+ public MyGame.Example.Ability testarrayofsortedstruct(MyGame.Example.Ability obj, int j) { int o = __offset(62); return o != 0 ? obj.__assign(__vector(o) + j * 8, bb) : null; }
+ public int testarrayofsortedstructLength() { int o = __offset(62); return o != 0 ? __vector_len(o) : 0; }
+ public int flex(int j) { int o = __offset(64); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+ public int flexLength() { int o = __offset(64); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer flexAsByteBuffer() { return __vector_as_bytebuffer(64, 1); }
+ public ByteBuffer flexInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 64, 1); }
+ public boolean mutateFlex(int j, int flex) { int o = __offset(64); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)flex); return true; } else { return false; } }
+ public MyGame.Example.Test test5(int j) { return test5(new MyGame.Example.Test(), j); }
+ public MyGame.Example.Test test5(MyGame.Example.Test obj, int j) { int o = __offset(66); return o != 0 ? obj.__assign(__vector(o) + j * 4, bb) : null; }
+ public int test5Length() { int o = __offset(66); return o != 0 ? __vector_len(o) : 0; }
+ public long vectorOfLongs(int j) { int o = __offset(68); return o != 0 ? bb.getLong(__vector(o) + j * 8) : 0; }
+ public int vectorOfLongsLength() { int o = __offset(68); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vectorOfLongsAsByteBuffer() { return __vector_as_bytebuffer(68, 8); }
+ public ByteBuffer vectorOfLongsInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 68, 8); }
+ public boolean mutateVectorOfLongs(int j, long vector_of_longs) { int o = __offset(68); if (o != 0) { bb.putLong(__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
+ public double vectorOfDoubles(int j) { int o = __offset(70); return o != 0 ? bb.getDouble(__vector(o) + j * 8) : 0; }
+ public int vectorOfDoublesLength() { int o = __offset(70); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vectorOfDoublesAsByteBuffer() { return __vector_as_bytebuffer(70, 8); }
+ public ByteBuffer vectorOfDoublesInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 70, 8); }
+ public boolean mutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __offset(70); if (o != 0) { bb.putDouble(__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
+ public MyGame.InParentNamespace parentNamespaceTest() { return parentNamespaceTest(new MyGame.InParentNamespace()); }
+ public MyGame.InParentNamespace parentNamespaceTest(MyGame.InParentNamespace obj) { int o = __offset(72); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+ public MyGame.Example.Referrable vectorOfReferrables(int j) { return vectorOfReferrables(new MyGame.Example.Referrable(), j); }
+ public MyGame.Example.Referrable vectorOfReferrables(MyGame.Example.Referrable obj, int j) { int o = __offset(74); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; }
+ public int vectorOfReferrablesLength() { int o = __offset(74); return o != 0 ? __vector_len(o) : 0; }
+ public MyGame.Example.Referrable vectorOfReferrablesByKey(long key) { int o = __offset(74); return o != 0 ? MyGame.Example.Referrable.__lookup_by_key(null, __vector(o), key, bb) : null; }
+ public MyGame.Example.Referrable vectorOfReferrablesByKey(MyGame.Example.Referrable obj, long key) { int o = __offset(74); return o != 0 ? MyGame.Example.Referrable.__lookup_by_key(obj, __vector(o), key, bb) : null; }
+ public long singleWeakReference() { int o = __offset(76); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateSingleWeakReference(long single_weak_reference) { int o = __offset(76); if (o != 0) { bb.putLong(o + bb_pos, single_weak_reference); return true; } else { return false; } }
+ public long vectorOfWeakReferences(int j) { int o = __offset(78); return o != 0 ? bb.getLong(__vector(o) + j * 8) : 0; }
+ public int vectorOfWeakReferencesLength() { int o = __offset(78); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vectorOfWeakReferencesAsByteBuffer() { return __vector_as_bytebuffer(78, 8); }
+ public ByteBuffer vectorOfWeakReferencesInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 78, 8); }
+ public boolean mutateVectorOfWeakReferences(int j, long vector_of_weak_references) { int o = __offset(78); if (o != 0) { bb.putLong(__vector(o) + j * 8, vector_of_weak_references); return true; } else { return false; } }
+ public MyGame.Example.Referrable vectorOfStrongReferrables(int j) { return vectorOfStrongReferrables(new MyGame.Example.Referrable(), j); }
+ public MyGame.Example.Referrable vectorOfStrongReferrables(MyGame.Example.Referrable obj, int j) { int o = __offset(80); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; }
+ public int vectorOfStrongReferrablesLength() { int o = __offset(80); return o != 0 ? __vector_len(o) : 0; }
+ public MyGame.Example.Referrable vectorOfStrongReferrablesByKey(long key) { int o = __offset(80); return o != 0 ? MyGame.Example.Referrable.__lookup_by_key(null, __vector(o), key, bb) : null; }
+ public MyGame.Example.Referrable vectorOfStrongReferrablesByKey(MyGame.Example.Referrable obj, long key) { int o = __offset(80); return o != 0 ? MyGame.Example.Referrable.__lookup_by_key(obj, __vector(o), key, bb) : null; }
+ public long coOwningReference() { int o = __offset(82); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateCoOwningReference(long co_owning_reference) { int o = __offset(82); if (o != 0) { bb.putLong(o + bb_pos, co_owning_reference); return true; } else { return false; } }
+ public long vectorOfCoOwningReferences(int j) { int o = __offset(84); return o != 0 ? bb.getLong(__vector(o) + j * 8) : 0; }
+ public int vectorOfCoOwningReferencesLength() { int o = __offset(84); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vectorOfCoOwningReferencesAsByteBuffer() { return __vector_as_bytebuffer(84, 8); }
+ public ByteBuffer vectorOfCoOwningReferencesInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 84, 8); }
+ public boolean mutateVectorOfCoOwningReferences(int j, long vector_of_co_owning_references) { int o = __offset(84); if (o != 0) { bb.putLong(__vector(o) + j * 8, vector_of_co_owning_references); return true; } else { return false; } }
+ public long nonOwningReference() { int o = __offset(86); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateNonOwningReference(long non_owning_reference) { int o = __offset(86); if (o != 0) { bb.putLong(o + bb_pos, non_owning_reference); return true; } else { return false; } }
+ public long vectorOfNonOwningReferences(int j) { int o = __offset(88); return o != 0 ? bb.getLong(__vector(o) + j * 8) : 0; }
+ public int vectorOfNonOwningReferencesLength() { int o = __offset(88); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vectorOfNonOwningReferencesAsByteBuffer() { return __vector_as_bytebuffer(88, 8); }
+ public ByteBuffer vectorOfNonOwningReferencesInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 88, 8); }
+ public boolean mutateVectorOfNonOwningReferences(int j, long vector_of_non_owning_references) { int o = __offset(88); if (o != 0) { bb.putLong(__vector(o) + j * 8, vector_of_non_owning_references); return true; } else { return false; } }
+ public byte anyUniqueType() { int o = __offset(90); return o != 0 ? bb.get(o + bb_pos) : 0; }
+ public boolean mutateAnyUniqueType(byte any_unique_type) { int o = __offset(90); if (o != 0) { bb.put(o + bb_pos, any_unique_type); return true; } else { return false; } }
+ public Table anyUnique(Table obj) { int o = __offset(92); return o != 0 ? __union(obj, o) : null; }
+ public byte anyAmbiguousType() { int o = __offset(94); return o != 0 ? bb.get(o + bb_pos) : 0; }
+ public boolean mutateAnyAmbiguousType(byte any_ambiguous_type) { int o = __offset(94); if (o != 0) { bb.put(o + bb_pos, any_ambiguous_type); return true; } else { return false; } }
+ public Table anyAmbiguous(Table obj) { int o = __offset(96); return o != 0 ? __union(obj, o) : null; }
+ public int vectorOfEnums(int j) { int o = __offset(98); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+ public int vectorOfEnumsLength() { int o = __offset(98); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vectorOfEnumsAsByteBuffer() { return __vector_as_bytebuffer(98, 1); }
+ public ByteBuffer vectorOfEnumsInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 98, 1); }
+ public boolean mutateVectorOfEnums(int j, int vector_of_enums) { int o = __offset(98); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)vector_of_enums); return true; } else { return false; } }
+
+ public static void startMonster(FlatBufferBuilder builder) { builder.startTable(48); }
+ public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
+ public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
+ public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
+ public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(3, nameOffset, 0); }
+ public static void addInventory(FlatBufferBuilder builder, int inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); }
+ public static int createInventoryVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+ public static void startInventoryVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static void addColor(FlatBufferBuilder builder, int color) { builder.addByte(6, (byte)color, (byte)8); }
+ public static void addTestType(FlatBufferBuilder builder, byte testType) { builder.addByte(7, testType, 0); }
+ public static void addTest(FlatBufferBuilder builder, int testOffset) { builder.addOffset(8, testOffset, 0); }
+ public static void addTest4(FlatBufferBuilder builder, int test4Offset) { builder.addOffset(9, test4Offset, 0); }
+ public static void startTest4Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); }
+ public static void addTestarrayofstring(FlatBufferBuilder builder, int testarrayofstringOffset) { builder.addOffset(10, testarrayofstringOffset, 0); }
+ public static int createTestarrayofstringVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startTestarrayofstringVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static void addTestarrayoftables(FlatBufferBuilder builder, int testarrayoftablesOffset) { builder.addOffset(11, testarrayoftablesOffset, 0); }
+ public static int createTestarrayoftablesVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static void addEnemy(FlatBufferBuilder builder, int enemyOffset) { builder.addOffset(12, enemyOffset, 0); }
+ public static void addTestnestedflatbuffer(FlatBufferBuilder builder, int testnestedflatbufferOffset) { builder.addOffset(13, testnestedflatbufferOffset, 0); }
+ public static int createTestnestedflatbufferVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+ public static void startTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static void addTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.addOffset(14, testemptyOffset, 0); }
+ public static void addTestbool(FlatBufferBuilder builder, boolean testbool) { builder.addBoolean(15, testbool, false); }
+ public static void addTesthashs32Fnv1(FlatBufferBuilder builder, int testhashs32Fnv1) { builder.addInt(16, testhashs32Fnv1, 0); }
+ public static void addTesthashu32Fnv1(FlatBufferBuilder builder, long testhashu32Fnv1) { builder.addInt(17, (int)testhashu32Fnv1, (int)0L); }
+ public static void addTesthashs64Fnv1(FlatBufferBuilder builder, long testhashs64Fnv1) { builder.addLong(18, testhashs64Fnv1, 0L); }
+ public static void addTesthashu64Fnv1(FlatBufferBuilder builder, long testhashu64Fnv1) { builder.addLong(19, testhashu64Fnv1, 0L); }
+ public static void addTesthashs32Fnv1a(FlatBufferBuilder builder, int testhashs32Fnv1a) { builder.addInt(20, testhashs32Fnv1a, 0); }
+ public static void addTesthashu32Fnv1a(FlatBufferBuilder builder, long testhashu32Fnv1a) { builder.addInt(21, (int)testhashu32Fnv1a, (int)0L); }
+ public static void addTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.addLong(22, testhashs64Fnv1a, 0L); }
+ public static void addTesthashu64Fnv1a(FlatBufferBuilder builder, long testhashu64Fnv1a) { builder.addLong(23, testhashu64Fnv1a, 0L); }
+ public static void addTestarrayofbools(FlatBufferBuilder builder, int testarrayofboolsOffset) { builder.addOffset(24, testarrayofboolsOffset, 0); }
+ public static int createTestarrayofboolsVector(FlatBufferBuilder builder, boolean[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addBoolean(data[i]); return builder.endVector(); }
+ public static void startTestarrayofboolsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static void addTestf(FlatBufferBuilder builder, float testf) { builder.addFloat(25, testf, 3.14159f); }
+ public static void addTestf2(FlatBufferBuilder builder, float testf2) { builder.addFloat(26, testf2, 3.0f); }
+ public static void addTestf3(FlatBufferBuilder builder, float testf3) { builder.addFloat(27, testf3, 0.0f); }
+ public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); }
+ public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static void addTestarrayofsortedstruct(FlatBufferBuilder builder, int testarrayofsortedstructOffset) { builder.addOffset(29, testarrayofsortedstructOffset, 0); }
+ public static void startTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 4); }
+ public static void addFlex(FlatBufferBuilder builder, int flexOffset) { builder.addOffset(30, flexOffset, 0); }
+ public static int createFlexVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+ public static void startFlexVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static void addTest5(FlatBufferBuilder builder, int test5Offset) { builder.addOffset(31, test5Offset, 0); }
+ public static void startTest5Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); }
+ public static void addVectorOfLongs(FlatBufferBuilder builder, int vectorOfLongsOffset) { builder.addOffset(32, vectorOfLongsOffset, 0); }
+ public static int createVectorOfLongsVector(FlatBufferBuilder builder, long[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addLong(data[i]); return builder.endVector(); }
+ public static void startVectorOfLongsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static void addVectorOfDoubles(FlatBufferBuilder builder, int vectorOfDoublesOffset) { builder.addOffset(33, vectorOfDoublesOffset, 0); }
+ public static int createVectorOfDoublesVector(FlatBufferBuilder builder, double[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addDouble(data[i]); return builder.endVector(); }
+ public static void startVectorOfDoublesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static void addParentNamespaceTest(FlatBufferBuilder builder, int parentNamespaceTestOffset) { builder.addOffset(34, parentNamespaceTestOffset, 0); }
+ public static void addVectorOfReferrables(FlatBufferBuilder builder, int vectorOfReferrablesOffset) { builder.addOffset(35, vectorOfReferrablesOffset, 0); }
+ public static int createVectorOfReferrablesVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startVectorOfReferrablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static void addSingleWeakReference(FlatBufferBuilder builder, long singleWeakReference) { builder.addLong(36, singleWeakReference, 0L); }
+ public static void addVectorOfWeakReferences(FlatBufferBuilder builder, int vectorOfWeakReferencesOffset) { builder.addOffset(37, vectorOfWeakReferencesOffset, 0); }
+ public static int createVectorOfWeakReferencesVector(FlatBufferBuilder builder, long[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addLong(data[i]); return builder.endVector(); }
+ public static void startVectorOfWeakReferencesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static void addVectorOfStrongReferrables(FlatBufferBuilder builder, int vectorOfStrongReferrablesOffset) { builder.addOffset(38, vectorOfStrongReferrablesOffset, 0); }
+ public static int createVectorOfStrongReferrablesVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startVectorOfStrongReferrablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static void addCoOwningReference(FlatBufferBuilder builder, long coOwningReference) { builder.addLong(39, coOwningReference, 0L); }
+ public static void addVectorOfCoOwningReferences(FlatBufferBuilder builder, int vectorOfCoOwningReferencesOffset) { builder.addOffset(40, vectorOfCoOwningReferencesOffset, 0); }
+ public static int createVectorOfCoOwningReferencesVector(FlatBufferBuilder builder, long[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addLong(data[i]); return builder.endVector(); }
+ public static void startVectorOfCoOwningReferencesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static void addNonOwningReference(FlatBufferBuilder builder, long nonOwningReference) { builder.addLong(41, nonOwningReference, 0L); }
+ public static void addVectorOfNonOwningReferences(FlatBufferBuilder builder, int vectorOfNonOwningReferencesOffset) { builder.addOffset(42, vectorOfNonOwningReferencesOffset, 0); }
+ public static int createVectorOfNonOwningReferencesVector(FlatBufferBuilder builder, long[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addLong(data[i]); return builder.endVector(); }
+ public static void startVectorOfNonOwningReferencesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static void addAnyUniqueType(FlatBufferBuilder builder, byte anyUniqueType) { builder.addByte(43, anyUniqueType, 0); }
+ public static void addAnyUnique(FlatBufferBuilder builder, int anyUniqueOffset) { builder.addOffset(44, anyUniqueOffset, 0); }
+ public static void addAnyAmbiguousType(FlatBufferBuilder builder, byte anyAmbiguousType) { builder.addByte(45, anyAmbiguousType, 0); }
+ public static void addAnyAmbiguous(FlatBufferBuilder builder, int anyAmbiguousOffset) { builder.addOffset(46, anyAmbiguousOffset, 0); }
+ public static void addVectorOfEnums(FlatBufferBuilder builder, int vectorOfEnumsOffset) { builder.addOffset(47, vectorOfEnumsOffset, 0); }
+ public static int createVectorOfEnumsVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+ public static void startVectorOfEnumsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static int endMonster(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ builder.required(o, 10); // name
+ return o;
+ }
+ public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); }
+ public static void finishSizePrefixedMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finishSizePrefixed(offset, "MONS"); }
+
+ @Override
+ protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); }
+
+ public static Monster __lookup_by_key(Monster obj, int vectorLocation, String key, ByteBuffer bb) {
+ byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get());
+ int span = bb.getInt(vectorLocation - 4);
+ int start = 0;
+ while (span != 0) {
+ int middle = span / 2;
+ int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);
+ int comp = compareStrings(__offset(10, bb.capacity() - tableOffset, bb), byteKey, bb);
+ if (comp > 0) {
+ span = middle;
+ } else if (comp < 0) {
+ middle++;
+ start += middle;
+ span -= middle;
+ } else {
+ return (obj == null ? new Monster() : obj).__assign(tableOffset, bb);
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/tests/MyGame/Example/Monster.kt b/tests/MyGame/Example/Monster.kt
new file mode 100644
index 0000000..71d72b8
--- /dev/null
+++ b/tests/MyGame/Example/Monster.kt
@@ -0,0 +1,974 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+/**
+ * an example documentation comment: monster object
+ */
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Monster : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Monster {
+ __init(_i, _bb)
+ return this
+ }
+ val pos : MyGame.Example.Vec3? get() = pos(MyGame.Example.Vec3())
+ fun pos(obj: MyGame.Example.Vec3) : MyGame.Example.Vec3? {
+ val o = __offset(4)
+ return if (o != 0) {
+ obj.__assign(o + bb_pos, bb)
+ } else {
+ null
+ }
+ }
+ val mana : Short
+ get() {
+ val o = __offset(6)
+ return if(o != 0) bb.getShort(o + bb_pos) else 150
+ }
+ fun mutateMana(mana: Short) : Boolean {
+ val o = __offset(6)
+ return if (o != 0) {
+ bb.putShort(o + bb_pos, mana)
+ true
+ } else {
+ false
+ }
+ }
+ val hp : Short
+ get() {
+ val o = __offset(8)
+ return if(o != 0) bb.getShort(o + bb_pos) else 100
+ }
+ fun mutateHp(hp: Short) : Boolean {
+ val o = __offset(8)
+ return if (o != 0) {
+ bb.putShort(o + bb_pos, hp)
+ true
+ } else {
+ false
+ }
+ }
+ val name : String?
+ get() {
+ val o = __offset(10)
+ return if (o != 0) __string(o + bb_pos) else null
+ }
+ val nameAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(10, 1)
+ fun nameInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 10, 1)
+ fun inventory(j: Int) : UByte {
+ val o = __offset(14)
+ return if (o != 0) {
+ bb.get(__vector(o) + j * 1).toUByte()
+ } else {
+ 0u
+ }
+ }
+ val inventoryLength : Int
+ get() {
+ val o = __offset(14); return if (o != 0) __vector_len(o) else 0
+ }
+ val inventoryAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(14, 1)
+ fun inventoryInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 14, 1)
+ fun mutateInventory(j: Int, inventory: UByte) : Boolean {
+ val o = __offset(14)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, inventory.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ val color : UByte
+ get() {
+ val o = __offset(16)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 8u
+ }
+ fun mutateColor(color: UByte) : Boolean {
+ val o = __offset(16)
+ return if (o != 0) {
+ bb.put(o + bb_pos, color.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ val testType : UByte
+ get() {
+ val o = __offset(18)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u
+ }
+ fun mutateTestType(testType: UByte) : Boolean {
+ val o = __offset(18)
+ return if (o != 0) {
+ bb.put(o + bb_pos, testType.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ fun test(obj: Table) : Table? {
+ val o = __offset(20); return if (o != 0) __union(obj, o) else null
+ }
+ fun test4(j: Int) : MyGame.Example.Test? = test4(MyGame.Example.Test(), j)
+ fun test4(obj: MyGame.Example.Test, j: Int) : MyGame.Example.Test? {
+ val o = __offset(22)
+ return if (o != 0) {
+ obj.__assign(__vector(o) + j * 4, bb)
+ } else {
+ null
+ }
+ }
+ val test4Length : Int
+ get() {
+ val o = __offset(22); return if (o != 0) __vector_len(o) else 0
+ }
+ fun testarrayofstring(j: Int) : String? {
+ val o = __offset(24)
+ return if (o != 0) {
+ __string(__vector(o) + j * 4)
+ } else {
+ null
+ }
+ }
+ val testarrayofstringLength : Int
+ get() {
+ val o = __offset(24); return if (o != 0) __vector_len(o) else 0
+ }
+ /**
+ * an example documentation comment: this will end up in the generated code
+ * multiline too
+ */
+ fun testarrayoftables(j: Int) : MyGame.Example.Monster? = testarrayoftables(MyGame.Example.Monster(), j)
+ fun testarrayoftables(obj: MyGame.Example.Monster, j: Int) : MyGame.Example.Monster? {
+ val o = __offset(26)
+ return if (o != 0) {
+ obj.__assign(__indirect(__vector(o) + j * 4), bb)
+ } else {
+ null
+ }
+ }
+ val testarrayoftablesLength : Int
+ get() {
+ val o = __offset(26); return if (o != 0) __vector_len(o) else 0
+ }
+ fun testarrayoftablesByKey(key: String) : MyGame.Example.Monster? {
+ val o = __offset(26)
+ return if (o != 0) {
+ MyGame.Example.Monster.__lookup_by_key(null, __vector(o), key, bb)
+ } else {
+ null
+ }
+ }
+ fun testarrayoftablesByKey(obj: MyGame.Example.Monster, key: String) : MyGame.Example.Monster? {
+ val o = __offset(26)
+ return if (o != 0) {
+ MyGame.Example.Monster.__lookup_by_key(obj, __vector(o), key, bb)
+ } else {
+ null
+ }
+ }
+ val enemy : MyGame.Example.Monster? get() = enemy(MyGame.Example.Monster())
+ fun enemy(obj: MyGame.Example.Monster) : MyGame.Example.Monster? {
+ val o = __offset(28)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ fun testnestedflatbuffer(j: Int) : UByte {
+ val o = __offset(30)
+ return if (o != 0) {
+ bb.get(__vector(o) + j * 1).toUByte()
+ } else {
+ 0u
+ }
+ }
+ val testnestedflatbufferLength : Int
+ get() {
+ val o = __offset(30); return if (o != 0) __vector_len(o) else 0
+ }
+ val testnestedflatbufferAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(30, 1)
+ fun testnestedflatbufferInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 30, 1)
+ val testnestedflatbufferAsMonster : MyGame.Example.Monster? get() = testnestedflatbufferAsMonster(MyGame.Example.Monster())
+ fun testnestedflatbufferAsMonster(obj: MyGame.Example.Monster) : MyGame.Example.Monster? {
+ val o = __offset(30)
+ return if (o != 0) {
+ obj.__assign(__indirect(__vector(o)), bb)
+ } else {
+ null
+ }
+ }
+ fun mutateTestnestedflatbuffer(j: Int, testnestedflatbuffer: UByte) : Boolean {
+ val o = __offset(30)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, testnestedflatbuffer.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ val testempty : MyGame.Example.Stat? get() = testempty(MyGame.Example.Stat())
+ fun testempty(obj: MyGame.Example.Stat) : MyGame.Example.Stat? {
+ val o = __offset(32)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ val testbool : Boolean
+ get() {
+ val o = __offset(34)
+ return if(o != 0) 0.toByte() != bb.get(o + bb_pos) else false
+ }
+ fun mutateTestbool(testbool: Boolean) : Boolean {
+ val o = __offset(34)
+ return if (o != 0) {
+ bb.put(o + bb_pos, (if(testbool) 1 else 0).toByte())
+ true
+ } else {
+ false
+ }
+ }
+ val testhashs32Fnv1 : Int
+ get() {
+ val o = __offset(36)
+ return if(o != 0) bb.getInt(o + bb_pos) else 0
+ }
+ fun mutateTesthashs32Fnv1(testhashs32Fnv1: Int) : Boolean {
+ val o = __offset(36)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, testhashs32Fnv1)
+ true
+ } else {
+ false
+ }
+ }
+ val testhashu32Fnv1 : UInt
+ get() {
+ val o = __offset(38)
+ return if(o != 0) bb.getInt(o + bb_pos).toUInt() else 0u
+ }
+ fun mutateTesthashu32Fnv1(testhashu32Fnv1: UInt) : Boolean {
+ val o = __offset(38)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, testhashu32Fnv1.toInt())
+ true
+ } else {
+ false
+ }
+ }
+ val testhashs64Fnv1 : Long
+ get() {
+ val o = __offset(40)
+ return if(o != 0) bb.getLong(o + bb_pos) else 0L
+ }
+ fun mutateTesthashs64Fnv1(testhashs64Fnv1: Long) : Boolean {
+ val o = __offset(40)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, testhashs64Fnv1)
+ true
+ } else {
+ false
+ }
+ }
+ val testhashu64Fnv1 : ULong
+ get() {
+ val o = __offset(42)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateTesthashu64Fnv1(testhashu64Fnv1: ULong) : Boolean {
+ val o = __offset(42)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, testhashu64Fnv1.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ val testhashs32Fnv1a : Int
+ get() {
+ val o = __offset(44)
+ return if(o != 0) bb.getInt(o + bb_pos) else 0
+ }
+ fun mutateTesthashs32Fnv1a(testhashs32Fnv1a: Int) : Boolean {
+ val o = __offset(44)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, testhashs32Fnv1a)
+ true
+ } else {
+ false
+ }
+ }
+ val testhashu32Fnv1a : UInt
+ get() {
+ val o = __offset(46)
+ return if(o != 0) bb.getInt(o + bb_pos).toUInt() else 0u
+ }
+ fun mutateTesthashu32Fnv1a(testhashu32Fnv1a: UInt) : Boolean {
+ val o = __offset(46)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, testhashu32Fnv1a.toInt())
+ true
+ } else {
+ false
+ }
+ }
+ val testhashs64Fnv1a : Long
+ get() {
+ val o = __offset(48)
+ return if(o != 0) bb.getLong(o + bb_pos) else 0L
+ }
+ fun mutateTesthashs64Fnv1a(testhashs64Fnv1a: Long) : Boolean {
+ val o = __offset(48)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, testhashs64Fnv1a)
+ true
+ } else {
+ false
+ }
+ }
+ val testhashu64Fnv1a : ULong
+ get() {
+ val o = __offset(50)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateTesthashu64Fnv1a(testhashu64Fnv1a: ULong) : Boolean {
+ val o = __offset(50)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, testhashu64Fnv1a.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ fun testarrayofbools(j: Int) : Boolean {
+ val o = __offset(52)
+ return if (o != 0) {
+ 0.toByte() != bb.get(__vector(o) + j * 1)
+ } else {
+ false
+ }
+ }
+ val testarrayofboolsLength : Int
+ get() {
+ val o = __offset(52); return if (o != 0) __vector_len(o) else 0
+ }
+ val testarrayofboolsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(52, 1)
+ fun testarrayofboolsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 52, 1)
+ fun mutateTestarrayofbools(j: Int, testarrayofbools: Boolean) : Boolean {
+ val o = __offset(52)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, (if(testarrayofbools) 1 else 0).toByte())
+ true
+ } else {
+ false
+ }
+ }
+ val testf : Float
+ get() {
+ val o = __offset(54)
+ return if(o != 0) bb.getFloat(o + bb_pos) else 3.14159f
+ }
+ fun mutateTestf(testf: Float) : Boolean {
+ val o = __offset(54)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, testf)
+ true
+ } else {
+ false
+ }
+ }
+ val testf2 : Float
+ get() {
+ val o = __offset(56)
+ return if(o != 0) bb.getFloat(o + bb_pos) else 3.0f
+ }
+ fun mutateTestf2(testf2: Float) : Boolean {
+ val o = __offset(56)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, testf2)
+ true
+ } else {
+ false
+ }
+ }
+ val testf3 : Float
+ get() {
+ val o = __offset(58)
+ return if(o != 0) bb.getFloat(o + bb_pos) else 0.0f
+ }
+ fun mutateTestf3(testf3: Float) : Boolean {
+ val o = __offset(58)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, testf3)
+ true
+ } else {
+ false
+ }
+ }
+ fun testarrayofstring2(j: Int) : String? {
+ val o = __offset(60)
+ return if (o != 0) {
+ __string(__vector(o) + j * 4)
+ } else {
+ null
+ }
+ }
+ val testarrayofstring2Length : Int
+ get() {
+ val o = __offset(60); return if (o != 0) __vector_len(o) else 0
+ }
+ fun testarrayofsortedstruct(j: Int) : MyGame.Example.Ability? = testarrayofsortedstruct(MyGame.Example.Ability(), j)
+ fun testarrayofsortedstruct(obj: MyGame.Example.Ability, j: Int) : MyGame.Example.Ability? {
+ val o = __offset(62)
+ return if (o != 0) {
+ obj.__assign(__vector(o) + j * 8, bb)
+ } else {
+ null
+ }
+ }
+ val testarrayofsortedstructLength : Int
+ get() {
+ val o = __offset(62); return if (o != 0) __vector_len(o) else 0
+ }
+ fun flex(j: Int) : UByte {
+ val o = __offset(64)
+ return if (o != 0) {
+ bb.get(__vector(o) + j * 1).toUByte()
+ } else {
+ 0u
+ }
+ }
+ val flexLength : Int
+ get() {
+ val o = __offset(64); return if (o != 0) __vector_len(o) else 0
+ }
+ val flexAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(64, 1)
+ fun flexInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 64, 1)
+ fun mutateFlex(j: Int, flex: UByte) : Boolean {
+ val o = __offset(64)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, flex.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ fun test5(j: Int) : MyGame.Example.Test? = test5(MyGame.Example.Test(), j)
+ fun test5(obj: MyGame.Example.Test, j: Int) : MyGame.Example.Test? {
+ val o = __offset(66)
+ return if (o != 0) {
+ obj.__assign(__vector(o) + j * 4, bb)
+ } else {
+ null
+ }
+ }
+ val test5Length : Int
+ get() {
+ val o = __offset(66); return if (o != 0) __vector_len(o) else 0
+ }
+ fun vectorOfLongs(j: Int) : Long {
+ val o = __offset(68)
+ return if (o != 0) {
+ bb.getLong(__vector(o) + j * 8)
+ } else {
+ 0
+ }
+ }
+ val vectorOfLongsLength : Int
+ get() {
+ val o = __offset(68); return if (o != 0) __vector_len(o) else 0
+ }
+ val vectorOfLongsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(68, 8)
+ fun vectorOfLongsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 68, 8)
+ fun mutateVectorOfLongs(j: Int, vectorOfLongs: Long) : Boolean {
+ val o = __offset(68)
+ return if (o != 0) {
+ bb.putLong(__vector(o) + j * 8, vectorOfLongs)
+ true
+ } else {
+ false
+ }
+ }
+ fun vectorOfDoubles(j: Int) : Double {
+ val o = __offset(70)
+ return if (o != 0) {
+ bb.getDouble(__vector(o) + j * 8)
+ } else {
+ 0.0
+ }
+ }
+ val vectorOfDoublesLength : Int
+ get() {
+ val o = __offset(70); return if (o != 0) __vector_len(o) else 0
+ }
+ val vectorOfDoublesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(70, 8)
+ fun vectorOfDoublesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 70, 8)
+ fun mutateVectorOfDoubles(j: Int, vectorOfDoubles: Double) : Boolean {
+ val o = __offset(70)
+ return if (o != 0) {
+ bb.putDouble(__vector(o) + j * 8, vectorOfDoubles)
+ true
+ } else {
+ false
+ }
+ }
+ val parentNamespaceTest : MyGame.InParentNamespace? get() = parentNamespaceTest(MyGame.InParentNamespace())
+ fun parentNamespaceTest(obj: MyGame.InParentNamespace) : MyGame.InParentNamespace? {
+ val o = __offset(72)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ fun vectorOfReferrables(j: Int) : MyGame.Example.Referrable? = vectorOfReferrables(MyGame.Example.Referrable(), j)
+ fun vectorOfReferrables(obj: MyGame.Example.Referrable, j: Int) : MyGame.Example.Referrable? {
+ val o = __offset(74)
+ return if (o != 0) {
+ obj.__assign(__indirect(__vector(o) + j * 4), bb)
+ } else {
+ null
+ }
+ }
+ val vectorOfReferrablesLength : Int
+ get() {
+ val o = __offset(74); return if (o != 0) __vector_len(o) else 0
+ }
+ fun vectorOfReferrablesByKey(key: ULong) : MyGame.Example.Referrable? {
+ val o = __offset(74)
+ return if (o != 0) {
+ MyGame.Example.Referrable.__lookup_by_key(null, __vector(o), key, bb)
+ } else {
+ null
+ }
+ }
+ fun vectorOfReferrablesByKey(obj: MyGame.Example.Referrable, key: ULong) : MyGame.Example.Referrable? {
+ val o = __offset(74)
+ return if (o != 0) {
+ MyGame.Example.Referrable.__lookup_by_key(obj, __vector(o), key, bb)
+ } else {
+ null
+ }
+ }
+ val singleWeakReference : ULong
+ get() {
+ val o = __offset(76)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateSingleWeakReference(singleWeakReference: ULong) : Boolean {
+ val o = __offset(76)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, singleWeakReference.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ fun vectorOfWeakReferences(j: Int) : ULong {
+ val o = __offset(78)
+ return if (o != 0) {
+ bb.getLong(__vector(o) + j * 8).toULong()
+ } else {
+ 0uL
+ }
+ }
+ val vectorOfWeakReferencesLength : Int
+ get() {
+ val o = __offset(78); return if (o != 0) __vector_len(o) else 0
+ }
+ val vectorOfWeakReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(78, 8)
+ fun vectorOfWeakReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 78, 8)
+ fun mutateVectorOfWeakReferences(j: Int, vectorOfWeakReferences: ULong) : Boolean {
+ val o = __offset(78)
+ return if (o != 0) {
+ bb.putLong(__vector(o) + j * 8, vectorOfWeakReferences.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ fun vectorOfStrongReferrables(j: Int) : MyGame.Example.Referrable? = vectorOfStrongReferrables(MyGame.Example.Referrable(), j)
+ fun vectorOfStrongReferrables(obj: MyGame.Example.Referrable, j: Int) : MyGame.Example.Referrable? {
+ val o = __offset(80)
+ return if (o != 0) {
+ obj.__assign(__indirect(__vector(o) + j * 4), bb)
+ } else {
+ null
+ }
+ }
+ val vectorOfStrongReferrablesLength : Int
+ get() {
+ val o = __offset(80); return if (o != 0) __vector_len(o) else 0
+ }
+ fun vectorOfStrongReferrablesByKey(key: ULong) : MyGame.Example.Referrable? {
+ val o = __offset(80)
+ return if (o != 0) {
+ MyGame.Example.Referrable.__lookup_by_key(null, __vector(o), key, bb)
+ } else {
+ null
+ }
+ }
+ fun vectorOfStrongReferrablesByKey(obj: MyGame.Example.Referrable, key: ULong) : MyGame.Example.Referrable? {
+ val o = __offset(80)
+ return if (o != 0) {
+ MyGame.Example.Referrable.__lookup_by_key(obj, __vector(o), key, bb)
+ } else {
+ null
+ }
+ }
+ val coOwningReference : ULong
+ get() {
+ val o = __offset(82)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateCoOwningReference(coOwningReference: ULong) : Boolean {
+ val o = __offset(82)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, coOwningReference.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ fun vectorOfCoOwningReferences(j: Int) : ULong {
+ val o = __offset(84)
+ return if (o != 0) {
+ bb.getLong(__vector(o) + j * 8).toULong()
+ } else {
+ 0uL
+ }
+ }
+ val vectorOfCoOwningReferencesLength : Int
+ get() {
+ val o = __offset(84); return if (o != 0) __vector_len(o) else 0
+ }
+ val vectorOfCoOwningReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(84, 8)
+ fun vectorOfCoOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 84, 8)
+ fun mutateVectorOfCoOwningReferences(j: Int, vectorOfCoOwningReferences: ULong) : Boolean {
+ val o = __offset(84)
+ return if (o != 0) {
+ bb.putLong(__vector(o) + j * 8, vectorOfCoOwningReferences.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ val nonOwningReference : ULong
+ get() {
+ val o = __offset(86)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateNonOwningReference(nonOwningReference: ULong) : Boolean {
+ val o = __offset(86)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, nonOwningReference.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ fun vectorOfNonOwningReferences(j: Int) : ULong {
+ val o = __offset(88)
+ return if (o != 0) {
+ bb.getLong(__vector(o) + j * 8).toULong()
+ } else {
+ 0uL
+ }
+ }
+ val vectorOfNonOwningReferencesLength : Int
+ get() {
+ val o = __offset(88); return if (o != 0) __vector_len(o) else 0
+ }
+ val vectorOfNonOwningReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(88, 8)
+ fun vectorOfNonOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 88, 8)
+ fun mutateVectorOfNonOwningReferences(j: Int, vectorOfNonOwningReferences: ULong) : Boolean {
+ val o = __offset(88)
+ return if (o != 0) {
+ bb.putLong(__vector(o) + j * 8, vectorOfNonOwningReferences.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ val anyUniqueType : UByte
+ get() {
+ val o = __offset(90)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u
+ }
+ fun mutateAnyUniqueType(anyUniqueType: UByte) : Boolean {
+ val o = __offset(90)
+ return if (o != 0) {
+ bb.put(o + bb_pos, anyUniqueType.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ fun anyUnique(obj: Table) : Table? {
+ val o = __offset(92); return if (o != 0) __union(obj, o) else null
+ }
+ val anyAmbiguousType : UByte
+ get() {
+ val o = __offset(94)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u
+ }
+ fun mutateAnyAmbiguousType(anyAmbiguousType: UByte) : Boolean {
+ val o = __offset(94)
+ return if (o != 0) {
+ bb.put(o + bb_pos, anyAmbiguousType.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ fun anyAmbiguous(obj: Table) : Table? {
+ val o = __offset(96); return if (o != 0) __union(obj, o) else null
+ }
+ fun vectorOfEnums(j: Int) : UByte {
+ val o = __offset(98)
+ return if (o != 0) {
+ bb.get(__vector(o) + j * 1).toUByte()
+ } else {
+ 0u
+ }
+ }
+ val vectorOfEnumsLength : Int
+ get() {
+ val o = __offset(98); return if (o != 0) __vector_len(o) else 0
+ }
+ val vectorOfEnumsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(98, 1)
+ fun vectorOfEnumsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 98, 1)
+ fun mutateVectorOfEnums(j: Int, vectorOfEnums: UByte) : Boolean {
+ val o = __offset(98)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, vectorOfEnums.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ override fun keysCompare(o1: Int, o2: Int, _bb: ByteBuffer) : Int {
+ return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb)
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsMonster(_bb: ByteBuffer): Monster = getRootAsMonster(_bb, Monster())
+ fun getRootAsMonster(_bb: ByteBuffer, obj: Monster): Monster {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun MonsterBufferHasIdentifier(_bb: ByteBuffer) : Boolean = __has_identifier(_bb, "MONS")
+ fun startMonster(builder: FlatBufferBuilder) = builder.startTable(48)
+ fun addPos(builder: FlatBufferBuilder, pos: Int) = builder.addStruct(0, pos, 0)
+ fun addMana(builder: FlatBufferBuilder, mana: Short) = builder.addShort(1, mana, 150)
+ fun addHp(builder: FlatBufferBuilder, hp: Short) = builder.addShort(2, hp, 100)
+ fun addName(builder: FlatBufferBuilder, name: Int) = builder.addOffset(3, name, 0)
+ fun addInventory(builder: FlatBufferBuilder, inventory: Int) = builder.addOffset(5, inventory, 0)
+ fun createInventoryVector(builder: FlatBufferBuilder, data: UByteArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addByte(data[i].toByte())
+ }
+ return builder.endVector()
+ }
+ fun startInventoryVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun addColor(builder: FlatBufferBuilder, color: UByte) = builder.addByte(6, color.toByte(), 8)
+ fun addTestType(builder: FlatBufferBuilder, testType: UByte) = builder.addByte(7, testType.toByte(), 0)
+ fun addTest(builder: FlatBufferBuilder, test: Int) = builder.addOffset(8, test, 0)
+ fun addTest4(builder: FlatBufferBuilder, test4: Int) = builder.addOffset(9, test4, 0)
+ fun startTest4Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 2)
+ fun addTestarrayofstring(builder: FlatBufferBuilder, testarrayofstring: Int) = builder.addOffset(10, testarrayofstring, 0)
+ fun createTestarrayofstringVector(builder: FlatBufferBuilder, data: IntArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addOffset(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startTestarrayofstringVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun addTestarrayoftables(builder: FlatBufferBuilder, testarrayoftables: Int) = builder.addOffset(11, testarrayoftables, 0)
+ fun createTestarrayoftablesVector(builder: FlatBufferBuilder, data: IntArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addOffset(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startTestarrayoftablesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun addEnemy(builder: FlatBufferBuilder, enemy: Int) = builder.addOffset(12, enemy, 0)
+ fun addTestnestedflatbuffer(builder: FlatBufferBuilder, testnestedflatbuffer: Int) = builder.addOffset(13, testnestedflatbuffer, 0)
+ fun createTestnestedflatbufferVector(builder: FlatBufferBuilder, data: UByteArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addByte(data[i].toByte())
+ }
+ return builder.endVector()
+ }
+ fun startTestnestedflatbufferVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun addTestempty(builder: FlatBufferBuilder, testempty: Int) = builder.addOffset(14, testempty, 0)
+ fun addTestbool(builder: FlatBufferBuilder, testbool: Boolean) = builder.addBoolean(15, testbool, false)
+ fun addTesthashs32Fnv1(builder: FlatBufferBuilder, testhashs32Fnv1: Int) = builder.addInt(16, testhashs32Fnv1, 0)
+ fun addTesthashu32Fnv1(builder: FlatBufferBuilder, testhashu32Fnv1: UInt) = builder.addInt(17, testhashu32Fnv1.toInt(), 0)
+ fun addTesthashs64Fnv1(builder: FlatBufferBuilder, testhashs64Fnv1: Long) = builder.addLong(18, testhashs64Fnv1, 0L)
+ fun addTesthashu64Fnv1(builder: FlatBufferBuilder, testhashu64Fnv1: ULong) = builder.addLong(19, testhashu64Fnv1.toLong(), 0)
+ fun addTesthashs32Fnv1a(builder: FlatBufferBuilder, testhashs32Fnv1a: Int) = builder.addInt(20, testhashs32Fnv1a, 0)
+ fun addTesthashu32Fnv1a(builder: FlatBufferBuilder, testhashu32Fnv1a: UInt) = builder.addInt(21, testhashu32Fnv1a.toInt(), 0)
+ fun addTesthashs64Fnv1a(builder: FlatBufferBuilder, testhashs64Fnv1a: Long) = builder.addLong(22, testhashs64Fnv1a, 0L)
+ fun addTesthashu64Fnv1a(builder: FlatBufferBuilder, testhashu64Fnv1a: ULong) = builder.addLong(23, testhashu64Fnv1a.toLong(), 0)
+ fun addTestarrayofbools(builder: FlatBufferBuilder, testarrayofbools: Int) = builder.addOffset(24, testarrayofbools, 0)
+ fun createTestarrayofboolsVector(builder: FlatBufferBuilder, data: BooleanArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addBoolean(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startTestarrayofboolsVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun addTestf(builder: FlatBufferBuilder, testf: Float) = builder.addFloat(25, testf, 3.14159)
+ fun addTestf2(builder: FlatBufferBuilder, testf2: Float) = builder.addFloat(26, testf2, 3.0)
+ fun addTestf3(builder: FlatBufferBuilder, testf3: Float) = builder.addFloat(27, testf3, 0.0)
+ fun addTestarrayofstring2(builder: FlatBufferBuilder, testarrayofstring2: Int) = builder.addOffset(28, testarrayofstring2, 0)
+ fun createTestarrayofstring2Vector(builder: FlatBufferBuilder, data: IntArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addOffset(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startTestarrayofstring2Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun addTestarrayofsortedstruct(builder: FlatBufferBuilder, testarrayofsortedstruct: Int) = builder.addOffset(29, testarrayofsortedstruct, 0)
+ fun startTestarrayofsortedstructVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 4)
+ fun addFlex(builder: FlatBufferBuilder, flex: Int) = builder.addOffset(30, flex, 0)
+ fun createFlexVector(builder: FlatBufferBuilder, data: UByteArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addByte(data[i].toByte())
+ }
+ return builder.endVector()
+ }
+ fun startFlexVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun addTest5(builder: FlatBufferBuilder, test5: Int) = builder.addOffset(31, test5, 0)
+ fun startTest5Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 2)
+ fun addVectorOfLongs(builder: FlatBufferBuilder, vectorOfLongs: Int) = builder.addOffset(32, vectorOfLongs, 0)
+ fun createVectorOfLongsVector(builder: FlatBufferBuilder, data: LongArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addLong(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfLongsVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun addVectorOfDoubles(builder: FlatBufferBuilder, vectorOfDoubles: Int) = builder.addOffset(33, vectorOfDoubles, 0)
+ fun createVectorOfDoublesVector(builder: FlatBufferBuilder, data: DoubleArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addDouble(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfDoublesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun addParentNamespaceTest(builder: FlatBufferBuilder, parentNamespaceTest: Int) = builder.addOffset(34, parentNamespaceTest, 0)
+ fun addVectorOfReferrables(builder: FlatBufferBuilder, vectorOfReferrables: Int) = builder.addOffset(35, vectorOfReferrables, 0)
+ fun createVectorOfReferrablesVector(builder: FlatBufferBuilder, data: IntArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addOffset(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfReferrablesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun addSingleWeakReference(builder: FlatBufferBuilder, singleWeakReference: ULong) = builder.addLong(36, singleWeakReference.toLong(), 0)
+ fun addVectorOfWeakReferences(builder: FlatBufferBuilder, vectorOfWeakReferences: Int) = builder.addOffset(37, vectorOfWeakReferences, 0)
+ fun createVectorOfWeakReferencesVector(builder: FlatBufferBuilder, data: ULongArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addLong(data[i].toLong())
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfWeakReferencesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun addVectorOfStrongReferrables(builder: FlatBufferBuilder, vectorOfStrongReferrables: Int) = builder.addOffset(38, vectorOfStrongReferrables, 0)
+ fun createVectorOfStrongReferrablesVector(builder: FlatBufferBuilder, data: IntArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addOffset(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfStrongReferrablesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun addCoOwningReference(builder: FlatBufferBuilder, coOwningReference: ULong) = builder.addLong(39, coOwningReference.toLong(), 0)
+ fun addVectorOfCoOwningReferences(builder: FlatBufferBuilder, vectorOfCoOwningReferences: Int) = builder.addOffset(40, vectorOfCoOwningReferences, 0)
+ fun createVectorOfCoOwningReferencesVector(builder: FlatBufferBuilder, data: ULongArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addLong(data[i].toLong())
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfCoOwningReferencesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun addNonOwningReference(builder: FlatBufferBuilder, nonOwningReference: ULong) = builder.addLong(41, nonOwningReference.toLong(), 0)
+ fun addVectorOfNonOwningReferences(builder: FlatBufferBuilder, vectorOfNonOwningReferences: Int) = builder.addOffset(42, vectorOfNonOwningReferences, 0)
+ fun createVectorOfNonOwningReferencesVector(builder: FlatBufferBuilder, data: ULongArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addLong(data[i].toLong())
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfNonOwningReferencesVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun addAnyUniqueType(builder: FlatBufferBuilder, anyUniqueType: UByte) = builder.addByte(43, anyUniqueType.toByte(), 0)
+ fun addAnyUnique(builder: FlatBufferBuilder, anyUnique: Int) = builder.addOffset(44, anyUnique, 0)
+ fun addAnyAmbiguousType(builder: FlatBufferBuilder, anyAmbiguousType: UByte) = builder.addByte(45, anyAmbiguousType.toByte(), 0)
+ fun addAnyAmbiguous(builder: FlatBufferBuilder, anyAmbiguous: Int) = builder.addOffset(46, anyAmbiguous, 0)
+ fun addVectorOfEnums(builder: FlatBufferBuilder, vectorOfEnums: Int) = builder.addOffset(47, vectorOfEnums, 0)
+ fun createVectorOfEnumsVector(builder: FlatBufferBuilder, data: UByteArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addByte(data[i].toByte())
+ }
+ return builder.endVector()
+ }
+ fun startVectorOfEnumsVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun endMonster(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ builder.required(o, 10)
+ return o
+ }
+ fun finishMonsterBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset, "MONS")
+ fun finishSizePrefixedMonsterBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset, "MONS")
+ fun __lookup_by_key(obj: Monster?, vectorLocation: Int, key: String, bb: ByteBuffer) : Monster? {
+ val byteKey = key.toByteArray(Table.UTF8_CHARSET.get()!!)
+ var span = bb.getInt(vectorLocation - 4)
+ var start = 0
+ while (span != 0) {
+ var middle = span / 2
+ val tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb)
+ val comp = compareStrings(__offset(10, bb.capacity() - tableOffset, bb), byteKey, bb)
+ when {
+ comp > 0 -> span = middle
+ comp < 0 -> {
+ middle++
+ start += middle
+ span -= middle
+ }
+ else -> {
+ return (obj ?: Monster()).__assign(tableOffset, bb)
+ }
+ }
+ }
+ return null
+ }
+ }
+}
diff --git a/tests/MyGame/Example/Monster.lua b/tests/MyGame/Example/Monster.lua
new file mode 100644
index 0000000..130c903
--- /dev/null
+++ b/tests/MyGame/Example/Monster.lua
@@ -0,0 +1,593 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+-- an example documentation comment: monster object
+local Monster = {} -- the module
+local Monster_mt = {} -- the class metatable
+
+function Monster.New()
+ local o = {}
+ setmetatable(o, {__index = Monster_mt})
+ return o
+end
+function Monster.GetRootAsMonster(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Monster.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Monster_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Monster_mt:Pos()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = o + self.view.pos
+ local obj = require('MyGame.Example.Vec3').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Mana()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 150
+end
+function Monster_mt:Hp()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 100
+end
+function Monster_mt:Name()
+ local o = self.view:Offset(10)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Monster_mt:Inventory(j)
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:InventoryLength()
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Color()
+ local o = self.view:Offset(16)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 8
+end
+function Monster_mt:TestType()
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Test()
+ local o = self.view:Offset(20)
+ if o ~= 0 then
+ local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
+ self.view:Union(obj, o)
+ return obj
+ end
+end
+function Monster_mt:Test4(j)
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ local obj = require('MyGame.Example.Test').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Test4Length()
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testarrayofstring(j)
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:String(a + ((j-1) * 4))
+ end
+ return ''
+end
+function Monster_mt:TestarrayofstringLength()
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+-- an example documentation comment: this will end up in the generated code
+-- multiline too
+function Monster_mt:Testarrayoftables(j)
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Example.Monster').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:TestarrayoftablesLength()
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Enemy()
+ local o = self.view:Offset(28)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('MyGame.Example.Monster').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Testnestedflatbuffer(j)
+ local o = self.view:Offset(30)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:TestnestedflatbufferLength()
+ local o = self.view:Offset(30)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testempty()
+ local o = self.view:Offset(32)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('MyGame.Example.Stat').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Testbool()
+ local o = self.view:Offset(34)
+ if o ~= 0 then
+ return (self.view:Get(flatbuffers.N.Bool, o + self.view.pos) ~= 0)
+ end
+ return false
+end
+function Monster_mt:Testhashs32Fnv1()
+ local o = self.view:Offset(36)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu32Fnv1()
+ local o = self.view:Offset(38)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashs64Fnv1()
+ local o = self.view:Offset(40)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu64Fnv1()
+ local o = self.view:Offset(42)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashs32Fnv1a()
+ local o = self.view:Offset(44)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu32Fnv1a()
+ local o = self.view:Offset(46)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashs64Fnv1a()
+ local o = self.view:Offset(48)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu64Fnv1a()
+ local o = self.view:Offset(50)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testarrayofbools(j)
+ local o = self.view:Offset(52)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Bool, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:TestarrayofboolsLength()
+ local o = self.view:Offset(52)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testf()
+ local o = self.view:Offset(54)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 3.14159
+end
+function Monster_mt:Testf2()
+ local o = self.view:Offset(56)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 3.0
+end
+function Monster_mt:Testf3()
+ local o = self.view:Offset(58)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 0.0
+end
+function Monster_mt:Testarrayofstring2(j)
+ local o = self.view:Offset(60)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:String(a + ((j-1) * 4))
+ end
+ return ''
+end
+function Monster_mt:Testarrayofstring2Length()
+ local o = self.view:Offset(60)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testarrayofsortedstruct(j)
+ local o = self.view:Offset(62)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 8)
+ local obj = require('MyGame.Example.Ability').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:TestarrayofsortedstructLength()
+ local o = self.view:Offset(62)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Flex(j)
+ local o = self.view:Offset(64)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:FlexLength()
+ local o = self.view:Offset(64)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Test5(j)
+ local o = self.view:Offset(66)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ local obj = require('MyGame.Example.Test').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Test5Length()
+ local o = self.view:Offset(66)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:VectorOfLongs(j)
+ local o = self.view:Offset(68)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Int64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfLongsLength()
+ local o = self.view:Offset(68)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:VectorOfDoubles(j)
+ local o = self.view:Offset(70)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfDoublesLength()
+ local o = self.view:Offset(70)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:ParentNamespaceTest()
+ local o = self.view:Offset(72)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('MyGame.InParentNamespace').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:VectorOfReferrables(j)
+ local o = self.view:Offset(74)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Example.Referrable').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:VectorOfReferrablesLength()
+ local o = self.view:Offset(74)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:SingleWeakReference()
+ local o = self.view:Offset(76)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:VectorOfWeakReferences(j)
+ local o = self.view:Offset(78)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfWeakReferencesLength()
+ local o = self.view:Offset(78)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:VectorOfStrongReferrables(j)
+ local o = self.view:Offset(80)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Example.Referrable').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:VectorOfStrongReferrablesLength()
+ local o = self.view:Offset(80)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:CoOwningReference()
+ local o = self.view:Offset(82)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:VectorOfCoOwningReferences(j)
+ local o = self.view:Offset(84)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfCoOwningReferencesLength()
+ local o = self.view:Offset(84)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:NonOwningReference()
+ local o = self.view:Offset(86)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:VectorOfNonOwningReferences(j)
+ local o = self.view:Offset(88)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfNonOwningReferencesLength()
+ local o = self.view:Offset(88)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:AnyUniqueType()
+ local o = self.view:Offset(90)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:AnyUnique()
+ local o = self.view:Offset(92)
+ if o ~= 0 then
+ local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
+ self.view:Union(obj, o)
+ return obj
+ end
+end
+function Monster_mt:AnyAmbiguousType()
+ local o = self.view:Offset(94)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:AnyAmbiguous()
+ local o = self.view:Offset(96)
+ if o ~= 0 then
+ local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
+ self.view:Union(obj, o)
+ return obj
+ end
+end
+function Monster_mt:VectorOfEnums(j)
+ local o = self.view:Offset(98)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:VectorOfEnumsLength()
+ local o = self.view:Offset(98)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster.Start(builder) builder:StartObject(48) end
+function Monster.AddPos(builder, pos) builder:PrependStructSlot(0, pos, 0) end
+function Monster.AddMana(builder, mana) builder:PrependInt16Slot(1, mana, 150) end
+function Monster.AddHp(builder, hp) builder:PrependInt16Slot(2, hp, 100) end
+function Monster.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(3, name, 0) end
+function Monster.AddInventory(builder, inventory) builder:PrependUOffsetTRelativeSlot(5, inventory, 0) end
+function Monster.StartInventoryVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddColor(builder, color) builder:PrependUint8Slot(6, color, 8) end
+function Monster.AddTestType(builder, testType) builder:PrependUint8Slot(7, testType, 0) end
+function Monster.AddTest(builder, test) builder:PrependUOffsetTRelativeSlot(8, test, 0) end
+function Monster.AddTest4(builder, test4) builder:PrependUOffsetTRelativeSlot(9, test4, 0) end
+function Monster.StartTest4Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end
+function Monster.AddTestarrayofstring(builder, testarrayofstring) builder:PrependUOffsetTRelativeSlot(10, testarrayofstring, 0) end
+function Monster.StartTestarrayofstringVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddTestarrayoftables(builder, testarrayoftables) builder:PrependUOffsetTRelativeSlot(11, testarrayoftables, 0) end
+function Monster.StartTestarrayoftablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddEnemy(builder, enemy) builder:PrependUOffsetTRelativeSlot(12, enemy, 0) end
+function Monster.AddTestnestedflatbuffer(builder, testnestedflatbuffer) builder:PrependUOffsetTRelativeSlot(13, testnestedflatbuffer, 0) end
+function Monster.StartTestnestedflatbufferVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddTestempty(builder, testempty) builder:PrependUOffsetTRelativeSlot(14, testempty, 0) end
+function Monster.AddTestbool(builder, testbool) builder:PrependBoolSlot(15, testbool, 0) end
+function Monster.AddTesthashs32Fnv1(builder, testhashs32Fnv1) builder:PrependInt32Slot(16, testhashs32Fnv1, 0) end
+function Monster.AddTesthashu32Fnv1(builder, testhashu32Fnv1) builder:PrependUint32Slot(17, testhashu32Fnv1, 0) end
+function Monster.AddTesthashs64Fnv1(builder, testhashs64Fnv1) builder:PrependInt64Slot(18, testhashs64Fnv1, 0) end
+function Monster.AddTesthashu64Fnv1(builder, testhashu64Fnv1) builder:PrependUint64Slot(19, testhashu64Fnv1, 0) end
+function Monster.AddTesthashs32Fnv1a(builder, testhashs32Fnv1a) builder:PrependInt32Slot(20, testhashs32Fnv1a, 0) end
+function Monster.AddTesthashu32Fnv1a(builder, testhashu32Fnv1a) builder:PrependUint32Slot(21, testhashu32Fnv1a, 0) end
+function Monster.AddTesthashs64Fnv1a(builder, testhashs64Fnv1a) builder:PrependInt64Slot(22, testhashs64Fnv1a, 0) end
+function Monster.AddTesthashu64Fnv1a(builder, testhashu64Fnv1a) builder:PrependUint64Slot(23, testhashu64Fnv1a, 0) end
+function Monster.AddTestarrayofbools(builder, testarrayofbools) builder:PrependUOffsetTRelativeSlot(24, testarrayofbools, 0) end
+function Monster.StartTestarrayofboolsVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddTestf(builder, testf) builder:PrependFloat32Slot(25, testf, 3.14159) end
+function Monster.AddTestf2(builder, testf2) builder:PrependFloat32Slot(26, testf2, 3.0) end
+function Monster.AddTestf3(builder, testf3) builder:PrependFloat32Slot(27, testf3, 0.0) end
+function Monster.AddTestarrayofstring2(builder, testarrayofstring2) builder:PrependUOffsetTRelativeSlot(28, testarrayofstring2, 0) end
+function Monster.StartTestarrayofstring2Vector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddTestarrayofsortedstruct(builder, testarrayofsortedstruct) builder:PrependUOffsetTRelativeSlot(29, testarrayofsortedstruct, 0) end
+function Monster.StartTestarrayofsortedstructVector(builder, numElems) return builder:StartVector(8, numElems, 4) end
+function Monster.AddFlex(builder, flex) builder:PrependUOffsetTRelativeSlot(30, flex, 0) end
+function Monster.StartFlexVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddTest5(builder, test5) builder:PrependUOffsetTRelativeSlot(31, test5, 0) end
+function Monster.StartTest5Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end
+function Monster.AddVectorOfLongs(builder, vectorOfLongs) builder:PrependUOffsetTRelativeSlot(32, vectorOfLongs, 0) end
+function Monster.StartVectorOfLongsVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddVectorOfDoubles(builder, vectorOfDoubles) builder:PrependUOffsetTRelativeSlot(33, vectorOfDoubles, 0) end
+function Monster.StartVectorOfDoublesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddParentNamespaceTest(builder, parentNamespaceTest) builder:PrependUOffsetTRelativeSlot(34, parentNamespaceTest, 0) end
+function Monster.AddVectorOfReferrables(builder, vectorOfReferrables) builder:PrependUOffsetTRelativeSlot(35, vectorOfReferrables, 0) end
+function Monster.StartVectorOfReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddSingleWeakReference(builder, singleWeakReference) builder:PrependUint64Slot(36, singleWeakReference, 0) end
+function Monster.AddVectorOfWeakReferences(builder, vectorOfWeakReferences) builder:PrependUOffsetTRelativeSlot(37, vectorOfWeakReferences, 0) end
+function Monster.StartVectorOfWeakReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddVectorOfStrongReferrables(builder, vectorOfStrongReferrables) builder:PrependUOffsetTRelativeSlot(38, vectorOfStrongReferrables, 0) end
+function Monster.StartVectorOfStrongReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddCoOwningReference(builder, coOwningReference) builder:PrependUint64Slot(39, coOwningReference, 0) end
+function Monster.AddVectorOfCoOwningReferences(builder, vectorOfCoOwningReferences) builder:PrependUOffsetTRelativeSlot(40, vectorOfCoOwningReferences, 0) end
+function Monster.StartVectorOfCoOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddNonOwningReference(builder, nonOwningReference) builder:PrependUint64Slot(41, nonOwningReference, 0) end
+function Monster.AddVectorOfNonOwningReferences(builder, vectorOfNonOwningReferences) builder:PrependUOffsetTRelativeSlot(42, vectorOfNonOwningReferences, 0) end
+function Monster.StartVectorOfNonOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddAnyUniqueType(builder, anyUniqueType) builder:PrependUint8Slot(43, anyUniqueType, 0) end
+function Monster.AddAnyUnique(builder, anyUnique) builder:PrependUOffsetTRelativeSlot(44, anyUnique, 0) end
+function Monster.AddAnyAmbiguousType(builder, anyAmbiguousType) builder:PrependUint8Slot(45, anyAmbiguousType, 0) end
+function Monster.AddAnyAmbiguous(builder, anyAmbiguous) builder:PrependUOffsetTRelativeSlot(46, anyAmbiguous, 0) end
+function Monster.AddVectorOfEnums(builder, vectorOfEnums) builder:PrependUOffsetTRelativeSlot(47, vectorOfEnums, 0) end
+function Monster.StartVectorOfEnumsVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.End(builder) return builder:EndObject() end
+
+return Monster -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php
new file mode 100644
index 0000000..7d6de87b
--- /dev/null
+++ b/tests/MyGame/Example/Monster.php
@@ -0,0 +1,1647 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+/// an example documentation comment: monster object
+class Monster extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Monster
+ */
+ public static function getRootAsMonster(ByteBuffer $bb)
+ {
+ $obj = new Monster();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function MonsterIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function MonsterBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::MonsterIdentifier());
+ }
+
+ public static function MonsterExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Monster
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getPos()
+ {
+ $obj = new Vec3();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0;
+ }
+
+ /**
+ * @return short
+ */
+ public function getMana()
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->bb->getShort($o + $this->bb_pos) : 150;
+ }
+
+ /**
+ * @return short
+ */
+ public function getHp()
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->bb->getShort($o + $this->bb_pos) : 100;
+ }
+
+ public function getName()
+ {
+ $o = $this->__offset(10);
+ return $o != 0 ? $this->__string($o + $this->bb_pos) : null;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getInventory($j)
+ {
+ $o = $this->__offset(14);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getInventoryLength()
+ {
+ $o = $this->__offset(14);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return string
+ */
+ public function getInventoryBytes()
+ {
+ return $this->__vector_as_bytes(14);
+ }
+
+ /**
+ * @return byte
+ */
+ public function getColor()
+ {
+ $o = $this->__offset(16);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \MyGame\Example\Color::Blue;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getTestType()
+ {
+ $o = $this->__offset(18);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \MyGame\Example\Any::NONE;
+ }
+
+ /**
+ * @returnint
+ */
+ public function getTest($obj)
+ {
+ $o = $this->__offset(20);
+ return $o != 0 ? $this->__union($obj, $o) : null;
+ }
+
+ /**
+ * @returnVectorOffset
+ */
+ public function getTest4($j)
+ {
+ $o = $this->__offset(22);
+ $obj = new Test();
+ return $o != 0 ? $obj->init($this->__vector($o) + $j *4, $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTest4Length()
+ {
+ $o = $this->__offset(22);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return string
+ */
+ public function getTestarrayofstring($j)
+ {
+ $o = $this->__offset(24);
+ return $o != 0 ? $this->__string($this->__vector($o) + $j * 4) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofstringLength()
+ {
+ $o = $this->__offset(24);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ /**
+ * @returnVectorOffset
+ */
+ public function getTestarrayoftables($j)
+ {
+ $o = $this->__offset(26);
+ $obj = new Monster();
+ return $o != 0 ? $obj->init($this->__indirect($this->__vector($o) + $j * 4), $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayoftablesLength()
+ {
+ $o = $this->__offset(26);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ public function getEnemy()
+ {
+ $obj = new Monster();
+ $o = $this->__offset(28);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getTestnestedflatbuffer($j)
+ {
+ $o = $this->__offset(30);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestnestedflatbufferLength()
+ {
+ $o = $this->__offset(30);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTestnestedflatbufferBytes()
+ {
+ return $this->__vector_as_bytes(30);
+ }
+
+ public function getTestempty()
+ {
+ $obj = new Stat();
+ $o = $this->__offset(32);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getTestbool()
+ {
+ $o = $this->__offset(34);
+ return $o != 0 ? $this->bb->getBool($o + $this->bb_pos) : false;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTesthashs32Fnv1()
+ {
+ $o = $this->__offset(36);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return uint
+ */
+ public function getTesthashu32Fnv1()
+ {
+ $o = $this->__offset(38);
+ return $o != 0 ? $this->bb->getUint($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return long
+ */
+ public function getTesthashs64Fnv1()
+ {
+ $o = $this->__offset(40);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getTesthashu64Fnv1()
+ {
+ $o = $this->__offset(42);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTesthashs32Fnv1a()
+ {
+ $o = $this->__offset(44);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return uint
+ */
+ public function getTesthashu32Fnv1a()
+ {
+ $o = $this->__offset(46);
+ return $o != 0 ? $this->bb->getUint($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return long
+ */
+ public function getTesthashs64Fnv1a()
+ {
+ $o = $this->__offset(48);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getTesthashu64Fnv1a()
+ {
+ $o = $this->__offset(50);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return bool
+ */
+ public function getTestarrayofbools($j)
+ {
+ $o = $this->__offset(52);
+ return $o != 0 ? $this->bb->getBool($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofboolsLength()
+ {
+ $o = $this->__offset(52);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return float
+ */
+ public function getTestf()
+ {
+ $o = $this->__offset(54);
+ return $o != 0 ? $this->bb->getFloat($o + $this->bb_pos) : 3.14159;
+ }
+
+ /**
+ * @return float
+ */
+ public function getTestf2()
+ {
+ $o = $this->__offset(56);
+ return $o != 0 ? $this->bb->getFloat($o + $this->bb_pos) : 3.0;
+ }
+
+ /**
+ * @return float
+ */
+ public function getTestf3()
+ {
+ $o = $this->__offset(58);
+ return $o != 0 ? $this->bb->getFloat($o + $this->bb_pos) : 0.0;
+ }
+
+ /**
+ * @param int offset
+ * @return string
+ */
+ public function getTestarrayofstring2($j)
+ {
+ $o = $this->__offset(60);
+ return $o != 0 ? $this->__string($this->__vector($o) + $j * 4) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofstring2Length()
+ {
+ $o = $this->__offset(60);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @returnVectorOffset
+ */
+ public function getTestarrayofsortedstruct($j)
+ {
+ $o = $this->__offset(62);
+ $obj = new Ability();
+ return $o != 0 ? $obj->init($this->__vector($o) + $j *8, $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTestarrayofsortedstructLength()
+ {
+ $o = $this->__offset(62);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getFlex($j)
+ {
+ $o = $this->__offset(64);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getFlexLength()
+ {
+ $o = $this->__offset(64);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return string
+ */
+ public function getFlexBytes()
+ {
+ return $this->__vector_as_bytes(64);
+ }
+
+ /**
+ * @returnVectorOffset
+ */
+ public function getTest5($j)
+ {
+ $o = $this->__offset(66);
+ $obj = new Test();
+ return $o != 0 ? $obj->init($this->__vector($o) + $j *4, $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTest5Length()
+ {
+ $o = $this->__offset(66);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return long
+ */
+ public function getVectorOfLongs($j)
+ {
+ $o = $this->__offset(68);
+ return $o != 0 ? $this->bb->getLong($this->__vector($o) + $j * 8) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfLongsLength()
+ {
+ $o = $this->__offset(68);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return double
+ */
+ public function getVectorOfDoubles($j)
+ {
+ $o = $this->__offset(70);
+ return $o != 0 ? $this->bb->getDouble($this->__vector($o) + $j * 8) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfDoublesLength()
+ {
+ $o = $this->__offset(70);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ public function getParentNamespaceTest()
+ {
+ $obj = new InParentNamespace();
+ $o = $this->__offset(72);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @returnVectorOffset
+ */
+ public function getVectorOfReferrables($j)
+ {
+ $o = $this->__offset(74);
+ $obj = new Referrable();
+ return $o != 0 ? $obj->init($this->__indirect($this->__vector($o) + $j * 4), $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfReferrablesLength()
+ {
+ $o = $this->__offset(74);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getSingleWeakReference()
+ {
+ $o = $this->__offset(76);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return ulong
+ */
+ public function getVectorOfWeakReferences($j)
+ {
+ $o = $this->__offset(78);
+ return $o != 0 ? $this->bb->getUlong($this->__vector($o) + $j * 8) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfWeakReferencesLength()
+ {
+ $o = $this->__offset(78);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @returnVectorOffset
+ */
+ public function getVectorOfStrongReferrables($j)
+ {
+ $o = $this->__offset(80);
+ $obj = new Referrable();
+ return $o != 0 ? $obj->init($this->__indirect($this->__vector($o) + $j * 4), $this->bb) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfStrongReferrablesLength()
+ {
+ $o = $this->__offset(80);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getCoOwningReference()
+ {
+ $o = $this->__offset(82);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return ulong
+ */
+ public function getVectorOfCoOwningReferences($j)
+ {
+ $o = $this->__offset(84);
+ return $o != 0 ? $this->bb->getUlong($this->__vector($o) + $j * 8) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfCoOwningReferencesLength()
+ {
+ $o = $this->__offset(84);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getNonOwningReference()
+ {
+ $o = $this->__offset(86);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return ulong
+ */
+ public function getVectorOfNonOwningReferences($j)
+ {
+ $o = $this->__offset(88);
+ return $o != 0 ? $this->bb->getUlong($this->__vector($o) + $j * 8) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfNonOwningReferencesLength()
+ {
+ $o = $this->__offset(88);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getAnyUniqueType()
+ {
+ $o = $this->__offset(90);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \MyGame\Example\AnyUniqueAliases::NONE;
+ }
+
+ /**
+ * @returnint
+ */
+ public function getAnyUnique($obj)
+ {
+ $o = $this->__offset(92);
+ return $o != 0 ? $this->__union($obj, $o) : null;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getAnyAmbiguousType()
+ {
+ $o = $this->__offset(94);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \MyGame\Example\AnyAmbiguousAliases::NONE;
+ }
+
+ /**
+ * @returnint
+ */
+ public function getAnyAmbiguous($obj)
+ {
+ $o = $this->__offset(96);
+ return $o != 0 ? $this->__union($obj, $o) : null;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getVectorOfEnums($j)
+ {
+ $o = $this->__offset(98);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVectorOfEnumsLength()
+ {
+ $o = $this->__offset(98);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @return string
+ */
+ public function getVectorOfEnumsBytes()
+ {
+ return $this->__vector_as_bytes(98);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startMonster(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(48);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Monster
+ */
+ public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct, $flex, $test5, $vector_of_longs, $vector_of_doubles, $parent_namespace_test, $vector_of_referrables, $single_weak_reference, $vector_of_weak_references, $vector_of_strong_referrables, $co_owning_reference, $vector_of_co_owning_references, $non_owning_reference, $vector_of_non_owning_references, $any_unique_type, $any_unique, $any_ambiguous_type, $any_ambiguous, $vector_of_enums)
+ {
+ $builder->startObject(48);
+ self::addPos($builder, $pos);
+ self::addMana($builder, $mana);
+ self::addHp($builder, $hp);
+ self::addName($builder, $name);
+ self::addInventory($builder, $inventory);
+ self::addColor($builder, $color);
+ self::addTestType($builder, $test_type);
+ self::addTest($builder, $test);
+ self::addTest4($builder, $test4);
+ self::addTestarrayofstring($builder, $testarrayofstring);
+ self::addTestarrayoftables($builder, $testarrayoftables);
+ self::addEnemy($builder, $enemy);
+ self::addTestnestedflatbuffer($builder, $testnestedflatbuffer);
+ self::addTestempty($builder, $testempty);
+ self::addTestbool($builder, $testbool);
+ self::addTesthashs32Fnv1($builder, $testhashs32_fnv1);
+ self::addTesthashu32Fnv1($builder, $testhashu32_fnv1);
+ self::addTesthashs64Fnv1($builder, $testhashs64_fnv1);
+ self::addTesthashu64Fnv1($builder, $testhashu64_fnv1);
+ self::addTesthashs32Fnv1a($builder, $testhashs32_fnv1a);
+ self::addTesthashu32Fnv1a($builder, $testhashu32_fnv1a);
+ self::addTesthashs64Fnv1a($builder, $testhashs64_fnv1a);
+ self::addTesthashu64Fnv1a($builder, $testhashu64_fnv1a);
+ self::addTestarrayofbools($builder, $testarrayofbools);
+ self::addTestf($builder, $testf);
+ self::addTestf2($builder, $testf2);
+ self::addTestf3($builder, $testf3);
+ self::addTestarrayofstring2($builder, $testarrayofstring2);
+ self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct);
+ self::addFlex($builder, $flex);
+ self::addTest5($builder, $test5);
+ self::addVectorOfLongs($builder, $vector_of_longs);
+ self::addVectorOfDoubles($builder, $vector_of_doubles);
+ self::addParentNamespaceTest($builder, $parent_namespace_test);
+ self::addVectorOfReferrables($builder, $vector_of_referrables);
+ self::addSingleWeakReference($builder, $single_weak_reference);
+ self::addVectorOfWeakReferences($builder, $vector_of_weak_references);
+ self::addVectorOfStrongReferrables($builder, $vector_of_strong_referrables);
+ self::addCoOwningReference($builder, $co_owning_reference);
+ self::addVectorOfCoOwningReferences($builder, $vector_of_co_owning_references);
+ self::addNonOwningReference($builder, $non_owning_reference);
+ self::addVectorOfNonOwningReferences($builder, $vector_of_non_owning_references);
+ self::addAnyUniqueType($builder, $any_unique_type);
+ self::addAnyUnique($builder, $any_unique);
+ self::addAnyAmbiguousType($builder, $any_ambiguous_type);
+ self::addAnyAmbiguous($builder, $any_ambiguous);
+ self::addVectorOfEnums($builder, $vector_of_enums);
+ $o = $builder->endObject();
+ $builder->required($o, 10); // name
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addPos(FlatBufferBuilder $builder, $pos)
+ {
+ $builder->addStructX(0, $pos, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param short
+ * @return void
+ */
+ public static function addMana(FlatBufferBuilder $builder, $mana)
+ {
+ $builder->addShortX(1, $mana, 150);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param short
+ * @return void
+ */
+ public static function addHp(FlatBufferBuilder $builder, $hp)
+ {
+ $builder->addShortX(2, $hp, 100);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param StringOffset
+ * @return void
+ */
+ public static function addName(FlatBufferBuilder $builder, $name)
+ {
+ $builder->addOffsetX(3, $name, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addInventory(FlatBufferBuilder $builder, $inventory)
+ {
+ $builder->addOffsetX(5, $inventory, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createInventoryVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startInventoryVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addColor(FlatBufferBuilder $builder, $color)
+ {
+ $builder->addByteX(6, $color, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addTestType(FlatBufferBuilder $builder, $testType)
+ {
+ $builder->addByteX(7, $testType, 0);
+ }
+
+ public static function addTest(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->addOffsetX(8, $offset, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTest4(FlatBufferBuilder $builder, $test4)
+ {
+ $builder->addOffsetX(9, $test4, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTest4Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 2);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTest4Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofstring(FlatBufferBuilder $builder, $testarrayofstring)
+ {
+ $builder->addOffsetX(10, $testarrayofstring, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofstringVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofstringVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayoftables(FlatBufferBuilder $builder, $testarrayoftables)
+ {
+ $builder->addOffsetX(11, $testarrayoftables, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayoftablesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayoftablesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addEnemy(FlatBufferBuilder $builder, $enemy)
+ {
+ $builder->addOffsetX(12, $enemy, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestnestedflatbuffer(FlatBufferBuilder $builder, $testnestedflatbuffer)
+ {
+ $builder->addOffsetX(13, $testnestedflatbuffer, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestnestedflatbufferVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestnestedflatbufferVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addTestempty(FlatBufferBuilder $builder, $testempty)
+ {
+ $builder->addOffsetX(14, $testempty, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param bool
+ * @return void
+ */
+ public static function addTestbool(FlatBufferBuilder $builder, $testbool)
+ {
+ $builder->addBoolX(15, $testbool, false);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addTesthashs32Fnv1(FlatBufferBuilder $builder, $testhashs32Fnv1)
+ {
+ $builder->addIntX(16, $testhashs32Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param uint
+ * @return void
+ */
+ public static function addTesthashu32Fnv1(FlatBufferBuilder $builder, $testhashu32Fnv1)
+ {
+ $builder->addUintX(17, $testhashu32Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addTesthashs64Fnv1(FlatBufferBuilder $builder, $testhashs64Fnv1)
+ {
+ $builder->addLongX(18, $testhashs64Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addTesthashu64Fnv1(FlatBufferBuilder $builder, $testhashu64Fnv1)
+ {
+ $builder->addUlongX(19, $testhashu64Fnv1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addTesthashs32Fnv1a(FlatBufferBuilder $builder, $testhashs32Fnv1a)
+ {
+ $builder->addIntX(20, $testhashs32Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param uint
+ * @return void
+ */
+ public static function addTesthashu32Fnv1a(FlatBufferBuilder $builder, $testhashu32Fnv1a)
+ {
+ $builder->addUintX(21, $testhashu32Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addTesthashs64Fnv1a(FlatBufferBuilder $builder, $testhashs64Fnv1a)
+ {
+ $builder->addLongX(22, $testhashs64Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addTesthashu64Fnv1a(FlatBufferBuilder $builder, $testhashu64Fnv1a)
+ {
+ $builder->addUlongX(23, $testhashu64Fnv1a, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofbools(FlatBufferBuilder $builder, $testarrayofbools)
+ {
+ $builder->addOffsetX(24, $testarrayofbools, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofboolsVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putBool($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofboolsVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param float
+ * @return void
+ */
+ public static function addTestf(FlatBufferBuilder $builder, $testf)
+ {
+ $builder->addFloatX(25, $testf, 3.14159);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param float
+ * @return void
+ */
+ public static function addTestf2(FlatBufferBuilder $builder, $testf2)
+ {
+ $builder->addFloatX(26, $testf2, 3.0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param float
+ * @return void
+ */
+ public static function addTestf3(FlatBufferBuilder $builder, $testf3)
+ {
+ $builder->addFloatX(27, $testf3, 0.0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofstring2(FlatBufferBuilder $builder, $testarrayofstring2)
+ {
+ $builder->addOffsetX(28, $testarrayofstring2, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofstring2Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofstring2Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTestarrayofsortedstruct(FlatBufferBuilder $builder, $testarrayofsortedstruct)
+ {
+ $builder->addOffsetX(29, $testarrayofsortedstruct, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTestarrayofsortedstructVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTestarrayofsortedstructVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addFlex(FlatBufferBuilder $builder, $flex)
+ {
+ $builder->addOffsetX(30, $flex, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createFlexVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startFlexVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addTest5(FlatBufferBuilder $builder, $test5)
+ {
+ $builder->addOffsetX(31, $test5, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createTest5Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 2);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startTest5Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfLongs(FlatBufferBuilder $builder, $vectorOfLongs)
+ {
+ $builder->addOffsetX(32, $vectorOfLongs, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfLongsVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 8);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putLong($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfLongsVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfDoubles(FlatBufferBuilder $builder, $vectorOfDoubles)
+ {
+ $builder->addOffsetX(33, $vectorOfDoubles, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfDoublesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 8);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putDouble($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfDoublesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addParentNamespaceTest(FlatBufferBuilder $builder, $parentNamespaceTest)
+ {
+ $builder->addOffsetX(34, $parentNamespaceTest, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfReferrables(FlatBufferBuilder $builder, $vectorOfReferrables)
+ {
+ $builder->addOffsetX(35, $vectorOfReferrables, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfReferrablesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfReferrablesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addSingleWeakReference(FlatBufferBuilder $builder, $singleWeakReference)
+ {
+ $builder->addUlongX(36, $singleWeakReference, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfWeakReferences(FlatBufferBuilder $builder, $vectorOfWeakReferences)
+ {
+ $builder->addOffsetX(37, $vectorOfWeakReferences, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfWeakReferencesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 8);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putUlong($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfWeakReferencesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfStrongReferrables(FlatBufferBuilder $builder, $vectorOfStrongReferrables)
+ {
+ $builder->addOffsetX(38, $vectorOfStrongReferrables, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfStrongReferrablesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfStrongReferrablesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addCoOwningReference(FlatBufferBuilder $builder, $coOwningReference)
+ {
+ $builder->addUlongX(39, $coOwningReference, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfCoOwningReferences(FlatBufferBuilder $builder, $vectorOfCoOwningReferences)
+ {
+ $builder->addOffsetX(40, $vectorOfCoOwningReferences, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfCoOwningReferencesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 8);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putUlong($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfCoOwningReferencesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addNonOwningReference(FlatBufferBuilder $builder, $nonOwningReference)
+ {
+ $builder->addUlongX(41, $nonOwningReference, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfNonOwningReferences(FlatBufferBuilder $builder, $vectorOfNonOwningReferences)
+ {
+ $builder->addOffsetX(42, $vectorOfNonOwningReferences, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfNonOwningReferencesVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 8);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putUlong($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfNonOwningReferencesVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addAnyUniqueType(FlatBufferBuilder $builder, $anyUniqueType)
+ {
+ $builder->addByteX(43, $anyUniqueType, 0);
+ }
+
+ public static function addAnyUnique(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->addOffsetX(44, $offset, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addAnyAmbiguousType(FlatBufferBuilder $builder, $anyAmbiguousType)
+ {
+ $builder->addByteX(45, $anyAmbiguousType, 0);
+ }
+
+ public static function addAnyAmbiguous(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->addOffsetX(46, $offset, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVectorOfEnums(FlatBufferBuilder $builder, $vectorOfEnums)
+ {
+ $builder->addOffsetX(47, $vectorOfEnums, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVectorOfEnumsVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVectorOfEnumsVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endMonster(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ $builder->required($o, 10); // name
+ return $o;
+ }
+
+ public static function finishMonsterBuffer(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->finish($offset, "MONS");
+ }
+}
diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py
new file mode 100644
index 0000000..5baf64d
--- /dev/null
+++ b/tests/MyGame/Example/Monster.py
@@ -0,0 +1,689 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+# an example documentation comment: monster object
+class Monster(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsMonster(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = Monster()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def MonsterBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # Monster
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # Monster
+ def Pos(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = o + self._tab.Pos
+ from .Vec3 import Vec3
+ obj = Vec3()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def Mana(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int16Flags, o + self._tab.Pos)
+ return 150
+
+ # Monster
+ def Hp(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int16Flags, o + self._tab.Pos)
+ return 100
+
+ # Monster
+ def Name(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
+ if o != 0:
+ return self._tab.String(o + self._tab.Pos)
+ return None
+
+ # Monster
+ def Inventory(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+ return 0
+
+ # Monster
+ def InventoryAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+ return 0
+
+ # Monster
+ def InventoryLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Color(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+ return 8
+
+ # Monster
+ def TestType(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Test(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
+ if o != 0:
+ from flatbuffers.table import Table
+ obj = Table(bytearray(), 0)
+ self._tab.Union(obj, o)
+ return obj
+ return None
+
+ # Monster
+ def Test4(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+ if o != 0:
+ x = self._tab.Vector(o)
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
+ from .Test import Test
+ obj = Test()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def Test4Length(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Testarrayofstring(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.String(a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4))
+ return ""
+
+ # Monster
+ def TestarrayofstringLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # an example documentation comment: this will end up in the generated code
+ # multiline too
+ # Monster
+ def Testarrayoftables(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+ if o != 0:
+ x = self._tab.Vector(o)
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
+ x = self._tab.Indirect(x)
+ from .Monster import Monster
+ obj = Monster()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def TestarrayoftablesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Enemy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(28))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .Monster import Monster
+ obj = Monster()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def Testnestedflatbuffer(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+ return 0
+
+ # Monster
+ def TestnestedflatbufferAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+ return 0
+
+ # Monster
+ def TestnestedflatbufferLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Testempty(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(32))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .Stat import Stat
+ obj = Stat()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def Testbool(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(34))
+ if o != 0:
+ return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos))
+ return False
+
+ # Monster
+ def Testhashs32Fnv1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(36))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashu32Fnv1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(38))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint32Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashs64Fnv1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(40))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashu64Fnv1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(42))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashs32Fnv1a(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(44))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashu32Fnv1a(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(46))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint32Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashs64Fnv1a(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(48))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testhashu64Fnv1a(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(50))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def Testarrayofbools(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.BoolFlags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+ return 0
+
+ # Monster
+ def TestarrayofboolsAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.BoolFlags, o)
+ return 0
+
+ # Monster
+ def TestarrayofboolsLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Testf(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(54))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return 3.14159
+
+ # Monster
+ def Testf2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(56))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return 3.0
+
+ # Monster
+ def Testf3(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(58))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return 0.0
+
+ # Monster
+ def Testarrayofstring2(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(60))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.String(a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4))
+ return ""
+
+ # Monster
+ def Testarrayofstring2Length(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(60))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Testarrayofsortedstruct(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62))
+ if o != 0:
+ x = self._tab.Vector(o)
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 8
+ from .Ability import Ability
+ obj = Ability()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def TestarrayofsortedstructLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Flex(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+ return 0
+
+ # Monster
+ def FlexAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+ return 0
+
+ # Monster
+ def FlexLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def Test5(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(66))
+ if o != 0:
+ x = self._tab.Vector(o)
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
+ from .Test import Test
+ obj = Test()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def Test5Length(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(66))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def VectorOfLongs(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Int64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # Monster
+ def VectorOfLongsAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int64Flags, o)
+ return 0
+
+ # Monster
+ def VectorOfLongsLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def VectorOfDoubles(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # Monster
+ def VectorOfDoublesAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float64Flags, o)
+ return 0
+
+ # Monster
+ def VectorOfDoublesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def ParentNamespaceTest(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(72))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .InParentNamespace import InParentNamespace
+ obj = InParentNamespace()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def VectorOfReferrables(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(74))
+ if o != 0:
+ x = self._tab.Vector(o)
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
+ x = self._tab.Indirect(x)
+ from .Referrable import Referrable
+ obj = Referrable()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def VectorOfReferrablesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(74))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def SingleWeakReference(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(76))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def VectorOfWeakReferences(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(78))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # Monster
+ def VectorOfWeakReferencesAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(78))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint64Flags, o)
+ return 0
+
+ # Monster
+ def VectorOfWeakReferencesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(78))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def VectorOfStrongReferrables(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(80))
+ if o != 0:
+ x = self._tab.Vector(o)
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
+ x = self._tab.Indirect(x)
+ from .Referrable import Referrable
+ obj = Referrable()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # Monster
+ def VectorOfStrongReferrablesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(80))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def CoOwningReference(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(82))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def VectorOfCoOwningReferences(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(84))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # Monster
+ def VectorOfCoOwningReferencesAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(84))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint64Flags, o)
+ return 0
+
+ # Monster
+ def VectorOfCoOwningReferencesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(84))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def NonOwningReference(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(86))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def VectorOfNonOwningReferences(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(88))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # Monster
+ def VectorOfNonOwningReferencesAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(88))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint64Flags, o)
+ return 0
+
+ # Monster
+ def VectorOfNonOwningReferencesLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(88))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # Monster
+ def AnyUniqueType(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(90))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def AnyUnique(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(92))
+ if o != 0:
+ from flatbuffers.table import Table
+ obj = Table(bytearray(), 0)
+ self._tab.Union(obj, o)
+ return obj
+ return None
+
+ # Monster
+ def AnyAmbiguousType(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(94))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+ return 0
+
+ # Monster
+ def AnyAmbiguous(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(96))
+ if o != 0:
+ from flatbuffers.table import Table
+ obj = Table(bytearray(), 0)
+ self._tab.Union(obj, o)
+ return obj
+ return None
+
+ # Monster
+ def VectorOfEnums(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(98))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+ return 0
+
+ # Monster
+ def VectorOfEnumsAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(98))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+ return 0
+
+ # Monster
+ def VectorOfEnumsLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(98))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+def MonsterStart(builder): builder.StartObject(48)
+def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0)
+def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150)
+def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100)
+def MonsterAddName(builder, name): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(name), 0)
+def MonsterAddInventory(builder, inventory): builder.PrependUOffsetTRelativeSlot(5, flatbuffers.number_types.UOffsetTFlags.py_type(inventory), 0)
+def MonsterStartInventoryVector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def MonsterAddColor(builder, color): builder.PrependUint8Slot(6, color, 8)
+def MonsterAddTestType(builder, testType): builder.PrependUint8Slot(7, testType, 0)
+def MonsterAddTest(builder, test): builder.PrependUOffsetTRelativeSlot(8, flatbuffers.number_types.UOffsetTFlags.py_type(test), 0)
+def MonsterAddTest4(builder, test4): builder.PrependUOffsetTRelativeSlot(9, flatbuffers.number_types.UOffsetTFlags.py_type(test4), 0)
+def MonsterStartTest4Vector(builder, numElems): return builder.StartVector(4, numElems, 2)
+def MonsterAddTestarrayofstring(builder, testarrayofstring): builder.PrependUOffsetTRelativeSlot(10, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring), 0)
+def MonsterStartTestarrayofstringVector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterAddTestarrayoftables(builder, testarrayoftables): builder.PrependUOffsetTRelativeSlot(11, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayoftables), 0)
+def MonsterStartTestarrayoftablesVector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterAddEnemy(builder, enemy): builder.PrependUOffsetTRelativeSlot(12, flatbuffers.number_types.UOffsetTFlags.py_type(enemy), 0)
+def MonsterAddTestnestedflatbuffer(builder, testnestedflatbuffer): builder.PrependUOffsetTRelativeSlot(13, flatbuffers.number_types.UOffsetTFlags.py_type(testnestedflatbuffer), 0)
+def MonsterStartTestnestedflatbufferVector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def MonsterAddTestempty(builder, testempty): builder.PrependUOffsetTRelativeSlot(14, flatbuffers.number_types.UOffsetTFlags.py_type(testempty), 0)
+def MonsterAddTestbool(builder, testbool): builder.PrependBoolSlot(15, testbool, 0)
+def MonsterAddTesthashs32Fnv1(builder, testhashs32Fnv1): builder.PrependInt32Slot(16, testhashs32Fnv1, 0)
+def MonsterAddTesthashu32Fnv1(builder, testhashu32Fnv1): builder.PrependUint32Slot(17, testhashu32Fnv1, 0)
+def MonsterAddTesthashs64Fnv1(builder, testhashs64Fnv1): builder.PrependInt64Slot(18, testhashs64Fnv1, 0)
+def MonsterAddTesthashu64Fnv1(builder, testhashu64Fnv1): builder.PrependUint64Slot(19, testhashu64Fnv1, 0)
+def MonsterAddTesthashs32Fnv1a(builder, testhashs32Fnv1a): builder.PrependInt32Slot(20, testhashs32Fnv1a, 0)
+def MonsterAddTesthashu32Fnv1a(builder, testhashu32Fnv1a): builder.PrependUint32Slot(21, testhashu32Fnv1a, 0)
+def MonsterAddTesthashs64Fnv1a(builder, testhashs64Fnv1a): builder.PrependInt64Slot(22, testhashs64Fnv1a, 0)
+def MonsterAddTesthashu64Fnv1a(builder, testhashu64Fnv1a): builder.PrependUint64Slot(23, testhashu64Fnv1a, 0)
+def MonsterAddTestarrayofbools(builder, testarrayofbools): builder.PrependUOffsetTRelativeSlot(24, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofbools), 0)
+def MonsterStartTestarrayofboolsVector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def MonsterAddTestf(builder, testf): builder.PrependFloat32Slot(25, testf, 3.14159)
+def MonsterAddTestf2(builder, testf2): builder.PrependFloat32Slot(26, testf2, 3.0)
+def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0)
+def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0)
+def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterAddTestarrayofsortedstruct(builder, testarrayofsortedstruct): builder.PrependUOffsetTRelativeSlot(29, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofsortedstruct), 0)
+def MonsterStartTestarrayofsortedstructVector(builder, numElems): return builder.StartVector(8, numElems, 4)
+def MonsterAddFlex(builder, flex): builder.PrependUOffsetTRelativeSlot(30, flatbuffers.number_types.UOffsetTFlags.py_type(flex), 0)
+def MonsterStartFlexVector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def MonsterAddTest5(builder, test5): builder.PrependUOffsetTRelativeSlot(31, flatbuffers.number_types.UOffsetTFlags.py_type(test5), 0)
+def MonsterStartTest5Vector(builder, numElems): return builder.StartVector(4, numElems, 2)
+def MonsterAddVectorOfLongs(builder, vectorOfLongs): builder.PrependUOffsetTRelativeSlot(32, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfLongs), 0)
+def MonsterStartVectorOfLongsVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddVectorOfDoubles(builder, vectorOfDoubles): builder.PrependUOffsetTRelativeSlot(33, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfDoubles), 0)
+def MonsterStartVectorOfDoublesVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddParentNamespaceTest(builder, parentNamespaceTest): builder.PrependUOffsetTRelativeSlot(34, flatbuffers.number_types.UOffsetTFlags.py_type(parentNamespaceTest), 0)
+def MonsterAddVectorOfReferrables(builder, vectorOfReferrables): builder.PrependUOffsetTRelativeSlot(35, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfReferrables), 0)
+def MonsterStartVectorOfReferrablesVector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterAddSingleWeakReference(builder, singleWeakReference): builder.PrependUint64Slot(36, singleWeakReference, 0)
+def MonsterAddVectorOfWeakReferences(builder, vectorOfWeakReferences): builder.PrependUOffsetTRelativeSlot(37, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfWeakReferences), 0)
+def MonsterStartVectorOfWeakReferencesVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddVectorOfStrongReferrables(builder, vectorOfStrongReferrables): builder.PrependUOffsetTRelativeSlot(38, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfStrongReferrables), 0)
+def MonsterStartVectorOfStrongReferrablesVector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterAddCoOwningReference(builder, coOwningReference): builder.PrependUint64Slot(39, coOwningReference, 0)
+def MonsterAddVectorOfCoOwningReferences(builder, vectorOfCoOwningReferences): builder.PrependUOffsetTRelativeSlot(40, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfCoOwningReferences), 0)
+def MonsterStartVectorOfCoOwningReferencesVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddNonOwningReference(builder, nonOwningReference): builder.PrependUint64Slot(41, nonOwningReference, 0)
+def MonsterAddVectorOfNonOwningReferences(builder, vectorOfNonOwningReferences): builder.PrependUOffsetTRelativeSlot(42, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfNonOwningReferences), 0)
+def MonsterStartVectorOfNonOwningReferencesVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddAnyUniqueType(builder, anyUniqueType): builder.PrependUint8Slot(43, anyUniqueType, 0)
+def MonsterAddAnyUnique(builder, anyUnique): builder.PrependUOffsetTRelativeSlot(44, flatbuffers.number_types.UOffsetTFlags.py_type(anyUnique), 0)
+def MonsterAddAnyAmbiguousType(builder, anyAmbiguousType): builder.PrependUint8Slot(45, anyAmbiguousType, 0)
+def MonsterAddAnyAmbiguous(builder, anyAmbiguous): builder.PrependUOffsetTRelativeSlot(46, flatbuffers.number_types.UOffsetTFlags.py_type(anyAmbiguous), 0)
+def MonsterAddVectorOfEnums(builder, vectorOfEnums): builder.PrependUOffsetTRelativeSlot(47, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfEnums), 0)
+def MonsterStartVectorOfEnumsVector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def MonsterEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/MonsterStorageGrpc.java b/tests/MyGame/Example/MonsterStorageGrpc.java
new file mode 100644
index 0000000..b9f070f
--- /dev/null
+++ b/tests/MyGame/Example/MonsterStorageGrpc.java
@@ -0,0 +1,470 @@
+//Generated by flatc compiler (version 1.11.0)
+//If you make any local changes, they will be lost
+//source: monster_test.fbs
+
+package MyGame.Example;
+
+import com.google.flatbuffers.grpc.FlatbuffersUtils;
+
+import java.nio.ByteBuffer;
+import static io.grpc.MethodDescriptor.generateFullMethodName;
+import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall;
+import static io.grpc.stub.ClientCalls.asyncClientStreamingCall;
+import static io.grpc.stub.ClientCalls.asyncServerStreamingCall;
+import static io.grpc.stub.ClientCalls.asyncUnaryCall;
+import static io.grpc.stub.ClientCalls.blockingServerStreamingCall;
+import static io.grpc.stub.ClientCalls.blockingUnaryCall;
+import static io.grpc.stub.ClientCalls.futureUnaryCall;
+import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall;
+import static io.grpc.stub.ServerCalls.asyncClientStreamingCall;
+import static io.grpc.stub.ServerCalls.asyncServerStreamingCall;
+import static io.grpc.stub.ServerCalls.asyncUnaryCall;
+import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;
+import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;
+
+/**
+ */
+@javax.annotation.Generated(
+ value = "by gRPC proto compiler",
+ comments = "Source: monster_test.fbs")
+public final class MonsterStorageGrpc {
+
+ private MonsterStorageGrpc() {}
+
+ public static final String SERVICE_NAME = "MyGame.Example.MonsterStorage";
+
+ // Static method descriptors that strictly reflect the proto.
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ @java.lang.Deprecated // Use {@link #getStoreMethod()} instead.
+ public static final io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> METHOD_STORE = getStoreMethod();
+
+ private static volatile io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> getStoreMethod;
+
+ private static volatile FlatbuffersUtils.FBExtactor<MyGame.Example.Monster> extractorOfMonster;
+ private static FlatbuffersUtils.FBExtactor<MyGame.Example.Monster> getExtractorOfMonster() {
+ if (extractorOfMonster != null) return extractorOfMonster;
+ synchronized (MonsterStorageGrpc.class) {
+ if (extractorOfMonster != null) return extractorOfMonster;
+ extractorOfMonster = new FlatbuffersUtils.FBExtactor<MyGame.Example.Monster>() {
+ public MyGame.Example.Monster extract (ByteBuffer buffer) {
+ return MyGame.Example.Monster.getRootAsMonster(buffer);
+ }
+ };
+ return extractorOfMonster;
+ }
+ }
+
+ private static volatile FlatbuffersUtils.FBExtactor<MyGame.Example.Stat> extractorOfStat;
+ private static FlatbuffersUtils.FBExtactor<MyGame.Example.Stat> getExtractorOfStat() {
+ if (extractorOfStat != null) return extractorOfStat;
+ synchronized (MonsterStorageGrpc.class) {
+ if (extractorOfStat != null) return extractorOfStat;
+ extractorOfStat = new FlatbuffersUtils.FBExtactor<MyGame.Example.Stat>() {
+ public MyGame.Example.Stat extract (ByteBuffer buffer) {
+ return MyGame.Example.Stat.getRootAsStat(buffer);
+ }
+ };
+ return extractorOfStat;
+ }
+ }
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ public static io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> getStoreMethod() {
+ io.grpc.MethodDescriptor<MyGame.Example.Monster, MyGame.Example.Stat> getStoreMethod;
+ if ((getStoreMethod = MonsterStorageGrpc.getStoreMethod) == null) {
+ synchronized (MonsterStorageGrpc.class) {
+ if ((getStoreMethod = MonsterStorageGrpc.getStoreMethod) == null) {
+ MonsterStorageGrpc.getStoreMethod = getStoreMethod =
+ io.grpc.MethodDescriptor.<MyGame.Example.Monster, MyGame.Example.Stat>newBuilder()
+ .setType(io.grpc.MethodDescriptor.MethodType.UNARY)
+ .setFullMethodName(generateFullMethodName(
+ "MyGame.Example.MonsterStorage", "Store"))
+ .setSampledToLocalTracing(true)
+ .setRequestMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Monster.class, getExtractorOfMonster()))
+ .setResponseMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Stat.class, getExtractorOfStat()))
+ .setSchemaDescriptor(null)
+ .build();
+ }
+ }
+ }
+ return getStoreMethod;
+ }
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ @java.lang.Deprecated // Use {@link #getRetrieveMethod()} instead.
+ public static final io.grpc.MethodDescriptor<MyGame.Example.Stat,
+ MyGame.Example.Monster> METHOD_RETRIEVE = getRetrieveMethod();
+
+ private static volatile io.grpc.MethodDescriptor<MyGame.Example.Stat,
+ MyGame.Example.Monster> getRetrieveMethod;
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ public static io.grpc.MethodDescriptor<MyGame.Example.Stat,
+ MyGame.Example.Monster> getRetrieveMethod() {
+ io.grpc.MethodDescriptor<MyGame.Example.Stat, MyGame.Example.Monster> getRetrieveMethod;
+ if ((getRetrieveMethod = MonsterStorageGrpc.getRetrieveMethod) == null) {
+ synchronized (MonsterStorageGrpc.class) {
+ if ((getRetrieveMethod = MonsterStorageGrpc.getRetrieveMethod) == null) {
+ MonsterStorageGrpc.getRetrieveMethod = getRetrieveMethod =
+ io.grpc.MethodDescriptor.<MyGame.Example.Stat, MyGame.Example.Monster>newBuilder()
+ .setType(io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING)
+ .setFullMethodName(generateFullMethodName(
+ "MyGame.Example.MonsterStorage", "Retrieve"))
+ .setSampledToLocalTracing(true)
+ .setRequestMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Stat.class, getExtractorOfStat()))
+ .setResponseMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Monster.class, getExtractorOfMonster()))
+ .setSchemaDescriptor(null)
+ .build();
+ }
+ }
+ }
+ return getRetrieveMethod;
+ }
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ @java.lang.Deprecated // Use {@link #getGetMaxHitPointMethod()} instead.
+ public static final io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> METHOD_GET_MAX_HIT_POINT = getGetMaxHitPointMethod();
+
+ private static volatile io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> getGetMaxHitPointMethod;
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ public static io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> getGetMaxHitPointMethod() {
+ io.grpc.MethodDescriptor<MyGame.Example.Monster, MyGame.Example.Stat> getGetMaxHitPointMethod;
+ if ((getGetMaxHitPointMethod = MonsterStorageGrpc.getGetMaxHitPointMethod) == null) {
+ synchronized (MonsterStorageGrpc.class) {
+ if ((getGetMaxHitPointMethod = MonsterStorageGrpc.getGetMaxHitPointMethod) == null) {
+ MonsterStorageGrpc.getGetMaxHitPointMethod = getGetMaxHitPointMethod =
+ io.grpc.MethodDescriptor.<MyGame.Example.Monster, MyGame.Example.Stat>newBuilder()
+ .setType(io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING)
+ .setFullMethodName(generateFullMethodName(
+ "MyGame.Example.MonsterStorage", "GetMaxHitPoint"))
+ .setSampledToLocalTracing(true)
+ .setRequestMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Monster.class, getExtractorOfMonster()))
+ .setResponseMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Stat.class, getExtractorOfStat()))
+ .setSchemaDescriptor(null)
+ .build();
+ }
+ }
+ }
+ return getGetMaxHitPointMethod;
+ }
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ @java.lang.Deprecated // Use {@link #getGetMinMaxHitPointsMethod()} instead.
+ public static final io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> METHOD_GET_MIN_MAX_HIT_POINTS = getGetMinMaxHitPointsMethod();
+
+ private static volatile io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> getGetMinMaxHitPointsMethod;
+
+ @io.grpc.ExperimentalApi("https://github.com/grpc/grpc-java/issues/1901")
+ public static io.grpc.MethodDescriptor<MyGame.Example.Monster,
+ MyGame.Example.Stat> getGetMinMaxHitPointsMethod() {
+ io.grpc.MethodDescriptor<MyGame.Example.Monster, MyGame.Example.Stat> getGetMinMaxHitPointsMethod;
+ if ((getGetMinMaxHitPointsMethod = MonsterStorageGrpc.getGetMinMaxHitPointsMethod) == null) {
+ synchronized (MonsterStorageGrpc.class) {
+ if ((getGetMinMaxHitPointsMethod = MonsterStorageGrpc.getGetMinMaxHitPointsMethod) == null) {
+ MonsterStorageGrpc.getGetMinMaxHitPointsMethod = getGetMinMaxHitPointsMethod =
+ io.grpc.MethodDescriptor.<MyGame.Example.Monster, MyGame.Example.Stat>newBuilder()
+ .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING)
+ .setFullMethodName(generateFullMethodName(
+ "MyGame.Example.MonsterStorage", "GetMinMaxHitPoints"))
+ .setSampledToLocalTracing(true)
+ .setRequestMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Monster.class, getExtractorOfMonster()))
+ .setResponseMarshaller(FlatbuffersUtils.marshaller(
+ MyGame.Example.Stat.class, getExtractorOfStat()))
+ .setSchemaDescriptor(null)
+ .build();
+ }
+ }
+ }
+ return getGetMinMaxHitPointsMethod;
+ }
+
+ /**
+ * Creates a new async stub that supports all call types for the service
+ */
+ public static MonsterStorageStub newStub(io.grpc.Channel channel) {
+ return new MonsterStorageStub(channel);
+ }
+
+ /**
+ * Creates a new blocking-style stub that supports unary and streaming output calls on the service
+ */
+ public static MonsterStorageBlockingStub newBlockingStub(
+ io.grpc.Channel channel) {
+ return new MonsterStorageBlockingStub(channel);
+ }
+
+ /**
+ * Creates a new ListenableFuture-style stub that supports unary calls on the service
+ */
+ public static MonsterStorageFutureStub newFutureStub(
+ io.grpc.Channel channel) {
+ return new MonsterStorageFutureStub(channel);
+ }
+
+ /**
+ */
+ public static abstract class MonsterStorageImplBase implements io.grpc.BindableService {
+
+ /**
+ */
+ public void store(MyGame.Example.Monster request,
+ io.grpc.stub.StreamObserver<MyGame.Example.Stat> responseObserver) {
+ asyncUnimplementedUnaryCall(getStoreMethod(), responseObserver);
+ }
+
+ /**
+ */
+ public void retrieve(MyGame.Example.Stat request,
+ io.grpc.stub.StreamObserver<MyGame.Example.Monster> responseObserver) {
+ asyncUnimplementedUnaryCall(getRetrieveMethod(), responseObserver);
+ }
+
+ /**
+ */
+ public io.grpc.stub.StreamObserver<MyGame.Example.Monster> getMaxHitPoint(
+ io.grpc.stub.StreamObserver<MyGame.Example.Stat> responseObserver) {
+ return asyncUnimplementedStreamingCall(getGetMaxHitPointMethod(), responseObserver);
+ }
+
+ /**
+ */
+ public io.grpc.stub.StreamObserver<MyGame.Example.Monster> getMinMaxHitPoints(
+ io.grpc.stub.StreamObserver<MyGame.Example.Stat> responseObserver) {
+ return asyncUnimplementedStreamingCall(getGetMinMaxHitPointsMethod(), responseObserver);
+ }
+
+ @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() {
+ return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor())
+ .addMethod(
+ getStoreMethod(),
+ asyncUnaryCall(
+ new MethodHandlers<
+ MyGame.Example.Monster,
+ MyGame.Example.Stat>(
+ this, METHODID_STORE)))
+ .addMethod(
+ getRetrieveMethod(),
+ asyncServerStreamingCall(
+ new MethodHandlers<
+ MyGame.Example.Stat,
+ MyGame.Example.Monster>(
+ this, METHODID_RETRIEVE)))
+ .addMethod(
+ getGetMaxHitPointMethod(),
+ asyncClientStreamingCall(
+ new MethodHandlers<
+ MyGame.Example.Monster,
+ MyGame.Example.Stat>(
+ this, METHODID_GET_MAX_HIT_POINT)))
+ .addMethod(
+ getGetMinMaxHitPointsMethod(),
+ asyncBidiStreamingCall(
+ new MethodHandlers<
+ MyGame.Example.Monster,
+ MyGame.Example.Stat>(
+ this, METHODID_GET_MIN_MAX_HIT_POINTS)))
+ .build();
+ }
+ }
+
+ /**
+ */
+ public static final class MonsterStorageStub extends io.grpc.stub.AbstractStub<MonsterStorageStub> {
+ private MonsterStorageStub(io.grpc.Channel channel) {
+ super(channel);
+ }
+
+ private MonsterStorageStub(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ super(channel, callOptions);
+ }
+
+ @java.lang.Override
+ protected MonsterStorageStub build(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ return new MonsterStorageStub(channel, callOptions);
+ }
+
+ /**
+ */
+ public void store(MyGame.Example.Monster request,
+ io.grpc.stub.StreamObserver<MyGame.Example.Stat> responseObserver) {
+ asyncUnaryCall(
+ getChannel().newCall(getStoreMethod(), getCallOptions()), request, responseObserver);
+ }
+
+ /**
+ */
+ public void retrieve(MyGame.Example.Stat request,
+ io.grpc.stub.StreamObserver<MyGame.Example.Monster> responseObserver) {
+ asyncServerStreamingCall(
+ getChannel().newCall(getRetrieveMethod(), getCallOptions()), request, responseObserver);
+ }
+
+ /**
+ */
+ public io.grpc.stub.StreamObserver<MyGame.Example.Monster> getMaxHitPoint(
+ io.grpc.stub.StreamObserver<MyGame.Example.Stat> responseObserver) {
+ return asyncClientStreamingCall(
+ getChannel().newCall(getGetMaxHitPointMethod(), getCallOptions()), responseObserver);
+ }
+
+ /**
+ */
+ public io.grpc.stub.StreamObserver<MyGame.Example.Monster> getMinMaxHitPoints(
+ io.grpc.stub.StreamObserver<MyGame.Example.Stat> responseObserver) {
+ return asyncBidiStreamingCall(
+ getChannel().newCall(getGetMinMaxHitPointsMethod(), getCallOptions()), responseObserver);
+ }
+ }
+
+ /**
+ */
+ public static final class MonsterStorageBlockingStub extends io.grpc.stub.AbstractStub<MonsterStorageBlockingStub> {
+ private MonsterStorageBlockingStub(io.grpc.Channel channel) {
+ super(channel);
+ }
+
+ private MonsterStorageBlockingStub(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ super(channel, callOptions);
+ }
+
+ @java.lang.Override
+ protected MonsterStorageBlockingStub build(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ return new MonsterStorageBlockingStub(channel, callOptions);
+ }
+
+ /**
+ */
+ public MyGame.Example.Stat store(MyGame.Example.Monster request) {
+ return blockingUnaryCall(
+ getChannel(), getStoreMethod(), getCallOptions(), request);
+ }
+
+ /**
+ */
+ public java.util.Iterator<MyGame.Example.Monster> retrieve(
+ MyGame.Example.Stat request) {
+ return blockingServerStreamingCall(
+ getChannel(), getRetrieveMethod(), getCallOptions(), request);
+ }
+ }
+
+ /**
+ */
+ public static final class MonsterStorageFutureStub extends io.grpc.stub.AbstractStub<MonsterStorageFutureStub> {
+ private MonsterStorageFutureStub(io.grpc.Channel channel) {
+ super(channel);
+ }
+
+ private MonsterStorageFutureStub(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ super(channel, callOptions);
+ }
+
+ @java.lang.Override
+ protected MonsterStorageFutureStub build(io.grpc.Channel channel,
+ io.grpc.CallOptions callOptions) {
+ return new MonsterStorageFutureStub(channel, callOptions);
+ }
+
+ /**
+ */
+ public com.google.common.util.concurrent.ListenableFuture<MyGame.Example.Stat> store(
+ MyGame.Example.Monster request) {
+ return futureUnaryCall(
+ getChannel().newCall(getStoreMethod(), getCallOptions()), request);
+ }
+ }
+
+ private static final int METHODID_STORE = 0;
+ private static final int METHODID_RETRIEVE = 1;
+ private static final int METHODID_GET_MIN_MAX_HIT_POINTS = 2;
+ private static final int METHODID_GET_MAX_HIT_POINT = 3;
+
+ private static final class MethodHandlers<Req, Resp> implements
+ io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,
+ io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,
+ io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,
+ io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {
+ private final MonsterStorageImplBase serviceImpl;
+ private final int methodId;
+
+ MethodHandlers(MonsterStorageImplBase serviceImpl, int methodId) {
+ this.serviceImpl = serviceImpl;
+ this.methodId = methodId;
+ }
+
+ @java.lang.Override
+ @java.lang.SuppressWarnings("unchecked")
+ public void invoke(Req request, io.grpc.stub.StreamObserver<Resp> responseObserver) {
+ switch (methodId) {
+ case METHODID_STORE:
+ serviceImpl.store((MyGame.Example.Monster) request,
+ (io.grpc.stub.StreamObserver<MyGame.Example.Stat>) responseObserver);
+ break;
+ case METHODID_RETRIEVE:
+ serviceImpl.retrieve((MyGame.Example.Stat) request,
+ (io.grpc.stub.StreamObserver<MyGame.Example.Monster>) responseObserver);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ @java.lang.Override
+ @java.lang.SuppressWarnings("unchecked")
+ public io.grpc.stub.StreamObserver<Req> invoke(
+ io.grpc.stub.StreamObserver<Resp> responseObserver) {
+ switch (methodId) {
+ case METHODID_GET_MAX_HIT_POINT:
+ return (io.grpc.stub.StreamObserver<Req>) serviceImpl.getMaxHitPoint(
+ (io.grpc.stub.StreamObserver<MyGame.Example.Stat>) responseObserver);
+ case METHODID_GET_MIN_MAX_HIT_POINTS:
+ return (io.grpc.stub.StreamObserver<Req>) serviceImpl.getMinMaxHitPoints(
+ (io.grpc.stub.StreamObserver<MyGame.Example.Stat>) responseObserver);
+ default:
+ throw new AssertionError();
+ }
+ }
+ }
+
+ private static volatile io.grpc.ServiceDescriptor serviceDescriptor;
+
+ public static io.grpc.ServiceDescriptor getServiceDescriptor() {
+ io.grpc.ServiceDescriptor result = serviceDescriptor;
+ if (result == null) {
+ synchronized (MonsterStorageGrpc.class) {
+ result = serviceDescriptor;
+ if (result == null) {
+ serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME)
+ .setSchemaDescriptor(null)
+ .addMethod(getStoreMethod())
+ .addMethod(getRetrieveMethod())
+ .addMethod(getGetMaxHitPointMethod())
+ .addMethod(getGetMinMaxHitPointsMethod())
+ .build();
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/tests/MyGame/Example/MonsterStorage_grpc.go b/tests/MyGame/Example/MonsterStorage_grpc.go
new file mode 100644
index 0000000..deeec29
--- /dev/null
+++ b/tests/MyGame/Example/MonsterStorage_grpc.go
@@ -0,0 +1,251 @@
+//Generated by gRPC Go plugin
+//If you make any local changes, they will be lost
+//source: monster_test
+
+package Example
+
+import "github.com/google/flatbuffers/go"
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+)
+
+// Client API for MonsterStorage service
+type MonsterStorageClient interface{
+ Store(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (* Stat, error)
+ Retrieve(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (MonsterStorage_RetrieveClient, error)
+ GetMaxHitPoint(ctx context.Context,
+ opts... grpc.CallOption) (MonsterStorage_GetMaxHitPointClient, error)
+ GetMinMaxHitPoints(ctx context.Context,
+ opts... grpc.CallOption) (MonsterStorage_GetMinMaxHitPointsClient, error)
+}
+
+type monsterStorageClient struct {
+ cc *grpc.ClientConn
+}
+
+func NewMonsterStorageClient(cc *grpc.ClientConn) MonsterStorageClient {
+ return &monsterStorageClient{cc}
+}
+
+func (c *monsterStorageClient) Store(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (* Stat, error) {
+ out := new(Stat)
+ err := grpc.Invoke(ctx, "/MyGame.Example.MonsterStorage/Store", in, out, c.cc, opts...)
+ if err != nil { return nil, err }
+ return out, nil
+}
+
+func (c *monsterStorageClient) Retrieve(ctx context.Context, in *flatbuffers.Builder,
+ opts... grpc.CallOption) (MonsterStorage_RetrieveClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_MonsterStorage_serviceDesc.Streams[0], c.cc, "/MyGame.Example.MonsterStorage/Retrieve", opts...)
+ if err != nil { return nil, err }
+ x := &monsterStorageRetrieveClient{stream}
+ if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }
+ if err := x.ClientStream.CloseSend(); err != nil { return nil, err }
+ return x,nil
+}
+
+type MonsterStorage_RetrieveClient interface {
+ Recv() (*Monster, error)
+ grpc.ClientStream
+}
+
+type monsterStorageRetrieveClient struct{
+ grpc.ClientStream
+}
+
+func (x *monsterStorageRetrieveClient) Recv() (*Monster, error) {
+ m := new(Monster)
+ if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }
+ return m, nil
+}
+
+func (c *monsterStorageClient) GetMaxHitPoint(ctx context.Context,
+ opts... grpc.CallOption) (MonsterStorage_GetMaxHitPointClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_MonsterStorage_serviceDesc.Streams[1], c.cc, "/MyGame.Example.MonsterStorage/GetMaxHitPoint", opts...)
+ if err != nil { return nil, err }
+ x := &monsterStorageGetMaxHitPointClient{stream}
+ return x,nil
+}
+
+type MonsterStorage_GetMaxHitPointClient interface {
+ Send(*flatbuffers.Builder) error
+ CloseAndRecv() (*Stat, error)
+ grpc.ClientStream
+}
+
+type monsterStorageGetMaxHitPointClient struct{
+ grpc.ClientStream
+}
+
+func (x *monsterStorageGetMaxHitPointClient) Send(m *flatbuffers.Builder) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *monsterStorageGetMaxHitPointClient) CloseAndRecv() (*Stat, error) {
+ if err := x.ClientStream.CloseSend(); err != nil { return nil, err }
+ m := new (Stat)
+ if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }
+ return m, nil
+}
+
+func (c *monsterStorageClient) GetMinMaxHitPoints(ctx context.Context,
+ opts... grpc.CallOption) (MonsterStorage_GetMinMaxHitPointsClient, error) {
+ stream, err := grpc.NewClientStream(ctx, &_MonsterStorage_serviceDesc.Streams[2], c.cc, "/MyGame.Example.MonsterStorage/GetMinMaxHitPoints", opts...)
+ if err != nil { return nil, err }
+ x := &monsterStorageGetMinMaxHitPointsClient{stream}
+ return x,nil
+}
+
+type MonsterStorage_GetMinMaxHitPointsClient interface {
+ Send(*flatbuffers.Builder) error
+ Recv() (*Stat, error)
+ grpc.ClientStream
+}
+
+type monsterStorageGetMinMaxHitPointsClient struct{
+ grpc.ClientStream
+}
+
+func (x *monsterStorageGetMinMaxHitPointsClient) Send(m *flatbuffers.Builder) error {
+ return x.ClientStream.SendMsg(m)
+}
+
+func (x *monsterStorageGetMinMaxHitPointsClient) Recv() (*Stat, error) {
+ m := new(Stat)
+ if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }
+ return m, nil
+}
+
+// Server API for MonsterStorage service
+type MonsterStorageServer interface {
+ Store(context.Context, *Monster) (*flatbuffers.Builder, error)
+ Retrieve(*Stat, MonsterStorage_RetrieveServer) error
+ GetMaxHitPoint(MonsterStorage_GetMaxHitPointServer) error
+ GetMinMaxHitPoints(MonsterStorage_GetMinMaxHitPointsServer) error
+}
+
+func RegisterMonsterStorageServer(s *grpc.Server, srv MonsterStorageServer) {
+ s.RegisterService(&_MonsterStorage_serviceDesc, srv)
+}
+
+func _MonsterStorage_Store_Handler(srv interface{}, ctx context.Context,
+ dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Monster)
+ if err := dec(in); err != nil { return nil, err }
+ if interceptor == nil { return srv.(MonsterStorageServer).Store(ctx, in) }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/MyGame.Example.MonsterStorage/Store",
+ }
+
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(MonsterStorageServer).Store(ctx, req.(* Monster))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+
+func _MonsterStorage_Retrieve_Handler(srv interface{}, stream grpc.ServerStream) error {
+ m := new(Stat)
+ if err := stream.RecvMsg(m); err != nil { return err }
+ return srv.(MonsterStorageServer).Retrieve(m, &monsterStorageRetrieveServer{stream})
+}
+
+type MonsterStorage_RetrieveServer interface {
+ Send(* flatbuffers.Builder) error
+ grpc.ServerStream
+}
+
+type monsterStorageRetrieveServer struct {
+ grpc.ServerStream
+}
+
+func (x *monsterStorageRetrieveServer) Send(m *flatbuffers.Builder) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+
+func _MonsterStorage_GetMaxHitPoint_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(MonsterStorageServer).GetMaxHitPoint(&monsterStorageGetMaxHitPointServer{stream})
+}
+
+type MonsterStorage_GetMaxHitPointServer interface {
+ Recv() (* Monster, error)
+ SendAndClose(* flatbuffers.Builder) error
+ grpc.ServerStream
+}
+
+type monsterStorageGetMaxHitPointServer struct {
+ grpc.ServerStream
+}
+
+func (x *monsterStorageGetMaxHitPointServer) Recv() (*Monster, error) {
+ m := new(Monster)
+ if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }
+ return m, nil
+}
+
+func (x *monsterStorageGetMaxHitPointServer) SendAndClose(m *flatbuffers.Builder) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+
+func _MonsterStorage_GetMinMaxHitPoints_Handler(srv interface{}, stream grpc.ServerStream) error {
+ return srv.(MonsterStorageServer).GetMinMaxHitPoints(&monsterStorageGetMinMaxHitPointsServer{stream})
+}
+
+type MonsterStorage_GetMinMaxHitPointsServer interface {
+ Send(* flatbuffers.Builder) error
+ Recv() (* Monster, error)
+ grpc.ServerStream
+}
+
+type monsterStorageGetMinMaxHitPointsServer struct {
+ grpc.ServerStream
+}
+
+func (x *monsterStorageGetMinMaxHitPointsServer) Send(m *flatbuffers.Builder) error {
+ return x.ServerStream.SendMsg(m)
+}
+
+func (x *monsterStorageGetMinMaxHitPointsServer) Recv() (*Monster, error) {
+ m := new(Monster)
+ if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }
+ return m, nil
+}
+
+
+var _MonsterStorage_serviceDesc = grpc.ServiceDesc{
+ ServiceName: "MyGame.Example.MonsterStorage",
+ HandlerType: (*MonsterStorageServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "Store",
+ Handler: _MonsterStorage_Store_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{
+ {
+ StreamName: "Retrieve",
+ Handler: _MonsterStorage_Retrieve_Handler,
+ ServerStreams: true,
+ },
+ {
+ StreamName: "GetMaxHitPoint",
+ Handler: _MonsterStorage_GetMaxHitPoint_Handler,
+ ClientStreams: true,
+ },
+ {
+ StreamName: "GetMinMaxHitPoints",
+ Handler: _MonsterStorage_GetMinMaxHitPoints_Handler,
+ ServerStreams: true,
+ ClientStreams: true,
+ },
+ },
+}
+
diff --git a/tests/MyGame/Example/NestedStruct.cs b/tests/MyGame/Example/NestedStruct.cs
new file mode 100644
index 0000000..3f1f2f0
--- /dev/null
+++ b/tests/MyGame/Example/NestedStruct.cs
@@ -0,0 +1,40 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct NestedStruct : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public NestedStruct __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int A(int j) { return __p.bb.GetInt(__p.bb_pos + 0 + j * 4); }
+ public void MutateA(int j, int a) { __p.bb.PutInt(__p.bb_pos + 0 + j * 4, a); }
+ public MyGame.Example.TestEnum B { get { return (MyGame.Example.TestEnum)__p.bb.GetSbyte(__p.bb_pos + 8); } }
+ public void MutateB(MyGame.Example.TestEnum b) { __p.bb.PutSbyte(__p.bb_pos + 8, (sbyte)b); }
+ public MyGame.Example.TestEnum C(int j) { return (MyGame.Example.TestEnum)__p.bb.GetSbyte(__p.bb_pos + 9 + j * 1); }
+ public void MutateC(int j, MyGame.Example.TestEnum c) { __p.bb.PutSbyte(__p.bb_pos + 9 + j * 1, (sbyte)c); }
+
+ public static Offset<MyGame.Example.NestedStruct> CreateNestedStruct(FlatBufferBuilder builder, int[] A, MyGame.Example.TestEnum B, MyGame.Example.TestEnum[] C) {
+ builder.Prep(4, 12);
+ builder.Pad(1);
+ for (int _idx0 = 2; _idx0 > 0; _idx0--) {
+ builder.PutSbyte((sbyte)C[_idx0-1]);
+ }
+ builder.PutSbyte((sbyte)B);
+ for (int _idx0 = 2; _idx0 > 0; _idx0--) {
+ builder.PutInt(A[_idx0-1]);
+ }
+ return new Offset<MyGame.Example.NestedStruct>(builder.Offset);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/NestedStruct.java b/tests/MyGame/Example/NestedStruct.java
new file mode 100644
index 0000000..3c8a8f6
--- /dev/null
+++ b/tests/MyGame/Example/NestedStruct.java
@@ -0,0 +1,35 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class NestedStruct extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public NestedStruct __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int a(int j) { return bb.getInt(bb_pos + 0 + j * 4); }
+ public void mutateA(int j, int a) { bb.putInt(bb_pos + 0 + j * 4, a); }
+ public byte b() { return bb.get(bb_pos + 8); }
+ public void mutateB(byte b) { bb.put(bb_pos + 8, b); }
+ public byte c(int j) { return bb.get(bb_pos + 9 + j * 1); }
+ public void mutateC(int j, byte c) { bb.put(bb_pos + 9 + j * 1, c); }
+
+ public static int createNestedStruct(FlatBufferBuilder builder, int[] a, byte b, byte[] c) {
+ builder.prep(4, 12);
+ builder.pad(1);
+ for (int _idx0 = 2; _idx0 > 0; _idx0--) {
+ builder.putByte(c[_idx0-1]);
+ }
+ builder.putByte(b);
+ for (int _idx0 = 2; _idx0 > 0; _idx0--) {
+ builder.putInt(a[_idx0-1]);
+ }
+ return builder.offset();
+ }
+}
+
diff --git a/tests/MyGame/Example/NestedStruct.py b/tests/MyGame/Example/NestedStruct.py
new file mode 100644
index 0000000..aa742f4
--- /dev/null
+++ b/tests/MyGame/Example/NestedStruct.py
@@ -0,0 +1,29 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class NestedStruct(object):
+ __slots__ = ['_tab']
+
+ # NestedStruct
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # NestedStruct
+ def A(self): return [self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0 + i * 4)) for i in range(2)]
+ # NestedStruct
+ def B(self): return self._tab.Get(flatbuffers.number_types.Int8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(8))
+ # NestedStruct
+ def C(self): return [self._tab.Get(flatbuffers.number_types.Int8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(9 + i * 1)) for i in range(2)]
+
+def CreateNestedStruct(builder, a, b, c):
+ builder.Prep(4, 12)
+ builder.Pad(1)
+ for _idx0 in range(2 , 0, -1):
+ builder.PrependInt8(c[_idx0-1])
+ builder.PrependInt8(b)
+ for _idx0 in range(2 , 0, -1):
+ builder.PrependInt32(a[_idx0-1])
+ return builder.Offset()
diff --git a/tests/MyGame/Example/Referrable.cs b/tests/MyGame/Example/Referrable.cs
new file mode 100644
index 0000000..5a79f91
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.cs
@@ -0,0 +1,65 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Referrable : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static Referrable GetRootAsReferrable(ByteBuffer _bb) { return GetRootAsReferrable(_bb, new Referrable()); }
+ public static Referrable GetRootAsReferrable(ByteBuffer _bb, Referrable obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Referrable __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public ulong Id { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateId(ulong id) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, id); return true; } else { return false; } }
+
+ public static Offset<MyGame.Example.Referrable> CreateReferrable(FlatBufferBuilder builder,
+ ulong id = 0) {
+ builder.StartTable(1);
+ Referrable.AddId(builder, id);
+ return Referrable.EndReferrable(builder);
+ }
+
+ public static void StartReferrable(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddId(FlatBufferBuilder builder, ulong id) { builder.AddUlong(0, id, 0); }
+ public static Offset<MyGame.Example.Referrable> EndReferrable(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.Example.Referrable>(o);
+ }
+
+ public static VectorOffset CreateSortedVectorOfReferrable(FlatBufferBuilder builder, Offset<Referrable>[] offsets) {
+ Array.Sort(offsets, (Offset<Referrable> o1, Offset<Referrable> o2) => builder.DataBuffer.GetUlong(Table.__offset(4, o1.Value, builder.DataBuffer)).CompareTo(builder.DataBuffer.GetUlong(Table.__offset(4, o2.Value, builder.DataBuffer))));
+ return builder.CreateVectorOfTables(offsets);
+ }
+
+ public static Referrable? __lookup_by_key(int vectorLocation, ulong key, ByteBuffer bb) {
+ int span = bb.GetInt(vectorLocation - 4);
+ int start = 0;
+ while (span != 0) {
+ int middle = span / 2;
+ int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
+ int comp = bb.GetUlong(Table.__offset(4, bb.Length - tableOffset, bb)).CompareTo(key);
+ if (comp > 0) {
+ span = middle;
+ } else if (comp < 0) {
+ middle++;
+ start += middle;
+ span -= middle;
+ } else {
+ return new Referrable().__assign(tableOffset, bb);
+ }
+ }
+ return null;
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Referrable.go b/tests/MyGame/Example/Referrable.go
new file mode 100644
index 0000000..0fb06fb
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.go
@@ -0,0 +1,49 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Referrable struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsReferrable(buf []byte, offset flatbuffers.UOffsetT) *Referrable {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &Referrable{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *Referrable) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Referrable) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *Referrable) Id() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Referrable) MutateId(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(4, n)
+}
+
+func ReferrableStart(builder *flatbuffers.Builder) {
+ builder.StartObject(1)
+}
+func ReferrableAddId(builder *flatbuffers.Builder, id uint64) {
+ builder.PrependUint64Slot(0, id, 0)
+}
+func ReferrableEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/Example/Referrable.java b/tests/MyGame/Example/Referrable.java
new file mode 100644
index 0000000..f154857
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.java
@@ -0,0 +1,63 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Referrable extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static Referrable getRootAsReferrable(ByteBuffer _bb) { return getRootAsReferrable(_bb, new Referrable()); }
+ public static Referrable getRootAsReferrable(ByteBuffer _bb, Referrable obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Referrable __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public long id() { int o = __offset(4); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateId(long id) { int o = __offset(4); if (o != 0) { bb.putLong(o + bb_pos, id); return true; } else { return false; } }
+
+ public static int createReferrable(FlatBufferBuilder builder,
+ long id) {
+ builder.startTable(1);
+ Referrable.addId(builder, id);
+ return Referrable.endReferrable(builder);
+ }
+
+ public static void startReferrable(FlatBufferBuilder builder) { builder.startTable(1); }
+ public static void addId(FlatBufferBuilder builder, long id) { builder.addLong(0, id, 0L); }
+ public static int endReferrable(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+
+ @Override
+ protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) {
+ long val_1 = _bb.getLong(__offset(4, o1, _bb));
+ long val_2 = _bb.getLong(__offset(4, o2, _bb));
+ return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;
+ }
+
+ public static Referrable __lookup_by_key(Referrable obj, int vectorLocation, long key, ByteBuffer bb) {
+ int span = bb.getInt(vectorLocation - 4);
+ int start = 0;
+ while (span != 0) {
+ int middle = span / 2;
+ int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);
+ long val = bb.getLong(__offset(4, bb.capacity() - tableOffset, bb));
+ int comp = val > key ? 1 : val < key ? -1 : 0;
+ if (comp > 0) {
+ span = middle;
+ } else if (comp < 0) {
+ middle++;
+ start += middle;
+ span -= middle;
+ } else {
+ return (obj == null ? new Referrable() : obj).__assign(tableOffset, bb);
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/tests/MyGame/Example/Referrable.kt b/tests/MyGame/Example/Referrable.kt
new file mode 100644
index 0000000..55ff1d8
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.kt
@@ -0,0 +1,80 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Referrable : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Referrable {
+ __init(_i, _bb)
+ return this
+ }
+ val id : ULong
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateId(id: ULong) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, id.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ override fun keysCompare(o1: Int, o2: Int, _bb: ByteBuffer) : Int {
+ val val_1 = _bb.getLong(__offset(4, o1, _bb))
+ val val_2 = _bb.getLong(__offset(4, o2, _bb))
+ return (val_1 - val_2).sign
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsReferrable(_bb: ByteBuffer): Referrable = getRootAsReferrable(_bb, Referrable())
+ fun getRootAsReferrable(_bb: ByteBuffer, obj: Referrable): Referrable {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createReferrable(builder: FlatBufferBuilder, id: ULong) : Int {
+ builder.startTable(1)
+ addId(builder, id)
+ return endReferrable(builder)
+ }
+ fun startReferrable(builder: FlatBufferBuilder) = builder.startTable(1)
+ fun addId(builder: FlatBufferBuilder, id: ULong) = builder.addLong(0, id.toLong(), 0)
+ fun endReferrable(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ fun __lookup_by_key(obj: Referrable?, vectorLocation: Int, key: ULong, bb: ByteBuffer) : Referrable? {
+ var span = bb.getInt(vectorLocation - 4)
+ var start = 0
+ while (span != 0) {
+ var middle = span / 2
+ val tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb)
+ val value = bb.getLong(__offset(4, bb.capacity() - tableOffset, bb)).toULong()
+ val comp = value.compareTo(key)
+ when {
+ comp > 0 -> span = middle
+ comp < 0 -> {
+ middle++
+ start += middle
+ span -= middle
+ }
+ else -> {
+ return (obj ?: Referrable()).__assign(tableOffset, bb)
+ }
+ }
+ }
+ return null
+ }
+ }
+}
diff --git a/tests/MyGame/Example/Referrable.lua b/tests/MyGame/Example/Referrable.lua
new file mode 100644
index 0000000..9b0f5a1
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Referrable = {} -- the module
+local Referrable_mt = {} -- the class metatable
+
+function Referrable.New()
+ local o = {}
+ setmetatable(o, {__index = Referrable_mt})
+ return o
+end
+function Referrable.GetRootAsReferrable(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Referrable.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Referrable_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Referrable_mt:Id()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Referrable.Start(builder) builder:StartObject(1) end
+function Referrable.AddId(builder, id) builder:PrependUint64Slot(0, id, 0) end
+function Referrable.End(builder) return builder:EndObject() end
+
+return Referrable -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Referrable.php b/tests/MyGame/Example/Referrable.php
new file mode 100644
index 0000000..5844011
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.php
@@ -0,0 +1,99 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Referrable extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Referrable
+ */
+ public static function getRootAsReferrable(ByteBuffer $bb)
+ {
+ $obj = new Referrable();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function ReferrableIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function ReferrableBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::ReferrableIdentifier());
+ }
+
+ public static function ReferrableExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Referrable
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getId()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startReferrable(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Referrable
+ */
+ public static function createReferrable(FlatBufferBuilder $builder, $id)
+ {
+ $builder->startObject(1);
+ self::addId($builder, $id);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addId(FlatBufferBuilder $builder, $id)
+ {
+ $builder->addUlongX(0, $id, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endReferrable(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example/Referrable.py b/tests/MyGame/Example/Referrable.py
new file mode 100644
index 0000000..eaec09b
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.py
@@ -0,0 +1,34 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class Referrable(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsReferrable(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = Referrable()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def ReferrableBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # Referrable
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # Referrable
+ def Id(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+def ReferrableStart(builder): builder.StartObject(1)
+def ReferrableAddId(builder, id): builder.PrependUint64Slot(0, id, 0)
+def ReferrableEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs
new file mode 100644
index 0000000..bcd1004
--- /dev/null
+++ b/tests/MyGame/Example/Stat.cs
@@ -0,0 +1,55 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Stat : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static Stat GetRootAsStat(ByteBuffer _bb) { return GetRootAsStat(_bb, new Stat()); }
+ public static Stat GetRootAsStat(ByteBuffer _bb, Stat obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Stat __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public string Id { get { int o = __p.__offset(4); return o != 0 ? __p.__string(o + __p.bb_pos) : null; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetIdBytes() { return __p.__vector_as_span(4); }
+#else
+ public ArraySegment<byte>? GetIdBytes() { return __p.__vector_as_arraysegment(4); }
+#endif
+ public byte[] GetIdArray() { return __p.__vector_as_array<byte>(4); }
+ public long Val { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateVal(long val) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, val); return true; } else { return false; } }
+ public ushort Count { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetUshort(o + __p.bb_pos) : (ushort)0; } }
+ public bool MutateCount(ushort count) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutUshort(o + __p.bb_pos, count); return true; } else { return false; } }
+
+ public static Offset<MyGame.Example.Stat> CreateStat(FlatBufferBuilder builder,
+ StringOffset idOffset = default(StringOffset),
+ long val = 0,
+ ushort count = 0) {
+ builder.StartTable(3);
+ Stat.AddVal(builder, val);
+ Stat.AddId(builder, idOffset);
+ Stat.AddCount(builder, count);
+ return Stat.EndStat(builder);
+ }
+
+ public static void StartStat(FlatBufferBuilder builder) { builder.StartTable(3); }
+ public static void AddId(FlatBufferBuilder builder, StringOffset idOffset) { builder.AddOffset(0, idOffset.Value, 0); }
+ public static void AddVal(FlatBufferBuilder builder, long val) { builder.AddLong(1, val, 0); }
+ public static void AddCount(FlatBufferBuilder builder, ushort count) { builder.AddUshort(2, count, 0); }
+ public static Offset<MyGame.Example.Stat> EndStat(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.Example.Stat>(o);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Stat.go b/tests/MyGame/Example/Stat.go
new file mode 100644
index 0000000..401712f
--- /dev/null
+++ b/tests/MyGame/Example/Stat.go
@@ -0,0 +1,75 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Stat struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsStat(buf []byte, offset flatbuffers.UOffsetT) *Stat {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &Stat{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *Stat) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Stat) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *Stat) Id() []byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ return rcv._tab.ByteVector(o + rcv._tab.Pos)
+ }
+ return nil
+}
+
+func (rcv *Stat) Val() int64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ return rcv._tab.GetInt64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Stat) MutateVal(n int64) bool {
+ return rcv._tab.MutateInt64Slot(6, n)
+}
+
+func (rcv *Stat) Count() uint16 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
+ if o != 0 {
+ return rcv._tab.GetUint16(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *Stat) MutateCount(n uint16) bool {
+ return rcv._tab.MutateUint16Slot(8, n)
+}
+
+func StatStart(builder *flatbuffers.Builder) {
+ builder.StartObject(3)
+}
+func StatAddId(builder *flatbuffers.Builder, id flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(id), 0)
+}
+func StatAddVal(builder *flatbuffers.Builder, val int64) {
+ builder.PrependInt64Slot(1, val, 0)
+}
+func StatAddCount(builder *flatbuffers.Builder, count uint16) {
+ builder.PrependUint16Slot(2, count, 0)
+}
+func StatEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/Example/Stat.java b/tests/MyGame/Example/Stat.java
new file mode 100644
index 0000000..58d34f3
--- /dev/null
+++ b/tests/MyGame/Example/Stat.java
@@ -0,0 +1,46 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Stat extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static Stat getRootAsStat(ByteBuffer _bb) { return getRootAsStat(_bb, new Stat()); }
+ public static Stat getRootAsStat(ByteBuffer _bb, Stat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Stat __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public String id() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
+ public ByteBuffer idAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
+ public ByteBuffer idInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 4, 1); }
+ public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos, val); return true; } else { return false; } }
+ public int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; }
+ public boolean mutateCount(int count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, (short)count); return true; } else { return false; } }
+
+ public static int createStat(FlatBufferBuilder builder,
+ int idOffset,
+ long val,
+ int count) {
+ builder.startTable(3);
+ Stat.addVal(builder, val);
+ Stat.addId(builder, idOffset);
+ Stat.addCount(builder, count);
+ return Stat.endStat(builder);
+ }
+
+ public static void startStat(FlatBufferBuilder builder) { builder.startTable(3); }
+ public static void addId(FlatBufferBuilder builder, int idOffset) { builder.addOffset(0, idOffset, 0); }
+ public static void addVal(FlatBufferBuilder builder, long val) { builder.addLong(1, val, 0L); }
+ public static void addCount(FlatBufferBuilder builder, int count) { builder.addShort(2, (short)count, (short)0); }
+ public static int endStat(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/MyGame/Example/Stat.kt b/tests/MyGame/Example/Stat.kt
new file mode 100644
index 0000000..26b293c
--- /dev/null
+++ b/tests/MyGame/Example/Stat.kt
@@ -0,0 +1,78 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Stat : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Stat {
+ __init(_i, _bb)
+ return this
+ }
+ val id : String?
+ get() {
+ val o = __offset(4)
+ return if (o != 0) __string(o + bb_pos) else null
+ }
+ val idAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(4, 1)
+ fun idInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 4, 1)
+ val val_ : Long
+ get() {
+ val o = __offset(6)
+ return if(o != 0) bb.getLong(o + bb_pos) else 0L
+ }
+ fun mutateVal_(val_: Long) : Boolean {
+ val o = __offset(6)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, val_)
+ true
+ } else {
+ false
+ }
+ }
+ val count : UShort
+ get() {
+ val o = __offset(8)
+ return if(o != 0) bb.getShort(o + bb_pos).toUShort() else 0u
+ }
+ fun mutateCount(count: UShort) : Boolean {
+ val o = __offset(8)
+ return if (o != 0) {
+ bb.putShort(o + bb_pos, count.toShort())
+ true
+ } else {
+ false
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsStat(_bb: ByteBuffer): Stat = getRootAsStat(_bb, Stat())
+ fun getRootAsStat(_bb: ByteBuffer, obj: Stat): Stat {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createStat(builder: FlatBufferBuilder, idOffset: Int, val_: Long, count: UShort) : Int {
+ builder.startTable(3)
+ addVal_(builder, val_)
+ addId(builder, idOffset)
+ addCount(builder, count)
+ return endStat(builder)
+ }
+ fun startStat(builder: FlatBufferBuilder) = builder.startTable(3)
+ fun addId(builder: FlatBufferBuilder, id: Int) = builder.addOffset(0, id, 0)
+ fun addVal_(builder: FlatBufferBuilder, val_: Long) = builder.addLong(1, val_, 0L)
+ fun addCount(builder: FlatBufferBuilder, count: UShort) = builder.addShort(2, count.toShort(), 0)
+ fun endStat(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/MyGame/Example/Stat.lua b/tests/MyGame/Example/Stat.lua
new file mode 100644
index 0000000..6999184
--- /dev/null
+++ b/tests/MyGame/Example/Stat.lua
@@ -0,0 +1,50 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Stat = {} -- the module
+local Stat_mt = {} -- the class metatable
+
+function Stat.New()
+ local o = {}
+ setmetatable(o, {__index = Stat_mt})
+ return o
+end
+function Stat.GetRootAsStat(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Stat.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Stat_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Stat_mt:Id()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Stat_mt:Val()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function Stat_mt:Count()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos)
+ end
+ return 0
+end
+function Stat.Start(builder) builder:StartObject(3) end
+function Stat.AddId(builder, id) builder:PrependUOffsetTRelativeSlot(0, id, 0) end
+function Stat.AddVal(builder, val) builder:PrependInt64Slot(1, val, 0) end
+function Stat.AddCount(builder, count) builder:PrependUint16Slot(2, count, 0) end
+function Stat.End(builder) return builder:EndObject() end
+
+return Stat -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Stat.php b/tests/MyGame/Example/Stat.php
new file mode 100644
index 0000000..6ef7034
--- /dev/null
+++ b/tests/MyGame/Example/Stat.php
@@ -0,0 +1,136 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Stat extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Stat
+ */
+ public static function getRootAsStat(ByteBuffer $bb)
+ {
+ $obj = new Stat();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function StatIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function StatBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::StatIdentifier());
+ }
+
+ public static function StatExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Stat
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getId()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->__string($o + $this->bb_pos) : null;
+ }
+
+ /**
+ * @return long
+ */
+ public function getVal()
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ushort
+ */
+ public function getCount()
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->bb->getUshort($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startStat(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(3);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Stat
+ */
+ public static function createStat(FlatBufferBuilder $builder, $id, $val, $count)
+ {
+ $builder->startObject(3);
+ self::addId($builder, $id);
+ self::addVal($builder, $val);
+ self::addCount($builder, $count);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param StringOffset
+ * @return void
+ */
+ public static function addId(FlatBufferBuilder $builder, $id)
+ {
+ $builder->addOffsetX(0, $id, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addVal(FlatBufferBuilder $builder, $val)
+ {
+ $builder->addLongX(1, $val, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ushort
+ * @return void
+ */
+ public static function addCount(FlatBufferBuilder $builder, $count)
+ {
+ $builder->addUshortX(2, $count, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endStat(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example/Stat.py b/tests/MyGame/Example/Stat.py
new file mode 100644
index 0000000..0fbd2a7
--- /dev/null
+++ b/tests/MyGame/Example/Stat.py
@@ -0,0 +1,50 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class Stat(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsStat(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = Stat()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def StatBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # Stat
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # Stat
+ def Id(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ return self._tab.String(o + self._tab.Pos)
+ return None
+
+ # Stat
+ def Val(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos)
+ return 0
+
+ # Stat
+ def Count(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint16Flags, o + self._tab.Pos)
+ return 0
+
+def StatStart(builder): builder.StartObject(3)
+def StatAddId(builder, id): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(id), 0)
+def StatAddVal(builder, val): builder.PrependInt64Slot(1, val, 0)
+def StatAddCount(builder, count): builder.PrependUint16Slot(2, count, 0)
+def StatEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Test.cs b/tests/MyGame/Example/Test.cs
new file mode 100644
index 0000000..cd91454
--- /dev/null
+++ b/tests/MyGame/Example/Test.cs
@@ -0,0 +1,33 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Test : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public Test __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public short A { get { return __p.bb.GetShort(__p.bb_pos + 0); } }
+ public void MutateA(short a) { __p.bb.PutShort(__p.bb_pos + 0, a); }
+ public sbyte B { get { return __p.bb.GetSbyte(__p.bb_pos + 2); } }
+ public void MutateB(sbyte b) { __p.bb.PutSbyte(__p.bb_pos + 2, b); }
+
+ public static Offset<MyGame.Example.Test> CreateTest(FlatBufferBuilder builder, short A, sbyte B) {
+ builder.Prep(2, 4);
+ builder.Pad(1);
+ builder.PutSbyte(B);
+ builder.PutShort(A);
+ return new Offset<MyGame.Example.Test>(builder.Offset);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Test.go b/tests/MyGame/Example/Test.go
new file mode 100644
index 0000000..53f53fd
--- /dev/null
+++ b/tests/MyGame/Example/Test.go
@@ -0,0 +1,42 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Test struct {
+ _tab flatbuffers.Struct
+}
+
+func (rcv *Test) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Test) Table() flatbuffers.Table {
+ return rcv._tab.Table
+}
+
+func (rcv *Test) A() int16 {
+ return rcv._tab.GetInt16(rcv._tab.Pos + flatbuffers.UOffsetT(0))
+}
+func (rcv *Test) MutateA(n int16) bool {
+ return rcv._tab.MutateInt16(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
+}
+
+func (rcv *Test) B() int8 {
+ return rcv._tab.GetInt8(rcv._tab.Pos + flatbuffers.UOffsetT(2))
+}
+func (rcv *Test) MutateB(n int8) bool {
+ return rcv._tab.MutateInt8(rcv._tab.Pos+flatbuffers.UOffsetT(2), n)
+}
+
+func CreateTest(builder *flatbuffers.Builder, a int16, b int8) flatbuffers.UOffsetT {
+ builder.Prep(2, 4)
+ builder.Pad(1)
+ builder.PrependInt8(b)
+ builder.PrependInt16(a)
+ return builder.Offset()
+}
diff --git a/tests/MyGame/Example/Test.java b/tests/MyGame/Example/Test.java
new file mode 100644
index 0000000..83fdeb0
--- /dev/null
+++ b/tests/MyGame/Example/Test.java
@@ -0,0 +1,28 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Test extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Test __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public short a() { return bb.getShort(bb_pos + 0); }
+ public void mutateA(short a) { bb.putShort(bb_pos + 0, a); }
+ public byte b() { return bb.get(bb_pos + 2); }
+ public void mutateB(byte b) { bb.put(bb_pos + 2, b); }
+
+ public static int createTest(FlatBufferBuilder builder, short a, byte b) {
+ builder.prep(2, 4);
+ builder.pad(1);
+ builder.putByte(b);
+ builder.putShort(a);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/MyGame/Example/Test.kt b/tests/MyGame/Example/Test.kt
new file mode 100644
index 0000000..f2ceed6
--- /dev/null
+++ b/tests/MyGame/Example/Test.kt
@@ -0,0 +1,33 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Test : Struct() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Test {
+ __init(_i, _bb)
+ return this
+ }
+ val a : Short get() = bb.getShort(bb_pos + 0)
+ fun mutateA(a: Short) : ByteBuffer = bb.putShort(bb_pos + 0, a)
+ val b : Byte get() = bb.get(bb_pos + 2)
+ fun mutateB(b: Byte) : ByteBuffer = bb.put(bb_pos + 2, b)
+ companion object {
+ fun createTest(builder: FlatBufferBuilder, a: Short, b: Byte) : Int {
+ builder.prep(2, 4)
+ builder.pad(1)
+ builder.putByte(b)
+ builder.putShort(a)
+ return builder.offset()
+ }
+ }
+}
diff --git a/tests/MyGame/Example/Test.lua b/tests/MyGame/Example/Test.lua
new file mode 100644
index 0000000..154067b
--- /dev/null
+++ b/tests/MyGame/Example/Test.lua
@@ -0,0 +1,32 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Test = {} -- the module
+local Test_mt = {} -- the class metatable
+
+function Test.New()
+ local o = {}
+ setmetatable(o, {__index = Test_mt})
+ return o
+end
+function Test_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Test_mt:A()
+ return self.view:Get(flatbuffers.N.Int16, self.view.pos + 0)
+end
+function Test_mt:B()
+ return self.view:Get(flatbuffers.N.Int8, self.view.pos + 2)
+end
+function Test.CreateTest(builder, a, b)
+ builder:Prep(2, 4)
+ builder:Pad(1)
+ builder:PrependInt8(b)
+ builder:PrependInt16(a)
+ return builder:Offset()
+end
+
+return Test -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Test.php b/tests/MyGame/Example/Test.php
new file mode 100644
index 0000000..13cced0
--- /dev/null
+++ b/tests/MyGame/Example/Test.php
@@ -0,0 +1,53 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Test extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Test
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return short
+ */
+ public function GetA()
+ {
+ return $this->bb->getShort($this->bb_pos + 0);
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function GetB()
+ {
+ return $this->bb->getSbyte($this->bb_pos + 2);
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createTest(FlatBufferBuilder $builder, $a, $b)
+ {
+ $builder->prep(2, 4);
+ $builder->pad(1);
+ $builder->putSbyte($b);
+ $builder->putShort($a);
+ return $builder->offset();
+ }
+}
diff --git a/tests/MyGame/Example/Test.py b/tests/MyGame/Example/Test.py
new file mode 100644
index 0000000..3b2fd45
--- /dev/null
+++ b/tests/MyGame/Example/Test.py
@@ -0,0 +1,24 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class Test(object):
+ __slots__ = ['_tab']
+
+ # Test
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # Test
+ def A(self): return self._tab.Get(flatbuffers.number_types.Int16Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
+ # Test
+ def B(self): return self._tab.Get(flatbuffers.number_types.Int8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(2))
+
+def CreateTest(builder, a, b):
+ builder.Prep(2, 4)
+ builder.Pad(1)
+ builder.PrependInt8(b)
+ builder.PrependInt16(a)
+ return builder.Offset()
diff --git a/tests/MyGame/Example/TestEnum.cs b/tests/MyGame/Example/TestEnum.cs
new file mode 100644
index 0000000..22e83b3
--- /dev/null
+++ b/tests/MyGame/Example/TestEnum.cs
@@ -0,0 +1,16 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+public enum TestEnum : sbyte
+{
+ A = 0,
+ B = 1,
+ C = 2,
+};
+
+
+}
diff --git a/tests/MyGame/Example/TestEnum.java b/tests/MyGame/Example/TestEnum.java
new file mode 100644
index 0000000..411bf8e
--- /dev/null
+++ b/tests/MyGame/Example/TestEnum.java
@@ -0,0 +1,15 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+public final class TestEnum {
+ private TestEnum() { }
+ public static final byte A = 0;
+ public static final byte B = 1;
+ public static final byte C = 2;
+
+ public static final String[] names = { "A", "B", "C", };
+
+ public static String name(int e) { return names[e]; }
+}
+
diff --git a/tests/MyGame/Example/TestEnum.kt b/tests/MyGame/Example/TestEnum.kt
new file mode 100644
index 0000000..ca4d7f8
--- /dev/null
+++ b/tests/MyGame/Example/TestEnum.kt
@@ -0,0 +1,14 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+@Suppress("unused")
+class TestEnum private constructor() {
+ companion object {
+ const val A: Byte = 0
+ const val B: Byte = 1
+ const val C: Byte = 2
+ val names : Array<String> = arrayOf("A", "B", "C")
+ fun name(e: Int) : String = names[e]
+ }
+}
diff --git a/tests/MyGame/Example/TestEnum.py b/tests/MyGame/Example/TestEnum.py
new file mode 100644
index 0000000..d49f10a
--- /dev/null
+++ b/tests/MyGame/Example/TestEnum.py
@@ -0,0 +1,9 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+class TestEnum(object):
+ A = 0
+ B = 1
+ C = 2
+
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.cs b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
new file mode 100644
index 0000000..f9ac42e
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
@@ -0,0 +1,40 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+internal partial struct TestSimpleTableWithEnum : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return GetRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
+ public static TestSimpleTableWithEnum GetRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public TestSimpleTableWithEnum __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public MyGame.Example.Color Color { get { int o = __p.__offset(4); return o != 0 ? (MyGame.Example.Color)__p.bb.Get(o + __p.bb_pos) : MyGame.Example.Color.Green; } }
+ public bool MutateColor(MyGame.Example.Color color) { int o = __p.__offset(4); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)color); return true; } else { return false; } }
+
+ public static Offset<MyGame.Example.TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(FlatBufferBuilder builder,
+ MyGame.Example.Color color = MyGame.Example.Color.Green) {
+ builder.StartTable(1);
+ TestSimpleTableWithEnum.AddColor(builder, color);
+ return TestSimpleTableWithEnum.EndTestSimpleTableWithEnum(builder);
+ }
+
+ public static void StartTestSimpleTableWithEnum(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddColor(FlatBufferBuilder builder, MyGame.Example.Color color) { builder.AddByte(0, (byte)color, 2); }
+ public static Offset<MyGame.Example.TestSimpleTableWithEnum> EndTestSimpleTableWithEnum(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.Example.TestSimpleTableWithEnum>(o);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.go b/tests/MyGame/Example/TestSimpleTableWithEnum.go
new file mode 100644
index 0000000..35a6c7c
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.go
@@ -0,0 +1,49 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type TestSimpleTableWithEnum struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsTestSimpleTableWithEnum(buf []byte, offset flatbuffers.UOffsetT) *TestSimpleTableWithEnum {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &TestSimpleTableWithEnum{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *TestSimpleTableWithEnum) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TestSimpleTableWithEnum) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *TestSimpleTableWithEnum) Color() Color {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ return Color(rcv._tab.GetByte(o + rcv._tab.Pos))
+ }
+ return 2
+}
+
+func (rcv *TestSimpleTableWithEnum) MutateColor(n Color) bool {
+ return rcv._tab.MutateByteSlot(4, byte(n))
+}
+
+func TestSimpleTableWithEnumStart(builder *flatbuffers.Builder) {
+ builder.StartObject(1)
+}
+func TestSimpleTableWithEnumAddColor(builder *flatbuffers.Builder, color Color) {
+ builder.PrependByteSlot(0, byte(color), 2)
+}
+func TestSimpleTableWithEnumEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.java b/tests/MyGame/Example/TestSimpleTableWithEnum.java
new file mode 100644
index 0000000..c9f1c63
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.java
@@ -0,0 +1,35 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+final class TestSimpleTableWithEnum extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return getRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
+ public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public TestSimpleTableWithEnum __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int color() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 2; }
+ public boolean mutateColor(int color) { int o = __offset(4); if (o != 0) { bb.put(o + bb_pos, (byte)color); return true; } else { return false; } }
+
+ public static int createTestSimpleTableWithEnum(FlatBufferBuilder builder,
+ int color) {
+ builder.startTable(1);
+ TestSimpleTableWithEnum.addColor(builder, color);
+ return TestSimpleTableWithEnum.endTestSimpleTableWithEnum(builder);
+ }
+
+ public static void startTestSimpleTableWithEnum(FlatBufferBuilder builder) { builder.startTable(1); }
+ public static void addColor(FlatBufferBuilder builder, int color) { builder.addByte(0, (byte)color, (byte)2); }
+ public static int endTestSimpleTableWithEnum(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.kt b/tests/MyGame/Example/TestSimpleTableWithEnum.kt
new file mode 100644
index 0000000..68c6abf
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.kt
@@ -0,0 +1,53 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class TestSimpleTableWithEnum : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : TestSimpleTableWithEnum {
+ __init(_i, _bb)
+ return this
+ }
+ val color : UByte
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 2u
+ }
+ fun mutateColor(color: UByte) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.put(o + bb_pos, color.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsTestSimpleTableWithEnum(_bb: ByteBuffer): TestSimpleTableWithEnum = getRootAsTestSimpleTableWithEnum(_bb, TestSimpleTableWithEnum())
+ fun getRootAsTestSimpleTableWithEnum(_bb: ByteBuffer, obj: TestSimpleTableWithEnum): TestSimpleTableWithEnum {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createTestSimpleTableWithEnum(builder: FlatBufferBuilder, color: UByte) : Int {
+ builder.startTable(1)
+ addColor(builder, color)
+ return endTestSimpleTableWithEnum(builder)
+ }
+ fun startTestSimpleTableWithEnum(builder: FlatBufferBuilder) = builder.startTable(1)
+ fun addColor(builder: FlatBufferBuilder, color: UByte) = builder.addByte(0, color.toByte(), 2)
+ fun endTestSimpleTableWithEnum(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.lua b/tests/MyGame/Example/TestSimpleTableWithEnum.lua
new file mode 100644
index 0000000..32c8251
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local TestSimpleTableWithEnum = {} -- the module
+local TestSimpleTableWithEnum_mt = {} -- the class metatable
+
+function TestSimpleTableWithEnum.New()
+ local o = {}
+ setmetatable(o, {__index = TestSimpleTableWithEnum_mt})
+ return o
+end
+function TestSimpleTableWithEnum.GetRootAsTestSimpleTableWithEnum(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TestSimpleTableWithEnum.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TestSimpleTableWithEnum_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TestSimpleTableWithEnum_mt:Color()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 2
+end
+function TestSimpleTableWithEnum.Start(builder) builder:StartObject(1) end
+function TestSimpleTableWithEnum.AddColor(builder, color) builder:PrependUint8Slot(0, color, 2) end
+function TestSimpleTableWithEnum.End(builder) return builder:EndObject() end
+
+return TestSimpleTableWithEnum -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.php b/tests/MyGame/Example/TestSimpleTableWithEnum.php
new file mode 100644
index 0000000..6429f8d
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.php
@@ -0,0 +1,99 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TestSimpleTableWithEnum extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TestSimpleTableWithEnum
+ */
+ public static function getRootAsTestSimpleTableWithEnum(ByteBuffer $bb)
+ {
+ $obj = new TestSimpleTableWithEnum();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function TestSimpleTableWithEnumIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function TestSimpleTableWithEnumBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::TestSimpleTableWithEnumIdentifier());
+ }
+
+ public static function TestSimpleTableWithEnumExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TestSimpleTableWithEnum
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getColor()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \MyGame\Example\Color::Green;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTestSimpleTableWithEnum(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TestSimpleTableWithEnum
+ */
+ public static function createTestSimpleTableWithEnum(FlatBufferBuilder $builder, $color)
+ {
+ $builder->startObject(1);
+ self::addColor($builder, $color);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addColor(FlatBufferBuilder $builder, $color)
+ {
+ $builder->addByteX(0, $color, 2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTestSimpleTableWithEnum(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.py b/tests/MyGame/Example/TestSimpleTableWithEnum.py
new file mode 100644
index 0000000..cb9c631
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.py
@@ -0,0 +1,34 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class TestSimpleTableWithEnum(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsTestSimpleTableWithEnum(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = TestSimpleTableWithEnum()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def TestSimpleTableWithEnumBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # TestSimpleTableWithEnum
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TestSimpleTableWithEnum
+ def Color(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+ return 2
+
+def TestSimpleTableWithEnumStart(builder): builder.StartObject(1)
+def TestSimpleTableWithEnumAddColor(builder, color): builder.PrependUint8Slot(0, color, 2)
+def TestSimpleTableWithEnumEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/TypeAliases.cs b/tests/MyGame/Example/TypeAliases.cs
new file mode 100644
index 0000000..a7b54d5
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.cs
@@ -0,0 +1,115 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct TypeAliases : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static TypeAliases GetRootAsTypeAliases(ByteBuffer _bb) { return GetRootAsTypeAliases(_bb, new TypeAliases()); }
+ public static TypeAliases GetRootAsTypeAliases(ByteBuffer _bb, TypeAliases obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public TypeAliases __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public sbyte I8 { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetSbyte(o + __p.bb_pos) : (sbyte)0; } }
+ public bool MutateI8(sbyte i8) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, i8); return true; } else { return false; } }
+ public byte U8 { get { int o = __p.__offset(6); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte)0; } }
+ public bool MutateU8(byte u8) { int o = __p.__offset(6); if (o != 0) { __p.bb.Put(o + __p.bb_pos, u8); return true; } else { return false; } }
+ public short I16 { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)0; } }
+ public bool MutateI16(short i16) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, i16); return true; } else { return false; } }
+ public ushort U16 { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetUshort(o + __p.bb_pos) : (ushort)0; } }
+ public bool MutateU16(ushort u16) { int o = __p.__offset(10); if (o != 0) { __p.bb.PutUshort(o + __p.bb_pos, u16); return true; } else { return false; } }
+ public int I32 { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateI32(int i32) { int o = __p.__offset(12); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, i32); return true; } else { return false; } }
+ public uint U32 { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
+ public bool MutateU32(uint u32) { int o = __p.__offset(14); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, u32); return true; } else { return false; } }
+ public long I64 { get { int o = __p.__offset(16); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+ public bool MutateI64(long i64) { int o = __p.__offset(16); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, i64); return true; } else { return false; } }
+ public ulong U64 { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+ public bool MutateU64(ulong u64) { int o = __p.__offset(18); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, u64); return true; } else { return false; } }
+ public float F32 { get { int o = __p.__offset(20); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } }
+ public bool MutateF32(float f32) { int o = __p.__offset(20); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, f32); return true; } else { return false; } }
+ public double F64 { get { int o = __p.__offset(22); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)0.0; } }
+ public bool MutateF64(double f64) { int o = __p.__offset(22); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, f64); return true; } else { return false; } }
+ public sbyte V8(int j) { int o = __p.__offset(24); return o != 0 ? __p.bb.GetSbyte(__p.__vector(o) + j * 1) : (sbyte)0; }
+ public int V8Length { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetV8Bytes() { return __p.__vector_as_span(24); }
+#else
+ public ArraySegment<byte>? GetV8Bytes() { return __p.__vector_as_arraysegment(24); }
+#endif
+ public sbyte[] GetV8Array() { return __p.__vector_as_array<sbyte>(24); }
+ public bool MutateV8(int j, sbyte v8) { int o = __p.__offset(24); if (o != 0) { __p.bb.PutSbyte(__p.__vector(o) + j * 1, v8); return true; } else { return false; } }
+ public double Vf64(int j) { int o = __p.__offset(26); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
+ public int Vf64Length { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetVf64Bytes() { return __p.__vector_as_span(26); }
+#else
+ public ArraySegment<byte>? GetVf64Bytes() { return __p.__vector_as_arraysegment(26); }
+#endif
+ public double[] GetVf64Array() { return __p.__vector_as_array<double>(26); }
+ public bool MutateVf64(int j, double vf64) { int o = __p.__offset(26); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vf64); return true; } else { return false; } }
+
+ public static Offset<MyGame.Example.TypeAliases> CreateTypeAliases(FlatBufferBuilder builder,
+ sbyte i8 = 0,
+ byte u8 = 0,
+ short i16 = 0,
+ ushort u16 = 0,
+ int i32 = 0,
+ uint u32 = 0,
+ long i64 = 0,
+ ulong u64 = 0,
+ float f32 = 0.0f,
+ double f64 = 0.0,
+ VectorOffset v8Offset = default(VectorOffset),
+ VectorOffset vf64Offset = default(VectorOffset)) {
+ builder.StartTable(12);
+ TypeAliases.AddF64(builder, f64);
+ TypeAliases.AddU64(builder, u64);
+ TypeAliases.AddI64(builder, i64);
+ TypeAliases.AddVf64(builder, vf64Offset);
+ TypeAliases.AddV8(builder, v8Offset);
+ TypeAliases.AddF32(builder, f32);
+ TypeAliases.AddU32(builder, u32);
+ TypeAliases.AddI32(builder, i32);
+ TypeAliases.AddU16(builder, u16);
+ TypeAliases.AddI16(builder, i16);
+ TypeAliases.AddU8(builder, u8);
+ TypeAliases.AddI8(builder, i8);
+ return TypeAliases.EndTypeAliases(builder);
+ }
+
+ public static void StartTypeAliases(FlatBufferBuilder builder) { builder.StartTable(12); }
+ public static void AddI8(FlatBufferBuilder builder, sbyte i8) { builder.AddSbyte(0, i8, 0); }
+ public static void AddU8(FlatBufferBuilder builder, byte u8) { builder.AddByte(1, u8, 0); }
+ public static void AddI16(FlatBufferBuilder builder, short i16) { builder.AddShort(2, i16, 0); }
+ public static void AddU16(FlatBufferBuilder builder, ushort u16) { builder.AddUshort(3, u16, 0); }
+ public static void AddI32(FlatBufferBuilder builder, int i32) { builder.AddInt(4, i32, 0); }
+ public static void AddU32(FlatBufferBuilder builder, uint u32) { builder.AddUint(5, u32, 0); }
+ public static void AddI64(FlatBufferBuilder builder, long i64) { builder.AddLong(6, i64, 0); }
+ public static void AddU64(FlatBufferBuilder builder, ulong u64) { builder.AddUlong(7, u64, 0); }
+ public static void AddF32(FlatBufferBuilder builder, float f32) { builder.AddFloat(8, f32, 0.0f); }
+ public static void AddF64(FlatBufferBuilder builder, double f64) { builder.AddDouble(9, f64, 0.0); }
+ public static void AddV8(FlatBufferBuilder builder, VectorOffset v8Offset) { builder.AddOffset(10, v8Offset.Value, 0); }
+ public static VectorOffset CreateV8Vector(FlatBufferBuilder builder, sbyte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddSbyte(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateV8VectorBlock(FlatBufferBuilder builder, sbyte[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartV8Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddVf64(FlatBufferBuilder builder, VectorOffset vf64Offset) { builder.AddOffset(11, vf64Offset.Value, 0); }
+ public static VectorOffset CreateVf64Vector(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddDouble(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateVf64VectorBlock(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartVf64Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static Offset<MyGame.Example.TypeAliases> EndTypeAliases(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.Example.TypeAliases>(o);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/TypeAliases.go b/tests/MyGame/Example/TypeAliases.go
new file mode 100644
index 0000000..d017b5b
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.go
@@ -0,0 +1,248 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type TypeAliases struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsTypeAliases(buf []byte, offset flatbuffers.UOffsetT) *TypeAliases {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &TypeAliases{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *TypeAliases) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TypeAliases) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *TypeAliases) I8() int8 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ return rcv._tab.GetInt8(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateI8(n int8) bool {
+ return rcv._tab.MutateInt8Slot(4, n)
+}
+
+func (rcv *TypeAliases) U8() byte {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ return rcv._tab.GetByte(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateU8(n byte) bool {
+ return rcv._tab.MutateByteSlot(6, n)
+}
+
+func (rcv *TypeAliases) I16() int16 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
+ if o != 0 {
+ return rcv._tab.GetInt16(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateI16(n int16) bool {
+ return rcv._tab.MutateInt16Slot(8, n)
+}
+
+func (rcv *TypeAliases) U16() uint16 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
+ if o != 0 {
+ return rcv._tab.GetUint16(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateU16(n uint16) bool {
+ return rcv._tab.MutateUint16Slot(10, n)
+}
+
+func (rcv *TypeAliases) I32() int32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(12))
+ if o != 0 {
+ return rcv._tab.GetInt32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateI32(n int32) bool {
+ return rcv._tab.MutateInt32Slot(12, n)
+}
+
+func (rcv *TypeAliases) U32() uint32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
+ if o != 0 {
+ return rcv._tab.GetUint32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateU32(n uint32) bool {
+ return rcv._tab.MutateUint32Slot(14, n)
+}
+
+func (rcv *TypeAliases) I64() int64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
+ if o != 0 {
+ return rcv._tab.GetInt64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateI64(n int64) bool {
+ return rcv._tab.MutateInt64Slot(16, n)
+}
+
+func (rcv *TypeAliases) U64() uint64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
+ if o != 0 {
+ return rcv._tab.GetUint64(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateU64(n uint64) bool {
+ return rcv._tab.MutateUint64Slot(18, n)
+}
+
+func (rcv *TypeAliases) F32() float32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(20))
+ if o != 0 {
+ return rcv._tab.GetFloat32(o + rcv._tab.Pos)
+ }
+ return 0.0
+}
+
+func (rcv *TypeAliases) MutateF32(n float32) bool {
+ return rcv._tab.MutateFloat32Slot(20, n)
+}
+
+func (rcv *TypeAliases) F64() float64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(22))
+ if o != 0 {
+ return rcv._tab.GetFloat64(o + rcv._tab.Pos)
+ }
+ return 0.0
+}
+
+func (rcv *TypeAliases) MutateF64(n float64) bool {
+ return rcv._tab.MutateFloat64Slot(22, n)
+}
+
+func (rcv *TypeAliases) V8(j int) int8 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetInt8(a + flatbuffers.UOffsetT(j*1))
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) V8Length() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateV8(j int, n int8) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateInt8(a+flatbuffers.UOffsetT(j*1), n)
+ }
+ return false
+}
+
+func (rcv *TypeAliases) Vf64(j int) float64 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.GetFloat64(a + flatbuffers.UOffsetT(j*8))
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) Vf64Length() int {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+ if o != 0 {
+ return rcv._tab.VectorLen(o)
+ }
+ return 0
+}
+
+func (rcv *TypeAliases) MutateVf64(j int, n float64) bool {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+ if o != 0 {
+ a := rcv._tab.Vector(o)
+ return rcv._tab.MutateFloat64(a+flatbuffers.UOffsetT(j*8), n)
+ }
+ return false
+}
+
+func TypeAliasesStart(builder *flatbuffers.Builder) {
+ builder.StartObject(12)
+}
+func TypeAliasesAddI8(builder *flatbuffers.Builder, i8 int8) {
+ builder.PrependInt8Slot(0, i8, 0)
+}
+func TypeAliasesAddU8(builder *flatbuffers.Builder, u8 byte) {
+ builder.PrependByteSlot(1, u8, 0)
+}
+func TypeAliasesAddI16(builder *flatbuffers.Builder, i16 int16) {
+ builder.PrependInt16Slot(2, i16, 0)
+}
+func TypeAliasesAddU16(builder *flatbuffers.Builder, u16 uint16) {
+ builder.PrependUint16Slot(3, u16, 0)
+}
+func TypeAliasesAddI32(builder *flatbuffers.Builder, i32 int32) {
+ builder.PrependInt32Slot(4, i32, 0)
+}
+func TypeAliasesAddU32(builder *flatbuffers.Builder, u32 uint32) {
+ builder.PrependUint32Slot(5, u32, 0)
+}
+func TypeAliasesAddI64(builder *flatbuffers.Builder, i64 int64) {
+ builder.PrependInt64Slot(6, i64, 0)
+}
+func TypeAliasesAddU64(builder *flatbuffers.Builder, u64 uint64) {
+ builder.PrependUint64Slot(7, u64, 0)
+}
+func TypeAliasesAddF32(builder *flatbuffers.Builder, f32 float32) {
+ builder.PrependFloat32Slot(8, f32, 0.0)
+}
+func TypeAliasesAddF64(builder *flatbuffers.Builder, f64 float64) {
+ builder.PrependFloat64Slot(9, f64, 0.0)
+}
+func TypeAliasesAddV8(builder *flatbuffers.Builder, v8 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(10, flatbuffers.UOffsetT(v8), 0)
+}
+func TypeAliasesStartV8Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(1, numElems, 1)
+}
+func TypeAliasesAddVf64(builder *flatbuffers.Builder, vf64 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(11, flatbuffers.UOffsetT(vf64), 0)
+}
+func TypeAliasesStartVf64Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+ return builder.StartVector(8, numElems, 8)
+}
+func TypeAliasesEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/Example/TypeAliases.java b/tests/MyGame/Example/TypeAliases.java
new file mode 100644
index 0000000..dde6acb
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.java
@@ -0,0 +1,100 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TypeAliases extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static TypeAliases getRootAsTypeAliases(ByteBuffer _bb) { return getRootAsTypeAliases(_bb, new TypeAliases()); }
+ public static TypeAliases getRootAsTypeAliases(ByteBuffer _bb, TypeAliases obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public TypeAliases __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public byte i8() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }
+ public boolean mutateI8(byte i8) { int o = __offset(4); if (o != 0) { bb.put(o + bb_pos, i8); return true; } else { return false; } }
+ public int u8() { int o = __offset(6); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 0; }
+ public boolean mutateU8(int u8) { int o = __offset(6); if (o != 0) { bb.put(o + bb_pos, (byte)u8); return true; } else { return false; } }
+ public short i16() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 0; }
+ public boolean mutateI16(short i16) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, i16); return true; } else { return false; } }
+ public int u16() { int o = __offset(10); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; }
+ public boolean mutateU16(int u16) { int o = __offset(10); if (o != 0) { bb.putShort(o + bb_pos, (short)u16); return true; } else { return false; } }
+ public int i32() { int o = __offset(12); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+ public boolean mutateI32(int i32) { int o = __offset(12); if (o != 0) { bb.putInt(o + bb_pos, i32); return true; } else { return false; } }
+ public long u32() { int o = __offset(14); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
+ public boolean mutateU32(long u32) { int o = __offset(14); if (o != 0) { bb.putInt(o + bb_pos, (int)u32); return true; } else { return false; } }
+ public long i64() { int o = __offset(16); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateI64(long i64) { int o = __offset(16); if (o != 0) { bb.putLong(o + bb_pos, i64); return true; } else { return false; } }
+ public long u64() { int o = __offset(18); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public boolean mutateU64(long u64) { int o = __offset(18); if (o != 0) { bb.putLong(o + bb_pos, u64); return true; } else { return false; } }
+ public float f32() { int o = __offset(20); return o != 0 ? bb.getFloat(o + bb_pos) : 0.0f; }
+ public boolean mutateF32(float f32) { int o = __offset(20); if (o != 0) { bb.putFloat(o + bb_pos, f32); return true; } else { return false; } }
+ public double f64() { int o = __offset(22); return o != 0 ? bb.getDouble(o + bb_pos) : 0.0; }
+ public boolean mutateF64(double f64) { int o = __offset(22); if (o != 0) { bb.putDouble(o + bb_pos, f64); return true; } else { return false; } }
+ public byte v8(int j) { int o = __offset(24); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
+ public int v8Length() { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer v8AsByteBuffer() { return __vector_as_bytebuffer(24, 1); }
+ public ByteBuffer v8InByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 24, 1); }
+ public boolean mutateV8(int j, byte v8) { int o = __offset(24); if (o != 0) { bb.put(__vector(o) + j * 1, v8); return true; } else { return false; } }
+ public double vf64(int j) { int o = __offset(26); return o != 0 ? bb.getDouble(__vector(o) + j * 8) : 0; }
+ public int vf64Length() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer vf64AsByteBuffer() { return __vector_as_bytebuffer(26, 8); }
+ public ByteBuffer vf64InByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 26, 8); }
+ public boolean mutateVf64(int j, double vf64) { int o = __offset(26); if (o != 0) { bb.putDouble(__vector(o) + j * 8, vf64); return true; } else { return false; } }
+
+ public static int createTypeAliases(FlatBufferBuilder builder,
+ byte i8,
+ int u8,
+ short i16,
+ int u16,
+ int i32,
+ long u32,
+ long i64,
+ long u64,
+ float f32,
+ double f64,
+ int v8Offset,
+ int vf64Offset) {
+ builder.startTable(12);
+ TypeAliases.addF64(builder, f64);
+ TypeAliases.addU64(builder, u64);
+ TypeAliases.addI64(builder, i64);
+ TypeAliases.addVf64(builder, vf64Offset);
+ TypeAliases.addV8(builder, v8Offset);
+ TypeAliases.addF32(builder, f32);
+ TypeAliases.addU32(builder, u32);
+ TypeAliases.addI32(builder, i32);
+ TypeAliases.addU16(builder, u16);
+ TypeAliases.addI16(builder, i16);
+ TypeAliases.addU8(builder, u8);
+ TypeAliases.addI8(builder, i8);
+ return TypeAliases.endTypeAliases(builder);
+ }
+
+ public static void startTypeAliases(FlatBufferBuilder builder) { builder.startTable(12); }
+ public static void addI8(FlatBufferBuilder builder, byte i8) { builder.addByte(0, i8, 0); }
+ public static void addU8(FlatBufferBuilder builder, int u8) { builder.addByte(1, (byte)u8, (byte)0); }
+ public static void addI16(FlatBufferBuilder builder, short i16) { builder.addShort(2, i16, 0); }
+ public static void addU16(FlatBufferBuilder builder, int u16) { builder.addShort(3, (short)u16, (short)0); }
+ public static void addI32(FlatBufferBuilder builder, int i32) { builder.addInt(4, i32, 0); }
+ public static void addU32(FlatBufferBuilder builder, long u32) { builder.addInt(5, (int)u32, (int)0L); }
+ public static void addI64(FlatBufferBuilder builder, long i64) { builder.addLong(6, i64, 0L); }
+ public static void addU64(FlatBufferBuilder builder, long u64) { builder.addLong(7, u64, 0L); }
+ public static void addF32(FlatBufferBuilder builder, float f32) { builder.addFloat(8, f32, 0.0f); }
+ public static void addF64(FlatBufferBuilder builder, double f64) { builder.addDouble(9, f64, 0.0); }
+ public static void addV8(FlatBufferBuilder builder, int v8Offset) { builder.addOffset(10, v8Offset, 0); }
+ public static int createV8Vector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+ public static void startV8Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static void addVf64(FlatBufferBuilder builder, int vf64Offset) { builder.addOffset(11, vf64Offset, 0); }
+ public static int createVf64Vector(FlatBufferBuilder builder, double[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addDouble(data[i]); return builder.endVector(); }
+ public static void startVf64Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static int endTypeAliases(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/MyGame/Example/TypeAliases.kt b/tests/MyGame/Example/TypeAliases.kt
new file mode 100644
index 0000000..d1e8816
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.kt
@@ -0,0 +1,263 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class TypeAliases : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : TypeAliases {
+ __init(_i, _bb)
+ return this
+ }
+ val i8 : Byte
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.get(o + bb_pos) else 0
+ }
+ fun mutateI8(i8: Byte) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.put(o + bb_pos, i8)
+ true
+ } else {
+ false
+ }
+ }
+ val u8 : UByte
+ get() {
+ val o = __offset(6)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u
+ }
+ fun mutateU8(u8: UByte) : Boolean {
+ val o = __offset(6)
+ return if (o != 0) {
+ bb.put(o + bb_pos, u8.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ val i16 : Short
+ get() {
+ val o = __offset(8)
+ return if(o != 0) bb.getShort(o + bb_pos) else 0
+ }
+ fun mutateI16(i16: Short) : Boolean {
+ val o = __offset(8)
+ return if (o != 0) {
+ bb.putShort(o + bb_pos, i16)
+ true
+ } else {
+ false
+ }
+ }
+ val u16 : UShort
+ get() {
+ val o = __offset(10)
+ return if(o != 0) bb.getShort(o + bb_pos).toUShort() else 0u
+ }
+ fun mutateU16(u16: UShort) : Boolean {
+ val o = __offset(10)
+ return if (o != 0) {
+ bb.putShort(o + bb_pos, u16.toShort())
+ true
+ } else {
+ false
+ }
+ }
+ val i32 : Int
+ get() {
+ val o = __offset(12)
+ return if(o != 0) bb.getInt(o + bb_pos) else 0
+ }
+ fun mutateI32(i32: Int) : Boolean {
+ val o = __offset(12)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, i32)
+ true
+ } else {
+ false
+ }
+ }
+ val u32 : UInt
+ get() {
+ val o = __offset(14)
+ return if(o != 0) bb.getInt(o + bb_pos).toUInt() else 0u
+ }
+ fun mutateU32(u32: UInt) : Boolean {
+ val o = __offset(14)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, u32.toInt())
+ true
+ } else {
+ false
+ }
+ }
+ val i64 : Long
+ get() {
+ val o = __offset(16)
+ return if(o != 0) bb.getLong(o + bb_pos) else 0L
+ }
+ fun mutateI64(i64: Long) : Boolean {
+ val o = __offset(16)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, i64)
+ true
+ } else {
+ false
+ }
+ }
+ val u64 : ULong
+ get() {
+ val o = __offset(18)
+ return if(o != 0) bb.getLong(o + bb_pos).toULong() else 0UL
+ }
+ fun mutateU64(u64: ULong) : Boolean {
+ val o = __offset(18)
+ return if (o != 0) {
+ bb.putLong(o + bb_pos, u64.toLong())
+ true
+ } else {
+ false
+ }
+ }
+ val f32 : Float
+ get() {
+ val o = __offset(20)
+ return if(o != 0) bb.getFloat(o + bb_pos) else 0.0f
+ }
+ fun mutateF32(f32: Float) : Boolean {
+ val o = __offset(20)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, f32)
+ true
+ } else {
+ false
+ }
+ }
+ val f64 : Double
+ get() {
+ val o = __offset(22)
+ return if(o != 0) bb.getDouble(o + bb_pos) else 0.0
+ }
+ fun mutateF64(f64: Double) : Boolean {
+ val o = __offset(22)
+ return if (o != 0) {
+ bb.putDouble(o + bb_pos, f64)
+ true
+ } else {
+ false
+ }
+ }
+ fun v8(j: Int) : Byte {
+ val o = __offset(24)
+ return if (o != 0) {
+ bb.get(__vector(o) + j * 1)
+ } else {
+ 0
+ }
+ }
+ val v8Length : Int
+ get() {
+ val o = __offset(24); return if (o != 0) __vector_len(o) else 0
+ }
+ val v8AsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(24, 1)
+ fun v8InByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 24, 1)
+ fun mutateV8(j: Int, v8: Byte) : Boolean {
+ val o = __offset(24)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, v8)
+ true
+ } else {
+ false
+ }
+ }
+ fun vf64(j: Int) : Double {
+ val o = __offset(26)
+ return if (o != 0) {
+ bb.getDouble(__vector(o) + j * 8)
+ } else {
+ 0.0
+ }
+ }
+ val vf64Length : Int
+ get() {
+ val o = __offset(26); return if (o != 0) __vector_len(o) else 0
+ }
+ val vf64AsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(26, 8)
+ fun vf64InByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 26, 8)
+ fun mutateVf64(j: Int, vf64: Double) : Boolean {
+ val o = __offset(26)
+ return if (o != 0) {
+ bb.putDouble(__vector(o) + j * 8, vf64)
+ true
+ } else {
+ false
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsTypeAliases(_bb: ByteBuffer): TypeAliases = getRootAsTypeAliases(_bb, TypeAliases())
+ fun getRootAsTypeAliases(_bb: ByteBuffer, obj: TypeAliases): TypeAliases {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createTypeAliases(builder: FlatBufferBuilder, i8: Byte, u8: UByte, i16: Short, u16: UShort, i32: Int, u32: UInt, i64: Long, u64: ULong, f32: Float, f64: Double, v8Offset: Int, vf64Offset: Int) : Int {
+ builder.startTable(12)
+ addF64(builder, f64)
+ addU64(builder, u64)
+ addI64(builder, i64)
+ addVf64(builder, vf64Offset)
+ addV8(builder, v8Offset)
+ addF32(builder, f32)
+ addU32(builder, u32)
+ addI32(builder, i32)
+ addU16(builder, u16)
+ addI16(builder, i16)
+ addU8(builder, u8)
+ addI8(builder, i8)
+ return endTypeAliases(builder)
+ }
+ fun startTypeAliases(builder: FlatBufferBuilder) = builder.startTable(12)
+ fun addI8(builder: FlatBufferBuilder, i8: Byte) = builder.addByte(0, i8, 0)
+ fun addU8(builder: FlatBufferBuilder, u8: UByte) = builder.addByte(1, u8.toByte(), 0)
+ fun addI16(builder: FlatBufferBuilder, i16: Short) = builder.addShort(2, i16, 0)
+ fun addU16(builder: FlatBufferBuilder, u16: UShort) = builder.addShort(3, u16.toShort(), 0)
+ fun addI32(builder: FlatBufferBuilder, i32: Int) = builder.addInt(4, i32, 0)
+ fun addU32(builder: FlatBufferBuilder, u32: UInt) = builder.addInt(5, u32.toInt(), 0)
+ fun addI64(builder: FlatBufferBuilder, i64: Long) = builder.addLong(6, i64, 0L)
+ fun addU64(builder: FlatBufferBuilder, u64: ULong) = builder.addLong(7, u64.toLong(), 0)
+ fun addF32(builder: FlatBufferBuilder, f32: Float) = builder.addFloat(8, f32, 0.0)
+ fun addF64(builder: FlatBufferBuilder, f64: Double) = builder.addDouble(9, f64, 0.0)
+ fun addV8(builder: FlatBufferBuilder, v8: Int) = builder.addOffset(10, v8, 0)
+ fun createV8Vector(builder: FlatBufferBuilder, data: ByteArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addByte(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startV8Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun addVf64(builder: FlatBufferBuilder, vf64: Int) = builder.addOffset(11, vf64, 0)
+ fun createVf64Vector(builder: FlatBufferBuilder, data: DoubleArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addDouble(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startVf64Vector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun endTypeAliases(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/MyGame/Example/TypeAliases.lua b/tests/MyGame/Example/TypeAliases.lua
new file mode 100644
index 0000000..90f569c
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.lua
@@ -0,0 +1,141 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local TypeAliases = {} -- the module
+local TypeAliases_mt = {} -- the class metatable
+
+function TypeAliases.New()
+ local o = {}
+ setmetatable(o, {__index = TypeAliases_mt})
+ return o
+end
+function TypeAliases.GetRootAsTypeAliases(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TypeAliases.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TypeAliases_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TypeAliases_mt:I8()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U8()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:I16()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U16()
+ local o = self.view:Offset(10)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:I32()
+ local o = self.view:Offset(12)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U32()
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:I64()
+ local o = self.view:Offset(16)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U64()
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:F32()
+ local o = self.view:Offset(20)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 0.0
+end
+function TypeAliases_mt:F64()
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float64, o + self.view.pos)
+ end
+ return 0.0
+end
+function TypeAliases_mt:V8(j)
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Int8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function TypeAliases_mt:V8Length()
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function TypeAliases_mt:Vf64(j)
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function TypeAliases_mt:Vf64Length()
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function TypeAliases.Start(builder) builder:StartObject(12) end
+function TypeAliases.AddI8(builder, i8) builder:PrependInt8Slot(0, i8, 0) end
+function TypeAliases.AddU8(builder, u8) builder:PrependUint8Slot(1, u8, 0) end
+function TypeAliases.AddI16(builder, i16) builder:PrependInt16Slot(2, i16, 0) end
+function TypeAliases.AddU16(builder, u16) builder:PrependUint16Slot(3, u16, 0) end
+function TypeAliases.AddI32(builder, i32) builder:PrependInt32Slot(4, i32, 0) end
+function TypeAliases.AddU32(builder, u32) builder:PrependUint32Slot(5, u32, 0) end
+function TypeAliases.AddI64(builder, i64) builder:PrependInt64Slot(6, i64, 0) end
+function TypeAliases.AddU64(builder, u64) builder:PrependUint64Slot(7, u64, 0) end
+function TypeAliases.AddF32(builder, f32) builder:PrependFloat32Slot(8, f32, 0.0) end
+function TypeAliases.AddF64(builder, f64) builder:PrependFloat64Slot(9, f64, 0.0) end
+function TypeAliases.AddV8(builder, v8) builder:PrependUOffsetTRelativeSlot(10, v8, 0) end
+function TypeAliases.StartV8Vector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function TypeAliases.AddVf64(builder, vf64) builder:PrependUOffsetTRelativeSlot(11, vf64, 0) end
+function TypeAliases.StartVf64Vector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function TypeAliases.End(builder) return builder:EndObject() end
+
+return TypeAliases -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/TypeAliases.php b/tests/MyGame/Example/TypeAliases.php
new file mode 100644
index 0000000..7629897
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.php
@@ -0,0 +1,387 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TypeAliases extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TypeAliases
+ */
+ public static function getRootAsTypeAliases(ByteBuffer $bb)
+ {
+ $obj = new TypeAliases();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function TypeAliasesIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function TypeAliasesBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::TypeAliasesIdentifier());
+ }
+
+ public static function TypeAliasesExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TypeAliases
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function getI8()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getSbyte($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getU8()
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return short
+ */
+ public function getI16()
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->bb->getShort($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ushort
+ */
+ public function getU16()
+ {
+ $o = $this->__offset(10);
+ return $o != 0 ? $this->bb->getUshort($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getI32()
+ {
+ $o = $this->__offset(12);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return uint
+ */
+ public function getU32()
+ {
+ $o = $this->__offset(14);
+ return $o != 0 ? $this->bb->getUint($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return long
+ */
+ public function getI64()
+ {
+ $o = $this->__offset(16);
+ return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return ulong
+ */
+ public function getU64()
+ {
+ $o = $this->__offset(18);
+ return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @return float
+ */
+ public function getF32()
+ {
+ $o = $this->__offset(20);
+ return $o != 0 ? $this->bb->getFloat($o + $this->bb_pos) : 0.0;
+ }
+
+ /**
+ * @return double
+ */
+ public function getF64()
+ {
+ $o = $this->__offset(22);
+ return $o != 0 ? $this->bb->getDouble($o + $this->bb_pos) : 0.0;
+ }
+
+ /**
+ * @param int offset
+ * @return sbyte
+ */
+ public function getV8($j)
+ {
+ $o = $this->__offset(24);
+ return $o != 0 ? $this->bb->getSbyte($this->__vector($o) + $j * 1) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getV8Length()
+ {
+ $o = $this->__offset(24);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return double
+ */
+ public function getVf64($j)
+ {
+ $o = $this->__offset(26);
+ return $o != 0 ? $this->bb->getDouble($this->__vector($o) + $j * 8) : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getVf64Length()
+ {
+ $o = $this->__offset(26);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTypeAliases(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(12);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TypeAliases
+ */
+ public static function createTypeAliases(FlatBufferBuilder $builder, $i8, $u8, $i16, $u16, $i32, $u32, $i64, $u64, $f32, $f64, $v8, $vf64)
+ {
+ $builder->startObject(12);
+ self::addI8($builder, $i8);
+ self::addU8($builder, $u8);
+ self::addI16($builder, $i16);
+ self::addU16($builder, $u16);
+ self::addI32($builder, $i32);
+ self::addU32($builder, $u32);
+ self::addI64($builder, $i64);
+ self::addU64($builder, $u64);
+ self::addF32($builder, $f32);
+ self::addF64($builder, $f64);
+ self::addV8($builder, $v8);
+ self::addVf64($builder, $vf64);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param sbyte
+ * @return void
+ */
+ public static function addI8(FlatBufferBuilder $builder, $i8)
+ {
+ $builder->addSbyteX(0, $i8, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addU8(FlatBufferBuilder $builder, $u8)
+ {
+ $builder->addByteX(1, $u8, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param short
+ * @return void
+ */
+ public static function addI16(FlatBufferBuilder $builder, $i16)
+ {
+ $builder->addShortX(2, $i16, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ushort
+ * @return void
+ */
+ public static function addU16(FlatBufferBuilder $builder, $u16)
+ {
+ $builder->addUshortX(3, $u16, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addI32(FlatBufferBuilder $builder, $i32)
+ {
+ $builder->addIntX(4, $i32, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param uint
+ * @return void
+ */
+ public static function addU32(FlatBufferBuilder $builder, $u32)
+ {
+ $builder->addUintX(5, $u32, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param long
+ * @return void
+ */
+ public static function addI64(FlatBufferBuilder $builder, $i64)
+ {
+ $builder->addLongX(6, $i64, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param ulong
+ * @return void
+ */
+ public static function addU64(FlatBufferBuilder $builder, $u64)
+ {
+ $builder->addUlongX(7, $u64, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param float
+ * @return void
+ */
+ public static function addF32(FlatBufferBuilder $builder, $f32)
+ {
+ $builder->addFloatX(8, $f32, 0.0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param double
+ * @return void
+ */
+ public static function addF64(FlatBufferBuilder $builder, $f64)
+ {
+ $builder->addDoubleX(9, $f64, 0.0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addV8(FlatBufferBuilder $builder, $v8)
+ {
+ $builder->addOffsetX(10, $v8, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createV8Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putSbyte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startV8Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addVf64(FlatBufferBuilder $builder, $vf64)
+ {
+ $builder->addOffsetX(11, $vf64, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createVf64Vector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(8, count($data), 8);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putDouble($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startVf64Vector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(8, $numElems, 8);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTypeAliases(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example/TypeAliases.py b/tests/MyGame/Example/TypeAliases.py
new file mode 100644
index 0000000..81e9b06
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.py
@@ -0,0 +1,154 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class TypeAliases(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsTypeAliases(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = TypeAliases()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def TypeAliasesBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # TypeAliases
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TypeAliases
+ def I8(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int8Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def U8(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def I16(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int16Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def U16(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint16Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def I32(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def U32(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint32Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def I64(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def U64(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+ return 0
+
+ # TypeAliases
+ def F32(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return 0.0
+
+ # TypeAliases
+ def F64(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+ return 0.0
+
+ # TypeAliases
+ def V8(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Int8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+ return 0
+
+ # TypeAliases
+ def V8AsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int8Flags, o)
+ return 0
+
+ # TypeAliases
+ def V8Length(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # TypeAliases
+ def Vf64(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # TypeAliases
+ def Vf64AsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float64Flags, o)
+ return 0
+
+ # TypeAliases
+ def Vf64Length(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+def TypeAliasesStart(builder): builder.StartObject(12)
+def TypeAliasesAddI8(builder, i8): builder.PrependInt8Slot(0, i8, 0)
+def TypeAliasesAddU8(builder, u8): builder.PrependUint8Slot(1, u8, 0)
+def TypeAliasesAddI16(builder, i16): builder.PrependInt16Slot(2, i16, 0)
+def TypeAliasesAddU16(builder, u16): builder.PrependUint16Slot(3, u16, 0)
+def TypeAliasesAddI32(builder, i32): builder.PrependInt32Slot(4, i32, 0)
+def TypeAliasesAddU32(builder, u32): builder.PrependUint32Slot(5, u32, 0)
+def TypeAliasesAddI64(builder, i64): builder.PrependInt64Slot(6, i64, 0)
+def TypeAliasesAddU64(builder, u64): builder.PrependUint64Slot(7, u64, 0)
+def TypeAliasesAddF32(builder, f32): builder.PrependFloat32Slot(8, f32, 0.0)
+def TypeAliasesAddF64(builder, f64): builder.PrependFloat64Slot(9, f64, 0.0)
+def TypeAliasesAddV8(builder, v8): builder.PrependUOffsetTRelativeSlot(10, flatbuffers.number_types.UOffsetTFlags.py_type(v8), 0)
+def TypeAliasesStartV8Vector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def TypeAliasesAddVf64(builder, vf64): builder.PrependUOffsetTRelativeSlot(11, flatbuffers.number_types.UOffsetTFlags.py_type(vf64), 0)
+def TypeAliasesStartVf64Vector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def TypeAliasesEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs
new file mode 100644
index 0000000..1dbb315
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.cs
@@ -0,0 +1,49 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Vec3 : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public Vec3 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public float X { get { return __p.bb.GetFloat(__p.bb_pos + 0); } }
+ public void MutateX(float x) { __p.bb.PutFloat(__p.bb_pos + 0, x); }
+ public float Y { get { return __p.bb.GetFloat(__p.bb_pos + 4); } }
+ public void MutateY(float y) { __p.bb.PutFloat(__p.bb_pos + 4, y); }
+ public float Z { get { return __p.bb.GetFloat(__p.bb_pos + 8); } }
+ public void MutateZ(float z) { __p.bb.PutFloat(__p.bb_pos + 8, z); }
+ public double Test1 { get { return __p.bb.GetDouble(__p.bb_pos + 16); } }
+ public void MutateTest1(double test1) { __p.bb.PutDouble(__p.bb_pos + 16, test1); }
+ public MyGame.Example.Color Test2 { get { return (MyGame.Example.Color)__p.bb.Get(__p.bb_pos + 24); } }
+ public void MutateTest2(MyGame.Example.Color test2) { __p.bb.Put(__p.bb_pos + 24, (byte)test2); }
+ public MyGame.Example.Test Test3 { get { return (new MyGame.Example.Test()).__assign(__p.bb_pos + 26, __p.bb); } }
+
+ public static Offset<MyGame.Example.Vec3> CreateVec3(FlatBufferBuilder builder, float X, float Y, float Z, double Test1, MyGame.Example.Color Test2, short test3_A, sbyte test3_B) {
+ builder.Prep(8, 32);
+ builder.Pad(2);
+ builder.Prep(2, 4);
+ builder.Pad(1);
+ builder.PutSbyte(test3_B);
+ builder.PutShort(test3_A);
+ builder.Pad(1);
+ builder.PutByte((byte)Test2);
+ builder.PutDouble(Test1);
+ builder.Pad(4);
+ builder.PutFloat(Z);
+ builder.PutFloat(Y);
+ builder.PutFloat(X);
+ return new Offset<MyGame.Example.Vec3>(builder.Offset);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Vec3.go b/tests/MyGame/Example/Vec3.go
new file mode 100644
index 0000000..9131afd
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.go
@@ -0,0 +1,80 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Vec3 struct {
+ _tab flatbuffers.Struct
+}
+
+func (rcv *Vec3) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Vec3) Table() flatbuffers.Table {
+ return rcv._tab.Table
+}
+
+func (rcv *Vec3) X() float32 {
+ return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
+}
+func (rcv *Vec3) MutateX(n float32) bool {
+ return rcv._tab.MutateFloat32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
+}
+
+func (rcv *Vec3) Y() float32 {
+ return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
+}
+func (rcv *Vec3) MutateY(n float32) bool {
+ return rcv._tab.MutateFloat32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
+}
+
+func (rcv *Vec3) Z() float32 {
+ return rcv._tab.GetFloat32(rcv._tab.Pos + flatbuffers.UOffsetT(8))
+}
+func (rcv *Vec3) MutateZ(n float32) bool {
+ return rcv._tab.MutateFloat32(rcv._tab.Pos+flatbuffers.UOffsetT(8), n)
+}
+
+func (rcv *Vec3) Test1() float64 {
+ return rcv._tab.GetFloat64(rcv._tab.Pos + flatbuffers.UOffsetT(16))
+}
+func (rcv *Vec3) MutateTest1(n float64) bool {
+ return rcv._tab.MutateFloat64(rcv._tab.Pos+flatbuffers.UOffsetT(16), n)
+}
+
+func (rcv *Vec3) Test2() Color {
+ return Color(rcv._tab.GetByte(rcv._tab.Pos + flatbuffers.UOffsetT(24)))
+}
+func (rcv *Vec3) MutateTest2(n Color) bool {
+ return rcv._tab.MutateByte(rcv._tab.Pos+flatbuffers.UOffsetT(24), byte(n))
+}
+
+func (rcv *Vec3) Test3(obj *Test) *Test {
+ if obj == nil {
+ obj = new(Test)
+ }
+ obj.Init(rcv._tab.Bytes, rcv._tab.Pos+26)
+ return obj
+}
+
+func CreateVec3(builder *flatbuffers.Builder, x float32, y float32, z float32, test1 float64, test2 Color, test3_a int16, test3_b int8) flatbuffers.UOffsetT {
+ builder.Prep(8, 32)
+ builder.Pad(2)
+ builder.Prep(2, 4)
+ builder.Pad(1)
+ builder.PrependInt8(test3_b)
+ builder.PrependInt16(test3_a)
+ builder.Pad(1)
+ builder.PrependByte(byte(test2))
+ builder.PrependFloat64(test1)
+ builder.Pad(4)
+ builder.PrependFloat32(z)
+ builder.PrependFloat32(y)
+ builder.PrependFloat32(x)
+ return builder.Offset()
+}
diff --git a/tests/MyGame/Example/Vec3.java b/tests/MyGame/Example/Vec3.java
new file mode 100644
index 0000000..0b67c74
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.java
@@ -0,0 +1,45 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Vec3 extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Vec3 __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public float x() { return bb.getFloat(bb_pos + 0); }
+ public void mutateX(float x) { bb.putFloat(bb_pos + 0, x); }
+ public float y() { return bb.getFloat(bb_pos + 4); }
+ public void mutateY(float y) { bb.putFloat(bb_pos + 4, y); }
+ public float z() { return bb.getFloat(bb_pos + 8); }
+ public void mutateZ(float z) { bb.putFloat(bb_pos + 8, z); }
+ public double test1() { return bb.getDouble(bb_pos + 16); }
+ public void mutateTest1(double test1) { bb.putDouble(bb_pos + 16, test1); }
+ public int test2() { return bb.get(bb_pos + 24) & 0xFF; }
+ public void mutateTest2(int test2) { bb.put(bb_pos + 24, (byte)test2); }
+ public MyGame.Example.Test test3() { return test3(new MyGame.Example.Test()); }
+ public MyGame.Example.Test test3(MyGame.Example.Test obj) { return obj.__assign(bb_pos + 26, bb); }
+
+ public static int createVec3(FlatBufferBuilder builder, float x, float y, float z, double test1, int test2, short test3_a, byte test3_b) {
+ builder.prep(8, 32);
+ builder.pad(2);
+ builder.prep(2, 4);
+ builder.pad(1);
+ builder.putByte(test3_b);
+ builder.putShort(test3_a);
+ builder.pad(1);
+ builder.putByte((byte)test2);
+ builder.putDouble(test1);
+ builder.pad(4);
+ builder.putFloat(z);
+ builder.putFloat(y);
+ builder.putFloat(x);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/MyGame/Example/Vec3.kt b/tests/MyGame/Example/Vec3.kt
new file mode 100644
index 0000000..90f1b4a
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.kt
@@ -0,0 +1,50 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Vec3 : Struct() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Vec3 {
+ __init(_i, _bb)
+ return this
+ }
+ val x : Float get() = bb.getFloat(bb_pos + 0)
+ fun mutateX(x: Float) : ByteBuffer = bb.putFloat(bb_pos + 0, x)
+ val y : Float get() = bb.getFloat(bb_pos + 4)
+ fun mutateY(y: Float) : ByteBuffer = bb.putFloat(bb_pos + 4, y)
+ val z : Float get() = bb.getFloat(bb_pos + 8)
+ fun mutateZ(z: Float) : ByteBuffer = bb.putFloat(bb_pos + 8, z)
+ val test1 : Double get() = bb.getDouble(bb_pos + 16)
+ fun mutateTest1(test1: Double) : ByteBuffer = bb.putDouble(bb_pos + 16, test1)
+ val test2 : UByte get() = bb.get(bb_pos + 24).toUByte()
+ fun mutateTest2(test2: UByte) : ByteBuffer = bb.put(bb_pos + 24, test2.toByte())
+ val test3 : MyGame.Example.Test? get() = test3(MyGame.Example.Test())
+ fun test3(obj: MyGame.Example.Test) : MyGame.Example.Test? = obj.__assign(bb_pos + 26, bb)
+ companion object {
+ fun createVec3(builder: FlatBufferBuilder, x: Float, y: Float, z: Float, test1: Double, test2: UByte, test3_a: Short, test3_b: Byte) : Int {
+ builder.prep(8, 32)
+ builder.pad(2)
+ builder.prep(2, 4)
+ builder.pad(1)
+ builder.putByte(test3_b)
+ builder.putShort(test3_a)
+ builder.pad(1)
+ builder.putByte(test2.toByte())
+ builder.putDouble(test1)
+ builder.pad(4)
+ builder.putFloat(z)
+ builder.putFloat(y)
+ builder.putFloat(x)
+ return builder.offset()
+ }
+ }
+}
diff --git a/tests/MyGame/Example/Vec3.lua b/tests/MyGame/Example/Vec3.lua
new file mode 100644
index 0000000..24d4cc1
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.lua
@@ -0,0 +1,54 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Vec3 = {} -- the module
+local Vec3_mt = {} -- the class metatable
+
+function Vec3.New()
+ local o = {}
+ setmetatable(o, {__index = Vec3_mt})
+ return o
+end
+function Vec3_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Vec3_mt:X()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 0)
+end
+function Vec3_mt:Y()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 4)
+end
+function Vec3_mt:Z()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 8)
+end
+function Vec3_mt:Test1()
+ return self.view:Get(flatbuffers.N.Float64, self.view.pos + 16)
+end
+function Vec3_mt:Test2()
+ return self.view:Get(flatbuffers.N.Uint8, self.view.pos + 24)
+end
+function Vec3_mt:Test3(obj)
+ obj:Init(self.view.bytes, self.view.pos + 26)
+ return obj
+end
+function Vec3.CreateVec3(builder, x, y, z, test1, test2, test3_a, test3_b)
+ builder:Prep(8, 32)
+ builder:Pad(2)
+ builder:Prep(2, 4)
+ builder:Pad(1)
+ builder:PrependInt8(test3_b)
+ builder:PrependInt16(test3_a)
+ builder:Pad(1)
+ builder:PrependUint8(test2)
+ builder:PrependFloat64(test1)
+ builder:Pad(4)
+ builder:PrependFloat32(z)
+ builder:PrependFloat32(y)
+ builder:PrependFloat32(x)
+ return builder:Offset()
+end
+
+return Vec3 -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example/Vec3.php b/tests/MyGame/Example/Vec3.php
new file mode 100644
index 0000000..4d149e6
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.php
@@ -0,0 +1,96 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Vec3 extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Vec3
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return float
+ */
+ public function GetX()
+ {
+ return $this->bb->getFloat($this->bb_pos + 0);
+ }
+
+ /**
+ * @return float
+ */
+ public function GetY()
+ {
+ return $this->bb->getFloat($this->bb_pos + 4);
+ }
+
+ /**
+ * @return float
+ */
+ public function GetZ()
+ {
+ return $this->bb->getFloat($this->bb_pos + 8);
+ }
+
+ /**
+ * @return double
+ */
+ public function GetTest1()
+ {
+ return $this->bb->getDouble($this->bb_pos + 16);
+ }
+
+ /**
+ * @return byte
+ */
+ public function GetTest2()
+ {
+ return $this->bb->getByte($this->bb_pos + 24);
+ }
+
+ /**
+ * @return Test
+ */
+ public function getTest3()
+ {
+ $obj = new Test();
+ $obj->init($this->bb_pos + 26, $this->bb);
+ return $obj;
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createVec3(FlatBufferBuilder $builder, $x, $y, $z, $test1, $test2, $test3_a, $test3_b)
+ {
+ $builder->prep(8, 32);
+ $builder->pad(2);
+ $builder->prep(2, 4);
+ $builder->pad(1);
+ $builder->putSbyte($test3_b);
+ $builder->putShort($test3_a);
+ $builder->pad(1);
+ $builder->putByte($test2);
+ $builder->putDouble($test1);
+ $builder->pad(4);
+ $builder->putFloat($z);
+ $builder->putFloat($y);
+ $builder->putFloat($x);
+ return $builder->offset();
+ }
+}
diff --git a/tests/MyGame/Example/Vec3.py b/tests/MyGame/Example/Vec3.py
new file mode 100644
index 0000000..1f32390
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.py
@@ -0,0 +1,44 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class Vec3(object):
+ __slots__ = ['_tab']
+
+ # Vec3
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # Vec3
+ def X(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
+ # Vec3
+ def Y(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
+ # Vec3
+ def Z(self): return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(8))
+ # Vec3
+ def Test1(self): return self._tab.Get(flatbuffers.number_types.Float64Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(16))
+ # Vec3
+ def Test2(self): return self._tab.Get(flatbuffers.number_types.Uint8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(24))
+ # Vec3
+ def Test3(self, obj):
+ obj.Init(self._tab.Bytes, self._tab.Pos + 26)
+ return obj
+
+
+def CreateVec3(builder, x, y, z, test1, test2, test3_a, test3_b):
+ builder.Prep(8, 32)
+ builder.Pad(2)
+ builder.Prep(2, 4)
+ builder.Pad(1)
+ builder.PrependInt8(test3_b)
+ builder.PrependInt16(test3_a)
+ builder.Pad(1)
+ builder.PrependUint8(test2)
+ builder.PrependFloat64(test1)
+ builder.Pad(4)
+ builder.PrependFloat32(z)
+ builder.PrependFloat32(y)
+ builder.PrependFloat32(x)
+ return builder.Offset()
diff --git a/tests/MyGame/Example/__init__.py b/tests/MyGame/Example/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/MyGame/Example/__init__.py
diff --git a/tests/MyGame/Example2/Monster.cs b/tests/MyGame/Example2/Monster.cs
new file mode 100644
index 0000000..a6e9dce
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.cs
@@ -0,0 +1,30 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example2
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Monster : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
+ public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+
+ public static void StartMonster(FlatBufferBuilder builder) { builder.StartTable(0); }
+ public static Offset<MyGame.Example2.Monster> EndMonster(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.Example2.Monster>(o);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/Example2/Monster.go b/tests/MyGame/Example2/Monster.go
new file mode 100644
index 0000000..d0fae94
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.go
@@ -0,0 +1,34 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package Example2
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Monster struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsMonster(buf []byte, offset flatbuffers.UOffsetT) *Monster {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &Monster{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *Monster) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func MonsterStart(builder *flatbuffers.Builder) {
+ builder.StartObject(0)
+}
+func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/Example2/Monster.java b/tests/MyGame/Example2/Monster.java
new file mode 100644
index 0000000..7e0cae1
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.java
@@ -0,0 +1,25 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example2;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Monster extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
+ public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Monster __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+
+ public static void startMonster(FlatBufferBuilder builder) { builder.startTable(0); }
+ public static int endMonster(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/MyGame/Example2/Monster.kt b/tests/MyGame/Example2/Monster.kt
new file mode 100644
index 0000000..de587ba
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.kt
@@ -0,0 +1,33 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example2
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Monster : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Monster {
+ __init(_i, _bb)
+ return this
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsMonster(_bb: ByteBuffer): Monster = getRootAsMonster(_bb, Monster())
+ fun getRootAsMonster(_bb: ByteBuffer, obj: Monster): Monster {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun startMonster(builder: FlatBufferBuilder) = builder.startTable(0)
+ fun endMonster(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/MyGame/Example2/Monster.lua b/tests/MyGame/Example2/Monster.lua
new file mode 100644
index 0000000..347b5db
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.lua
@@ -0,0 +1,27 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example2
+
+local flatbuffers = require('flatbuffers')
+
+local Monster = {} -- the module
+local Monster_mt = {} -- the class metatable
+
+function Monster.New()
+ local o = {}
+ setmetatable(o, {__index = Monster_mt})
+ return o
+end
+function Monster.GetRootAsMonster(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Monster.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Monster_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Monster.Start(builder) builder:StartObject(0) end
+function Monster.End(builder) return builder:EndObject() end
+
+return Monster -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/Example2/Monster.php b/tests/MyGame/Example2/Monster.php
new file mode 100644
index 0000000..b00f150
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.php
@@ -0,0 +1,79 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example2;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Monster extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Monster
+ */
+ public static function getRootAsMonster(ByteBuffer $bb)
+ {
+ $obj = new Monster();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function MonsterIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function MonsterBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::MonsterIdentifier());
+ }
+
+ public static function MonsterExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Monster
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startMonster(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Monster
+ */
+ public static function createMonster(FlatBufferBuilder $builder, )
+ {
+ $builder->startObject(0);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endMonster(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/Example2/Monster.py b/tests/MyGame/Example2/Monster.py
new file mode 100644
index 0000000..44cc906
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.py
@@ -0,0 +1,26 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example2
+
+import flatbuffers
+
+class Monster(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsMonster(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = Monster()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def MonsterBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # Monster
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+def MonsterStart(builder): builder.StartObject(0)
+def MonsterEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example2/__init__.py b/tests/MyGame/Example2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/MyGame/Example2/__init__.py
diff --git a/tests/MyGame/InParentNamespace.cs b/tests/MyGame/InParentNamespace.cs
new file mode 100644
index 0000000..869c400
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.cs
@@ -0,0 +1,30 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct InParentNamespace : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static InParentNamespace GetRootAsInParentNamespace(ByteBuffer _bb) { return GetRootAsInParentNamespace(_bb, new InParentNamespace()); }
+ public static InParentNamespace GetRootAsInParentNamespace(ByteBuffer _bb, InParentNamespace obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public InParentNamespace __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+
+ public static void StartInParentNamespace(FlatBufferBuilder builder) { builder.StartTable(0); }
+ public static Offset<MyGame.InParentNamespace> EndInParentNamespace(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.InParentNamespace>(o);
+ }
+};
+
+
+}
diff --git a/tests/MyGame/InParentNamespace.go b/tests/MyGame/InParentNamespace.go
new file mode 100644
index 0000000..fc6ce32
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.go
@@ -0,0 +1,34 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package MyGame
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type InParentNamespace struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsInParentNamespace(buf []byte, offset flatbuffers.UOffsetT) *InParentNamespace {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &InParentNamespace{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *InParentNamespace) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *InParentNamespace) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func InParentNamespaceStart(builder *flatbuffers.Builder) {
+ builder.StartObject(0)
+}
+func InParentNamespaceEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/MyGame/InParentNamespace.java b/tests/MyGame/InParentNamespace.java
new file mode 100644
index 0000000..fd10bc3
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.java
@@ -0,0 +1,25 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class InParentNamespace extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static InParentNamespace getRootAsInParentNamespace(ByteBuffer _bb) { return getRootAsInParentNamespace(_bb, new InParentNamespace()); }
+ public static InParentNamespace getRootAsInParentNamespace(ByteBuffer _bb, InParentNamespace obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public InParentNamespace __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+
+ public static void startInParentNamespace(FlatBufferBuilder builder) { builder.startTable(0); }
+ public static int endInParentNamespace(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/MyGame/InParentNamespace.kt b/tests/MyGame/InParentNamespace.kt
new file mode 100644
index 0000000..76779fc
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.kt
@@ -0,0 +1,33 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class InParentNamespace : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : InParentNamespace {
+ __init(_i, _bb)
+ return this
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsInParentNamespace(_bb: ByteBuffer): InParentNamespace = getRootAsInParentNamespace(_bb, InParentNamespace())
+ fun getRootAsInParentNamespace(_bb: ByteBuffer, obj: InParentNamespace): InParentNamespace {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun startInParentNamespace(builder: FlatBufferBuilder) = builder.startTable(0)
+ fun endInParentNamespace(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/MyGame/InParentNamespace.lua b/tests/MyGame/InParentNamespace.lua
new file mode 100644
index 0000000..b3fa0c8
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.lua
@@ -0,0 +1,27 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: MyGame
+
+local flatbuffers = require('flatbuffers')
+
+local InParentNamespace = {} -- the module
+local InParentNamespace_mt = {} -- the class metatable
+
+function InParentNamespace.New()
+ local o = {}
+ setmetatable(o, {__index = InParentNamespace_mt})
+ return o
+end
+function InParentNamespace.GetRootAsInParentNamespace(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = InParentNamespace.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function InParentNamespace_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function InParentNamespace.Start(builder) builder:StartObject(0) end
+function InParentNamespace.End(builder) return builder:EndObject() end
+
+return InParentNamespace -- return the module
\ No newline at end of file
diff --git a/tests/MyGame/InParentNamespace.php b/tests/MyGame/InParentNamespace.php
new file mode 100644
index 0000000..e13a4f3
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.php
@@ -0,0 +1,79 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class InParentNamespace extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return InParentNamespace
+ */
+ public static function getRootAsInParentNamespace(ByteBuffer $bb)
+ {
+ $obj = new InParentNamespace();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function InParentNamespaceIdentifier()
+ {
+ return "MONS";
+ }
+
+ public static function InParentNamespaceBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::InParentNamespaceIdentifier());
+ }
+
+ public static function InParentNamespaceExtension()
+ {
+ return "mon";
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return InParentNamespace
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startInParentNamespace(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return InParentNamespace
+ */
+ public static function createInParentNamespace(FlatBufferBuilder $builder, )
+ {
+ $builder->startObject(0);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endInParentNamespace(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/MyGame/InParentNamespace.py b/tests/MyGame/InParentNamespace.py
new file mode 100644
index 0000000..3bfcca7
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.py
@@ -0,0 +1,26 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: MyGame
+
+import flatbuffers
+
+class InParentNamespace(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsInParentNamespace(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = InParentNamespace()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def InParentNamespaceBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x53", size_prefixed=size_prefixed)
+
+ # InParentNamespace
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+def InParentNamespaceStart(builder): builder.StartObject(0)
+def InParentNamespaceEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/MonsterExtra.cs b/tests/MyGame/MonsterExtra.cs
new file mode 100644
index 0000000..5706390
--- /dev/null
+++ b/tests/MyGame/MonsterExtra.cs
@@ -0,0 +1,108 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct MonsterExtra : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static MonsterExtra GetRootAsMonsterExtra(ByteBuffer _bb) { return GetRootAsMonsterExtra(_bb, new MonsterExtra()); }
+ public static MonsterExtra GetRootAsMonsterExtra(ByteBuffer _bb, MonsterExtra obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool MonsterExtraBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "MONE"); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public MonsterExtra __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public double D0 { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.NaN; } }
+ public bool MutateD0(double d0) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, d0); return true; } else { return false; } }
+ public double D1 { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.NaN; } }
+ public bool MutateD1(double d1) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, d1); return true; } else { return false; } }
+ public double D2 { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.PositiveInfinity; } }
+ public bool MutateD2(double d2) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, d2); return true; } else { return false; } }
+ public double D3 { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.NegativeInfinity; } }
+ public bool MutateD3(double d3) { int o = __p.__offset(10); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, d3); return true; } else { return false; } }
+ public float F0 { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NaN; } }
+ public bool MutateF0(float f0) { int o = __p.__offset(12); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, f0); return true; } else { return false; } }
+ public float F1 { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NaN; } }
+ public bool MutateF1(float f1) { int o = __p.__offset(14); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, f1); return true; } else { return false; } }
+ public float F2 { get { int o = __p.__offset(16); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.PositiveInfinity; } }
+ public bool MutateF2(float f2) { int o = __p.__offset(16); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, f2); return true; } else { return false; } }
+ public float F3 { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NegativeInfinity; } }
+ public bool MutateF3(float f3) { int o = __p.__offset(18); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, f3); return true; } else { return false; } }
+ public double Dvec(int j) { int o = __p.__offset(20); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
+ public int DvecLength { get { int o = __p.__offset(20); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetDvecBytes() { return __p.__vector_as_span(20); }
+#else
+ public ArraySegment<byte>? GetDvecBytes() { return __p.__vector_as_arraysegment(20); }
+#endif
+ public double[] GetDvecArray() { return __p.__vector_as_array<double>(20); }
+ public bool MutateDvec(int j, double dvec) { int o = __p.__offset(20); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, dvec); return true; } else { return false; } }
+ public float Fvec(int j) { int o = __p.__offset(22); return o != 0 ? __p.bb.GetFloat(__p.__vector(o) + j * 4) : (float)0; }
+ public int FvecLength { get { int o = __p.__offset(22); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetFvecBytes() { return __p.__vector_as_span(22); }
+#else
+ public ArraySegment<byte>? GetFvecBytes() { return __p.__vector_as_arraysegment(22); }
+#endif
+ public float[] GetFvecArray() { return __p.__vector_as_array<float>(22); }
+ public bool MutateFvec(int j, float fvec) { int o = __p.__offset(22); if (o != 0) { __p.bb.PutFloat(__p.__vector(o) + j * 4, fvec); return true; } else { return false; } }
+
+ public static Offset<MyGame.MonsterExtra> CreateMonsterExtra(FlatBufferBuilder builder,
+ double d0 = Double.NaN,
+ double d1 = Double.NaN,
+ double d2 = Double.PositiveInfinity,
+ double d3 = Double.NegativeInfinity,
+ float f0 = Single.NaN,
+ float f1 = Single.NaN,
+ float f2 = Single.PositiveInfinity,
+ float f3 = Single.NegativeInfinity,
+ VectorOffset dvecOffset = default(VectorOffset),
+ VectorOffset fvecOffset = default(VectorOffset)) {
+ builder.StartTable(10);
+ MonsterExtra.AddD3(builder, d3);
+ MonsterExtra.AddD2(builder, d2);
+ MonsterExtra.AddD1(builder, d1);
+ MonsterExtra.AddD0(builder, d0);
+ MonsterExtra.AddFvec(builder, fvecOffset);
+ MonsterExtra.AddDvec(builder, dvecOffset);
+ MonsterExtra.AddF3(builder, f3);
+ MonsterExtra.AddF2(builder, f2);
+ MonsterExtra.AddF1(builder, f1);
+ MonsterExtra.AddF0(builder, f0);
+ return MonsterExtra.EndMonsterExtra(builder);
+ }
+
+ public static void StartMonsterExtra(FlatBufferBuilder builder) { builder.StartTable(10); }
+ public static void AddD0(FlatBufferBuilder builder, double d0) { builder.AddDouble(0, d0, Double.NaN); }
+ public static void AddD1(FlatBufferBuilder builder, double d1) { builder.AddDouble(1, d1, Double.NaN); }
+ public static void AddD2(FlatBufferBuilder builder, double d2) { builder.AddDouble(2, d2, Double.PositiveInfinity); }
+ public static void AddD3(FlatBufferBuilder builder, double d3) { builder.AddDouble(3, d3, Double.NegativeInfinity); }
+ public static void AddF0(FlatBufferBuilder builder, float f0) { builder.AddFloat(4, f0, Single.NaN); }
+ public static void AddF1(FlatBufferBuilder builder, float f1) { builder.AddFloat(5, f1, Single.NaN); }
+ public static void AddF2(FlatBufferBuilder builder, float f2) { builder.AddFloat(6, f2, Single.PositiveInfinity); }
+ public static void AddF3(FlatBufferBuilder builder, float f3) { builder.AddFloat(7, f3, Single.NegativeInfinity); }
+ public static void AddDvec(FlatBufferBuilder builder, VectorOffset dvecOffset) { builder.AddOffset(8, dvecOffset.Value, 0); }
+ public static VectorOffset CreateDvecVector(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddDouble(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateDvecVectorBlock(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); builder.Add(data); return builder.EndVector(); }
+ public static void StartDvecVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+ public static void AddFvec(FlatBufferBuilder builder, VectorOffset fvecOffset) { builder.AddOffset(9, fvecOffset.Value, 0); }
+ public static VectorOffset CreateFvecVector(FlatBufferBuilder builder, float[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddFloat(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateFvecVectorBlock(FlatBufferBuilder builder, float[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartFvecVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static Offset<MyGame.MonsterExtra> EndMonsterExtra(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<MyGame.MonsterExtra>(o);
+ }
+ public static void FinishMonsterExtraBuffer(FlatBufferBuilder builder, Offset<MyGame.MonsterExtra> offset) { builder.Finish(offset.Value, "MONE"); }
+ public static void FinishSizePrefixedMonsterExtraBuffer(FlatBufferBuilder builder, Offset<MyGame.MonsterExtra> offset) { builder.FinishSizePrefixed(offset.Value, "MONE"); }
+};
+
+
+}
diff --git a/tests/MyGame/MonsterExtra.java b/tests/MyGame/MonsterExtra.java
new file mode 100644
index 0000000..3022596
--- /dev/null
+++ b/tests/MyGame/MonsterExtra.java
@@ -0,0 +1,93 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class MonsterExtra extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static MonsterExtra getRootAsMonsterExtra(ByteBuffer _bb) { return getRootAsMonsterExtra(_bb, new MonsterExtra()); }
+ public static MonsterExtra getRootAsMonsterExtra(ByteBuffer _bb, MonsterExtra obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public static boolean MonsterExtraBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MONE"); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public MonsterExtra __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public double d0() { int o = __offset(4); return o != 0 ? bb.getDouble(o + bb_pos) : Double.NaN; }
+ public boolean mutateD0(double d0) { int o = __offset(4); if (o != 0) { bb.putDouble(o + bb_pos, d0); return true; } else { return false; } }
+ public double d1() { int o = __offset(6); return o != 0 ? bb.getDouble(o + bb_pos) : Double.NaN; }
+ public boolean mutateD1(double d1) { int o = __offset(6); if (o != 0) { bb.putDouble(o + bb_pos, d1); return true; } else { return false; } }
+ public double d2() { int o = __offset(8); return o != 0 ? bb.getDouble(o + bb_pos) : Double.POSITIVE_INFINITY; }
+ public boolean mutateD2(double d2) { int o = __offset(8); if (o != 0) { bb.putDouble(o + bb_pos, d2); return true; } else { return false; } }
+ public double d3() { int o = __offset(10); return o != 0 ? bb.getDouble(o + bb_pos) : Double.NEGATIVE_INFINITY; }
+ public boolean mutateD3(double d3) { int o = __offset(10); if (o != 0) { bb.putDouble(o + bb_pos, d3); return true; } else { return false; } }
+ public float f0() { int o = __offset(12); return o != 0 ? bb.getFloat(o + bb_pos) : Float.NaN; }
+ public boolean mutateF0(float f0) { int o = __offset(12); if (o != 0) { bb.putFloat(o + bb_pos, f0); return true; } else { return false; } }
+ public float f1() { int o = __offset(14); return o != 0 ? bb.getFloat(o + bb_pos) : Float.NaN; }
+ public boolean mutateF1(float f1) { int o = __offset(14); if (o != 0) { bb.putFloat(o + bb_pos, f1); return true; } else { return false; } }
+ public float f2() { int o = __offset(16); return o != 0 ? bb.getFloat(o + bb_pos) : Float.POSITIVE_INFINITY; }
+ public boolean mutateF2(float f2) { int o = __offset(16); if (o != 0) { bb.putFloat(o + bb_pos, f2); return true; } else { return false; } }
+ public float f3() { int o = __offset(18); return o != 0 ? bb.getFloat(o + bb_pos) : Float.NEGATIVE_INFINITY; }
+ public boolean mutateF3(float f3) { int o = __offset(18); if (o != 0) { bb.putFloat(o + bb_pos, f3); return true; } else { return false; } }
+ public double dvec(int j) { int o = __offset(20); return o != 0 ? bb.getDouble(__vector(o) + j * 8) : 0; }
+ public int dvecLength() { int o = __offset(20); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer dvecAsByteBuffer() { return __vector_as_bytebuffer(20, 8); }
+ public ByteBuffer dvecInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 20, 8); }
+ public boolean mutateDvec(int j, double dvec) { int o = __offset(20); if (o != 0) { bb.putDouble(__vector(o) + j * 8, dvec); return true; } else { return false; } }
+ public float fvec(int j) { int o = __offset(22); return o != 0 ? bb.getFloat(__vector(o) + j * 4) : 0; }
+ public int fvecLength() { int o = __offset(22); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer fvecAsByteBuffer() { return __vector_as_bytebuffer(22, 4); }
+ public ByteBuffer fvecInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 22, 4); }
+ public boolean mutateFvec(int j, float fvec) { int o = __offset(22); if (o != 0) { bb.putFloat(__vector(o) + j * 4, fvec); return true; } else { return false; } }
+
+ public static int createMonsterExtra(FlatBufferBuilder builder,
+ double d0,
+ double d1,
+ double d2,
+ double d3,
+ float f0,
+ float f1,
+ float f2,
+ float f3,
+ int dvecOffset,
+ int fvecOffset) {
+ builder.startTable(10);
+ MonsterExtra.addD3(builder, d3);
+ MonsterExtra.addD2(builder, d2);
+ MonsterExtra.addD1(builder, d1);
+ MonsterExtra.addD0(builder, d0);
+ MonsterExtra.addFvec(builder, fvecOffset);
+ MonsterExtra.addDvec(builder, dvecOffset);
+ MonsterExtra.addF3(builder, f3);
+ MonsterExtra.addF2(builder, f2);
+ MonsterExtra.addF1(builder, f1);
+ MonsterExtra.addF0(builder, f0);
+ return MonsterExtra.endMonsterExtra(builder);
+ }
+
+ public static void startMonsterExtra(FlatBufferBuilder builder) { builder.startTable(10); }
+ public static void addD0(FlatBufferBuilder builder, double d0) { builder.addDouble(0, d0, Double.NaN); }
+ public static void addD1(FlatBufferBuilder builder, double d1) { builder.addDouble(1, d1, Double.NaN); }
+ public static void addD2(FlatBufferBuilder builder, double d2) { builder.addDouble(2, d2, Double.POSITIVE_INFINITY); }
+ public static void addD3(FlatBufferBuilder builder, double d3) { builder.addDouble(3, d3, Double.NEGATIVE_INFINITY); }
+ public static void addF0(FlatBufferBuilder builder, float f0) { builder.addFloat(4, f0, Float.NaN); }
+ public static void addF1(FlatBufferBuilder builder, float f1) { builder.addFloat(5, f1, Float.NaN); }
+ public static void addF2(FlatBufferBuilder builder, float f2) { builder.addFloat(6, f2, Float.POSITIVE_INFINITY); }
+ public static void addF3(FlatBufferBuilder builder, float f3) { builder.addFloat(7, f3, Float.NEGATIVE_INFINITY); }
+ public static void addDvec(FlatBufferBuilder builder, int dvecOffset) { builder.addOffset(8, dvecOffset, 0); }
+ public static int createDvecVector(FlatBufferBuilder builder, double[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addDouble(data[i]); return builder.endVector(); }
+ public static void startDvecVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+ public static void addFvec(FlatBufferBuilder builder, int fvecOffset) { builder.addOffset(9, fvecOffset, 0); }
+ public static int createFvecVector(FlatBufferBuilder builder, float[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addFloat(data[i]); return builder.endVector(); }
+ public static void startFvecVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static int endMonsterExtra(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+ public static void finishMonsterExtraBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONE"); }
+ public static void finishSizePrefixedMonsterExtraBuffer(FlatBufferBuilder builder, int offset) { builder.finishSizePrefixed(offset, "MONE"); }
+}
+
diff --git a/tests/MyGame/MonsterExtra.kt b/tests/MyGame/MonsterExtra.kt
new file mode 100644
index 0000000..96ea731
--- /dev/null
+++ b/tests/MyGame/MonsterExtra.kt
@@ -0,0 +1,234 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class MonsterExtra : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : MonsterExtra {
+ __init(_i, _bb)
+ return this
+ }
+ val d0 : Double
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.getDouble(o + bb_pos) else Double.NaN
+ }
+ fun mutateD0(d0: Double) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.putDouble(o + bb_pos, d0)
+ true
+ } else {
+ false
+ }
+ }
+ val d1 : Double
+ get() {
+ val o = __offset(6)
+ return if(o != 0) bb.getDouble(o + bb_pos) else Double.NaN
+ }
+ fun mutateD1(d1: Double) : Boolean {
+ val o = __offset(6)
+ return if (o != 0) {
+ bb.putDouble(o + bb_pos, d1)
+ true
+ } else {
+ false
+ }
+ }
+ val d2 : Double
+ get() {
+ val o = __offset(8)
+ return if(o != 0) bb.getDouble(o + bb_pos) else Double.POSITIVE_INFINITY
+ }
+ fun mutateD2(d2: Double) : Boolean {
+ val o = __offset(8)
+ return if (o != 0) {
+ bb.putDouble(o + bb_pos, d2)
+ true
+ } else {
+ false
+ }
+ }
+ val d3 : Double
+ get() {
+ val o = __offset(10)
+ return if(o != 0) bb.getDouble(o + bb_pos) else Double.NEGATIVE_INFINITY
+ }
+ fun mutateD3(d3: Double) : Boolean {
+ val o = __offset(10)
+ return if (o != 0) {
+ bb.putDouble(o + bb_pos, d3)
+ true
+ } else {
+ false
+ }
+ }
+ val f0 : Float
+ get() {
+ val o = __offset(12)
+ return if(o != 0) bb.getFloat(o + bb_pos) else Float.NaN
+ }
+ fun mutateF0(f0: Float) : Boolean {
+ val o = __offset(12)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, f0)
+ true
+ } else {
+ false
+ }
+ }
+ val f1 : Float
+ get() {
+ val o = __offset(14)
+ return if(o != 0) bb.getFloat(o + bb_pos) else Float.NaN
+ }
+ fun mutateF1(f1: Float) : Boolean {
+ val o = __offset(14)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, f1)
+ true
+ } else {
+ false
+ }
+ }
+ val f2 : Float
+ get() {
+ val o = __offset(16)
+ return if(o != 0) bb.getFloat(o + bb_pos) else Float.POSITIVE_INFINITY
+ }
+ fun mutateF2(f2: Float) : Boolean {
+ val o = __offset(16)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, f2)
+ true
+ } else {
+ false
+ }
+ }
+ val f3 : Float
+ get() {
+ val o = __offset(18)
+ return if(o != 0) bb.getFloat(o + bb_pos) else Float.NEGATIVE_INFINITY
+ }
+ fun mutateF3(f3: Float) : Boolean {
+ val o = __offset(18)
+ return if (o != 0) {
+ bb.putFloat(o + bb_pos, f3)
+ true
+ } else {
+ false
+ }
+ }
+ fun dvec(j: Int) : Double {
+ val o = __offset(20)
+ return if (o != 0) {
+ bb.getDouble(__vector(o) + j * 8)
+ } else {
+ 0.0
+ }
+ }
+ val dvecLength : Int
+ get() {
+ val o = __offset(20); return if (o != 0) __vector_len(o) else 0
+ }
+ val dvecAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(20, 8)
+ fun dvecInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 20, 8)
+ fun mutateDvec(j: Int, dvec: Double) : Boolean {
+ val o = __offset(20)
+ return if (o != 0) {
+ bb.putDouble(__vector(o) + j * 8, dvec)
+ true
+ } else {
+ false
+ }
+ }
+ fun fvec(j: Int) : Float {
+ val o = __offset(22)
+ return if (o != 0) {
+ bb.getFloat(__vector(o) + j * 4)
+ } else {
+ 0.0f
+ }
+ }
+ val fvecLength : Int
+ get() {
+ val o = __offset(22); return if (o != 0) __vector_len(o) else 0
+ }
+ val fvecAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(22, 4)
+ fun fvecInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 22, 4)
+ fun mutateFvec(j: Int, fvec: Float) : Boolean {
+ val o = __offset(22)
+ return if (o != 0) {
+ bb.putFloat(__vector(o) + j * 4, fvec)
+ true
+ } else {
+ false
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsMonsterExtra(_bb: ByteBuffer): MonsterExtra = getRootAsMonsterExtra(_bb, MonsterExtra())
+ fun getRootAsMonsterExtra(_bb: ByteBuffer, obj: MonsterExtra): MonsterExtra {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun MonsterExtraBufferHasIdentifier(_bb: ByteBuffer) : Boolean = __has_identifier(_bb, "MONE")
+ fun createMonsterExtra(builder: FlatBufferBuilder, d0: Double, d1: Double, d2: Double, d3: Double, f0: Float, f1: Float, f2: Float, f3: Float, dvecOffset: Int, fvecOffset: Int) : Int {
+ builder.startTable(10)
+ addD3(builder, d3)
+ addD2(builder, d2)
+ addD1(builder, d1)
+ addD0(builder, d0)
+ addFvec(builder, fvecOffset)
+ addDvec(builder, dvecOffset)
+ addF3(builder, f3)
+ addF2(builder, f2)
+ addF1(builder, f1)
+ addF0(builder, f0)
+ return endMonsterExtra(builder)
+ }
+ fun startMonsterExtra(builder: FlatBufferBuilder) = builder.startTable(10)
+ fun addD0(builder: FlatBufferBuilder, d0: Double) = builder.addDouble(0, d0, Double.NaN)
+ fun addD1(builder: FlatBufferBuilder, d1: Double) = builder.addDouble(1, d1, Double.NaN)
+ fun addD2(builder: FlatBufferBuilder, d2: Double) = builder.addDouble(2, d2, Double.POSITIVE_INFINITY)
+ fun addD3(builder: FlatBufferBuilder, d3: Double) = builder.addDouble(3, d3, Double.NEGATIVE_INFINITY)
+ fun addF0(builder: FlatBufferBuilder, f0: Float) = builder.addFloat(4, f0, Double.NaN)
+ fun addF1(builder: FlatBufferBuilder, f1: Float) = builder.addFloat(5, f1, Double.NaN)
+ fun addF2(builder: FlatBufferBuilder, f2: Float) = builder.addFloat(6, f2, Double.POSITIVE_INFINITY)
+ fun addF3(builder: FlatBufferBuilder, f3: Float) = builder.addFloat(7, f3, Double.NEGATIVE_INFINITY)
+ fun addDvec(builder: FlatBufferBuilder, dvec: Int) = builder.addOffset(8, dvec, 0)
+ fun createDvecVector(builder: FlatBufferBuilder, data: DoubleArray) : Int {
+ builder.startVector(8, data.size, 8)
+ for (i in data.size - 1 downTo 0) {
+ builder.addDouble(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startDvecVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(8, numElems, 8)
+ fun addFvec(builder: FlatBufferBuilder, fvec: Int) = builder.addOffset(9, fvec, 0)
+ fun createFvecVector(builder: FlatBufferBuilder, data: FloatArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addFloat(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startFvecVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun endMonsterExtra(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ fun finishMonsterExtraBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset, "MONE")
+ fun finishSizePrefixedMonsterExtraBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset, "MONE")
+ }
+}
diff --git a/tests/MyGame/MonsterExtra.py b/tests/MyGame/MonsterExtra.py
new file mode 100644
index 0000000..1f7dcb2
--- /dev/null
+++ b/tests/MyGame/MonsterExtra.py
@@ -0,0 +1,138 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: MyGame
+
+import flatbuffers
+
+class MonsterExtra(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsMonsterExtra(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = MonsterExtra()
+ x.Init(buf, n + offset)
+ return x
+
+ @classmethod
+ def MonsterExtraBufferHasIdentifier(cls, buf, offset, size_prefixed=False):
+ return flatbuffers.util.BufferHasIdentifier(buf, offset, b"\x4D\x4F\x4E\x45", size_prefixed=size_prefixed)
+
+ # MonsterExtra
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # MonsterExtra
+ def D0(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+ return float('nan')
+
+ # MonsterExtra
+ def D1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+ return float('nan')
+
+ # MonsterExtra
+ def D2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+ return float('inf')
+
+ # MonsterExtra
+ def D3(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+ return float('-inf')
+
+ # MonsterExtra
+ def F0(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return float('nan')
+
+ # MonsterExtra
+ def F1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return float('nan')
+
+ # MonsterExtra
+ def F2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return float('inf')
+
+ # MonsterExtra
+ def F3(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+ return float('-inf')
+
+ # MonsterExtra
+ def Dvec(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Float64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+ return 0
+
+ # MonsterExtra
+ def DvecAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float64Flags, o)
+ return 0
+
+ # MonsterExtra
+ def DvecLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+ # MonsterExtra
+ def Fvec(self, j):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+ if o != 0:
+ a = self._tab.Vector(o)
+ return self._tab.Get(flatbuffers.number_types.Float32Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4))
+ return 0
+
+ # MonsterExtra
+ def FvecAsNumpy(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+ if o != 0:
+ return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float32Flags, o)
+ return 0
+
+ # MonsterExtra
+ def FvecLength(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+ if o != 0:
+ return self._tab.VectorLen(o)
+ return 0
+
+def MonsterExtraStart(builder): builder.StartObject(10)
+def MonsterExtraAddD0(builder, d0): builder.PrependFloat64Slot(0, d0, float('nan'))
+def MonsterExtraAddD1(builder, d1): builder.PrependFloat64Slot(1, d1, float('nan'))
+def MonsterExtraAddD2(builder, d2): builder.PrependFloat64Slot(2, d2, float('inf'))
+def MonsterExtraAddD3(builder, d3): builder.PrependFloat64Slot(3, d3, float('-inf'))
+def MonsterExtraAddF0(builder, f0): builder.PrependFloat32Slot(4, f0, float('nan'))
+def MonsterExtraAddF1(builder, f1): builder.PrependFloat32Slot(5, f1, float('nan'))
+def MonsterExtraAddF2(builder, f2): builder.PrependFloat32Slot(6, f2, float('inf'))
+def MonsterExtraAddF3(builder, f3): builder.PrependFloat32Slot(7, f3, float('-inf'))
+def MonsterExtraAddDvec(builder, dvec): builder.PrependUOffsetTRelativeSlot(8, flatbuffers.number_types.UOffsetTFlags.py_type(dvec), 0)
+def MonsterExtraStartDvecVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterExtraAddFvec(builder, fvec): builder.PrependUOffsetTRelativeSlot(9, flatbuffers.number_types.UOffsetTFlags.py_type(fvec), 0)
+def MonsterExtraStartFvecVector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterExtraEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/__init__.py b/tests/MyGame/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/MyGame/__init__.py
diff --git a/tests/PythonTest.sh b/tests/PythonTest.sh
new file mode 100755
index 0000000..e4dbe8d
--- /dev/null
+++ b/tests/PythonTest.sh
@@ -0,0 +1,79 @@
+#!/bin/bash -eu
+#
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+test_dir="$(pwd)"
+gen_code_path=${test_dir}
+runtime_library_dir=${test_dir}/../python
+
+# Emit Python code for the example schema in the test dir:
+${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_test.fbs
+
+# Syntax: run_tests <interpreter> <benchmark vtable dedupes>
+# <benchmark read count> <benchmark build count>
+interpreters_tested=()
+function run_tests() {
+ if $(which ${1} >/dev/null); then
+ echo "Testing with interpreter: ${1}"
+ PYTHONDONTWRITEBYTECODE=1 \
+ JYTHONDONTWRITEBYTECODE=1 \
+ PYTHONPATH=${runtime_library_dir}:${gen_code_path} \
+ JYTHONPATH=${runtime_library_dir}:${gen_code_path} \
+ COMPARE_GENERATED_TO_GO=0 \
+ COMPARE_GENERATED_TO_JAVA=0 \
+ $1 py_test.py $2 $3 $4
+ interpreters_tested+=(${1})
+ echo
+ fi
+}
+
+# Run test suite with these interpreters. The arguments are benchmark counts.
+run_tests python2.6 100 100 100
+run_tests python2.7 100 100 100
+run_tests python3 100 100 100
+run_tests pypy 100 100 100
+
+# NOTE: We'd like to support python2.5 in the future.
+
+# NOTE: Jython 2.7.0 fails due to a bug in the stdlib `struct` library:
+# http://bugs.jython.org/issue2188
+
+if [ ${#interpreters_tested[@]} -eq 0 ]; then
+ echo "No Python interpeters found on this system, could not run tests."
+ exit 1
+fi
+
+# Run test suite with default python intereter.
+# (If the Python program `coverage` is available, it will be run, too.
+# Install `coverage` with `pip install coverage`.)
+if $(which coverage >/dev/null); then
+ echo 'Found coverage utility, running coverage with default Python:'
+
+ PYTHONDONTWRITEBYTECODE=1 \
+ PYTHONPATH=${runtime_library_dir}:${gen_code_path} \
+ coverage run --source=flatbuffers,MyGame py_test.py 0 0 0 > /dev/null
+
+ echo
+ cov_result=`coverage report --omit="*flatbuffers/vendor*,*py_test*" \
+ | tail -n 1 | awk ' { print $4 } '`
+ echo "Code coverage: ${cov_result}"
+else
+ echo -n "Did not find coverage utility for default Python, skipping. "
+ echo "Install with 'pip install coverage'."
+fi
+
+echo
+echo "OK: all tests passed for ${#interpreters_tested[@]} interpreters: ${interpreters_tested[@]}."
diff --git a/tests/RustTest.bat b/tests/RustTest.bat
new file mode 100644
index 0000000..ba9cfd2
--- /dev/null
+++ b/tests/RustTest.bat
@@ -0,0 +1,23 @@
+@echo off
+rem Copyright 2018 Google Inc. All rights reserved.
+rem
+rem Licensed under the Apache License, Version 2.0 (the "License");
+rem you may not use this file except in compliance with the License.
+rem You may obtain a copy of the License at
+rem
+rem http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing, software
+rem distributed under the License is distributed on an "AS IS" BASIS,
+rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+rem See the License for the specific language governing permissions and
+rem limitations under the License.
+
+rem Compile then run the Rust test.
+
+rem TODO(rw): how do we make this script abort the calling script in appveyor?
+
+cd rust_usage_test
+cargo test -- --quiet || exit /b 1
+cargo run --bin=alloc_check || exit /b 1
+cd ..
diff --git a/tests/RustTest.sh b/tests/RustTest.sh
new file mode 100755
index 0000000..0a3974b
--- /dev/null
+++ b/tests/RustTest.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+set -e
+#
+# Copyright 2018 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [[ "$1" == "mips-unknown-linux-gnu" ]]; then
+ TARGET_FLAG="--target mips-unknown-linux-gnu"
+ export CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_LINKER=mips-linux-gnu-gcc
+ export CARGO_TARGET_MIPS_UNKNOWN_LINUX_GNU_RUNNER="qemu-mips -L /usr/mips-linux-gnu"
+fi
+
+cd ./rust_usage_test
+cargo test $TARGET_FLAG -- --quiet
+TEST_RESULT=$?
+if [[ $TEST_RESULT == 0 ]]; then
+ echo "OK: Rust tests passed."
+else
+ echo "KO: Rust tests failed."
+ exit 1
+fi
+
+cargo run $TARGET_FLAG --bin=alloc_check
+TEST_RESULT=$?
+if [[ $TEST_RESULT == 0 ]]; then
+ echo "OK: Rust heap alloc test passed."
+else
+ echo "KO: Rust heap alloc test failed."
+ exit 1
+fi
+
+cargo bench $TARGET_FLAG
diff --git a/tests/TestAll.sh b/tests/TestAll.sh
new file mode 100644
index 0000000..0fc0acd
--- /dev/null
+++ b/tests/TestAll.sh
@@ -0,0 +1,63 @@
+echo "************************ Java:"
+
+sh JavaTest.sh
+
+echo "************************ Kotlin:"
+
+sh KotlinTest.sh
+
+echo "************************ Go:"
+
+sh GoTest.sh
+
+echo "************************ Python:"
+
+sh PythonTest.sh
+
+echo "************************ JavaScript:"
+
+sh JavaScriptTest.sh
+# FIXME does not exist:
+# sh JavaScriptUnionVectorTest.sh
+
+echo "************************ TypeScript:"
+
+sh TypeScriptTest.sh
+
+echo "************************ C++:"
+
+cd ..
+./flattests
+cd tests
+
+echo "************************ C#:"
+
+cd FlatBuffers.Test
+sh NetTest.sh
+cd ..
+
+echo "************************ PHP:"
+
+php phpTest.php
+sh phpUnionVectorTest.sh
+
+echo "************************ Dart:"
+
+sh DartTest.sh
+
+echo "************************ Rust:"
+
+sh RustTest.sh
+
+echo "************************ Lobster:"
+
+# TODO: test if available.
+# lobster lobstertest.lobster
+
+echo "************************ C:"
+
+echo "(in a different repo)"
+
+echo "************************ Swift:"
+
+echo "(in a different repo)"
diff --git a/tests/TypeScriptTest.sh b/tests/TypeScriptTest.sh
new file mode 100755
index 0000000..fa650a4
--- /dev/null
+++ b/tests/TypeScriptTest.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+
+npm install @types/flatbuffers
+
+../flatc --ts --no-fb-import --gen-mutable -o ts -I include_test monster_test.fbs
+../flatc -b -I include_test monster_test.fbs unicode_test.json
+tsc --strict --noUnusedParameters --noUnusedLocals --noImplicitReturns --strictNullChecks ts/monster_test_generated.ts
+node JavaScriptTest ./ts/monster_test_generated
+
+../flatc --ts --js --no-fb-import -o ts union_vector/union_vector.fbs
+
+# test JS version first, then transpile and rerun for TS
+node JavaScriptUnionVectorTest ./ts/union_vector_generated
+tsc --strict --noUnusedParameters --noUnusedLocals --noImplicitReturns --strictNullChecks ts/union_vector_generated.ts
+node JavaScriptUnionVectorTest ./ts/union_vector_generated
+
+npm uninstall @types/flatbuffers
diff --git a/tests/arrays_test.bfbs b/tests/arrays_test.bfbs
new file mode 100644
index 0000000..2a89968
--- /dev/null
+++ b/tests/arrays_test.bfbs
Binary files differ
diff --git a/tests/arrays_test.fbs b/tests/arrays_test.fbs
new file mode 100644
index 0000000..40bce66
--- /dev/null
+++ b/tests/arrays_test.fbs
@@ -0,0 +1,24 @@
+namespace MyGame.Example;
+
+enum TestEnum : byte { A, B, C }
+
+struct NestedStruct{
+ a:[int:2];
+ b:TestEnum;
+ c:[TestEnum:2];
+}
+
+struct ArrayStruct{
+ a:float;
+ b:[int:0xF];
+ c:byte;
+ d:[NestedStruct:2];
+}
+
+table ArrayTable{
+ a:ArrayStruct;
+}
+
+root_type ArrayTable;
+file_identifier "ARRT";
+file_extension "mon";
diff --git a/tests/arrays_test.golden b/tests/arrays_test.golden
new file mode 100644
index 0000000..c032688
--- /dev/null
+++ b/tests/arrays_test.golden
@@ -0,0 +1,19 @@
+{
+ a : {
+ a: 12.34,
+ b: [1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF],
+ c: -127,
+ d: [
+ {
+ a : [-1,2],
+ b : A,
+ c : [C, B]
+ },
+ {
+ a : [3,-4],
+ b : B,
+ c : [B, A]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/tests/arrays_test.schema.json b/tests/arrays_test.schema.json
new file mode 100644
index 0000000..6803a1a
--- /dev/null
+++ b/tests/arrays_test.schema.json
@@ -0,0 +1,60 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "definitions": {
+ "MyGame_Example_TestEnum" : {
+ "type" : "string",
+ "enum": ["A", "B", "C"]
+ },
+ "MyGame_Example_NestedStruct" : {
+ "type" : "object",
+ "properties" : {
+ "a" : {
+ "type" : "array", "items" : { "type" : "number" },
+ "minItems": 2,
+ "maxItems": 2
+ },
+ "b" : {
+ "$ref" : "#/definitions/MyGame_Example_TestEnum"
+ },
+ "c" : {
+ "$ref" : "#/definitions/MyGame_Example_TestEnum",
+ "minItems": 2,
+ "maxItems": 2
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_ArrayStruct" : {
+ "type" : "object",
+ "properties" : {
+ "a" : {
+ "type" : "number"
+ },
+ "b" : {
+ "type" : "array", "items" : { "type" : "number" },
+ "minItems": 15,
+ "maxItems": 15
+ },
+ "c" : {
+ "type" : "number"
+ },
+ "d" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_NestedStruct" },
+ "minItems": 2,
+ "maxItems": 2
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_ArrayTable" : {
+ "type" : "object",
+ "properties" : {
+ "a" : {
+ "$ref" : "#/definitions/MyGame_Example_ArrayStruct"
+ }
+ },
+ "additionalProperties" : false
+ }
+ },
+ "$ref" : "#/definitions/MyGame_Example_ArrayTable"
+}
diff --git a/tests/arrays_test_generated.h b/tests/arrays_test_generated.h
new file mode 100644
index 0000000..9875785
--- /dev/null
+++ b/tests/arrays_test_generated.h
@@ -0,0 +1,419 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_ARRAYSTEST_MYGAME_EXAMPLE_H_
+#define FLATBUFFERS_GENERATED_ARRAYSTEST_MYGAME_EXAMPLE_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace MyGame {
+namespace Example {
+
+struct NestedStruct;
+
+struct ArrayStruct;
+
+struct ArrayTable;
+struct ArrayTableT;
+
+bool operator==(const NestedStruct &lhs, const NestedStruct &rhs);
+bool operator!=(const NestedStruct &lhs, const NestedStruct &rhs);
+bool operator==(const ArrayStruct &lhs, const ArrayStruct &rhs);
+bool operator!=(const ArrayStruct &lhs, const ArrayStruct &rhs);
+bool operator==(const ArrayTableT &lhs, const ArrayTableT &rhs);
+bool operator!=(const ArrayTableT &lhs, const ArrayTableT &rhs);
+
+inline const flatbuffers::TypeTable *NestedStructTypeTable();
+
+inline const flatbuffers::TypeTable *ArrayStructTypeTable();
+
+inline const flatbuffers::TypeTable *ArrayTableTypeTable();
+
+enum class TestEnum : int8_t {
+ A = 0,
+ B = 1,
+ C = 2,
+ MIN = A,
+ MAX = C
+};
+
+inline const TestEnum (&EnumValuesTestEnum())[3] {
+ static const TestEnum values[] = {
+ TestEnum::A,
+ TestEnum::B,
+ TestEnum::C
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesTestEnum() {
+ static const char * const names[4] = {
+ "A",
+ "B",
+ "C",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameTestEnum(TestEnum e) {
+ if (e < TestEnum::A || e > TestEnum::C) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesTestEnum()[index];
+}
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) NestedStruct FLATBUFFERS_FINAL_CLASS {
+ private:
+ int32_t a_[2];
+ int8_t b_;
+ int8_t c_[2];
+ int8_t padding0__;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return NestedStructTypeTable();
+ }
+ NestedStruct() {
+ memset(static_cast<void *>(this), 0, sizeof(NestedStruct));
+ }
+ NestedStruct(MyGame::Example::TestEnum _b)
+ : b_(flatbuffers::EndianScalar(static_cast<int8_t>(_b))) {
+ std::memset(a_, 0, sizeof(a_));
+ std::memset(c_, 0, sizeof(c_));
+ (void)padding0__;
+ }
+ const flatbuffers::Array<int32_t, 2> *a() const {
+ return reinterpret_cast<const flatbuffers::Array<int32_t, 2> *>(a_);
+ }
+ flatbuffers::Array<int32_t, 2> *mutable_a() {
+ return reinterpret_cast<flatbuffers::Array<int32_t, 2> *>(a_);
+ }
+ MyGame::Example::TestEnum b() const {
+ return static_cast<MyGame::Example::TestEnum>(flatbuffers::EndianScalar(b_));
+ }
+ void mutate_b(MyGame::Example::TestEnum _b) {
+ flatbuffers::WriteScalar(&b_, static_cast<int8_t>(_b));
+ }
+ const flatbuffers::Array<MyGame::Example::TestEnum, 2> *c() const {
+ return reinterpret_cast<const flatbuffers::Array<MyGame::Example::TestEnum, 2> *>(c_);
+ }
+ flatbuffers::Array<MyGame::Example::TestEnum, 2> *mutable_c() {
+ return reinterpret_cast<flatbuffers::Array<MyGame::Example::TestEnum, 2> *>(c_);
+ }
+};
+FLATBUFFERS_STRUCT_END(NestedStruct, 12);
+
+inline bool operator==(const NestedStruct &lhs, const NestedStruct &rhs) {
+ return
+ (lhs.a() == rhs.a()) &&
+ (lhs.b() == rhs.b()) &&
+ (lhs.c() == rhs.c());
+}
+
+inline bool operator!=(const NestedStruct &lhs, const NestedStruct &rhs) {
+ return !(lhs == rhs);
+}
+
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) ArrayStruct FLATBUFFERS_FINAL_CLASS {
+ private:
+ float a_;
+ int32_t b_[15];
+ int8_t c_;
+ int8_t padding0__; int16_t padding1__;
+ MyGame::Example::NestedStruct d_[2];
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return ArrayStructTypeTable();
+ }
+ ArrayStruct() {
+ memset(static_cast<void *>(this), 0, sizeof(ArrayStruct));
+ }
+ ArrayStruct(float _a, int8_t _c)
+ : a_(flatbuffers::EndianScalar(_a)),
+ c_(flatbuffers::EndianScalar(_c)),
+ padding0__(0),
+ padding1__(0) {
+ std::memset(b_, 0, sizeof(b_));
+ (void)padding0__; (void)padding1__;
+ std::memset(d_, 0, sizeof(d_));
+ }
+ float a() const {
+ return flatbuffers::EndianScalar(a_);
+ }
+ void mutate_a(float _a) {
+ flatbuffers::WriteScalar(&a_, _a);
+ }
+ const flatbuffers::Array<int32_t, 15> *b() const {
+ return reinterpret_cast<const flatbuffers::Array<int32_t, 15> *>(b_);
+ }
+ flatbuffers::Array<int32_t, 15> *mutable_b() {
+ return reinterpret_cast<flatbuffers::Array<int32_t, 15> *>(b_);
+ }
+ int8_t c() const {
+ return flatbuffers::EndianScalar(c_);
+ }
+ void mutate_c(int8_t _c) {
+ flatbuffers::WriteScalar(&c_, _c);
+ }
+ const flatbuffers::Array<MyGame::Example::NestedStruct, 2> *d() const {
+ return reinterpret_cast<const flatbuffers::Array<MyGame::Example::NestedStruct, 2> *>(d_);
+ }
+ flatbuffers::Array<MyGame::Example::NestedStruct, 2> *mutable_d() {
+ return reinterpret_cast<flatbuffers::Array<MyGame::Example::NestedStruct, 2> *>(d_);
+ }
+};
+FLATBUFFERS_STRUCT_END(ArrayStruct, 92);
+
+inline bool operator==(const ArrayStruct &lhs, const ArrayStruct &rhs) {
+ return
+ (lhs.a() == rhs.a()) &&
+ (lhs.b() == rhs.b()) &&
+ (lhs.c() == rhs.c()) &&
+ (lhs.d() == rhs.d());
+}
+
+inline bool operator!=(const ArrayStruct &lhs, const ArrayStruct &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct ArrayTableT : public flatbuffers::NativeTable {
+ typedef ArrayTable TableType;
+ flatbuffers::unique_ptr<MyGame::Example::ArrayStruct> a;
+ ArrayTableT() {
+ }
+};
+
+inline bool operator==(const ArrayTableT &lhs, const ArrayTableT &rhs) {
+ return
+ (lhs.a == rhs.a);
+}
+
+inline bool operator!=(const ArrayTableT &lhs, const ArrayTableT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct ArrayTable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef ArrayTableT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return ArrayTableTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_A = 4
+ };
+ const MyGame::Example::ArrayStruct *a() const {
+ return GetStruct<const MyGame::Example::ArrayStruct *>(VT_A);
+ }
+ MyGame::Example::ArrayStruct *mutable_a() {
+ return GetStruct<MyGame::Example::ArrayStruct *>(VT_A);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<MyGame::Example::ArrayStruct>(verifier, VT_A) &&
+ verifier.EndTable();
+ }
+ ArrayTableT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(ArrayTableT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<ArrayTable> Pack(flatbuffers::FlatBufferBuilder &_fbb, const ArrayTableT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct ArrayTableBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_a(const MyGame::Example::ArrayStruct *a) {
+ fbb_.AddStruct(ArrayTable::VT_A, a);
+ }
+ explicit ArrayTableBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ ArrayTableBuilder &operator=(const ArrayTableBuilder &);
+ flatbuffers::Offset<ArrayTable> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ArrayTable>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ArrayTable> CreateArrayTable(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const MyGame::Example::ArrayStruct *a = 0) {
+ ArrayTableBuilder builder_(_fbb);
+ builder_.add_a(a);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<ArrayTable> CreateArrayTable(flatbuffers::FlatBufferBuilder &_fbb, const ArrayTableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline ArrayTableT *ArrayTable::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new ArrayTableT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void ArrayTable::UnPackTo(ArrayTableT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = a(); if (_e) _o->a = flatbuffers::unique_ptr<MyGame::Example::ArrayStruct>(new MyGame::Example::ArrayStruct(*_e)); };
+}
+
+inline flatbuffers::Offset<ArrayTable> ArrayTable::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ArrayTableT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateArrayTable(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<ArrayTable> CreateArrayTable(flatbuffers::FlatBufferBuilder &_fbb, const ArrayTableT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ArrayTableT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _a = _o->a ? _o->a.get() : 0;
+ return MyGame::Example::CreateArrayTable(
+ _fbb,
+ _a);
+}
+
+inline const flatbuffers::TypeTable *TestEnumTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::TestEnumTypeTable
+ };
+ static const char * const names[] = {
+ "A",
+ "B",
+ "C"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *NestedStructTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::TestEnumTypeTable
+ };
+ static const int64_t values[] = { 0, 8, 9, 12 };
+ static const char * const names[] = {
+ "a",
+ "b",
+ "c"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 3, type_codes, type_refs, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *ArrayStructTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_CHAR, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::NestedStructTypeTable
+ };
+ static const int64_t values[] = { 0, 4, 64, 68, 92 };
+ static const char * const names[] = {
+ "a",
+ "b",
+ "c",
+ "d"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 4, type_codes, type_refs, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *ArrayTableTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::ArrayStructTypeTable
+ };
+ static const char * const names[] = {
+ "a"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const MyGame::Example::ArrayTable *GetArrayTable(const void *buf) {
+ return flatbuffers::GetRoot<MyGame::Example::ArrayTable>(buf);
+}
+
+inline const MyGame::Example::ArrayTable *GetSizePrefixedArrayTable(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<MyGame::Example::ArrayTable>(buf);
+}
+
+inline ArrayTable *GetMutableArrayTable(void *buf) {
+ return flatbuffers::GetMutableRoot<ArrayTable>(buf);
+}
+
+inline const char *ArrayTableIdentifier() {
+ return "ARRT";
+}
+
+inline bool ArrayTableBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(
+ buf, ArrayTableIdentifier());
+}
+
+inline bool VerifyArrayTableBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<MyGame::Example::ArrayTable>(ArrayTableIdentifier());
+}
+
+inline bool VerifySizePrefixedArrayTableBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<MyGame::Example::ArrayTable>(ArrayTableIdentifier());
+}
+
+inline const char *ArrayTableExtension() {
+ return "mon";
+}
+
+inline void FinishArrayTableBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::Example::ArrayTable> root) {
+ fbb.Finish(root, ArrayTableIdentifier());
+}
+
+inline void FinishSizePrefixedArrayTableBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::Example::ArrayTable> root) {
+ fbb.FinishSizePrefixed(root, ArrayTableIdentifier());
+}
+
+inline flatbuffers::unique_ptr<MyGame::Example::ArrayTableT> UnPackArrayTable(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MyGame::Example::ArrayTableT>(GetArrayTable(buf)->UnPack(res));
+}
+
+inline flatbuffers::unique_ptr<MyGame::Example::ArrayTableT> UnPackSizePrefixedArrayTable(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MyGame::Example::ArrayTableT>(GetSizePrefixedArrayTable(buf)->UnPack(res));
+}
+
+} // namespace Example
+} // namespace MyGame
+
+#endif // FLATBUFFERS_GENERATED_ARRAYSTEST_MYGAME_EXAMPLE_H_
diff --git a/tests/docker/Dockerfile.testing.build_flatc_debian_stretch b/tests/docker/Dockerfile.testing.build_flatc_debian_stretch
new file mode 100644
index 0000000..197a555
--- /dev/null
+++ b/tests/docker/Dockerfile.testing.build_flatc_debian_stretch
@@ -0,0 +1,9 @@
+FROM debian:9.6-slim as base
+RUN apt -qq update >/dev/null
+RUN apt -qq install -y cmake make build-essential >/dev/null
+FROM base
+WORKDIR /code
+ADD . .
+RUN cmake -G "Unix Makefiles"
+RUN make flatc
+RUN ls flatc
diff --git a/tests/docker/TODO.Dockerfile.testing.php.hhvm_2019_01_16 b/tests/docker/TODO.Dockerfile.testing.php.hhvm_2019_01_16
new file mode 100644
index 0000000..e5023fa
--- /dev/null
+++ b/tests/docker/TODO.Dockerfile.testing.php.hhvm_2019_01_16
@@ -0,0 +1,18 @@
+# This does not pass tests due to the following error:
+#
+# Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Google\FlatBuffers\ByteBuffer::getX() expects parameter 1 by reference, but the call was not annotated with '&'. in /code/php/FlatbufferBuilder.php:971
+# Stack trace:
+# #0 /code/tests/phpTest.php(277): Google\FlatBuffers\FlatbufferBuilder->sizedByteArray()
+# #1 /code/tests/phpTest.php(79): fuzzTest1()
+# #2 /code/tests/phpTest.php(86): main()
+# #3 {main}
+# thrown in in /code/php/FlatbufferBuilder.php:971
+FROM hhvm/hhvm:2019.01.16 as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN hhvm --version
+RUN hhvm phpTest.php
+RUN ../flatc --php -o php union_vector/union_vector.fbs
+RUN hhvm phpUnionVectorTest.php
diff --git a/tests/docker/TODO.Dockerfile.testing.python.cpython_with_conda b/tests/docker/TODO.Dockerfile.testing.python.cpython_with_conda
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/docker/TODO.Dockerfile.testing.python.cpython_with_conda
diff --git a/tests/docker/TODO.Dockerfile.testing.python.cpython_with_numpy b/tests/docker/TODO.Dockerfile.testing.python.cpython_with_numpy
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/docker/TODO.Dockerfile.testing.python.cpython_with_numpy
diff --git a/tests/docker/TODO.Dockerfile.testing.python.pypy_6_0_0_py2 b/tests/docker/TODO.Dockerfile.testing.python.pypy_6_0_0_py2
new file mode 100644
index 0000000..849b92e
--- /dev/null
+++ b/tests/docker/TODO.Dockerfile.testing.python.pypy_6_0_0_py2
@@ -0,0 +1,7 @@
+FROM pypy:2-6.0.0-slim as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN pypy --version
+RUN ./PythonTest.sh
diff --git a/tests/docker/TODO.Dockerfile.testing.python.pypy_6_0_0_py3 b/tests/docker/TODO.Dockerfile.testing.python.pypy_6_0_0_py3
new file mode 100644
index 0000000..2df6b2a
--- /dev/null
+++ b/tests/docker/TODO.Dockerfile.testing.python.pypy_6_0_0_py3
@@ -0,0 +1,7 @@
+FROM pypy:3-6.0.0-slim as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN pypy --version
+RUN ./PythonTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.csharp.mono_5_18 b/tests/docker/languages/Dockerfile.testing.csharp.mono_5_18
new file mode 100644
index 0000000..e6ba550
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.csharp.mono_5_18
@@ -0,0 +1,8 @@
+FROM mono:5.18 as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN mono --version
+WORKDIR /code/tests/FlatBuffers.Test
+RUN sh NetTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.golang.1_11 b/tests/docker/languages/Dockerfile.testing.golang.1_11
new file mode 100644
index 0000000..81707ea
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.golang.1_11
@@ -0,0 +1,7 @@
+FROM golang:1.11-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN go version
+RUN ./GoTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.java.openjdk_10_0_2 b/tests/docker/languages/Dockerfile.testing.java.openjdk_10_0_2
new file mode 100644
index 0000000..82c3add
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.java.openjdk_10_0_2
@@ -0,0 +1,7 @@
+FROM openjdk:10.0.2-jdk-slim-sid as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN java -version
+RUN ./JavaTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.java.openjdk_11_0_1 b/tests/docker/languages/Dockerfile.testing.java.openjdk_11_0_1
new file mode 100644
index 0000000..ac1c3cc
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.java.openjdk_11_0_1
@@ -0,0 +1,7 @@
+FROM openjdk:11.0.1-jdk-slim-sid as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN java -version
+RUN ./JavaTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.node.10_13_0 b/tests/docker/languages/Dockerfile.testing.node.10_13_0
new file mode 100644
index 0000000..b821105
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.node.10_13_0
@@ -0,0 +1,8 @@
+FROM node:10.13.0-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN node --version
+RUN ../flatc -b -I include_test monster_test.fbs unicode_test.json
+RUN node JavaScriptTest ./monster_test_generated
diff --git a/tests/docker/languages/Dockerfile.testing.node.11_2_0 b/tests/docker/languages/Dockerfile.testing.node.11_2_0
new file mode 100644
index 0000000..f6b48e6
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.node.11_2_0
@@ -0,0 +1,8 @@
+FROM node:11.2.0-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN node --version
+RUN ../flatc -b -I include_test monster_test.fbs unicode_test.json
+RUN node JavaScriptTest ./monster_test_generated
diff --git a/tests/docker/languages/Dockerfile.testing.php.zend_7_3 b/tests/docker/languages/Dockerfile.testing.php.zend_7_3
new file mode 100644
index 0000000..6cdf43c
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.php.zend_7_3
@@ -0,0 +1,8 @@
+FROM php:7.3-cli-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN php --version
+RUN php phpTest.php
+RUN sh phpUnionVectorTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.python.cpython_2_7_15 b/tests/docker/languages/Dockerfile.testing.python.cpython_2_7_15
new file mode 100644
index 0000000..e68303e
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.python.cpython_2_7_15
@@ -0,0 +1,8 @@
+FROM python:2.7.15-slim-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN python --version
+RUN pip install coverage
+RUN ./PythonTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.python.cpython_3_7_1 b/tests/docker/languages/Dockerfile.testing.python.cpython_3_7_1
new file mode 100644
index 0000000..7c2f15c
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.python.cpython_3_7_1
@@ -0,0 +1,8 @@
+FROM python:3.7.1-slim-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN python --version
+RUN pip install coverage
+RUN ./PythonTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.rust.1_30_1 b/tests/docker/languages/Dockerfile.testing.rust.1_30_1
new file mode 100644
index 0000000..4d1755c
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.rust.1_30_1
@@ -0,0 +1,7 @@
+FROM rust:1.30.1-slim-stretch as base
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN rustc --version
+RUN ./RustTest.sh
diff --git a/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_30_1 b/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_30_1
new file mode 100644
index 0000000..f2e93f4
--- /dev/null
+++ b/tests/docker/languages/Dockerfile.testing.rust.big_endian.1_30_1
@@ -0,0 +1,15 @@
+FROM rust:1.30.1-slim-stretch as base
+RUN apt -qq update -y && apt -qq install -y \
+ gcc-mips-linux-gnu \
+ libexpat1 \
+ libmagic1 \
+ libmpdec2 \
+ libreadline7 \
+ qemu-user
+RUN rustup target add mips-unknown-linux-gnu
+WORKDIR /code
+ADD . .
+RUN cp flatc_debian_stretch flatc
+WORKDIR /code/tests
+RUN rustc --version
+RUN ./RustTest.sh mips-unknown-linux-gnu
diff --git a/tests/fuzzer/CMakeLists.txt b/tests/fuzzer/CMakeLists.txt
new file mode 100644
index 0000000..7df5df2
--- /dev/null
+++ b/tests/fuzzer/CMakeLists.txt
@@ -0,0 +1,91 @@
+cmake_minimum_required(VERSION 3.9)
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+project(FlatBuffersFuzzerTests)
+
+set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -pedantic -Werror -Wextra -Wno-unused-parameter -fsigned-char")
+
+set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -g -fsigned-char -fno-omit-frame-pointer")
+
+# Typical slowdown introduced by MemorySanitizer (memory) is 3x.
+# '-fsanitize=address' not allowed with '-fsanitize=memory'
+if(YES)
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer,address,undefined")
+else()
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer,memory,undefined -fsanitize-memory-track-origins=2")
+endif()
+
+set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} -fsanitize-coverage=edge,trace-cmp")
+
+# enable link-time optimisation
+# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto")
+
+# https://llvm.org/docs/Passes.html
+# save IR to see call graph
+# make one bitcode file:> llvm-link *.bc -o out.bc
+# print call-graph:> opt out.bc -analyze -print-callgraph &> callgraph.txt
+# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -save-temps -flto")
+
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
+
+set(FLATBUFFERS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../")
+
+set(FlatBuffers_Library_SRCS
+ ${FLATBUFFERS_DIR}/include/flatbuffers/code_generators.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/base.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/flatbuffers.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/hash.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/idl.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/util.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/reflection.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/reflection_generated.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/stl_emulation.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/flexbuffers.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/registry.h
+ ${FLATBUFFERS_DIR}/include/flatbuffers/minireflect.h
+ ${FLATBUFFERS_DIR}/src/code_generators.cpp
+ ${FLATBUFFERS_DIR}/src/idl_parser.cpp
+ ${FLATBUFFERS_DIR}/src/idl_gen_text.cpp
+ ${FLATBUFFERS_DIR}/src/reflection.cpp
+ ${FLATBUFFERS_DIR}/src/util.cpp
+ ${FLATBUFFERS_DIR}/tests/test_assert.cpp
+)
+
+include_directories(${FLATBUFFERS_DIR}/include)
+include_directories(${FLATBUFFERS_DIR}/tests)
+add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
+
+# FLATBUFFERS_ASSERT should assert in Release as well.
+# Redefine FLATBUFFERS_ASSERT macro definition.
+# Declare as PUBLIC to cover asserts in all included header files.
+target_compile_definitions(flatbuffers PUBLIC
+ FLATBUFFERS_ASSERT=fuzzer_assert_impl)
+target_compile_definitions(flatbuffers PUBLIC
+ FLATBUFFERS_ASSERT_INCLUDE="${CMAKE_CURRENT_SOURCE_DIR}/fuzzer_assert.h")
+
+if(NOT DEFINED FLATBUFFERS_MAX_PARSING_DEPTH)
+ # Force checking of RecursionError in the test
+ set(FLATBUFFERS_MAX_PARSING_DEPTH 8)
+endif()
+message(STATUS "FLATBUFFERS_MAX_PARSING_DEPTH: ${FLATBUFFERS_MAX_PARSING_DEPTH}")
+target_compile_definitions(flatbuffers PRIVATE FLATBUFFERS_MAX_PARSING_DEPTH=8)
+
+# Setup fuzzer tests.
+
+add_executable(scalar_fuzzer flatbuffers_scalar_fuzzer.cc)
+target_link_libraries(scalar_fuzzer PRIVATE flatbuffers)
+
+add_executable(parser_fuzzer flatbuffers_parser_fuzzer.cc)
+target_link_libraries(parser_fuzzer PRIVATE flatbuffers)
+
+add_executable(verifier_fuzzer flatbuffers_verifier_fuzzer.cc)
+target_link_libraries(verifier_fuzzer PRIVATE flatbuffers)
diff --git a/tests/fuzzer/flatbuffers_parser_fuzzer.cc b/tests/fuzzer/flatbuffers_parser_fuzzer.cc
new file mode 100644
index 0000000..87dd2d2
--- /dev/null
+++ b/tests/fuzzer/flatbuffers_parser_fuzzer.cc
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+#include <clocale>
+#include <string>
+
+#include "flatbuffers/idl.h"
+#include "test_init.h"
+
+static constexpr uint8_t flags_strict_json = 0x01;
+static constexpr uint8_t flags_skip_unexpected_fields_in_json = 0x02;
+static constexpr uint8_t flags_allow_non_utf8 = 0x04;
+// static constexpr uint8_t flags_flag_3 = 0x08;
+// static constexpr uint8_t flags_flag_4 = 0x10;
+// static constexpr uint8_t flags_flag_5 = 0x20;
+// static constexpr uint8_t flags_flag_6 = 0x40;
+// static constexpr uint8_t flags_flag_7 = 0x80;
+
+// Utility for test run.
+OneTimeTestInit OneTimeTestInit::one_time_init_;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // Reserve one byte for Parser flags and one byte for repetition counter.
+ if (size < 3) return 0;
+ const uint8_t flags = data[0];
+ // normalize to ascii alphabet
+ const int extra_rep_number = data[1] >= '0' ? (data[1] - '0') : 0;
+ data += 2;
+ size -= 2; // bypass
+
+ const std::string original(reinterpret_cast<const char *>(data), size);
+ auto input = std::string(original.c_str()); // until '\0'
+ if (input.empty()) return 0;
+
+ flatbuffers::IDLOptions opts;
+ opts.strict_json = (flags & flags_strict_json);
+ opts.skip_unexpected_fields_in_json =
+ (flags & flags_skip_unexpected_fields_in_json);
+ opts.allow_non_utf8 = (flags & flags_allow_non_utf8);
+
+ flatbuffers::Parser parser(opts);
+
+ // Guarantee 0-termination in the input.
+ auto parse_input = input.c_str();
+
+ // The fuzzer can adjust the number repetition if a side-effects have found.
+ // Each test should pass at least two times to ensure that the parser doesn't
+ // have any hidden-states or locale-depended effects.
+ for (auto cnt = 0; cnt < (extra_rep_number + 2); cnt++) {
+ // Each even run (0,2,4..) will test locale independed code.
+ auto use_locale = !!OneTimeTestInit::test_locale() && (0 == (cnt % 2));
+ // Set new locale.
+ if (use_locale) {
+ FLATBUFFERS_ASSERT(setlocale(LC_ALL, OneTimeTestInit::test_locale()));
+ }
+
+ // Check Parser.
+ parser.Parse(parse_input);
+
+ // Restore locale.
+ if (use_locale) { FLATBUFFERS_ASSERT(setlocale(LC_ALL, "C")); }
+ }
+
+ return 0;
+}
diff --git a/tests/fuzzer/flatbuffers_scalar_fuzzer.cc b/tests/fuzzer/flatbuffers_scalar_fuzzer.cc
new file mode 100644
index 0000000..074a488
--- /dev/null
+++ b/tests/fuzzer/flatbuffers_scalar_fuzzer.cc
@@ -0,0 +1,351 @@
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <clocale>
+#include <memory>
+#include <regex>
+#include <string>
+
+#include "flatbuffers/idl.h"
+#include "test_init.h"
+
+static constexpr uint8_t flags_scalar_type = 0x0F; // type of scalar value
+static constexpr uint8_t flags_quotes_kind = 0x10; // quote " or '
+// reserved for future: json {named} or [unnamed]
+// static constexpr uint8_t flags_json_bracer = 0x20;
+
+// Find all 'subj' sub-strings and replace first character of sub-string.
+// BreakSequence("testest","tes", 'X') -> "XesXest".
+// BreakSequence("xxx","xx", 'Y') -> "YYx".
+static void BreakSequence(std::string &s, const char *subj, char repl) {
+ size_t pos = 0;
+ while (pos = s.find(subj, pos), pos != std::string::npos) {
+ s.at(pos) = repl;
+ pos++;
+ }
+}
+
+// Remove all leading and trailing symbols matched with pattern set.
+// StripString("xy{xy}y", "xy") -> "{xy}"
+static std::string StripString(const std::string &s, const char *pattern,
+ size_t *pos = nullptr) {
+ if (pos) *pos = 0;
+ // leading
+ auto first = s.find_first_not_of(pattern);
+ if (std::string::npos == first) return "";
+ if (pos) *pos = first;
+ // trailing
+ auto last = s.find_last_not_of(pattern);
+ assert(last < s.length());
+ assert(first <= last);
+ return s.substr(first, last - first + 1);
+}
+
+class RegexMatcher {
+ protected:
+ virtual bool MatchNumber(const std::string &input) const = 0;
+
+ public:
+ virtual ~RegexMatcher() = default;
+
+ struct MatchResult {
+ size_t pos{ 0 };
+ size_t len{ 0 };
+ bool res{ false };
+ bool quoted{ false };
+ };
+
+ MatchResult Match(const std::string &input) const {
+ MatchResult r;
+ // strip leading and trailing "spaces" accepted by flatbuffer
+ auto test = StripString(input, "\t\r\n ", &r.pos);
+ r.len = test.size();
+ // check quotes
+ if (test.size() >= 2) {
+ auto fch = test.front();
+ auto lch = test.back();
+ r.quoted = (fch == lch) && (fch == '\'' || fch == '\"');
+ if (r.quoted) {
+ // remove quotes for regex test
+ test = test.substr(1, test.size() - 2);
+ }
+ }
+ // Fast check:
+ if (test.empty()) return r;
+ // A string with a valid scalar shouldn't have non-ascii or non-printable
+ // symbols.
+ for (auto c : test) {
+ if ((c < ' ') || (c > '~')) return r;
+ }
+ // Check with regex
+ r.res = MatchNumber(test);
+ return r;
+ }
+
+ bool MatchRegexList(const std::string &input,
+ const std::vector<std::regex> &re_list) const {
+ auto str = StripString(input, " ");
+ if (str.empty()) return false;
+ for (auto &re : re_list) {
+ std::smatch match;
+ if (std::regex_match(str, match, re)) return true;
+ }
+ return false;
+ }
+};
+
+class IntegerRegex : public RegexMatcher {
+ protected:
+ bool MatchNumber(const std::string &input) const override {
+ static const std::vector<std::regex> re_list = {
+ std::regex{ R"(^[-+]?[0-9]+$)", std::regex_constants::optimize },
+
+ std::regex{
+ R"(^[-+]?0[xX][0-9a-fA-F]+$)", std::regex_constants::optimize }
+ };
+ return MatchRegexList(input, re_list);
+ }
+
+ public:
+ IntegerRegex() = default;
+ virtual ~IntegerRegex() = default;
+};
+
+class UIntegerRegex : public RegexMatcher {
+ protected:
+ bool MatchNumber(const std::string &input) const override {
+ static const std::vector<std::regex> re_list = {
+ std::regex{ R"(^[+]?[0-9]+$)", std::regex_constants::optimize },
+ std::regex{
+ R"(^[+]?0[xX][0-9a-fA-F]+$)", std::regex_constants::optimize },
+ // accept -0 number
+ std::regex{ R"(^[-](?:0[xX])?0+$)", std::regex_constants::optimize }
+ };
+ return MatchRegexList(input, re_list);
+ }
+
+ public:
+ UIntegerRegex() = default;
+ virtual ~UIntegerRegex() = default;
+};
+
+class BooleanRegex : public IntegerRegex {
+ protected:
+ bool MatchNumber(const std::string &input) const override {
+ if (input == "true" || input == "false") return true;
+ return IntegerRegex::MatchNumber(input);
+ }
+
+ public:
+ BooleanRegex() = default;
+ virtual ~BooleanRegex() = default;
+};
+
+class FloatRegex : public RegexMatcher {
+ protected:
+ bool MatchNumber(const std::string &input) const override {
+ static const std::vector<std::regex> re_list = {
+ // hex-float
+ std::regex{
+ R"(^[-+]?0[xX](?:(?:[.][0-9a-fA-F]+)|(?:[0-9a-fA-F]+[.][0-9a-fA-F]*)|(?:[0-9a-fA-F]+))[pP][-+]?[0-9]+$)",
+ std::regex_constants::optimize },
+ // dec-float
+ std::regex{
+ R"(^[-+]?(?:(?:[.][0-9]+)|(?:[0-9]+[.][0-9]*)|(?:[0-9]+))(?:[eE][-+]?[0-9]+)?$)",
+ std::regex_constants::optimize },
+
+ std::regex{ R"(^[-+]?(?:nan|inf|infinity)$)",
+ std::regex_constants::optimize | std::regex_constants::icase }
+ };
+ return MatchRegexList(input, re_list);
+ }
+
+ public:
+ FloatRegex() = default;
+ virtual ~FloatRegex() = default;
+};
+
+class ScalarReferenceResult {
+ private:
+ ScalarReferenceResult(const char *_type, RegexMatcher::MatchResult _matched)
+ : type(_type), matched(_matched) {}
+
+ public:
+ // Decode scalar type and check if the input string satisfies the scalar type.
+ static ScalarReferenceResult Check(uint8_t code, const std::string &input) {
+ switch (code) {
+ case 0x0: return { "double", FloatRegex().Match(input) };
+ case 0x1: return { "float", FloatRegex().Match(input) };
+ case 0x2: return { "int8", IntegerRegex().Match(input) };
+ case 0x3: return { "int16", IntegerRegex().Match(input) };
+ case 0x4: return { "int32", IntegerRegex().Match(input) };
+ case 0x5: return { "int64", IntegerRegex().Match(input) };
+ case 0x6: return { "uint8", UIntegerRegex().Match(input) };
+ case 0x7: return { "uint16", UIntegerRegex().Match(input) };
+ case 0x8: return { "uint32", UIntegerRegex().Match(input) };
+ case 0x9: return { "uint64", UIntegerRegex().Match(input) };
+ case 0xA: return { "bool", BooleanRegex().Match(input) };
+ default: return { "float", FloatRegex().Match(input) };
+ };
+ }
+
+ const char *type;
+ const RegexMatcher::MatchResult matched;
+};
+
+bool Parse(flatbuffers::Parser &parser, const std::string &json,
+ std::string *_text) {
+ auto done = parser.Parse(json.c_str());
+ if (done) {
+ TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), _text),
+ true);
+ } else {
+ *_text = parser.error_;
+ }
+ return done;
+}
+
+// Utility for test run.
+OneTimeTestInit OneTimeTestInit::one_time_init_;
+
+// llvm std::regex have problem with stack overflow, limit maximum length.
+// ./scalar_fuzzer -max_len=3000
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // Reserve one byte for Parser flags and one byte for repetition counter.
+ if (size < 3) return 0;
+ const uint8_t flags = data[0];
+ // normalize to ascii alphabet
+ const int extra_rep_number = data[1] >= '0' ? (data[1] - '0') : 0;
+ data += 2;
+ size -= 2; // bypass
+
+ // Guarantee 0-termination.
+ const std::string original(reinterpret_cast<const char *>(data), size);
+ auto input = std::string(original.c_str()); // until '\0'
+ if (input.empty()) return 0;
+
+ // Break comments in json to avoid complexity with regex matcher.
+ // The string " 12345 /* text */" will be accepted if insert it to string
+ // expression: "table X { Y: " + " 12345 /* text */" + "; }.
+ // But strings like this will complicate regex matcher.
+ // We reject this by transform "/* text */ 12345" to "@* text */ 12345".
+ BreakSequence(input, "//", '@'); // "//" -> "@/"
+ BreakSequence(input, "/*", '@'); // "/*" -> "@*"
+ // Break all known scalar functions (todo: add them to regex?):
+ for (auto f : { "deg", "rad", "sin", "cos", "tan", "asin", "acos", "atan" }) {
+ BreakSequence(input, f, '_'); // ident -> ident
+ }
+
+ // Extract type of scalar from 'flags' and check if the input string satisfies
+ // the scalar type.
+ const auto ref_res =
+ ScalarReferenceResult::Check(flags & flags_scalar_type, input);
+ auto &recheck = ref_res.matched;
+
+ // Create parser
+ flatbuffers::IDLOptions opts;
+ opts.force_defaults = true;
+ opts.output_default_scalars_in_json = true;
+ opts.indent_step = -1;
+ opts.strict_json = true;
+
+ flatbuffers::Parser parser(opts);
+ auto schema =
+ "table X { Y: " + std::string(ref_res.type) + "; } root_type X;";
+ TEST_EQ_FUNC(parser.Parse(schema.c_str()), true);
+
+ // The fuzzer can adjust the number repetition if a side-effects have found.
+ // Each test should pass at least two times to ensure that the parser doesn't
+ // have any hidden-states or locale-depended effects.
+ for (auto cnt = 0; cnt < (extra_rep_number + 2); cnt++) {
+ // Each even run (0,2,4..) will test locale independed code.
+ auto use_locale = !!OneTimeTestInit::test_locale() && (0 == (cnt % 2));
+ // Set new locale.
+ if (use_locale) {
+ FLATBUFFERS_ASSERT(setlocale(LC_ALL, OneTimeTestInit::test_locale()));
+ }
+
+ // Parse original input as-is.
+ auto orig_scalar = "{ \"Y\" : " + input + " }";
+ std::string orig_back;
+ auto orig_done = Parse(parser, orig_scalar, &orig_back);
+
+ if (recheck.res != orig_done) {
+ // look for "does not fit" or "doesn't fit" or "out of range"
+ auto not_fit =
+ (true == recheck.res)
+ ? ((orig_back.find("does not fit") != std::string::npos) ||
+ (orig_back.find("out of range") != std::string::npos))
+ : false;
+
+ if (false == not_fit) {
+ TEST_OUTPUT_LINE("Stage 1 failed: Parser(%d) != Regex(%d)", orig_done,
+ recheck.res);
+ TEST_EQ_STR(orig_back.c_str(),
+ input.substr(recheck.pos, recheck.len).c_str());
+ TEST_EQ_FUNC(orig_done, recheck.res);
+ }
+ }
+
+ // Try to make quoted string and test it.
+ std::string qouted_input;
+ if (true == recheck.quoted) {
+ // we can't simply remove quotes, they may be nested "'12'".
+ // Original string "\'12\'" converted to "'12'".
+ // The string can be an invalid string by JSON rules, but after quotes
+ // removed can transform to valid.
+ assert(recheck.len >= 2);
+ } else {
+ const auto quote = (flags & flags_quotes_kind) ? '\"' : '\'';
+ qouted_input = input; // copy
+ qouted_input.insert(recheck.pos + recheck.len, 1, quote);
+ qouted_input.insert(recheck.pos, 1, quote);
+ }
+
+ // Test quoted version of the string
+ if (!qouted_input.empty()) {
+ auto fix_scalar = "{ \"Y\" : " + qouted_input + " }";
+ std::string fix_back;
+ auto fix_done = Parse(parser, fix_scalar, &fix_back);
+
+ if (orig_done != fix_done) {
+ TEST_OUTPUT_LINE("Stage 2 failed: Parser(%d) != Regex(%d)", fix_done,
+ orig_done);
+ TEST_EQ_STR(fix_back.c_str(), orig_back.c_str());
+ }
+ if (orig_done) { TEST_EQ_STR(fix_back.c_str(), orig_back.c_str()); }
+ TEST_EQ_FUNC(fix_done, orig_done);
+ }
+
+ // Create new parser and test default value
+ if (true == orig_done) {
+ flatbuffers::Parser def_parser(opts); // re-use options
+ auto def_schema = "table X { Y: " + std::string(ref_res.type) + " = " +
+ input + "; } root_type X;" +
+ "{}"; // <- with empty json {}!
+
+ auto def_done = def_parser.Parse(def_schema.c_str());
+ if (false == def_done) {
+ TEST_OUTPUT_LINE("Stage 3.1 failed with _error = %s",
+ def_parser.error_.c_str());
+ FLATBUFFERS_ASSERT(false);
+ }
+ // Compare with print.
+ std::string ref_string, def_string;
+ FLATBUFFERS_ASSERT(GenerateText(
+ parser, parser.builder_.GetBufferPointer(), &ref_string));
+ FLATBUFFERS_ASSERT(GenerateText(
+ def_parser, def_parser.builder_.GetBufferPointer(), &def_string));
+ if (ref_string != def_string) {
+ TEST_OUTPUT_LINE("Stage 3.2 failed: '%s' != '%s'", def_string.c_str(),
+ ref_string.c_str());
+ FLATBUFFERS_ASSERT(false);
+ }
+ }
+
+ // Restore locale.
+ if (use_locale) { FLATBUFFERS_ASSERT(setlocale(LC_ALL, "C")); }
+ }
+ return 0;
+}
diff --git a/tests/fuzzer/flatbuffers_verifier_fuzzer.cc b/tests/fuzzer/flatbuffers_verifier_fuzzer.cc
new file mode 100644
index 0000000..d7d453c
--- /dev/null
+++ b/tests/fuzzer/flatbuffers_verifier_fuzzer.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+#include <string>
+
+#include "monster_test_generated.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ flatbuffers::Verifier verifier(data, size);
+ MyGame::Example::VerifyMonsterBuffer(verifier);
+ return 0;
+}
diff --git a/tests/fuzzer/fuzzer_assert.h b/tests/fuzzer/fuzzer_assert.h
new file mode 100644
index 0000000..afdcf78
--- /dev/null
+++ b/tests/fuzzer/fuzzer_assert.h
@@ -0,0 +1,9 @@
+#ifndef FUZZER_ASSERT_IMPL_H_
+#define FUZZER_ASSERT_IMPL_H_
+
+// Declare Debug/Release independed assert macro.
+#define fuzzer_assert_impl(x) (!!(x) ? static_cast<void>(0) : __builtin_trap())
+
+extern "C" void __builtin_trap(void);
+
+#endif // !FUZZER_ASSERT_IMPL_H_
diff --git a/tests/fuzzer/readme.md b/tests/fuzzer/readme.md
new file mode 100644
index 0000000..c5e147b
--- /dev/null
+++ b/tests/fuzzer/readme.md
@@ -0,0 +1,55 @@
+# Test Flatbuffers library with help of libFuzzer
+Test suite of Flatbuffers library has fuzzer section with tests are based on libFuzzer library.
+
+> LibFuzzer is in-process, coverage-guided, evolutionary fuzzing engine.
+LibFuzzer is linked with the library under test, and feeds fuzzed inputs to the library via a specific fuzzing entrypoint (aka “target function”);
+the fuzzer then tracks which areas of the code are reached, and generates mutations on the corpus of input data in order to maximize the code coverage.
+The code coverage information for libFuzzer is provided by LLVM’s SanitizerCoverage instrumentation.
+
+For details about **libFuzzer** see: https://llvm.org/docs/LibFuzzer.html
+
+To build and run these tests LLVM compiler (with clang frontend) and CMake should be installed before.
+
+The fuzzer section include three tests:
+- `verifier_fuzzer` checks stability of deserialization engine for `Monster` schema;
+- `parser_fuzzer` checks stability of schema and json parser under various inputs;
+- `scalar_parser` focused on validation of the parser while parse numeric scalars in schema and/or json files;
+
+## Run tests with a specific locale
+The grammar of the Flatbuffers library is based on printable-ASCII characters.
+By design, the Flatbuffers library should be independent of the global or thread locales used by an end-user application.
+Set environment variable `FLATBUFFERS_TEST_LOCALE` to run a fuzzer with a specific C-locale:
+```sh
+>FLATBUFFERS_TEST_LOCALE="" ./scalar_parser
+>FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./parser_fuzzer
+```
+
+## Run fuzzer
+These are examples of running a fuzzer.
+Flags may vary and depend on a version of the libFuzzer library.
+For details, run a fuzzer with `-help` flag: `./parser_fuzzer -help=1`
+
+`./verifier_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 ../.corpus_verifier/`
+
+`./parser_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 ../.corpus_parser/`
+
+`./scalar_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 -max_len=3000 ../.corpus_parser/ ../.seed_parser/`
+
+Flag `-only_ascii=1` is useful for fast number-compatibility checking while run `scalar_fuzzer`:
+`./scalar_fuzzer -only_ascii=1 -reduce_depth=1 -use_value_profile=1 -shrink=1 -max_len=3000 -timeout=10 -rss_limit_mb=2048 -jobs=2 ../.corpus_parser/ ../.seed_parser/`
+
+Run with a specific C-locale:
+`FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./scalar_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 -max_len=3000 -timeout=10 -rss_limit_mb=2048 ../.corpus_parser/ ../.seed_parser/`
+
+## Merge (minimize) corpus
+The **libFuzzer** allow to filter (minimize) corpus with help of `-merge` flag:
+> -merge
+ If set to 1, any corpus inputs from the 2nd, 3rd etc. corpus directories that trigger new code coverage will be merged into the first corpus directory.
+ Defaults to 0. This flag can be used to minimize a corpus.
+
+Merge several seeds to one (a new collected corpus to the seed collection, for example):
+`./scalar_fuzzer -merge=1 ../.seed_parser/ ../.corpus_parser/`
+
+## Know limitations
+- LLVM 7.0 std::regex library has problem with stack overflow, maximum length of input for `scalar_fuzzer` run should be limited to 3000.
+ Example: `./scalar_fuzzer -max_len=3000`
diff --git a/tests/fuzzer/test_init.h b/tests/fuzzer/test_init.h
new file mode 100644
index 0000000..3d8d07c
--- /dev/null
+++ b/tests/fuzzer/test_init.h
@@ -0,0 +1,56 @@
+
+#ifndef FUZZER_TEST_INIT_H_
+#define FUZZER_TEST_INIT_H_
+
+#include "fuzzer_assert.h"
+#include "test_assert.h"
+
+static_assert(__has_feature(memory_sanitizer) ||
+ __has_feature(address_sanitizer),
+ "sanitizer disabled");
+
+// Utility for test run.
+struct OneTimeTestInit {
+ // Declare trap for the Flatbuffers test engine.
+ // This hook terminate program both in Debug and Release.
+ static bool TestFailListener(const char *expval, const char *val,
+ const char *exp, const char *file, int line,
+ const char *func = 0) {
+ (void)expval;
+ (void)val;
+ (void)exp;
+ (void)file;
+ (void)line;
+ (void)func;
+ // FLATBUFFERS_ASSERT redefined to be fully independent of the Flatbuffers
+ // library implementation (see test_assert.h for details).
+ fuzzer_assert_impl(false); // terminate
+ return false;
+ }
+
+ OneTimeTestInit() : has_locale_(false) {
+ // Fuzzer test should be independent of the test engine implementation.
+ // This hook will terminate test if TEST_EQ/TEST_ASSERT asserted.
+ InitTestEngine(OneTimeTestInit::TestFailListener);
+
+ // Read a locale for the test.
+ if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
+ &test_locale_)) {
+ TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
+ test_locale_.c_str());
+ test_locale_ = flatbuffers::RemoveStringQuotes(test_locale_);
+ has_locale_ = true;
+ }
+ }
+
+ static const char *test_locale() {
+ return one_time_init_.has_locale_ ? nullptr
+ : one_time_init_.test_locale_.c_str();
+ }
+
+ bool has_locale_;
+ std::string test_locale_;
+ static OneTimeTestInit one_time_init_;
+};
+
+#endif // !FUZZER_TEST_INIT_H_
\ No newline at end of file
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
new file mode 100644
index 0000000..59033b8
--- /dev/null
+++ b/tests/generate_code.bat
@@ -0,0 +1,46 @@
+:: Copyright 2015 Google Inc. All rights reserved.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+
+set buildtype=Release
+if "%1"=="-b" set buildtype=%2
+
+..\%buildtype%\flatc.exe --cpp --java --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --grpc --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json || goto FAIL
+..\%buildtype%\flatc.exe --cpp --java --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs || goto FAIL
+..\%buildtype%\flatc.exe --cpp --java --csharp --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs || goto FAIL
+..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs || goto FAIL
+..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs || goto FAIL
+..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs || goto FAIL
+..\%buildtype%\flatc.exe --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --scoped-enums --jsonschema --cpp-ptr-type flatbuffers::unique_ptr arrays_test.fbs || goto FAIL
+..\%buildtype%\flatc.exe --cpp --gen-mutable --gen-object-api --reflect-names --cpp-ptr-type flatbuffers::unique_ptr native_type_test.fbs || goto FAIL
+
+IF NOT "%MONSTER_EXTRA%"=="skip" (
+ @echo Generate MosterExtra
+ ..\%buildtype%\flatc.exe --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs monsterdata_extra.json || goto FAIL
+) else (
+ @echo monster_extra.fbs skipped (the strtod function from MSVC2013 or older doesn't support NaN/Inf arguments)
+)
+
+cd ../samples
+..\%buildtype%\flatc.exe --cpp --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs || goto FAIL
+..\%buildtype%\flatc.exe -b --schema --bfbs-comments --bfbs-builtins monster.fbs || goto FAIL
+cd ../reflection
+call generate_code.bat %1 %2 || goto FAIL
+
+set EXITCODE=0
+goto SUCCESS
+:FAIL
+set EXITCODE=1
+:SUCCESS
+cd ../tests
+EXIT /B %EXITCODE%
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
new file mode 100755
index 0000000..d086c2f
--- /dev/null
+++ b/tests/generate_code.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright 2015 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -e
+
+../flatc --cpp --java --kotlin --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --grpc --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
+../flatc --cpp --java --kotlin --csharp --dart --go --binary --lobster --lua --python --js --ts --php --rust --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+../flatc --cpp --java --kotlin --csharp --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
+../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs
+../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test arrays_test.fbs
+../flatc --jsonschema --schema -I include_test monster_test.fbs
+../flatc --cpp --java --kotlin --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs monsterdata_extra.json
+../flatc --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes --scoped-enums --jsonschema --cpp-ptr-type flatbuffers::unique_ptr arrays_test.fbs
+cd ../samples
+../flatc --cpp --kotlin --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
+../flatc -b --schema --bfbs-comments --bfbs-builtins monster.fbs
+cd ../reflection
+./generate_code.sh
diff --git a/tests/go_test.go b/tests/go_test.go
new file mode 100644
index 0000000..4784705
--- /dev/null
+++ b/tests/go_test.go
@@ -0,0 +1,1889 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+ mygame "MyGame" // refers to generated code
+ example "MyGame/Example" // refers to generated code
+
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "reflect"
+ "sort"
+ "testing"
+
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+var (
+ cppData, javaData, outData string
+ fuzz bool
+ fuzzFields, fuzzObjects int
+)
+
+func init() {
+ flag.StringVar(&cppData, "cpp_data", "",
+ "location of monsterdata_test.mon to verify against (required)")
+ flag.StringVar(&javaData, "java_data", "",
+ "location of monsterdata_java_wire.mon to verify against (optional)")
+ flag.StringVar(&outData, "out_data", "",
+ "location to write generated Go data")
+ flag.BoolVar(&fuzz, "fuzz", false, "perform fuzzing")
+ flag.IntVar(&fuzzFields, "fuzz_fields", 4, "fields per fuzzer object")
+ flag.IntVar(&fuzzObjects, "fuzz_objects", 10000,
+ "number of fuzzer objects (higher is slower and more thorough")
+ flag.Parse()
+
+ if cppData == "" {
+ fmt.Fprintf(os.Stderr, "cpp_data argument is required\n")
+ os.Exit(1)
+ }
+}
+
+// Store specific byte patterns in these variables for the fuzzer. These
+// values are taken verbatim from the C++ function FuzzTest1.
+var (
+ overflowingInt32Val = flatbuffers.GetInt32([]byte{0x83, 0x33, 0x33, 0x33})
+ overflowingInt64Val = flatbuffers.GetInt64([]byte{0x84, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44})
+)
+
+// TestAll runs all checks, failing if any errors occur.
+func TestAll(t *testing.T) {
+ // Verify that the Go FlatBuffers runtime library generates the
+ // expected bytes (does not use any schema):
+ CheckByteLayout(t.Fatalf)
+ CheckMutateMethods(t.Fatalf)
+
+ // Verify that panics are raised during exceptional conditions:
+ CheckNotInObjectError(t.Fatalf)
+ CheckStringIsNestedError(t.Fatalf)
+ CheckByteStringIsNestedError(t.Fatalf)
+ CheckStructIsNotInlineError(t.Fatalf)
+ CheckFinishedBytesError(t.Fatalf)
+
+ // Verify that GetRootAs works for non-root tables
+ CheckGetRootAsForNonRootTable(t.Fatalf)
+ CheckTableAccessors(t.Fatalf)
+
+ // Verify that using the generated Go code builds a buffer without
+ // returning errors:
+ generated, off := CheckGeneratedBuild(t.Fatalf)
+
+ // Verify that the buffer generated by Go code is readable by the
+ // generated Go code:
+ CheckReadBuffer(generated, off, t.Fatalf)
+ CheckMutateBuffer(generated, off, t.Fatalf)
+
+ // Verify that the buffer generated by C++ code is readable by the
+ // generated Go code:
+ monsterDataCpp, err := ioutil.ReadFile(cppData)
+ if err != nil {
+ t.Fatal(err)
+ }
+ CheckReadBuffer(monsterDataCpp, 0, t.Fatalf)
+ CheckMutateBuffer(monsterDataCpp, 0, t.Fatalf)
+
+ // Verify that vtables are deduplicated when written:
+ CheckVtableDeduplication(t.Fatalf)
+
+ // Verify the enum names
+ CheckEnumNames(t.Fatalf)
+
+ // Verify enum String methods
+ CheckEnumString(t.Fatalf)
+
+ // Verify the enum values maps
+ CheckEnumValues(t.Fatalf)
+
+ // Verify that the Go code used in FlatBuffers documentation passes
+ // some sanity checks:
+ CheckDocExample(generated, off, t.Fatalf)
+
+ // Check Builder.CreateByteVector
+ CheckCreateByteVector(t.Fatalf)
+
+ // Check a parent namespace import
+ CheckParentNamespace(t.Fatalf)
+
+ // If the filename of the FlatBuffers file generated by the Java test
+ // is given, check that Go code can read it, and that Go code
+ // generates an identical buffer when used to create the example data:
+ if javaData != "" {
+ monsterDataJava, err := ioutil.ReadFile(javaData)
+ if err != nil {
+ t.Fatal(err)
+ }
+ CheckReadBuffer(monsterDataJava, 0, t.Fatalf)
+ CheckByteEquality(generated[off:], monsterDataJava, t.Fatalf)
+ }
+
+ // Verify that various fuzzing scenarios produce a valid FlatBuffer.
+ if fuzz {
+ checkFuzz(fuzzFields, fuzzObjects, t.Fatalf)
+ }
+
+ // Write the generated buffer out to a file:
+ err = ioutil.WriteFile(outData, generated[off:], os.FileMode(0644))
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// CheckReadBuffer checks that the given buffer is evaluated correctly
+// as the example Monster.
+func CheckReadBuffer(buf []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) {
+ // try the two ways of generating a monster
+ monster1 := example.GetRootAsMonster(buf, offset)
+ monster2 := &example.Monster{}
+ flatbuffers.GetRootAs(buf, offset, monster2)
+ for _, monster := range []*example.Monster{monster1, monster2} {
+ if got := monster.Hp(); 80 != got {
+ fail(FailString("hp", 80, got))
+ }
+
+ // default
+ if got := monster.Mana(); 150 != got {
+ fail(FailString("mana", 150, got))
+ }
+
+ if got := monster.Name(); !bytes.Equal([]byte("MyMonster"), got) {
+ fail(FailString("name", "MyMonster", got))
+ }
+
+ if got := monster.Color(); example.ColorBlue != got {
+ fail(FailString("color", example.ColorBlue, got))
+ }
+
+ if got := monster.Testbool(); true != got {
+ fail(FailString("testbool", true, got))
+ }
+
+ // initialize a Vec3 from Pos()
+ vec := new(example.Vec3)
+ vec = monster.Pos(vec)
+ if vec == nil {
+ fail("vec3 initialization failed")
+ }
+
+ // check that new allocs equal given ones:
+ vec2 := monster.Pos(nil)
+ if !reflect.DeepEqual(vec, vec2) {
+ fail("fresh allocation failed")
+ }
+
+ // verify the properties of the Vec3
+ if got := vec.X(); float32(1.0) != got {
+ fail(FailString("Pos.X", float32(1.0), got))
+ }
+
+ if got := vec.Y(); float32(2.0) != got {
+ fail(FailString("Pos.Y", float32(2.0), got))
+ }
+
+ if got := vec.Z(); float32(3.0) != got {
+ fail(FailString("Pos.Z", float32(3.0), got))
+ }
+
+ if got := vec.Test1(); float64(3.0) != got {
+ fail(FailString("Pos.Test1", float64(3.0), got))
+ }
+
+ if got := vec.Test2(); example.ColorGreen != got {
+ fail(FailString("Pos.Test2", example.ColorGreen, got))
+ }
+
+ // initialize a Test from Test3(...)
+ t := new(example.Test)
+ t = vec.Test3(t)
+ if t == nil {
+ fail("vec.Test3(&t) failed")
+ }
+
+ // check that new allocs equal given ones:
+ t2 := vec.Test3(nil)
+ if !reflect.DeepEqual(t, t2) {
+ fail("fresh allocation failed")
+ }
+
+ // verify the properties of the Test
+ if got := t.A(); int16(5) != got {
+ fail(FailString("t.A()", int16(5), got))
+ }
+
+ if got := t.B(); int8(6) != got {
+ fail(FailString("t.B()", int8(6), got))
+ }
+
+ if got := monster.TestType(); example.AnyMonster != got {
+ fail(FailString("monster.TestType()", example.AnyMonster, got))
+ }
+
+ // initialize a Table from a union field Test(...)
+ var table2 flatbuffers.Table
+ if ok := monster.Test(&table2); !ok {
+ fail("monster.Test(&monster2) failed")
+ }
+
+ // initialize a Monster from the Table from the union
+ var monster2 example.Monster
+ monster2.Init(table2.Bytes, table2.Pos)
+
+ if got := monster2.Name(); !bytes.Equal([]byte("Fred"), got) {
+ fail(FailString("monster2.Name()", "Fred", got))
+ }
+
+ inventorySlice := monster.InventoryBytes()
+ if len(inventorySlice) != monster.InventoryLength() {
+ fail(FailString("len(monster.InventoryBytes) != monster.InventoryLength", len(inventorySlice), monster.InventoryLength()))
+ }
+
+ if got := monster.InventoryLength(); 5 != got {
+ fail(FailString("monster.InventoryLength", 5, got))
+ }
+
+ invsum := 0
+ l := monster.InventoryLength()
+ for i := 0; i < l; i++ {
+ v := monster.Inventory(i)
+ if v != inventorySlice[i] {
+ fail(FailString("monster inventory slice[i] != Inventory(i)", v, inventorySlice[i]))
+ }
+ invsum += int(v)
+ }
+ if invsum != 10 {
+ fail(FailString("monster inventory sum", 10, invsum))
+ }
+
+ if got := monster.Test4Length(); 2 != got {
+ fail(FailString("monster.Test4Length()", 2, got))
+ }
+
+ var test0 example.Test
+ ok := monster.Test4(&test0, 0)
+ if !ok {
+ fail(FailString("monster.Test4(&test0, 0)", true, ok))
+ }
+
+ var test1 example.Test
+ ok = monster.Test4(&test1, 1)
+ if !ok {
+ fail(FailString("monster.Test4(&test1, 1)", true, ok))
+ }
+
+ // the position of test0 and test1 are swapped in monsterdata_java_wire
+ // and monsterdata_test_wire, so ignore ordering
+ v0 := test0.A()
+ v1 := test0.B()
+ v2 := test1.A()
+ v3 := test1.B()
+ sum := int(v0) + int(v1) + int(v2) + int(v3)
+
+ if 100 != sum {
+ fail(FailString("test0 and test1 sum", 100, sum))
+ }
+
+ if got := monster.TestarrayofstringLength(); 2 != got {
+ fail(FailString("Testarrayofstring length", 2, got))
+ }
+
+ if got := monster.Testarrayofstring(0); !bytes.Equal([]byte("test1"), got) {
+ fail(FailString("Testarrayofstring(0)", "test1", got))
+ }
+
+ if got := monster.Testarrayofstring(1); !bytes.Equal([]byte("test2"), got) {
+ fail(FailString("Testarrayofstring(1)", "test2", got))
+ }
+ }
+}
+
+// CheckMutateBuffer checks that the given buffer can be mutated correctly
+// as the example Monster. Only available scalar values are mutated.
+func CheckMutateBuffer(org []byte, offset flatbuffers.UOffsetT, fail func(string, ...interface{})) {
+ // make a copy to mutate
+ buf := make([]byte, len(org))
+ copy(buf, org)
+
+ // load monster data from the buffer
+ monster := example.GetRootAsMonster(buf, offset)
+
+ // test case struct
+ type testcase struct {
+ field string
+ testfn func() bool
+ }
+
+ testForOriginalValues := []testcase{
+ testcase{"Hp", func() bool { return monster.Hp() == 80 }},
+ testcase{"Mana", func() bool { return monster.Mana() == 150 }},
+ testcase{"Testbool", func() bool { return monster.Testbool() == true }},
+ testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(1.0) }},
+ testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(2.0) }},
+ testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(3.0) }},
+ testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(3.0) }},
+ testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == example.ColorGreen }},
+ testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(5) }},
+ testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(6) }},
+ testcase{"Inventory[2]", func() bool { return monster.Inventory(2) == byte(2) }},
+ }
+
+ testMutability := []testcase{
+ testcase{"Hp", func() bool { return monster.MutateHp(70) }},
+ testcase{"Mana", func() bool { return !monster.MutateMana(140) }},
+ testcase{"Testbool", func() bool { return monster.MutateTestbool(false) }},
+ testcase{"Pos.X", func() bool { return monster.Pos(nil).MutateX(10.0) }},
+ testcase{"Pos.Y", func() bool { return monster.Pos(nil).MutateY(20.0) }},
+ testcase{"Pos.Z", func() bool { return monster.Pos(nil).MutateZ(30.0) }},
+ testcase{"Pos.Test1", func() bool { return monster.Pos(nil).MutateTest1(30.0) }},
+ testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(example.ColorBlue) }},
+ testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).MutateA(50) }},
+ testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).MutateB(60) }},
+ testcase{"Inventory[2]", func() bool { return monster.MutateInventory(2, 200) }},
+ }
+
+ testForMutatedValues := []testcase{
+ testcase{"Hp", func() bool { return monster.Hp() == 70 }},
+ testcase{"Mana", func() bool { return monster.Mana() == 150 }},
+ testcase{"Testbool", func() bool { return monster.Testbool() == false }},
+ testcase{"Pos.X'", func() bool { return monster.Pos(nil).X() == float32(10.0) }},
+ testcase{"Pos.Y'", func() bool { return monster.Pos(nil).Y() == float32(20.0) }},
+ testcase{"Pos.Z'", func() bool { return monster.Pos(nil).Z() == float32(30.0) }},
+ testcase{"Pos.Test1'", func() bool { return monster.Pos(nil).Test1() == float64(30.0) }},
+ testcase{"Pos.Test2'", func() bool { return monster.Pos(nil).Test2() == example.ColorBlue }},
+ testcase{"Pos.Test3.A", func() bool { return monster.Pos(nil).Test3(nil).A() == int16(50) }},
+ testcase{"Pos.Test3.B", func() bool { return monster.Pos(nil).Test3(nil).B() == int8(60) }},
+ testcase{"Inventory[2]", func() bool { return monster.Inventory(2) == byte(200) }},
+ }
+
+ testInvalidEnumValues := []testcase{
+ testcase{"Pos.Test2", func() bool { return monster.Pos(nil).MutateTest2(example.Color(20)) }},
+ testcase{"Pos.Test2", func() bool { return monster.Pos(nil).Test2() == example.Color(20) }},
+ }
+
+ // make sure original values are okay
+ for _, t := range testForOriginalValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected original value")
+ }
+ }
+
+ // try to mutate fields and check mutability
+ for _, t := range testMutability {
+ if !t.testfn() {
+ fail(FailString("field '"+t.field+"' failed mutability test", true, false))
+ }
+ }
+
+ // test whether values have changed
+ for _, t := range testForMutatedValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected mutated value")
+ }
+ }
+
+ // make sure the buffer has changed
+ if reflect.DeepEqual(buf, org) {
+ fail("mutate buffer failed")
+ }
+
+ // To make sure the buffer has changed accordingly
+ // Read data from the buffer and verify all fields
+ monster = example.GetRootAsMonster(buf, offset)
+ for _, t := range testForMutatedValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected mutated value")
+ }
+ }
+
+ // a couple extra tests for "invalid" enum values, which don't correspond to
+ // anything in the schema, but are allowed
+ for _, t := range testInvalidEnumValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't work with an invalid enum value")
+ }
+ }
+
+ // reverting all fields to original values should
+ // re-create the original buffer. Mutate all fields
+ // back to their original values and compare buffers.
+ // This test is done to make sure mutations do not do
+ // any unnecessary changes to the buffer.
+ monster = example.GetRootAsMonster(buf, offset)
+ monster.MutateHp(80)
+ monster.MutateTestbool(true)
+ monster.Pos(nil).MutateX(1.0)
+ monster.Pos(nil).MutateY(2.0)
+ monster.Pos(nil).MutateZ(3.0)
+ monster.Pos(nil).MutateTest1(3.0)
+ monster.Pos(nil).MutateTest2(example.ColorGreen)
+ monster.Pos(nil).Test3(nil).MutateA(5)
+ monster.Pos(nil).Test3(nil).MutateB(6)
+ monster.MutateInventory(2, 2)
+
+ for _, t := range testForOriginalValues {
+ if !t.testfn() {
+ fail("field '" + t.field + "' doesn't have the expected original value")
+ }
+ }
+
+ // buffer should have original values
+ if !reflect.DeepEqual(buf, org) {
+ fail("revert changes failed")
+ }
+}
+
+// Low level stress/fuzz test: serialize/deserialize a variety of
+// different kinds of data in different combinations
+func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) {
+
+ // Values we're testing against: chosen to ensure no bits get chopped
+ // off anywhere, and also be different from eachother.
+ boolVal := true
+ int8Val := int8(-127) // 0x81
+ uint8Val := uint8(0xFF)
+ int16Val := int16(-32222) // 0x8222
+ uint16Val := uint16(0xFEEE)
+ int32Val := int32(overflowingInt32Val)
+ uint32Val := uint32(0xFDDDDDDD)
+ int64Val := int64(overflowingInt64Val)
+ uint64Val := uint64(0xFCCCCCCCCCCCCCCC)
+ float32Val := float32(3.14159)
+ float64Val := float64(3.14159265359)
+
+ testValuesMax := 11 // hardcoded to the number of scalar types
+
+ builder := flatbuffers.NewBuilder(0)
+ l := NewLCG()
+
+ objects := make([]flatbuffers.UOffsetT, fuzzObjects)
+
+ // Generate fuzzObjects random objects each consisting of
+ // fuzzFields fields, each of a random type.
+ for i := 0; i < fuzzObjects; i++ {
+ builder.StartObject(fuzzFields)
+
+ for f := 0; f < fuzzFields; f++ {
+ choice := l.Next() % uint32(testValuesMax)
+ switch choice {
+ case 0:
+ builder.PrependBoolSlot(int(f), boolVal, false)
+ case 1:
+ builder.PrependInt8Slot(int(f), int8Val, 0)
+ case 2:
+ builder.PrependUint8Slot(int(f), uint8Val, 0)
+ case 3:
+ builder.PrependInt16Slot(int(f), int16Val, 0)
+ case 4:
+ builder.PrependUint16Slot(int(f), uint16Val, 0)
+ case 5:
+ builder.PrependInt32Slot(int(f), int32Val, 0)
+ case 6:
+ builder.PrependUint32Slot(int(f), uint32Val, 0)
+ case 7:
+ builder.PrependInt64Slot(int(f), int64Val, 0)
+ case 8:
+ builder.PrependUint64Slot(int(f), uint64Val, 0)
+ case 9:
+ builder.PrependFloat32Slot(int(f), float32Val, 0)
+ case 10:
+ builder.PrependFloat64Slot(int(f), float64Val, 0)
+ }
+ }
+
+ off := builder.EndObject()
+
+ // store the offset from the end of the builder buffer,
+ // since it will keep growing:
+ objects[i] = off
+ }
+
+ // Do some bookkeeping to generate stats on fuzzes:
+ stats := map[string]int{}
+ check := func(desc string, want, got interface{}) {
+ stats[desc]++
+ if want != got {
+ fail("%s want %v got %v", desc, want, got)
+ }
+ }
+
+ l = NewLCG() // Reset.
+
+ // Test that all objects we generated are readable and return the
+ // expected values. We generate random objects in the same order
+ // so this is deterministic.
+ for i := 0; i < fuzzObjects; i++ {
+
+ table := &flatbuffers.Table{
+ Bytes: builder.Bytes,
+ Pos: flatbuffers.UOffsetT(len(builder.Bytes)) - objects[i],
+ }
+
+ for j := 0; j < fuzzFields; j++ {
+ f := flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + j) * flatbuffers.SizeVOffsetT)
+ choice := l.Next() % uint32(testValuesMax)
+
+ switch choice {
+ case 0:
+ check("bool", boolVal, table.GetBoolSlot(f, false))
+ case 1:
+ check("int8", int8Val, table.GetInt8Slot(f, 0))
+ case 2:
+ check("uint8", uint8Val, table.GetUint8Slot(f, 0))
+ case 3:
+ check("int16", int16Val, table.GetInt16Slot(f, 0))
+ case 4:
+ check("uint16", uint16Val, table.GetUint16Slot(f, 0))
+ case 5:
+ check("int32", int32Val, table.GetInt32Slot(f, 0))
+ case 6:
+ check("uint32", uint32Val, table.GetUint32Slot(f, 0))
+ case 7:
+ check("int64", int64Val, table.GetInt64Slot(f, 0))
+ case 8:
+ check("uint64", uint64Val, table.GetUint64Slot(f, 0))
+ case 9:
+ check("float32", float32Val, table.GetFloat32Slot(f, 0))
+ case 10:
+ check("float64", float64Val, table.GetFloat64Slot(f, 0))
+ }
+ }
+ }
+
+ // If enough checks were made, verify that all scalar types were used:
+ if fuzzFields*fuzzObjects >= testValuesMax {
+ if len(stats) != testValuesMax {
+ fail("fuzzing failed to test all scalar types")
+ }
+ }
+
+ // Print some counts, if needed:
+ if testing.Verbose() {
+ if fuzzFields == 0 || fuzzObjects == 0 {
+ fmt.Printf("fuzz\tfields: %d\tobjects: %d\t[none]\t%d\n",
+ fuzzFields, fuzzObjects, 0)
+ } else {
+ keys := make([]string, 0, len(stats))
+ for k := range stats {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ fmt.Printf("fuzz\tfields: %d\tobjects: %d\t%s\t%d\n",
+ fuzzFields, fuzzObjects, k, stats[k])
+ }
+ }
+ }
+
+ return
+}
+
+// FailString makes a message for when expectations differ from reality.
+func FailString(name string, want, got interface{}) string {
+ return fmt.Sprintf("bad %s: want %#v got %#v", name, want, got)
+}
+
+// CheckByteLayout verifies the bytes of a Builder in various scenarios.
+func CheckByteLayout(fail func(string, ...interface{})) {
+ var b *flatbuffers.Builder
+
+ var i int
+ check := func(want []byte) {
+ i++
+ got := b.Bytes[b.Head():]
+ if !bytes.Equal(want, got) {
+ fail("case %d: want\n%v\nbut got\n%v\n", i, want, got)
+ }
+ }
+
+ // test 1: numbers
+
+ b = flatbuffers.NewBuilder(0)
+ check([]byte{})
+ b.PrependBool(true)
+ check([]byte{1})
+ b.PrependInt8(-127)
+ check([]byte{129, 1})
+ b.PrependUint8(255)
+ check([]byte{255, 129, 1})
+ b.PrependInt16(-32222)
+ check([]byte{0x22, 0x82, 0, 255, 129, 1}) // first pad
+ b.PrependUint16(0xFEEE)
+ check([]byte{0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1}) // no pad this time
+ b.PrependInt32(-53687092)
+ check([]byte{204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1})
+ b.PrependUint32(0x98765432)
+ check([]byte{0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1})
+
+ // test 1b: numbers 2
+
+ b = flatbuffers.NewBuilder(0)
+ b.PrependUint64(0x1122334455667788)
+ check([]byte{0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11})
+
+ // test 2: 1xbyte vector
+
+ b = flatbuffers.NewBuilder(0)
+ check([]byte{})
+ b.StartVector(flatbuffers.SizeByte, 1, 1)
+ check([]byte{0, 0, 0}) // align to 4bytes
+ b.PrependByte(1)
+ check([]byte{1, 0, 0, 0})
+ b.EndVector(1)
+ check([]byte{1, 0, 0, 0, 1, 0, 0, 0}) // padding
+
+ // test 3: 2xbyte vector
+
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeByte, 2, 1)
+ check([]byte{0, 0}) // align to 4bytes
+ b.PrependByte(1)
+ check([]byte{1, 0, 0})
+ b.PrependByte(2)
+ check([]byte{2, 1, 0, 0})
+ b.EndVector(2)
+ check([]byte{2, 0, 0, 0, 2, 1, 0, 0}) // padding
+
+ // test 3b: 11xbyte vector matches builder size
+
+ b = flatbuffers.NewBuilder(12)
+ b.StartVector(flatbuffers.SizeByte, 8, 1)
+ start := []byte{}
+ check(start)
+ for i := 1; i < 12; i++ {
+ b.PrependByte(byte(i))
+ start = append([]byte{byte(i)}, start...)
+ check(start)
+ }
+ b.EndVector(8)
+ check(append([]byte{8, 0, 0, 0}, start...))
+
+ // test 4: 1xuint16 vector
+
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeUint16, 1, 1)
+ check([]byte{0, 0}) // align to 4bytes
+ b.PrependUint16(1)
+ check([]byte{1, 0, 0, 0})
+ b.EndVector(1)
+ check([]byte{1, 0, 0, 0, 1, 0, 0, 0}) // padding
+
+ // test 5: 2xuint16 vector
+
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeUint16, 2, 1)
+ check([]byte{}) // align to 4bytes
+ b.PrependUint16(0xABCD)
+ check([]byte{0xCD, 0xAB})
+ b.PrependUint16(0xDCBA)
+ check([]byte{0xBA, 0xDC, 0xCD, 0xAB})
+ b.EndVector(2)
+ check([]byte{2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB})
+
+ // test 6: CreateString
+
+ b = flatbuffers.NewBuilder(0)
+ b.CreateString("foo")
+ check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad
+ b.CreateString("moop")
+ check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad
+ 3, 0, 0, 0, 'f', 'o', 'o', 0})
+
+ // test 6b: CreateString unicode
+
+ b = flatbuffers.NewBuilder(0)
+ // These characters are chinese from blog.golang.org/strings
+ // We use escape codes here so that editors without unicode support
+ // aren't bothered:
+ uni_str := "\u65e5\u672c\u8a9e"
+ b.CreateString(uni_str)
+ check([]byte{9, 0, 0, 0, 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // null-terminated, 2-byte pad
+ 0, 0})
+
+ // test 6c: CreateByteString
+
+ b = flatbuffers.NewBuilder(0)
+ b.CreateByteString([]byte("foo"))
+ check([]byte{3, 0, 0, 0, 'f', 'o', 'o', 0}) // 0-terminated, no pad
+ b.CreateByteString([]byte("moop"))
+ check([]byte{4, 0, 0, 0, 'm', 'o', 'o', 'p', 0, 0, 0, 0, // 0-terminated, 3-byte pad
+ 3, 0, 0, 0, 'f', 'o', 'o', 0})
+
+ // test 7: empty vtable
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(0)
+ check([]byte{})
+ b.EndObject()
+ check([]byte{4, 0, 4, 0, 4, 0, 0, 0})
+
+ // test 8: vtable with one true bool
+ b = flatbuffers.NewBuilder(0)
+ check([]byte{})
+ b.StartObject(1)
+ check([]byte{})
+ b.PrependBoolSlot(0, true, false)
+ b.EndObject()
+ check([]byte{
+ 6, 0, // vtable bytes
+ 8, 0, // length of object including vtable offset
+ 7, 0, // start of bool value
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, 0, // padded to 4 bytes
+ 1, // bool value
+ })
+
+ // test 9: vtable with one default bool
+ b = flatbuffers.NewBuilder(0)
+ check([]byte{})
+ b.StartObject(1)
+ check([]byte{})
+ b.PrependBoolSlot(0, false, false)
+ b.EndObject()
+ check([]byte{
+ 4, 0, // vtable bytes
+ 4, 0, // end of object from here
+ // entry 1 is zero and not stored.
+ 4, 0, 0, 0, // offset for start of vtable (int32)
+ })
+
+ // test 10: vtable with one int16
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(1)
+ b.PrependInt16Slot(0, 0x789A, 0)
+ b.EndObject()
+ check([]byte{
+ 6, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 6, 0, // offset to value
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, // padding to 4 bytes
+ 0x9A, 0x78,
+ })
+
+ // test 11: vtable with two int16
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(2)
+ b.PrependInt16Slot(0, 0x3456, 0)
+ b.PrependInt16Slot(1, 0x789A, 0)
+ b.EndObject()
+ check([]byte{
+ 8, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 6, 0, // offset to value 0
+ 4, 0, // offset to value 1
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0x9A, 0x78, // value 1
+ 0x56, 0x34, // value 0
+ })
+
+ // test 12: vtable with int16 and bool
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(2)
+ b.PrependInt16Slot(0, 0x3456, 0)
+ b.PrependBoolSlot(1, true, false)
+ b.EndObject()
+ check([]byte{
+ 8, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 6, 0, // offset to value 0
+ 5, 0, // offset to value 1
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0, // padding
+ 1, // value 1
+ 0x56, 0x34, // value 0
+ })
+
+ // test 12: vtable with empty vector
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeByte, 0, 1)
+ vecend := b.EndVector(0)
+ b.StartObject(1)
+ b.PrependUOffsetTSlot(0, vecend, 0)
+ b.EndObject()
+ check([]byte{
+ 6, 0, // vtable bytes
+ 8, 0,
+ 4, 0, // offset to vector offset
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 4, 0, 0, 0,
+ 0, 0, 0, 0, // length of vector (not in struct)
+ })
+
+ // test 12b: vtable with empty vector of byte and some scalars
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeByte, 0, 1)
+ vecend = b.EndVector(0)
+ b.StartObject(2)
+ b.PrependInt16Slot(0, 55, 0)
+ b.PrependUOffsetTSlot(1, vecend, 0)
+ b.EndObject()
+ check([]byte{
+ 8, 0, // vtable bytes
+ 12, 0,
+ 10, 0, // offset to value 0
+ 4, 0, // offset to vector offset
+ 8, 0, 0, 0, // vtable loc
+ 8, 0, 0, 0, // value 1
+ 0, 0, 55, 0, // value 0
+
+ 0, 0, 0, 0, // length of vector (not in struct)
+ })
+
+ // test 13: vtable with 1 int16 and 2-vector of int16
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeInt16, 2, 1)
+ b.PrependInt16(0x1234)
+ b.PrependInt16(0x5678)
+ vecend = b.EndVector(2)
+ b.StartObject(2)
+ b.PrependUOffsetTSlot(1, vecend, 0)
+ b.PrependInt16Slot(0, 55, 0)
+ b.EndObject()
+ check([]byte{
+ 8, 0, // vtable bytes
+ 12, 0, // length of object
+ 6, 0, // start of value 0 from end of vtable
+ 8, 0, // start of value 1 from end of buffer
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, // padding
+ 55, 0, // value 0
+ 4, 0, 0, 0, // vector position from here
+ 2, 0, 0, 0, // length of vector (uint32)
+ 0x78, 0x56, // vector value 1
+ 0x34, 0x12, // vector value 0
+ })
+
+ // test 14: vtable with 1 struct of 1 int8, 1 int16, 1 int32
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(1)
+ b.Prep(4+4+4, 0)
+ b.PrependInt8(55)
+ b.Pad(3)
+ b.PrependInt16(0x1234)
+ b.Pad(2)
+ b.PrependInt32(0x12345678)
+ structStart := b.Offset()
+ b.PrependStructSlot(0, structStart, 0)
+ b.EndObject()
+ check([]byte{
+ 6, 0, // vtable bytes
+ 16, 0, // end of object from here
+ 4, 0, // start of struct from here
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 0x78, 0x56, 0x34, 0x12, // value 2
+ 0, 0, // padding
+ 0x34, 0x12, // value 1
+ 0, 0, 0, // padding
+ 55, // value 0
+ })
+
+ // test 15: vtable with 1 vector of 2 struct of 2 int8
+ b = flatbuffers.NewBuilder(0)
+ b.StartVector(flatbuffers.SizeInt8*2, 2, 1)
+ b.PrependInt8(33)
+ b.PrependInt8(44)
+ b.PrependInt8(55)
+ b.PrependInt8(66)
+ vecend = b.EndVector(2)
+ b.StartObject(1)
+ b.PrependUOffsetTSlot(0, vecend, 0)
+ b.EndObject()
+ check([]byte{
+ 6, 0, // vtable bytes
+ 8, 0,
+ 4, 0, // offset of vector offset
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 4, 0, 0, 0, // vector start offset
+
+ 2, 0, 0, 0, // vector length
+ 66, // vector value 1,1
+ 55, // vector value 1,0
+ 44, // vector value 0,1
+ 33, // vector value 0,0
+ })
+
+ // test 16: table with some elements
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(2)
+ b.PrependInt8Slot(0, 33, 0)
+ b.PrependInt16Slot(1, 66, 0)
+ off := b.EndObject()
+ b.Finish(off)
+
+ check([]byte{
+ 12, 0, 0, 0, // root of table: points to vtable offset
+
+ 8, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 7, 0, // start of value 0
+ 4, 0, // start of value 1
+
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+
+ 66, 0, // value 1
+ 0, // padding
+ 33, // value 0
+ })
+
+ // test 17: one unfinished table and one finished table
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(2)
+ b.PrependInt8Slot(0, 33, 0)
+ b.PrependInt8Slot(1, 44, 0)
+ off = b.EndObject()
+ b.Finish(off)
+
+ b.StartObject(3)
+ b.PrependInt8Slot(0, 55, 0)
+ b.PrependInt8Slot(1, 66, 0)
+ b.PrependInt8Slot(2, 77, 0)
+ off = b.EndObject()
+ b.Finish(off)
+
+ check([]byte{
+ 16, 0, 0, 0, // root of table: points to object
+ 0, 0, // padding
+
+ 10, 0, // vtable bytes
+ 8, 0, // size of object
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 5, 0, // start of value 2
+ 10, 0, 0, 0, // offset for start of vtable (int32)
+ 0, // padding
+ 77, // value 2
+ 66, // value 1
+ 55, // value 0
+
+ 12, 0, 0, 0, // root of table: points to object
+
+ 8, 0, // vtable bytes
+ 8, 0, // size of object
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, // padding
+ 44, // value 1
+ 33, // value 0
+ })
+
+ // test 18: a bunch of bools
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(8)
+ b.PrependBoolSlot(0, true, false)
+ b.PrependBoolSlot(1, true, false)
+ b.PrependBoolSlot(2, true, false)
+ b.PrependBoolSlot(3, true, false)
+ b.PrependBoolSlot(4, true, false)
+ b.PrependBoolSlot(5, true, false)
+ b.PrependBoolSlot(6, true, false)
+ b.PrependBoolSlot(7, true, false)
+ off = b.EndObject()
+ b.Finish(off)
+
+ check([]byte{
+ 24, 0, 0, 0, // root of table: points to vtable offset
+
+ 20, 0, // vtable bytes
+ 12, 0, // size of object
+ 11, 0, // start of value 0
+ 10, 0, // start of value 1
+ 9, 0, // start of value 2
+ 8, 0, // start of value 3
+ 7, 0, // start of value 4
+ 6, 0, // start of value 5
+ 5, 0, // start of value 6
+ 4, 0, // start of value 7
+ 20, 0, 0, 0, // vtable offset
+
+ 1, // value 7
+ 1, // value 6
+ 1, // value 5
+ 1, // value 4
+ 1, // value 3
+ 1, // value 2
+ 1, // value 1
+ 1, // value 0
+ })
+
+ // test 19: three bools
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(3)
+ b.PrependBoolSlot(0, true, false)
+ b.PrependBoolSlot(1, true, false)
+ b.PrependBoolSlot(2, true, false)
+ off = b.EndObject()
+ b.Finish(off)
+
+ check([]byte{
+ 16, 0, 0, 0, // root of table: points to vtable offset
+
+ 0, 0, // padding
+
+ 10, 0, // vtable bytes
+ 8, 0, // size of object
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 5, 0, // start of value 2
+ 10, 0, 0, 0, // vtable offset from here
+
+ 0, // padding
+ 1, // value 2
+ 1, // value 1
+ 1, // value 0
+ })
+
+ // test 20: some floats
+ b = flatbuffers.NewBuilder(0)
+ b.StartObject(1)
+ b.PrependFloat32Slot(0, 1.0, 0.0)
+ off = b.EndObject()
+
+ check([]byte{
+ 6, 0, // vtable bytes
+ 8, 0, // size of object
+ 4, 0, // start of value 0
+ 6, 0, 0, 0, // vtable offset
+
+ 0, 0, 128, 63, // value 0
+ })
+}
+
+// CheckManualBuild builds a Monster manually.
+func CheckManualBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) {
+ b := flatbuffers.NewBuilder(0)
+ str := b.CreateString("MyMonster")
+
+ b.StartVector(1, 5, 1)
+ b.PrependByte(4)
+ b.PrependByte(3)
+ b.PrependByte(2)
+ b.PrependByte(1)
+ b.PrependByte(0)
+ inv := b.EndVector(5)
+
+ b.StartObject(13)
+ b.PrependInt16Slot(2, 20, 100)
+ mon2 := b.EndObject()
+
+ // Test4Vector
+ b.StartVector(4, 2, 1)
+
+ // Test 0
+ b.Prep(2, 4)
+ b.Pad(1)
+ b.PlaceInt8(20)
+ b.PlaceInt16(10)
+
+ // Test 1
+ b.Prep(2, 4)
+ b.Pad(1)
+ b.PlaceInt8(40)
+ b.PlaceInt16(30)
+
+ // end testvector
+ test4 := b.EndVector(2)
+
+ b.StartObject(13)
+
+ // a vec3
+ b.Prep(16, 32)
+ b.Pad(2)
+ b.Prep(2, 4)
+ b.Pad(1)
+ b.PlaceByte(6)
+ b.PlaceInt16(5)
+ b.Pad(1)
+ b.PlaceByte(4)
+ b.PlaceFloat64(3.0)
+ b.Pad(4)
+ b.PlaceFloat32(3.0)
+ b.PlaceFloat32(2.0)
+ b.PlaceFloat32(1.0)
+ vec3Loc := b.Offset()
+ // end vec3
+
+ b.PrependStructSlot(0, vec3Loc, 0) // vec3. noop
+ b.PrependInt16Slot(2, 80, 100) // hp
+ b.PrependUOffsetTSlot(3, str, 0)
+ b.PrependUOffsetTSlot(5, inv, 0) // inventory
+ b.PrependByteSlot(7, 1, 0)
+ b.PrependUOffsetTSlot(8, mon2, 0)
+ b.PrependUOffsetTSlot(9, test4, 0)
+ mon := b.EndObject()
+
+ b.Finish(mon)
+
+ return b.Bytes, b.Head()
+}
+
+func CheckGetRootAsForNonRootTable(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ str := b.CreateString("MyStat")
+ example.StatStart(b)
+ example.StatAddId(b, str)
+ example.StatAddVal(b, 12345678)
+ example.StatAddCount(b, 12345)
+ stat_end := example.StatEnd(b)
+ b.Finish(stat_end)
+
+ stat := example.GetRootAsStat(b.Bytes, b.Head())
+
+ if got := stat.Id(); !bytes.Equal([]byte("MyStat"), got) {
+ fail(FailString("stat.Id()", "MyStat", got))
+ }
+
+ if got := stat.Val(); 12345678 != got {
+ fail(FailString("stat.Val()", 12345678, got))
+ }
+
+ if got := stat.Count(); 12345 != got {
+ fail(FailString("stat.Count()", 12345, got))
+ }
+}
+
+// CheckGeneratedBuild uses generated code to build the example Monster.
+func CheckGeneratedBuild(fail func(string, ...interface{})) ([]byte, flatbuffers.UOffsetT) {
+ b := flatbuffers.NewBuilder(0)
+ str := b.CreateString("MyMonster")
+ test1 := b.CreateString("test1")
+ test2 := b.CreateString("test2")
+ fred := b.CreateString("Fred")
+
+ example.MonsterStartInventoryVector(b, 5)
+ b.PrependByte(4)
+ b.PrependByte(3)
+ b.PrependByte(2)
+ b.PrependByte(1)
+ b.PrependByte(0)
+ inv := b.EndVector(5)
+
+ example.MonsterStart(b)
+ example.MonsterAddName(b, fred)
+ mon2 := example.MonsterEnd(b)
+
+ example.MonsterStartTest4Vector(b, 2)
+ example.CreateTest(b, 10, 20)
+ example.CreateTest(b, 30, 40)
+ test4 := b.EndVector(2)
+
+ example.MonsterStartTestarrayofstringVector(b, 2)
+ b.PrependUOffsetT(test2)
+ b.PrependUOffsetT(test1)
+ testArrayOfString := b.EndVector(2)
+
+ example.MonsterStart(b)
+
+ pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, example.ColorGreen, 5, 6)
+ example.MonsterAddPos(b, pos)
+
+ example.MonsterAddHp(b, 80)
+ example.MonsterAddName(b, str)
+ example.MonsterAddTestbool(b, true)
+ example.MonsterAddInventory(b, inv)
+ example.MonsterAddTestType(b, 1)
+ example.MonsterAddTest(b, mon2)
+ example.MonsterAddTest4(b, test4)
+ example.MonsterAddTestarrayofstring(b, testArrayOfString)
+ mon := example.MonsterEnd(b)
+
+ b.Finish(mon)
+
+ return b.Bytes, b.Head()
+}
+
+// CheckTableAccessors checks that the table accessors work as expected.
+func CheckTableAccessors(fail func(string, ...interface{})) {
+ // test struct accessor
+ b := flatbuffers.NewBuilder(0)
+ pos := example.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 4, 5, 6)
+ b.Finish(pos)
+ vec3Bytes := b.FinishedBytes()
+ vec3 := &example.Vec3{}
+ flatbuffers.GetRootAs(vec3Bytes, 0, vec3)
+
+ if bytes.Compare(vec3Bytes, vec3.Table().Bytes) != 0 {
+ fail("invalid vec3 table")
+ }
+
+ // test table accessor
+ b = flatbuffers.NewBuilder(0)
+ str := b.CreateString("MyStat")
+ example.StatStart(b)
+ example.StatAddId(b, str)
+ example.StatAddVal(b, 12345678)
+ example.StatAddCount(b, 12345)
+ pos = example.StatEnd(b)
+ b.Finish(pos)
+ statBytes := b.FinishedBytes()
+ stat := &example.Stat{}
+ flatbuffers.GetRootAs(statBytes, 0, stat)
+
+ if bytes.Compare(statBytes, stat.Table().Bytes) != 0 {
+ fail("invalid stat table")
+ }
+}
+
+// CheckVtableDeduplication verifies that vtables are deduplicated.
+func CheckVtableDeduplication(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+
+ b.StartObject(4)
+ b.PrependByteSlot(0, 0, 0)
+ b.PrependByteSlot(1, 11, 0)
+ b.PrependByteSlot(2, 22, 0)
+ b.PrependInt16Slot(3, 33, 0)
+ obj0 := b.EndObject()
+
+ b.StartObject(4)
+ b.PrependByteSlot(0, 0, 0)
+ b.PrependByteSlot(1, 44, 0)
+ b.PrependByteSlot(2, 55, 0)
+ b.PrependInt16Slot(3, 66, 0)
+ obj1 := b.EndObject()
+
+ b.StartObject(4)
+ b.PrependByteSlot(0, 0, 0)
+ b.PrependByteSlot(1, 77, 0)
+ b.PrependByteSlot(2, 88, 0)
+ b.PrependInt16Slot(3, 99, 0)
+ obj2 := b.EndObject()
+
+ got := b.Bytes[b.Head():]
+
+ want := []byte{
+ 240, 255, 255, 255, // == -12. offset to dedupped vtable.
+ 99, 0,
+ 88,
+ 77,
+ 248, 255, 255, 255, // == -8. offset to dedupped vtable.
+ 66, 0,
+ 55,
+ 44,
+ 12, 0,
+ 8, 0,
+ 0, 0,
+ 7, 0,
+ 6, 0,
+ 4, 0,
+ 12, 0, 0, 0,
+ 33, 0,
+ 22,
+ 11,
+ }
+
+ if !bytes.Equal(want, got) {
+ fail("testVtableDeduplication want:\n%d %v\nbut got:\n%d %v\n",
+ len(want), want, len(got), got)
+ }
+
+ table0 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj0}
+ table1 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj1}
+ table2 := &flatbuffers.Table{Bytes: b.Bytes, Pos: flatbuffers.UOffsetT(len(b.Bytes)) - obj2}
+
+ testTable := func(tab *flatbuffers.Table, a flatbuffers.VOffsetT, b, c, d byte) {
+ // vtable size
+ if got := tab.GetVOffsetTSlot(0, 0); 12 != got {
+ fail("failed 0, 0: %d", got)
+ }
+ // object size
+ if got := tab.GetVOffsetTSlot(2, 0); 8 != got {
+ fail("failed 2, 0: %d", got)
+ }
+ // default value
+ if got := tab.GetVOffsetTSlot(4, 0); a != got {
+ fail("failed 4, 0: %d", got)
+ }
+ if got := tab.GetByteSlot(6, 0); b != got {
+ fail("failed 6, 0: %d", got)
+ }
+ if val := tab.GetByteSlot(8, 0); c != val {
+ fail("failed 8, 0: %d", got)
+ }
+ if got := tab.GetByteSlot(10, 0); d != got {
+ fail("failed 10, 0: %d", got)
+ }
+ }
+
+ testTable(table0, 0, 11, 22, 33)
+ testTable(table1, 0, 44, 55, 66)
+ testTable(table2, 0, 77, 88, 99)
+}
+
+// CheckNotInObjectError verifies that `EndObject` fails if not inside an
+// object.
+func CheckNotInObjectError(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+
+ defer func() {
+ r := recover()
+ if r == nil {
+ fail("expected panic in CheckNotInObjectError")
+ }
+ }()
+ b.EndObject()
+}
+
+// CheckStringIsNestedError verifies that a string can not be created inside
+// another object.
+func CheckStringIsNestedError(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ b.StartObject(0)
+ defer func() {
+ r := recover()
+ if r == nil {
+ fail("expected panic in CheckStringIsNestedError")
+ }
+ }()
+ b.CreateString("foo")
+}
+
+// CheckByteStringIsNestedError verifies that a bytestring can not be created
+// inside another object.
+func CheckByteStringIsNestedError(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ b.StartObject(0)
+ defer func() {
+ r := recover()
+ if r == nil {
+ fail("expected panic in CheckByteStringIsNestedError")
+ }
+ }()
+ b.CreateByteString([]byte("foo"))
+}
+
+// CheckStructIsNotInlineError verifies that writing a struct in a location
+// away from where it is used will cause a panic.
+func CheckStructIsNotInlineError(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ b.StartObject(0)
+ defer func() {
+ r := recover()
+ if r == nil {
+ fail("expected panic in CheckStructIsNotInlineError")
+ }
+ }()
+ b.PrependStructSlot(0, 1, 0)
+}
+
+// CheckFinishedBytesError verifies that `FinishedBytes` panics if the table
+// is not finished.
+func CheckFinishedBytesError(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+
+ defer func() {
+ r := recover()
+ if r == nil {
+ fail("expected panic in CheckFinishedBytesError")
+ }
+ }()
+ b.FinishedBytes()
+}
+
+// CheckEnumNames checks that the generated enum names are correct.
+func CheckEnumNames(fail func(string, ...interface{})) {
+ {
+ want := map[example.Any]string{
+ example.AnyNONE: "NONE",
+ example.AnyMonster: "Monster",
+ example.AnyTestSimpleTableWithEnum: "TestSimpleTableWithEnum",
+ example.AnyMyGame_Example2_Monster: "MyGame_Example2_Monster",
+ }
+ got := example.EnumNamesAny
+ if !reflect.DeepEqual(got, want) {
+ fail("enum name is not equal")
+ }
+ }
+ {
+ want := map[example.Color]string{
+ example.ColorRed: "Red",
+ example.ColorGreen: "Green",
+ example.ColorBlue: "Blue",
+ }
+ got := example.EnumNamesColor
+ if !reflect.DeepEqual(got, want) {
+ fail("enum name is not equal")
+ }
+ }
+}
+
+// CheckEnumString checks the String method on generated enum types.
+func CheckEnumString(fail func(string, ...interface{})) {
+ if got := example.AnyMonster.String(); got != "Monster" {
+ fail("Monster.String: %q != %q", got, "Monster")
+ }
+ if got := fmt.Sprintf("color: %s", example.ColorGreen); got != "color: Green" {
+ fail("color.String: %q != %q", got, "color: Green")
+ }
+}
+
+// CheckEnumValues checks that the generated enum values maps are correct.
+func CheckEnumValues(fail func(string, ...interface{})) {
+ {
+ want := map[string]example.Any{
+ "NONE": example.AnyNONE,
+ "Monster": example.AnyMonster,
+ "TestSimpleTableWithEnum": example.AnyTestSimpleTableWithEnum,
+ "MyGame_Example2_Monster": example.AnyMyGame_Example2_Monster,
+ }
+ got := example.EnumValuesAny
+ if !reflect.DeepEqual(got, want) {
+ fail("enum name is not equal")
+ }
+ }
+ {
+ want := map[string]example.Color{
+ "Red": example.ColorRed,
+ "Green": example.ColorGreen,
+ "Blue": example.ColorBlue,
+ }
+ got := example.EnumValuesColor
+ if !reflect.DeepEqual(got, want) {
+ fail("enum name is not equal")
+ }
+ }
+}
+
+// CheckDocExample checks that the code given in FlatBuffers documentation
+// is syntactically correct.
+func CheckDocExample(buf []byte, off flatbuffers.UOffsetT, fail func(string, ...interface{})) {
+ monster := example.GetRootAsMonster(buf, off)
+ _ = monster.Hp()
+ _ = monster.Pos(nil)
+ for i := 0; i < monster.InventoryLength(); i++ {
+ _ = monster.Inventory(i) // do something here
+ }
+
+ builder := flatbuffers.NewBuilder(0)
+
+ example.MonsterStartInventoryVector(builder, 5)
+ for i := 4; i >= 0; i-- {
+ builder.PrependByte(byte(i))
+ }
+ inv := builder.EndVector(5)
+
+ str := builder.CreateString("MyMonster")
+ example.MonsterStart(builder)
+ example.MonsterAddPos(builder, example.CreateVec3(builder, 1.0, 2.0, 3.0, 3.0, example.Color(4), 5, 6))
+ example.MonsterAddHp(builder, 80)
+ example.MonsterAddName(builder, str)
+ example.MonsterAddInventory(builder, inv)
+ example.MonsterAddTestType(builder, 1)
+ example.MonsterAddColor(builder, example.ColorRed)
+ // example.MonsterAddTest(builder, mon2)
+ // example.MonsterAddTest4(builder, test4s)
+ _ = example.MonsterEnd(builder)
+}
+
+func CheckCreateByteVector(fail func(string, ...interface{})) {
+ raw := [30]byte{}
+ for i := 0; i < len(raw); i++ {
+ raw[i] = byte(i)
+ }
+
+ for size := 0; size < len(raw); size++ {
+ b1 := flatbuffers.NewBuilder(0)
+ b2 := flatbuffers.NewBuilder(0)
+ b1.StartVector(1, size, 1)
+ for i := size - 1; i >= 0; i-- {
+ b1.PrependByte(raw[i])
+ }
+ b1.EndVector(size)
+ b2.CreateByteVector(raw[:size])
+ CheckByteEquality(b1.Bytes, b2.Bytes, fail)
+ }
+}
+
+func CheckParentNamespace(fail func(string, ...interface{})) {
+ var empty, nonempty []byte
+
+ // create monster with an empty parent namespace field
+ {
+ builder := flatbuffers.NewBuilder(0)
+
+ example.MonsterStart(builder)
+ m := example.MonsterEnd(builder)
+ builder.Finish(m)
+
+ empty = make([]byte, len(builder.FinishedBytes()))
+ copy(empty, builder.FinishedBytes())
+ }
+
+ // create monster with a non-empty parent namespace field
+ {
+ builder := flatbuffers.NewBuilder(0)
+ mygame.InParentNamespaceStart(builder)
+ pn := mygame.InParentNamespaceEnd(builder)
+
+ example.MonsterStart(builder)
+ example.MonsterAddParentNamespaceTest(builder, pn)
+ m := example.MonsterEnd(builder)
+
+ builder.Finish(m)
+
+ nonempty = make([]byte, len(builder.FinishedBytes()))
+ copy(nonempty, builder.FinishedBytes())
+ }
+
+ // read monster with empty parent namespace field
+ {
+ m := example.GetRootAsMonster(empty, 0)
+ if m.ParentNamespaceTest(nil) != nil {
+ fail("expected nil ParentNamespaceTest for empty field")
+ }
+ }
+
+ // read monster with non-empty parent namespace field
+ {
+ m := example.GetRootAsMonster(nonempty, 0)
+ if m.ParentNamespaceTest(nil) == nil {
+ fail("expected non-nil ParentNamespaceTest for non-empty field")
+ }
+ }
+}
+
+// Include simple random number generator to ensure results will be the
+// same cross platform.
+// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
+type LCG uint32
+
+const InitialLCGSeed = 48271
+
+func NewLCG() *LCG {
+ n := uint32(InitialLCGSeed)
+ l := LCG(n)
+ return &l
+}
+
+func (lcg *LCG) Reset() {
+ *lcg = InitialLCGSeed
+}
+
+func (lcg *LCG) Next() uint32 {
+ n := uint32((uint64(*lcg) * uint64(279470273)) % uint64(4294967291))
+ *lcg = LCG(n)
+ return n
+}
+
+// CheckByteEquality verifies that two byte buffers are the same.
+func CheckByteEquality(a, b []byte, fail func(string, ...interface{})) {
+ if !bytes.Equal(a, b) {
+ fail("objects are not byte-wise equal")
+ }
+}
+
+// CheckMutateMethods checks all mutate methods one by one
+func CheckMutateMethods(fail func(string, ...interface{})) {
+ b := flatbuffers.NewBuilder(0)
+ b.StartObject(15)
+ b.PrependBoolSlot(0, true, false)
+ b.PrependByteSlot(1, 1, 0)
+ b.PrependUint8Slot(2, 2, 0)
+ b.PrependUint16Slot(3, 3, 0)
+ b.PrependUint32Slot(4, 4, 0)
+ b.PrependUint64Slot(5, 5, 0)
+ b.PrependInt8Slot(6, 6, 0)
+ b.PrependInt16Slot(7, 7, 0)
+ b.PrependInt32Slot(8, 8, 0)
+ b.PrependInt64Slot(9, 9, 0)
+ b.PrependFloat32Slot(10, 10, 0)
+ b.PrependFloat64Slot(11, 11, 0)
+
+ b.PrependUOffsetTSlot(12, 12, 0)
+ uoVal := b.Offset() - 12
+
+ b.PrependVOffsetT(13)
+ b.Slot(13)
+
+ b.PrependSOffsetT(14)
+ b.Slot(14)
+ soVal := flatbuffers.SOffsetT(b.Offset() - 14)
+
+ offset := b.EndObject()
+
+ t := &flatbuffers.Table{
+ Bytes: b.Bytes,
+ Pos: flatbuffers.UOffsetT(len(b.Bytes)) - offset,
+ }
+
+ calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) {
+ return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT)
+ }
+ calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) {
+ return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset))
+ }
+
+ type testcase struct {
+ field string
+ testfn func() bool
+ }
+
+ testForOriginalValues := []testcase{
+ testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }},
+ testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }},
+ testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }},
+ testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }},
+ testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }},
+ testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }},
+ testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }},
+ testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }},
+ testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }},
+ testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }},
+ testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }},
+ testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }},
+ testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }},
+ testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }},
+ testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }},
+ }
+
+ testMutability := []testcase{
+ testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }},
+ testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }},
+ testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }},
+ testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }},
+ testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }},
+ testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }},
+ testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }},
+ testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }},
+ testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }},
+ testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }},
+ testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }},
+ testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }},
+ testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }},
+ testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }},
+ testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }},
+ }
+
+ testMutabilityWithoutSlot := []testcase{
+ testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }},
+ testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }},
+ testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }},
+ testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }},
+ testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }},
+ testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }},
+ testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }},
+ testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }},
+ testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }},
+ }
+
+ testForMutatedValues := []testcase{
+ testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }},
+ testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }},
+ testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }},
+ testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }},
+ testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }},
+ testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }},
+ testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }},
+ testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }},
+ testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }},
+ testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }},
+ testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }},
+ testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }},
+ testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }},
+ testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }},
+ testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }},
+ }
+
+ // make sure original values are okay
+ for _, t := range testForOriginalValues {
+ if !t.testfn() {
+ fail(t.field + "' field doesn't have the expected original value")
+ }
+ }
+
+ // try to mutate fields and check mutability
+ for _, t := range testMutability {
+ if !t.testfn() {
+ fail(FailString(t.field+"' field failed mutability test", "passed", "failed"))
+ }
+ }
+
+ // try to mutate fields and check mutability
+ // these have wrong slots so should fail
+ for _, t := range testMutabilityWithoutSlot {
+ if t.testfn() {
+ fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed"))
+ }
+ }
+
+ // test whether values have changed
+ for _, t := range testForMutatedValues {
+ if !t.testfn() {
+ fail(t.field + "' field doesn't have the expected mutated value")
+ }
+ }
+}
+
+// BenchmarkVtableDeduplication measures the speed of vtable deduplication
+// by creating prePop vtables, then populating b.N objects with a
+// different single vtable.
+//
+// When b.N is large (as in long benchmarks), memory usage may be high.
+func BenchmarkVtableDeduplication(b *testing.B) {
+ prePop := 10
+ builder := flatbuffers.NewBuilder(0)
+
+ // pre-populate some vtables:
+ for i := 0; i < prePop; i++ {
+ builder.StartObject(i)
+ for j := 0; j < i; j++ {
+ builder.PrependInt16Slot(j, int16(j), 0)
+ }
+ builder.EndObject()
+ }
+
+ // benchmark deduplication of a new vtable:
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ lim := prePop
+
+ builder.StartObject(lim)
+ for j := 0; j < lim; j++ {
+ builder.PrependInt16Slot(j, int16(j), 0)
+ }
+ builder.EndObject()
+ }
+}
+
+// BenchmarkParseGold measures the speed of parsing the 'gold' data
+// used throughout this test suite.
+func BenchmarkParseGold(b *testing.B) {
+ buf, offset := CheckGeneratedBuild(b.Fatalf)
+ monster := example.GetRootAsMonster(buf, offset)
+
+ // use these to prevent allocations:
+ reuse_pos := example.Vec3{}
+ reuse_test3 := example.Test{}
+ reuse_table2 := flatbuffers.Table{}
+ reuse_monster2 := example.Monster{}
+ reuse_test4_0 := example.Test{}
+ reuse_test4_1 := example.Test{}
+
+ b.SetBytes(int64(len(buf[offset:])))
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ monster.Hp()
+ monster.Mana()
+ name := monster.Name()
+ _ = name[0]
+ _ = name[len(name)-1]
+
+ monster.Pos(&reuse_pos)
+ reuse_pos.X()
+ reuse_pos.Y()
+ reuse_pos.Z()
+ reuse_pos.Test1()
+ reuse_pos.Test2()
+ reuse_pos.Test3(&reuse_test3)
+ reuse_test3.A()
+ reuse_test3.B()
+ monster.TestType()
+ monster.Test(&reuse_table2)
+ reuse_monster2.Init(reuse_table2.Bytes, reuse_table2.Pos)
+ name2 := reuse_monster2.Name()
+ _ = name2[0]
+ _ = name2[len(name2)-1]
+ monster.InventoryLength()
+ l := monster.InventoryLength()
+ for i := 0; i < l; i++ {
+ monster.Inventory(i)
+ }
+ monster.Test4Length()
+ monster.Test4(&reuse_test4_0, 0)
+ monster.Test4(&reuse_test4_1, 1)
+
+ reuse_test4_0.A()
+ reuse_test4_0.B()
+ reuse_test4_1.A()
+ reuse_test4_1.B()
+
+ monster.TestarrayofstringLength()
+ str0 := monster.Testarrayofstring(0)
+ _ = str0[0]
+ _ = str0[len(str0)-1]
+ str1 := monster.Testarrayofstring(1)
+ _ = str1[0]
+ _ = str1[len(str1)-1]
+ }
+}
+
+// BenchmarkBuildGold uses generated code to build the example Monster.
+func BenchmarkBuildGold(b *testing.B) {
+ buf, offset := CheckGeneratedBuild(b.Fatalf)
+ bytes_length := int64(len(buf[offset:]))
+
+ reuse_str := "MyMonster"
+ reuse_test1 := "test1"
+ reuse_test2 := "test2"
+ reuse_fred := "Fred"
+
+ b.SetBytes(bytes_length)
+ bldr := flatbuffers.NewBuilder(0)
+ b.ResetTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ bldr.Reset()
+
+ str := bldr.CreateString(reuse_str)
+ test1 := bldr.CreateString(reuse_test1)
+ test2 := bldr.CreateString(reuse_test2)
+ fred := bldr.CreateString(reuse_fred)
+
+ example.MonsterStartInventoryVector(bldr, 5)
+ bldr.PrependByte(4)
+ bldr.PrependByte(3)
+ bldr.PrependByte(2)
+ bldr.PrependByte(1)
+ bldr.PrependByte(0)
+ inv := bldr.EndVector(5)
+
+ example.MonsterStart(bldr)
+ example.MonsterAddName(bldr, fred)
+ mon2 := example.MonsterEnd(bldr)
+
+ example.MonsterStartTest4Vector(bldr, 2)
+ example.CreateTest(bldr, 10, 20)
+ example.CreateTest(bldr, 30, 40)
+ test4 := bldr.EndVector(2)
+
+ example.MonsterStartTestarrayofstringVector(bldr, 2)
+ bldr.PrependUOffsetT(test2)
+ bldr.PrependUOffsetT(test1)
+ testArrayOfString := bldr.EndVector(2)
+
+ example.MonsterStart(bldr)
+
+ pos := example.CreateVec3(bldr, 1.0, 2.0, 3.0, 3.0, example.ColorGreen, 5, 6)
+ example.MonsterAddPos(bldr, pos)
+
+ example.MonsterAddHp(bldr, 80)
+ example.MonsterAddName(bldr, str)
+ example.MonsterAddInventory(bldr, inv)
+ example.MonsterAddTestType(bldr, 1)
+ example.MonsterAddTest(bldr, mon2)
+ example.MonsterAddTest4(bldr, test4)
+ example.MonsterAddTestarrayofstring(bldr, testArrayOfString)
+ mon := example.MonsterEnd(bldr)
+
+ bldr.Finish(mon)
+ }
+}
diff --git a/tests/include_test/include_test1.fbs b/tests/include_test/include_test1.fbs
new file mode 100644
index 0000000..804856a
--- /dev/null
+++ b/tests/include_test/include_test1.fbs
@@ -0,0 +1,7 @@
+include "sub/include_test2.fbs";
+include "sub/include_test2.fbs"; // should be skipped
+include "include_test1.fbs"; // should be skipped
+
+table TableA {
+ b:MyGame.OtherNameSpace.TableB;
+}
diff --git a/tests/include_test/sub/include_test2.fbs b/tests/include_test/sub/include_test2.fbs
new file mode 100644
index 0000000..7225735
--- /dev/null
+++ b/tests/include_test/sub/include_test2.fbs
@@ -0,0 +1,12 @@
+include "include_test1.fbs";
+include "sub/include_test2.fbs"; // should be skipped
+
+namespace MyGame.OtherNameSpace;
+
+enum FromInclude:long { IncludeVal }
+
+struct Unused { a:int; }
+
+table TableB {
+ a:TableA;
+}
diff --git a/tests/javatest.bin b/tests/javatest.bin
new file mode 100644
index 0000000..804dbba
--- /dev/null
+++ b/tests/javatest.bin
Binary files differ
diff --git a/tests/lobstertest.lobster b/tests/lobstertest.lobster
new file mode 100644
index 0000000..7ea9b38
--- /dev/null
+++ b/tests/lobstertest.lobster
@@ -0,0 +1,137 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import from "../lobster/"
+import monster_test_generated
+
+def check_read_buffer(buf):
+ // CheckReadBuffer checks that the given buffer is evaluated correctly as the example Monster.
+ let monster = MyGame_Example_GetRootAsMonster(buf)
+
+ assert monster.hp == 80
+ assert monster.mana == 150
+ assert monster.name == "MyMonster"
+
+ let vec = monster.pos
+ assert vec
+ assert vec.x == 1.0
+ assert vec.y == 2.0
+ assert vec.z == 3.0
+ assert vec.test1 == 3.0
+ assert vec.test2 == 2
+
+ let t = vec.test3
+ assert t
+ assert t.a == 5
+ assert t.b == 6
+
+ assert monster.test_type == MyGame_Example_Any_Monster
+ assert monster.test_as_Monster.name == "Fred"
+
+ assert monster.inventory_length == 5
+ assert sum(map(monster.inventory_length) i: monster.inventory(i)) == 10
+
+ for(5) i:
+ assert monster.vector_of_longs(i) == pow(10, i * 2)
+
+ assert equal([-1.7976931348623157e+308, 0, 1.7976931348623157e+308],
+ (map(monster.vector_of_doubles_length) i: monster.vector_of_doubles(i)))
+
+ assert monster.test4_length == 2
+ let test0 = monster.test4(0)
+ let test1 = monster.test4(1)
+ assert test0.a + test0.b + test1.a + test1.b == 100
+
+ assert monster.testarrayofstring_length == 2
+ assert monster.testarrayofstring(0) == "test1"
+ assert monster.testarrayofstring(1) == "test2"
+
+ assert monster.testarrayoftables_length == 0
+ assert monster.testnestedflatbuffer_length == 0
+ assert not monster.testempty()
+
+def make_monster_from_generated_code():
+ // Use generated code to build the example Monster.
+ let b = flatbuffers_builder {}
+
+ let name = b.CreateString("MyMonster")
+ let fred = b.CreateString("Fred")
+
+ let inv = b.MyGame_Example_MonsterCreateInventoryVector([ 0, 1, 2, 3, 4 ])
+
+ let mon2 = MyGame_Example_MonsterBuilder { b }
+ .start()
+ .add_name(fred)
+ .end()
+
+ b.MyGame_Example_MonsterStartTest4Vector(2)
+ b.MyGame_Example_CreateTest(10, 20)
+ b.MyGame_Example_CreateTest(30, 40)
+ let test4 = b.EndVector(2)
+
+ let test_array_of_string = b.MyGame_Example_MonsterCreateTestarrayofstringVector(
+ [ b.CreateString("test1"), b.CreateString("test2") ])
+
+ let vector_of_longs = b.MyGame_Example_MonsterCreateVectorOfLongsVector(
+ [ 1, 100, 10000, 1000000, 100000000 ])
+
+ let vector_of_doubles = b.MyGame_Example_MonsterCreateVectorOfDoublesVector(
+ [ -1.7976931348623157e+308, 0, 1.7976931348623157e+308 ])
+
+ let mon = MyGame_Example_MonsterBuilder { b }
+ .start()
+ .add_pos(b.MyGame_Example_CreateVec3(1.0, 2.0, 3.0, 3.0,
+ MyGame_Example_Color_Green, 5, 6))
+ .add_hp(80)
+ .add_name(name)
+ .add_inventory(inv)
+ .add_test_type(MyGame_Example_Any_Monster)
+ .add_test(mon2)
+ .add_test4(test4)
+ .add_testarrayofstring(test_array_of_string)
+ .add_vector_of_longs(vector_of_longs)
+ .add_vector_of_doubles(vector_of_doubles)
+ .end()
+
+ b.Finish(mon)
+
+ return b.SizedCopy()
+
+// Verify that the canonical flatbuffer file (produced by the C++ implementation)
+// is readable by the generated Lobster code.
+let fb2 = read_file("monsterdata_test.mon")
+assert fb2
+check_read_buffer(fb2)
+
+// Verify that using the generated Lobster code builds a buffer without
+// returning errors, and is interpreted correctly.
+let fb1 = make_monster_from_generated_code()
+check_read_buffer(fb1)
+// Write the result to file for no good reason.
+write_file("monsterdata_lobster_wire.mon", fb1)
+
+// Test converting the buffer to JSON and parsing the JSON back again.
+let schema = read_file("monster_test.fbs")
+assert schema
+let includedirs = [ "include_test" ]
+// Convert binary to JSON:
+let json, err1 = flatbuffers_binary_to_json(schema, fb1, includedirs)
+assert not err1
+// Parse JSON back to binary:
+let fb3, err2 = flatbuffers_json_to_binary(schema, json, includedirs)
+assert not err2
+// Check the resulting binary again (full roundtrip test):
+check_read_buffer(fb3)
+
+print "Lobster test succesful!"
\ No newline at end of file
diff --git a/tests/luatest.lua b/tests/luatest.lua
new file mode 100644
index 0000000..c85a4ec
--- /dev/null
+++ b/tests/luatest.lua
@@ -0,0 +1,296 @@
+package.path = string.format("../lua/?.lua;./?.lua;%s",package.path)
+
+local function checkReadBuffer(buf, offset, sizePrefix)
+ offset = offset or 0
+
+ if type(buf) == "string" then
+ buf = flatbuffers.binaryArray.New(buf)
+ end
+
+ if sizePrefix then
+ local size = flatbuffers.N.Int32:Unpack(buf, offset)
+ assert(size == #buf - offset - 4)
+ offset = offset + flatbuffers.N.Int32.bytewidth
+ end
+
+ local mon = monster.GetRootAsMonster(buf, offset)
+ assert(mon:Hp() == 80, "Monster Hp is not 80")
+ assert(mon:Mana() == 150, "Monster Mana is not 150")
+ assert(mon:Name() == "MyMonster", "Monster Name is not MyMonster")
+
+ local vec = assert(mon:Pos(), "Monster Position is nil")
+ assert(vec:X() == 1.0)
+ assert(vec:Y() == 2.0)
+ assert(vec:Z() == 3.0)
+ assert(vec:Test1() == 3.0)
+ assert(vec:Test2() == 2)
+
+ local t = require("MyGame.Example.Test").New()
+ t = assert(vec:Test3(t))
+
+ assert(t:A() == 5)
+ assert(t:B() == 6)
+
+ local ut = require("MyGame.Example.Any")
+ assert(mon:TestType() == ut.Monster)
+
+ local table2 = mon:Test()
+ assert(getmetatable(table2) == "flatbuffers.view.mt")
+
+ local mon2 = monster.New()
+ mon2:Init(table2.bytes, table2.pos)
+
+ assert(mon2:Name() == "Fred")
+
+ assert(mon:InventoryLength() == 5)
+ local invsum = 0
+ for i=1,mon:InventoryLength() do
+ local v = mon:Inventory(i)
+ invsum = invsum + v
+ end
+ assert(invsum == 10)
+
+ for i=1,5 do
+ assert(mon:VectorOfLongs(i) == 10^((i-1)*2))
+ end
+
+ local dbls = { -1.7976931348623157e+308, 0, 1.7976931348623157e+308}
+ for i=1,mon:VectorOfDoublesLength() do
+ assert(mon:VectorOfDoubles(i) == dbls[i])
+ end
+
+ assert(mon:Test4Length() == 2)
+
+ local test0 = mon:Test4(1)
+ local test1 = mon:Test4(2)
+
+ local v0 = test0:A()
+ local v1 = test0:B()
+ local v2 = test1:A()
+ local v3 = test1:B()
+
+ local sumtest12 = v0 + v1 + v2 + v3
+ assert(sumtest12 == 100)
+
+ assert(mon:TestarrayofstringLength() == 2)
+ assert(mon:Testarrayofstring(1) == "test1")
+ assert(mon:Testarrayofstring(2) == "test2")
+
+ assert(mon:TestarrayoftablesLength() == 0)
+ assert(mon:TestnestedflatbufferLength() == 0)
+ assert(mon:Testempty() == nil)
+end
+
+local function generateMonster(sizePrefix)
+ local b = flatbuffers.Builder(0)
+ local str = b:CreateString("MyMonster")
+ local test1 = b:CreateString("test1")
+ local test2 = b:CreateString("test2")
+ local fred = b:CreateString("Fred")
+
+ monster.StartInventoryVector(b, 5)
+ b:PrependByte(4)
+ b:PrependByte(3)
+ b:PrependByte(2)
+ b:PrependByte(1)
+ b:PrependByte(0)
+ local inv = b:EndVector(5)
+
+ monster.Start(b)
+ monster.AddName(b, fred)
+ local mon2 = monster.End(b)
+
+ monster.StartTest4Vector(b, 2)
+ test.CreateTest(b, 10, 20)
+ test.CreateTest(b, 30, 40)
+ local test4 = b:EndVector(2)
+
+ monster.StartTestarrayofstringVector(b, 2)
+ b:PrependUOffsetTRelative(test2)
+ b:PrependUOffsetTRelative(test1)
+ local testArrayOfString = b:EndVector(2)
+
+ monster.StartVectorOfLongsVector(b, 5)
+ b:PrependInt64(100000000)
+ b:PrependInt64(1000000)
+ b:PrependInt64(10000)
+ b:PrependInt64(100)
+ b:PrependInt64(1)
+ local vectorOfLongs = b:EndVector(5)
+
+ monster.StartVectorOfDoublesVector(b, 3)
+ b:PrependFloat64(1.7976931348623157e+308)
+ b:PrependFloat64(0)
+ b:PrependFloat64(-1.7976931348623157e+308)
+ local vectorOfDoubles = b:EndVector(3)
+
+ monster.Start(b)
+ local pos = vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
+ monster.AddPos(b, pos)
+
+ monster.AddHp(b, 80)
+ monster.AddName(b, str)
+ monster.AddInventory(b, inv)
+ monster.AddTestType(b, 1)
+ monster.AddTest(b, mon2)
+ monster.AddTest4(b, test4)
+ monster.AddTestbool(b, true)
+ monster.AddTestbool(b, false)
+ monster.AddTestbool(b, null)
+ monster.AddTestbool(b,"true")
+ monster.AddTestarrayofstring(b, testArrayOfString)
+ monster.AddVectorOfLongs(b, vectorOfLongs)
+ monster.AddVectorOfDoubles(b, vectorOfDoubles)
+ local mon = monster.End(b)
+
+ if sizePrefix then
+ b:FinishSizePrefixed(mon)
+ else
+ b:Finish(mon)
+ end
+ return b:Output(true), b:Head()
+end
+
+local function sizePrefix(sizePrefix)
+ local buf,offset = generateMonster(sizePrefix)
+ checkReadBuffer(buf, offset, sizePrefix)
+end
+
+local function testCanonicalData()
+ local f = assert(io.open('monsterdata_test.mon', 'rb'))
+ local wireData = f:read("*a")
+ f:close()
+ checkReadBuffer(wireData)
+end
+
+local function benchmarkMakeMonster(count)
+ local length = #(generateMonster())
+
+ --require("flatbuffers.profiler")
+ --profiler = newProfiler("call")
+ --profiler:start()
+
+ local s = os.clock()
+ for i=1,count do
+ generateMonster()
+ end
+ local e = os.clock()
+
+ --profiler:stop()
+
+ --local outfile = io.open( "profile.txt", "w+" )
+ --profiler:report( outfile, true)
+ --outfile:close()
+
+
+ local dur = (e - s)
+ local rate = count / (dur * 1000)
+ local data = (length * count) / (1024 * 1024)
+ local dataRate = data / dur
+
+ print(string.format('built %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
+ count, length, dur, rate, dataRate))
+end
+
+local function benchmarkReadBuffer(count)
+ local f = assert(io.open('monsterdata_test.mon', 'rb'))
+ local buf = f:read("*a")
+ f:close()
+
+ local s = os.clock()
+ for i=1,count do
+ checkReadBuffer(buf)
+ end
+ local e = os.clock()
+
+ local dur = (e - s)
+ local rate = count / (dur * 1000)
+ local data = (#buf * count) / (1024 * 1024)
+ local dataRate = data / dur
+
+ print(string.format('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
+ count, #buf, dur, rate, dataRate))
+end
+
+local tests =
+{
+ {
+ f = sizePrefix,
+ d = "Test size prefix",
+ args = {{true}, {false}}
+ },
+ {
+ f = testCanonicalData,
+ d = "Tests Canonical flatbuffer file included in repo"
+ },
+ {
+ f = benchmarkMakeMonster,
+ d = "Benchmark making monsters",
+ args = {
+ {100},
+ {1000},
+ {10000},
+ }
+ },
+ {
+ f = benchmarkReadBuffer,
+ d = "Benchmark reading monsters",
+ args = {
+ {100},
+ {1000},
+ {10000},
+ -- uncomment following to run 1 million to compare.
+ -- Took ~141 seconds on my machine
+ --{1000000},
+ }
+ },
+}
+
+local result, err = xpcall(function()
+ flatbuffers = assert(require("flatbuffers"))
+ monster = assert(require("MyGame.Example.Monster"))
+ test = assert(require("MyGame.Example.Test"))
+ vec3 = assert(require("MyGame.Example.Vec3"))
+
+ local function buildArgList(tbl)
+ local s = ""
+ for _,item in ipairs(tbl) do
+ s = s .. tostring(item) .. ","
+ end
+ return s:sub(1,-2)
+ end
+
+ local testsPassed, testsFailed = 0,0
+ for _,test in ipairs(tests) do
+ local allargs = test.args or {{}}
+ for _,args in ipairs(allargs) do
+ local results, err = xpcall(test.f,debug.traceback, table.unpack(args))
+ if results then
+ testsPassed = testsPassed + 1
+ else
+ testsFailed = testsFailed + 1
+ print(string.format(" Test [%s](%s) failed: \n\t%s",
+ test.d or "",
+ buildArgList(args),
+ err))
+ end
+ end
+ end
+
+ local totalTests = testsPassed + testsFailed
+ print(string.format("# of test passed: %d / %d (%.2f%%)",
+ testsPassed,
+ totalTests,
+ totalTests ~= 0
+ and 100 * (testsPassed / totalTests)
+ or 0)
+ )
+
+ return 0
+end, debug.traceback)
+
+if not result then
+ print("Unable to run tests due to test framework error: ",err)
+end
+
+os.exit(result or -1)
diff --git a/tests/monster_extra.fbs b/tests/monster_extra.fbs
new file mode 100644
index 0000000..d0fc7fe
--- /dev/null
+++ b/tests/monster_extra.fbs
@@ -0,0 +1,21 @@
+namespace MyGame;
+
+// Not all programming languages support this extra table.
+table MonsterExtra {
+ // Float-point values with NaN and Inf defaults.
+ d0:double = nan;
+ d1:double = -nan; // parser must ignore sign of NaN
+ d2:double = +inf;
+ d3:double = -inf;
+ f0:float = -nan; // parser must ignore sign of NaN
+ f1:float = +nan;
+ f2:float = +inf;
+ f3:float = -inf;
+ dvec : [double];
+ fvec : [float];
+}
+
+root_type MonsterExtra;
+
+file_identifier "MONE";
+file_extension "mon";
diff --git a/tests/monster_extra_generated.h b/tests/monster_extra_generated.h
new file mode 100644
index 0000000..d7ff900
--- /dev/null
+++ b/tests/monster_extra_generated.h
@@ -0,0 +1,406 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_MONSTEREXTRA_MYGAME_H_
+#define FLATBUFFERS_GENERATED_MONSTEREXTRA_MYGAME_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace MyGame {
+
+struct MonsterExtra;
+struct MonsterExtraT;
+
+bool operator==(const MonsterExtraT &lhs, const MonsterExtraT &rhs);
+bool operator!=(const MonsterExtraT &lhs, const MonsterExtraT &rhs);
+
+inline const flatbuffers::TypeTable *MonsterExtraTypeTable();
+
+struct MonsterExtraT : public flatbuffers::NativeTable {
+ typedef MonsterExtra TableType;
+ double d0;
+ double d1;
+ double d2;
+ double d3;
+ float f0;
+ float f1;
+ float f2;
+ float f3;
+ std::vector<double> dvec;
+ std::vector<float> fvec;
+ MonsterExtraT()
+ : d0(std::numeric_limits<double>::quiet_NaN()),
+ d1(std::numeric_limits<double>::quiet_NaN()),
+ d2(std::numeric_limits<double>::infinity()),
+ d3(-std::numeric_limits<double>::infinity()),
+ f0(std::numeric_limits<float>::quiet_NaN()),
+ f1(std::numeric_limits<float>::quiet_NaN()),
+ f2(std::numeric_limits<float>::infinity()),
+ f3(-std::numeric_limits<float>::infinity()) {
+ }
+};
+
+inline bool operator==(const MonsterExtraT &lhs, const MonsterExtraT &rhs) {
+ return
+ (lhs.d0 == rhs.d0) &&
+ (lhs.d1 == rhs.d1) &&
+ (lhs.d2 == rhs.d2) &&
+ (lhs.d3 == rhs.d3) &&
+ (lhs.f0 == rhs.f0) &&
+ (lhs.f1 == rhs.f1) &&
+ (lhs.f2 == rhs.f2) &&
+ (lhs.f3 == rhs.f3) &&
+ (lhs.dvec == rhs.dvec) &&
+ (lhs.fvec == rhs.fvec);
+}
+
+inline bool operator!=(const MonsterExtraT &lhs, const MonsterExtraT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct MonsterExtra FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterExtraT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return MonsterExtraTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_D0 = 4,
+ VT_D1 = 6,
+ VT_D2 = 8,
+ VT_D3 = 10,
+ VT_F0 = 12,
+ VT_F1 = 14,
+ VT_F2 = 16,
+ VT_F3 = 18,
+ VT_DVEC = 20,
+ VT_FVEC = 22
+ };
+ double d0() const {
+ return GetField<double>(VT_D0, std::numeric_limits<double>::quiet_NaN());
+ }
+ bool mutate_d0(double _d0) {
+ return SetField<double>(VT_D0, _d0, std::numeric_limits<double>::quiet_NaN());
+ }
+ double d1() const {
+ return GetField<double>(VT_D1, std::numeric_limits<double>::quiet_NaN());
+ }
+ bool mutate_d1(double _d1) {
+ return SetField<double>(VT_D1, _d1, std::numeric_limits<double>::quiet_NaN());
+ }
+ double d2() const {
+ return GetField<double>(VT_D2, std::numeric_limits<double>::infinity());
+ }
+ bool mutate_d2(double _d2) {
+ return SetField<double>(VT_D2, _d2, std::numeric_limits<double>::infinity());
+ }
+ double d3() const {
+ return GetField<double>(VT_D3, -std::numeric_limits<double>::infinity());
+ }
+ bool mutate_d3(double _d3) {
+ return SetField<double>(VT_D3, _d3, -std::numeric_limits<double>::infinity());
+ }
+ float f0() const {
+ return GetField<float>(VT_F0, std::numeric_limits<float>::quiet_NaN());
+ }
+ bool mutate_f0(float _f0) {
+ return SetField<float>(VT_F0, _f0, std::numeric_limits<float>::quiet_NaN());
+ }
+ float f1() const {
+ return GetField<float>(VT_F1, std::numeric_limits<float>::quiet_NaN());
+ }
+ bool mutate_f1(float _f1) {
+ return SetField<float>(VT_F1, _f1, std::numeric_limits<float>::quiet_NaN());
+ }
+ float f2() const {
+ return GetField<float>(VT_F2, std::numeric_limits<float>::infinity());
+ }
+ bool mutate_f2(float _f2) {
+ return SetField<float>(VT_F2, _f2, std::numeric_limits<float>::infinity());
+ }
+ float f3() const {
+ return GetField<float>(VT_F3, -std::numeric_limits<float>::infinity());
+ }
+ bool mutate_f3(float _f3) {
+ return SetField<float>(VT_F3, _f3, -std::numeric_limits<float>::infinity());
+ }
+ const flatbuffers::Vector<double> *dvec() const {
+ return GetPointer<const flatbuffers::Vector<double> *>(VT_DVEC);
+ }
+ flatbuffers::Vector<double> *mutable_dvec() {
+ return GetPointer<flatbuffers::Vector<double> *>(VT_DVEC);
+ }
+ const flatbuffers::Vector<float> *fvec() const {
+ return GetPointer<const flatbuffers::Vector<float> *>(VT_FVEC);
+ }
+ flatbuffers::Vector<float> *mutable_fvec() {
+ return GetPointer<flatbuffers::Vector<float> *>(VT_FVEC);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<double>(verifier, VT_D0) &&
+ VerifyField<double>(verifier, VT_D1) &&
+ VerifyField<double>(verifier, VT_D2) &&
+ VerifyField<double>(verifier, VT_D3) &&
+ VerifyField<float>(verifier, VT_F0) &&
+ VerifyField<float>(verifier, VT_F1) &&
+ VerifyField<float>(verifier, VT_F2) &&
+ VerifyField<float>(verifier, VT_F3) &&
+ VerifyOffset(verifier, VT_DVEC) &&
+ verifier.VerifyVector(dvec()) &&
+ VerifyOffset(verifier, VT_FVEC) &&
+ verifier.VerifyVector(fvec()) &&
+ verifier.EndTable();
+ }
+ MonsterExtraT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(MonsterExtraT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<MonsterExtra> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct MonsterExtraBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_d0(double d0) {
+ fbb_.AddElement<double>(MonsterExtra::VT_D0, d0, std::numeric_limits<double>::quiet_NaN());
+ }
+ void add_d1(double d1) {
+ fbb_.AddElement<double>(MonsterExtra::VT_D1, d1, std::numeric_limits<double>::quiet_NaN());
+ }
+ void add_d2(double d2) {
+ fbb_.AddElement<double>(MonsterExtra::VT_D2, d2, std::numeric_limits<double>::infinity());
+ }
+ void add_d3(double d3) {
+ fbb_.AddElement<double>(MonsterExtra::VT_D3, d3, -std::numeric_limits<double>::infinity());
+ }
+ void add_f0(float f0) {
+ fbb_.AddElement<float>(MonsterExtra::VT_F0, f0, std::numeric_limits<float>::quiet_NaN());
+ }
+ void add_f1(float f1) {
+ fbb_.AddElement<float>(MonsterExtra::VT_F1, f1, std::numeric_limits<float>::quiet_NaN());
+ }
+ void add_f2(float f2) {
+ fbb_.AddElement<float>(MonsterExtra::VT_F2, f2, std::numeric_limits<float>::infinity());
+ }
+ void add_f3(float f3) {
+ fbb_.AddElement<float>(MonsterExtra::VT_F3, f3, -std::numeric_limits<float>::infinity());
+ }
+ void add_dvec(flatbuffers::Offset<flatbuffers::Vector<double>> dvec) {
+ fbb_.AddOffset(MonsterExtra::VT_DVEC, dvec);
+ }
+ void add_fvec(flatbuffers::Offset<flatbuffers::Vector<float>> fvec) {
+ fbb_.AddOffset(MonsterExtra::VT_FVEC, fvec);
+ }
+ explicit MonsterExtraBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ MonsterExtraBuilder &operator=(const MonsterExtraBuilder &);
+ flatbuffers::Offset<MonsterExtra> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<MonsterExtra>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<MonsterExtra> CreateMonsterExtra(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ double d0 = std::numeric_limits<double>::quiet_NaN(),
+ double d1 = std::numeric_limits<double>::quiet_NaN(),
+ double d2 = std::numeric_limits<double>::infinity(),
+ double d3 = -std::numeric_limits<double>::infinity(),
+ float f0 = std::numeric_limits<float>::quiet_NaN(),
+ float f1 = std::numeric_limits<float>::quiet_NaN(),
+ float f2 = std::numeric_limits<float>::infinity(),
+ float f3 = -std::numeric_limits<float>::infinity(),
+ flatbuffers::Offset<flatbuffers::Vector<double>> dvec = 0,
+ flatbuffers::Offset<flatbuffers::Vector<float>> fvec = 0) {
+ MonsterExtraBuilder builder_(_fbb);
+ builder_.add_d3(d3);
+ builder_.add_d2(d2);
+ builder_.add_d1(d1);
+ builder_.add_d0(d0);
+ builder_.add_fvec(fvec);
+ builder_.add_dvec(dvec);
+ builder_.add_f3(f3);
+ builder_.add_f2(f2);
+ builder_.add_f1(f1);
+ builder_.add_f0(f0);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<MonsterExtra> CreateMonsterExtraDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ double d0 = std::numeric_limits<double>::quiet_NaN(),
+ double d1 = std::numeric_limits<double>::quiet_NaN(),
+ double d2 = std::numeric_limits<double>::infinity(),
+ double d3 = -std::numeric_limits<double>::infinity(),
+ float f0 = std::numeric_limits<float>::quiet_NaN(),
+ float f1 = std::numeric_limits<float>::quiet_NaN(),
+ float f2 = std::numeric_limits<float>::infinity(),
+ float f3 = -std::numeric_limits<float>::infinity(),
+ const std::vector<double> *dvec = nullptr,
+ const std::vector<float> *fvec = nullptr) {
+ auto dvec__ = dvec ? _fbb.CreateVector<double>(*dvec) : 0;
+ auto fvec__ = fvec ? _fbb.CreateVector<float>(*fvec) : 0;
+ return MyGame::CreateMonsterExtra(
+ _fbb,
+ d0,
+ d1,
+ d2,
+ d3,
+ f0,
+ f1,
+ f2,
+ f3,
+ dvec__,
+ fvec__);
+}
+
+flatbuffers::Offset<MonsterExtra> CreateMonsterExtra(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline MonsterExtraT *MonsterExtra::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new MonsterExtraT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void MonsterExtra::UnPackTo(MonsterExtraT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = d0(); _o->d0 = _e; };
+ { auto _e = d1(); _o->d1 = _e; };
+ { auto _e = d2(); _o->d2 = _e; };
+ { auto _e = d3(); _o->d3 = _e; };
+ { auto _e = f0(); _o->f0 = _e; };
+ { auto _e = f1(); _o->f1 = _e; };
+ { auto _e = f2(); _o->f2 = _e; };
+ { auto _e = f3(); _o->f3 = _e; };
+ { auto _e = dvec(); if (_e) { _o->dvec.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->dvec[_i] = _e->Get(_i); } } };
+ { auto _e = fvec(); if (_e) { _o->fvec.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->fvec[_i] = _e->Get(_i); } } };
+}
+
+inline flatbuffers::Offset<MonsterExtra> MonsterExtra::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonsterExtra(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<MonsterExtra> CreateMonsterExtra(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterExtraT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _d0 = _o->d0;
+ auto _d1 = _o->d1;
+ auto _d2 = _o->d2;
+ auto _d3 = _o->d3;
+ auto _f0 = _o->f0;
+ auto _f1 = _o->f1;
+ auto _f2 = _o->f2;
+ auto _f3 = _o->f3;
+ auto _dvec = _o->dvec.size() ? _fbb.CreateVector(_o->dvec) : 0;
+ auto _fvec = _o->fvec.size() ? _fbb.CreateVector(_o->fvec) : 0;
+ return MyGame::CreateMonsterExtra(
+ _fbb,
+ _d0,
+ _d1,
+ _d2,
+ _d3,
+ _f0,
+ _f1,
+ _f2,
+ _f3,
+ _dvec,
+ _fvec);
+}
+
+inline const flatbuffers::TypeTable *MonsterExtraTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_DOUBLE, 0, -1 },
+ { flatbuffers::ET_DOUBLE, 0, -1 },
+ { flatbuffers::ET_DOUBLE, 0, -1 },
+ { flatbuffers::ET_DOUBLE, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_DOUBLE, 1, -1 },
+ { flatbuffers::ET_FLOAT, 1, -1 }
+ };
+ static const char * const names[] = {
+ "d0",
+ "d1",
+ "d2",
+ "d3",
+ "f0",
+ "f1",
+ "f2",
+ "f3",
+ "dvec",
+ "fvec"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 10, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const MyGame::MonsterExtra *GetMonsterExtra(const void *buf) {
+ return flatbuffers::GetRoot<MyGame::MonsterExtra>(buf);
+}
+
+inline const MyGame::MonsterExtra *GetSizePrefixedMonsterExtra(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<MyGame::MonsterExtra>(buf);
+}
+
+inline MonsterExtra *GetMutableMonsterExtra(void *buf) {
+ return flatbuffers::GetMutableRoot<MonsterExtra>(buf);
+}
+
+inline const char *MonsterExtraIdentifier() {
+ return "MONE";
+}
+
+inline bool MonsterExtraBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(
+ buf, MonsterExtraIdentifier());
+}
+
+inline bool VerifyMonsterExtraBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<MyGame::MonsterExtra>(MonsterExtraIdentifier());
+}
+
+inline bool VerifySizePrefixedMonsterExtraBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<MyGame::MonsterExtra>(MonsterExtraIdentifier());
+}
+
+inline const char *MonsterExtraExtension() {
+ return "mon";
+}
+
+inline void FinishMonsterExtraBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::MonsterExtra> root) {
+ fbb.Finish(root, MonsterExtraIdentifier());
+}
+
+inline void FinishSizePrefixedMonsterExtraBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::MonsterExtra> root) {
+ fbb.FinishSizePrefixed(root, MonsterExtraIdentifier());
+}
+
+inline std::unique_ptr<MyGame::MonsterExtraT> UnPackMonsterExtra(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return std::unique_ptr<MyGame::MonsterExtraT>(GetMonsterExtra(buf)->UnPack(res));
+}
+
+inline std::unique_ptr<MyGame::MonsterExtraT> UnPackSizePrefixedMonsterExtra(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return std::unique_ptr<MyGame::MonsterExtraT>(GetSizePrefixedMonsterExtra(buf)->UnPack(res));
+}
+
+} // namespace MyGame
+
+#endif // FLATBUFFERS_GENERATED_MONSTEREXTRA_MYGAME_H_
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
new file mode 100644
index 0000000..02d618d
--- /dev/null
+++ b/tests/monster_test.bfbs
Binary files differ
diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs
new file mode 100644
index 0000000..d791094
--- /dev/null
+++ b/tests/monster_test.fbs
@@ -0,0 +1,138 @@
+// test schema file
+
+include "include_test1.fbs";
+
+namespace MyGame;
+
+table InParentNamespace {}
+
+namespace MyGame.Example2;
+
+table Monster {} // Test having same name as below, but in different namespace.
+
+namespace MyGame.Example;
+
+attribute "priority";
+
+/// Composite components of Monster color.
+enum Color:ubyte (bit_flags) {
+ Red = 0, // color Red = (1u << 0)
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ Green,
+ /// \brief color Blue (1u << 3)
+ Blue = 3,
+}
+
+union Any { Monster, TestSimpleTableWithEnum, MyGame.Example2.Monster }
+
+union AnyUniqueAliases { M: Monster, TS: TestSimpleTableWithEnum, M2: MyGame.Example2.Monster }
+union AnyAmbiguousAliases { M1: Monster, M2: Monster, M3: Monster }
+
+struct Test { a:short; b:byte; }
+
+table TestSimpleTableWithEnum (csharp_partial, private) {
+ color: Color = Green;
+}
+
+struct Vec3 (force_align: 8) {
+ x:float;
+ y:float;
+ z:float;
+ test1:double;
+ test2:Color;
+ test3:Test;
+}
+
+struct Ability {
+ id:uint(key);
+ distance:uint;
+}
+
+table Stat {
+ id:string;
+ val:long;
+ count:ushort;
+}
+
+table Referrable {
+ id:ulong(key, hash:"fnv1a_64");
+}
+
+/// an example documentation comment: monster object
+table Monster {
+ pos:Vec3 (id: 0);
+ hp:short = 100 (id: 2);
+ mana:short = 150 (id: 1);
+ name:string (id: 3, required, key);
+ color:Color = Blue (id: 6);
+ inventory:[ubyte] (id: 5);
+ friendly:bool = false (deprecated, priority: 1, id: 4);
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ testarrayoftables:[Monster] (id: 11);
+ testarrayofstring:[string] (id: 10);
+ testarrayofstring2:[string] (id: 28);
+ testarrayofbools:[bool] (id: 24);
+ testarrayofsortedstruct:[Ability] (id: 29);
+ enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace.
+ test:Any (id: 8);
+ test4:[Test] (id: 9);
+ test5:[Test] (id: 31);
+ testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster");
+ testempty:Stat (id:14);
+ testbool:bool (id:15);
+ testhashs32_fnv1:int (id:16, hash:"fnv1_32");
+ testhashu32_fnv1:uint (id:17, hash:"fnv1_32");
+ testhashs64_fnv1:long (id:18, hash:"fnv1_64");
+ testhashu64_fnv1:ulong (id:19, hash:"fnv1_64");
+ testhashs32_fnv1a:int (id:20, hash:"fnv1a_32");
+ testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32", cpp_type:"Stat");
+ testhashs64_fnv1a:long (id:22, hash:"fnv1a_64");
+ testhashu64_fnv1a:ulong (id:23, hash:"fnv1a_64");
+ testf:float = 3.14159 (id:25);
+ testf2:float = 3 (id:26);
+ testf3:float (id:27);
+ flex:[ubyte] (id:30, flexbuffer);
+ vector_of_longs:[long] (id:32);
+ vector_of_doubles:[double] (id:33);
+ parent_namespace_test:InParentNamespace (id:34);
+ vector_of_referrables:[Referrable](id:35);
+ single_weak_reference:ulong(id:36, hash:"fnv1a_64", cpp_type:"ReferrableT");
+ vector_of_weak_references:[ulong](id:37, hash:"fnv1a_64", cpp_type:"ReferrableT");
+ vector_of_strong_referrables:[Referrable](id:38, cpp_ptr_type:"default_ptr_type"); //was shared_ptr
+ co_owning_reference:ulong(id:39, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked"); //was shared_ptr as well
+ vector_of_co_owning_references:[ulong](id:40, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"default_ptr_type", cpp_ptr_type_get:".get()"); //was shared_ptr
+ non_owning_reference:ulong(id:41, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked", cpp_ptr_type_get:""); //was weak_ptr
+ vector_of_non_owning_references:[ulong](id:42, hash:"fnv1a_64", cpp_type:"ReferrableT", cpp_ptr_type:"naked", cpp_ptr_type_get:""); //was weak_ptr
+ any_unique:AnyUniqueAliases(id:44);
+ any_ambiguous:AnyAmbiguousAliases (id:46);
+ vector_of_enums:[Color] (id:47);
+}
+
+table TypeAliases {
+ i8:int8;
+ u8:uint8;
+ i16:int16;
+ u16:uint16;
+ i32:int32;
+ u32:uint32;
+ i64:int64;
+ u64:uint64;
+ f32:float32;
+ f64:float64;
+ v8:[int8];
+ vf64:[float64];
+}
+
+rpc_service MonsterStorage {
+ Store(Monster):Stat (streaming: "none");
+ Retrieve(Stat):Monster (streaming: "server", idempotent);
+ GetMaxHitPoint(Monster):Stat (streaming: "client");
+ GetMinMaxHitPoints(Monster):Stat (streaming: "bidi");
+}
+
+root_type Monster;
+
+file_identifier "MONS";
+file_extension "mon";
diff --git a/tests/monster_test.grpc.fb.cc b/tests/monster_test.grpc.fb.cc
new file mode 100644
index 0000000..f83e604
--- /dev/null
+++ b/tests/monster_test.grpc.fb.cc
@@ -0,0 +1,142 @@
+// Generated by the gRPC C++ plugin.
+// If you make any local change, they will be lost.
+// source: monster_test
+
+#include "monster_test_generated.h"
+#include "monster_test.grpc.fb.h"
+
+#include <grpc++/impl/codegen/async_stream.h>
+#include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpc++/impl/codegen/channel_interface.h>
+#include <grpc++/impl/codegen/client_unary_call.h>
+#include <grpc++/impl/codegen/method_handler_impl.h>
+#include <grpc++/impl/codegen/rpc_service_method.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/sync_stream.h>
+namespace MyGame {
+namespace Example {
+
+static const char* MonsterStorage_method_names[] = {
+ "/MyGame.Example.MonsterStorage/Store",
+ "/MyGame.Example.MonsterStorage/Retrieve",
+ "/MyGame.Example.MonsterStorage/GetMaxHitPoint",
+ "/MyGame.Example.MonsterStorage/GetMinMaxHitPoints",
+};
+
+std::unique_ptr< MonsterStorage::Stub> MonsterStorage::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {
+ std::unique_ptr< MonsterStorage::Stub> stub(new MonsterStorage::Stub(channel));
+ return stub;
+}
+
+MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel)
+ : channel_(channel) , rpcmethod_Store_(MonsterStorage_method_names[0], ::grpc::internal::RpcMethod::NORMAL_RPC, channel)
+ , rpcmethod_Retrieve_(MonsterStorage_method_names[1], ::grpc::internal::RpcMethod::SERVER_STREAMING, channel)
+ , rpcmethod_GetMaxHitPoint_(MonsterStorage_method_names[2], ::grpc::internal::RpcMethod::CLIENT_STREAMING, channel)
+ , rpcmethod_GetMinMaxHitPoints_(MonsterStorage_method_names[3], ::grpc::internal::RpcMethod::BIDI_STREAMING, channel)
+ {}
+
+::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) {
+ return ::grpc::internal::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response);
+}
+
+::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return ::grpc::internal::ClientAsyncResponseReaderFactory< flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_Store_, context, request, true);
+}
+
+::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::PrepareAsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return ::grpc::internal::ClientAsyncResponseReaderFactory< flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_Store_, context, request, false);
+}
+
+::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
+ return ::grpc::internal::ClientReaderFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), rpcmethod_Retrieve_, context, request);
+}
+
+::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
+ return ::grpc::internal::ClientAsyncReaderFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_Retrieve_, context, request, true, tag);
+}
+
+::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::PrepareAsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq) {
+ return ::grpc::internal::ClientAsyncReaderFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_Retrieve_, context, request, false, nullptr);
+}
+
+::grpc::ClientWriter< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::GetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response) {
+ return ::grpc::internal::ClientWriterFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), rpcmethod_GetMaxHitPoint_, context, response);
+}
+
+::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::AsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) {
+ return ::grpc::internal::ClientAsyncWriterFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_GetMaxHitPoint_, context, response, true, tag);
+}
+
+::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::PrepareAsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq) {
+ return ::grpc::internal::ClientAsyncWriterFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_GetMaxHitPoint_, context, response, false, nullptr);
+}
+
+::grpc::ClientReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::GetMinMaxHitPointsRaw(::grpc::ClientContext* context) {
+ return ::grpc::internal::ClientReaderWriterFactory< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), rpcmethod_GetMinMaxHitPoints_, context);
+}
+
+::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::AsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
+ return ::grpc::internal::ClientAsyncReaderWriterFactory< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_GetMinMaxHitPoints_, context, true, tag);
+}
+
+::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::PrepareAsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) {
+ return ::grpc::internal::ClientAsyncReaderWriterFactory< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_GetMinMaxHitPoints_, context, false, nullptr);
+}
+
+MonsterStorage::Service::Service() {
+ AddMethod(new ::grpc::internal::RpcServiceMethod(
+ MonsterStorage_method_names[0],
+ ::grpc::internal::RpcMethod::NORMAL_RPC,
+ new ::grpc::internal::RpcMethodHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
+ std::mem_fn(&MonsterStorage::Service::Store), this)));
+ AddMethod(new ::grpc::internal::RpcServiceMethod(
+ MonsterStorage_method_names[1],
+ ::grpc::internal::RpcMethod::SERVER_STREAMING,
+ new ::grpc::internal::ServerStreamingHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(
+ std::mem_fn(&MonsterStorage::Service::Retrieve), this)));
+ AddMethod(new ::grpc::internal::RpcServiceMethod(
+ MonsterStorage_method_names[2],
+ ::grpc::internal::RpcMethod::CLIENT_STREAMING,
+ new ::grpc::internal::ClientStreamingHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
+ std::mem_fn(&MonsterStorage::Service::GetMaxHitPoint), this)));
+ AddMethod(new ::grpc::internal::RpcServiceMethod(
+ MonsterStorage_method_names[3],
+ ::grpc::internal::RpcMethod::BIDI_STREAMING,
+ new ::grpc::internal::BidiStreamingHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
+ std::mem_fn(&MonsterStorage::Service::GetMinMaxHitPoints), this)));
+}
+
+MonsterStorage::Service::~Service() {
+}
+
+::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) {
+ (void) context;
+ (void) request;
+ (void) response;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) {
+ (void) context;
+ (void) request;
+ (void) writer;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+::grpc::Status MonsterStorage::Service::GetMaxHitPoint(::grpc::ServerContext* context, ::grpc::ServerReader< flatbuffers::grpc::Message<Monster>>* reader, flatbuffers::grpc::Message<Stat>* response) {
+ (void) context;
+ (void) reader;
+ (void) response;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+::grpc::Status MonsterStorage::Service::GetMinMaxHitPoints(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>* stream) {
+ (void) context;
+ (void) stream;
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+}
+
+
+} // namespace MyGame
+} // namespace Example
+
diff --git a/tests/monster_test.grpc.fb.h b/tests/monster_test.grpc.fb.h
new file mode 100644
index 0000000..72402ec
--- /dev/null
+++ b/tests/monster_test.grpc.fb.h
@@ -0,0 +1,350 @@
+// Generated by the gRPC C++ plugin.
+// If you make any local change, they will be lost.
+// source: monster_test
+#ifndef GRPC_monster_5ftest__INCLUDED
+#define GRPC_monster_5ftest__INCLUDED
+
+#include "monster_test_generated.h"
+#include "flatbuffers/grpc.h"
+
+#include <grpc++/impl/codegen/async_stream.h>
+#include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpc++/impl/codegen/method_handler_impl.h>
+#include <grpc++/impl/codegen/proto_utils.h>
+#include <grpc++/impl/codegen/rpc_method.h>
+#include <grpc++/impl/codegen/service_type.h>
+#include <grpc++/impl/codegen/status.h>
+#include <grpc++/impl/codegen/stub_options.h>
+#include <grpc++/impl/codegen/sync_stream.h>
+
+namespace grpc {
+class CompletionQueue;
+class Channel;
+class ServerCompletionQueue;
+class ServerContext;
+} // namespace grpc
+
+namespace MyGame {
+namespace Example {
+
+class MonsterStorage final {
+ public:
+ static constexpr char const* service_full_name() {
+ return "MyGame.Example.MonsterStorage";
+ }
+ class StubInterface {
+ public:
+ virtual ~StubInterface() {}
+ virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) = 0;
+ std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>> PrepareAsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>>(PrepareAsyncStoreRaw(context, request, cq));
+ }
+ std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
+ return std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
+ return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>> PrepareAsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>>(PrepareAsyncRetrieveRaw(context, request, cq));
+ }
+ std::unique_ptr< ::grpc::ClientWriterInterface< flatbuffers::grpc::Message<Monster>>> GetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response) {
+ return std::unique_ptr< ::grpc::ClientWriterInterface< flatbuffers::grpc::Message<Monster>>>(GetMaxHitPointRaw(context, response));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncWriterInterface< flatbuffers::grpc::Message<Monster>>> AsyncGetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) {
+ return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< flatbuffers::grpc::Message<Monster>>>(AsyncGetMaxHitPointRaw(context, response, cq, tag));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncWriterInterface< flatbuffers::grpc::Message<Monster>>> PrepareAsyncGetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncWriterInterface< flatbuffers::grpc::Message<Monster>>>(PrepareAsyncGetMaxHitPointRaw(context, response, cq));
+ }
+ std::unique_ptr< ::grpc::ClientReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> GetMinMaxHitPoints(::grpc::ClientContext* context) {
+ return std::unique_ptr< ::grpc::ClientReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(GetMinMaxHitPointsRaw(context));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> AsyncGetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
+ return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(AsyncGetMinMaxHitPointsRaw(context, cq, tag));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> PrepareAsyncGetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(PrepareAsyncGetMinMaxHitPointsRaw(context, cq));
+ }
+ private:
+ virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
+ virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>* PrepareAsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
+ virtual ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) = 0;
+ virtual ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
+ virtual ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>* PrepareAsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq) = 0;
+ virtual ::grpc::ClientWriterInterface< flatbuffers::grpc::Message<Monster>>* GetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response) = 0;
+ virtual ::grpc::ClientAsyncWriterInterface< flatbuffers::grpc::Message<Monster>>* AsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) = 0;
+ virtual ::grpc::ClientAsyncWriterInterface< flatbuffers::grpc::Message<Monster>>* PrepareAsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq) = 0;
+ virtual ::grpc::ClientReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* GetMinMaxHitPointsRaw(::grpc::ClientContext* context) = 0;
+ virtual ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* AsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) = 0;
+ virtual ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* PrepareAsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) = 0;
+ };
+ class Stub final : public StubInterface {
+ public:
+ Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
+ ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) override;
+ std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>> PrepareAsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>>(PrepareAsyncStoreRaw(context, request, cq));
+ }
+ std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
+ return std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
+ return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>> PrepareAsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>>(PrepareAsyncRetrieveRaw(context, request, cq));
+ }
+ std::unique_ptr< ::grpc::ClientWriter< flatbuffers::grpc::Message<Monster>>> GetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response) {
+ return std::unique_ptr< ::grpc::ClientWriter< flatbuffers::grpc::Message<Monster>>>(GetMaxHitPointRaw(context, response));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>> AsyncGetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) {
+ return std::unique_ptr< ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>>(AsyncGetMaxHitPointRaw(context, response, cq, tag));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>> PrepareAsyncGetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>>(PrepareAsyncGetMaxHitPointRaw(context, response, cq));
+ }
+ std::unique_ptr< ::grpc::ClientReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> GetMinMaxHitPoints(::grpc::ClientContext* context) {
+ return std::unique_ptr< ::grpc::ClientReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(GetMinMaxHitPointsRaw(context));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> AsyncGetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
+ return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(AsyncGetMinMaxHitPointsRaw(context, cq, tag));
+ }
+ std::unique_ptr< ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> PrepareAsyncGetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) {
+ return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(PrepareAsyncGetMinMaxHitPointsRaw(context, cq));
+ }
+
+ private:
+ std::shared_ptr< ::grpc::ChannelInterface> channel_;
+ ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) override;
+ ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* PrepareAsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) override;
+ ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) override;
+ ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) override;
+ ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* PrepareAsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq) override;
+ ::grpc::ClientWriter< flatbuffers::grpc::Message<Monster>>* GetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response) override;
+ ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>* AsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) override;
+ ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>* PrepareAsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq) override;
+ ::grpc::ClientReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* GetMinMaxHitPointsRaw(::grpc::ClientContext* context) override;
+ ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* AsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) override;
+ ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* PrepareAsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) override;
+ const ::grpc::internal::RpcMethod rpcmethod_Store_;
+ const ::grpc::internal::RpcMethod rpcmethod_Retrieve_;
+ const ::grpc::internal::RpcMethod rpcmethod_GetMaxHitPoint_;
+ const ::grpc::internal::RpcMethod rpcmethod_GetMinMaxHitPoints_;
+ };
+ static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
+
+ class Service : public ::grpc::Service {
+ public:
+ Service();
+ virtual ~Service();
+ virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response);
+ virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer);
+ virtual ::grpc::Status GetMaxHitPoint(::grpc::ServerContext* context, ::grpc::ServerReader< flatbuffers::grpc::Message<Monster>>* reader, flatbuffers::grpc::Message<Stat>* response);
+ virtual ::grpc::Status GetMinMaxHitPoints(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>* stream);
+ };
+ template <class BaseClass>
+ class WithAsyncMethod_Store : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithAsyncMethod_Store() {
+ ::grpc::Service::MarkMethodAsync(0);
+ }
+ ~WithAsyncMethod_Store() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ void RequestStore(::grpc::ServerContext* context, flatbuffers::grpc::Message<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::grpc::Message<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+ ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
+ }
+ };
+ template <class BaseClass>
+ class WithAsyncMethod_Retrieve : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithAsyncMethod_Retrieve() {
+ ::grpc::Service::MarkMethodAsync(1);
+ }
+ ~WithAsyncMethod_Retrieve() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerAsyncWriter< flatbuffers::grpc::Message<Monster>>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+ ::grpc::Service::RequestAsyncServerStreaming(1, context, request, writer, new_call_cq, notification_cq, tag);
+ }
+ };
+ template <class BaseClass>
+ class WithAsyncMethod_GetMaxHitPoint : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithAsyncMethod_GetMaxHitPoint() {
+ ::grpc::Service::MarkMethodAsync(2);
+ }
+ ~WithAsyncMethod_GetMaxHitPoint() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status GetMaxHitPoint(::grpc::ServerContext* context, ::grpc::ServerReader< flatbuffers::grpc::Message<Monster>>* reader, flatbuffers::grpc::Message<Stat>* response) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ void RequestGetMaxHitPoint(::grpc::ServerContext* context, ::grpc::ServerAsyncReader< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>* reader, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+ ::grpc::Service::RequestAsyncClientStreaming(2, context, reader, new_call_cq, notification_cq, tag);
+ }
+ };
+ template <class BaseClass>
+ class WithAsyncMethod_GetMinMaxHitPoints : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithAsyncMethod_GetMinMaxHitPoints() {
+ ::grpc::Service::MarkMethodAsync(3);
+ }
+ ~WithAsyncMethod_GetMinMaxHitPoints() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status GetMinMaxHitPoints(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>* stream) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ void RequestGetMinMaxHitPoints(::grpc::ServerContext* context, ::grpc::ServerAsyncReaderWriter< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>* stream, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+ ::grpc::Service::RequestAsyncBidiStreaming(3, context, stream, new_call_cq, notification_cq, tag);
+ }
+ };
+ typedef WithAsyncMethod_Store< WithAsyncMethod_Retrieve< WithAsyncMethod_GetMaxHitPoint< WithAsyncMethod_GetMinMaxHitPoints< Service > > > > AsyncService;
+ template <class BaseClass>
+ class WithGenericMethod_Store : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithGenericMethod_Store() {
+ ::grpc::Service::MarkMethodGeneric(0);
+ }
+ ~WithGenericMethod_Store() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ };
+ template <class BaseClass>
+ class WithGenericMethod_Retrieve : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithGenericMethod_Retrieve() {
+ ::grpc::Service::MarkMethodGeneric(1);
+ }
+ ~WithGenericMethod_Retrieve() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ };
+ template <class BaseClass>
+ class WithGenericMethod_GetMaxHitPoint : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithGenericMethod_GetMaxHitPoint() {
+ ::grpc::Service::MarkMethodGeneric(2);
+ }
+ ~WithGenericMethod_GetMaxHitPoint() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status GetMaxHitPoint(::grpc::ServerContext* context, ::grpc::ServerReader< flatbuffers::grpc::Message<Monster>>* reader, flatbuffers::grpc::Message<Stat>* response) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ };
+ template <class BaseClass>
+ class WithGenericMethod_GetMinMaxHitPoints : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithGenericMethod_GetMinMaxHitPoints() {
+ ::grpc::Service::MarkMethodGeneric(3);
+ }
+ ~WithGenericMethod_GetMinMaxHitPoints() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable synchronous version of this method
+ ::grpc::Status GetMinMaxHitPoints(::grpc::ServerContext* context, ::grpc::ServerReaderWriter< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>* stream) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ };
+ template <class BaseClass>
+ class WithStreamedUnaryMethod_Store : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithStreamedUnaryMethod_Store() {
+ ::grpc::Service::MarkMethodStreamed(0,
+ new ::grpc::internal::StreamedUnaryHandler< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(std::bind(&WithStreamedUnaryMethod_Store<BaseClass>::StreamedStore, this, std::placeholders::_1, std::placeholders::_2)));
+ }
+ ~WithStreamedUnaryMethod_Store() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable regular version of this method
+ ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ // replace default version of method with streamed unary
+ virtual ::grpc::Status StreamedStore(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< flatbuffers::grpc::Message<Monster>,flatbuffers::grpc::Message<Stat>>* server_unary_streamer) = 0;
+ };
+ typedef WithStreamedUnaryMethod_Store< Service > StreamedUnaryService;
+ template <class BaseClass>
+ class WithSplitStreamingMethod_Retrieve : public BaseClass {
+ private:
+ void BaseClassMustBeDerivedFromService(const Service *service) {}
+ public:
+ WithSplitStreamingMethod_Retrieve() {
+ ::grpc::Service::MarkMethodStreamed(1,
+ new ::grpc::internal::SplitServerStreamingHandler< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(std::bind(&WithSplitStreamingMethod_Retrieve<BaseClass>::StreamedRetrieve, this, std::placeholders::_1, std::placeholders::_2)));
+ }
+ ~WithSplitStreamingMethod_Retrieve() override {
+ BaseClassMustBeDerivedFromService(this);
+ }
+ // disable regular version of this method
+ ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
+ abort();
+ return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+ }
+ // replace default version of method with split streamed
+ virtual ::grpc::Status StreamedRetrieve(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< flatbuffers::grpc::Message<Stat>,flatbuffers::grpc::Message<Monster>>* server_split_streamer) = 0;
+ };
+ typedef WithSplitStreamingMethod_Retrieve< Service > SplitStreamedService;
+ typedef WithStreamedUnaryMethod_Store< WithSplitStreamingMethod_Retrieve< Service > > StreamedService;
+};
+
+} // namespace Example
+} // namespace MyGame
+
+
+#endif // GRPC_monster_5ftest__INCLUDED
diff --git a/tests/monster_test.schema.json b/tests/monster_test.schema.json
new file mode 100644
index 0000000..7fb7500
--- /dev/null
+++ b/tests/monster_test.schema.json
@@ -0,0 +1,340 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "definitions": {
+ "MyGame_OtherNameSpace_FromInclude" : {
+ "type" : "string",
+ "enum": ["IncludeVal"]
+ },
+ "MyGame_Example_Color" : {
+ "type" : "string",
+ "enum": ["Red", "Green", "Blue"]
+ },
+ "MyGame_Example_Any" : {
+ "type" : "string",
+ "enum": ["NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster"]
+ },
+ "MyGame_Example_AnyUniqueAliases" : {
+ "type" : "string",
+ "enum": ["NONE", "M", "TS", "M2"]
+ },
+ "MyGame_Example_AnyAmbiguousAliases" : {
+ "type" : "string",
+ "enum": ["NONE", "M1", "M2", "M3"]
+ },
+ "MyGame_OtherNameSpace_Unused" : {
+ "type" : "object",
+ "properties" : {
+ "a" : {
+ "type" : "number"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_OtherNameSpace_TableB" : {
+ "type" : "object",
+ "properties" : {
+ "a" : {
+ "$ref" : "#/definitions/TableA"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "TableA" : {
+ "type" : "object",
+ "properties" : {
+ "b" : {
+ "$ref" : "#/definitions/MyGame_OtherNameSpace_TableB"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_InParentNamespace" : {
+ "type" : "object",
+ "properties" : {
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example2_Monster" : {
+ "type" : "object",
+ "properties" : {
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_Test" : {
+ "type" : "object",
+ "properties" : {
+ "a" : {
+ "type" : "number"
+ },
+ "b" : {
+ "type" : "number"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_TestSimpleTableWithEnum" : {
+ "type" : "object",
+ "properties" : {
+ "color" : {
+ "$ref" : "#/definitions/MyGame_Example_Color"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_Vec3" : {
+ "type" : "object",
+ "properties" : {
+ "x" : {
+ "type" : "number"
+ },
+ "y" : {
+ "type" : "number"
+ },
+ "z" : {
+ "type" : "number"
+ },
+ "test1" : {
+ "type" : "number"
+ },
+ "test2" : {
+ "$ref" : "#/definitions/MyGame_Example_Color"
+ },
+ "test3" : {
+ "$ref" : "#/definitions/MyGame_Example_Test"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_Ability" : {
+ "type" : "object",
+ "properties" : {
+ "id" : {
+ "type" : "number"
+ },
+ "distance" : {
+ "type" : "number"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_Stat" : {
+ "type" : "object",
+ "properties" : {
+ "id" : {
+ "type" : "string"
+ },
+ "val" : {
+ "type" : "number"
+ },
+ "count" : {
+ "type" : "number"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_Referrable" : {
+ "type" : "object",
+ "properties" : {
+ "id" : {
+ "type" : "number"
+ }
+ },
+ "additionalProperties" : false
+ },
+ "MyGame_Example_Monster" : {
+ "type" : "object",
+ "description" : " an example documentation comment: monster object",
+ "properties" : {
+ "pos" : {
+ "$ref" : "#/definitions/MyGame_Example_Vec3"
+ },
+ "mana" : {
+ "type" : "number"
+ },
+ "hp" : {
+ "type" : "number"
+ },
+ "name" : {
+ "type" : "string"
+ },
+ "friendly" : {
+ "type" : "boolean"
+ },
+ "inventory" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "color" : {
+ "$ref" : "#/definitions/MyGame_Example_Color"
+ },
+ "test_type" : {
+ "$ref" : "#/definitions/MyGame_Example_Any"
+ },
+ "test" : {
+ "anyOf": [{ "$ref" : "#/definitions/MyGame_Example_Monster" },{ "$ref" : "#/definitions/MyGame_Example_TestSimpleTableWithEnum" },{ "$ref" : "#/definitions/MyGame_Example2_Monster" }]
+ },
+ "test4" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Test" }
+ },
+ "testarrayofstring" : {
+ "type" : "array", "items" : { "type" : "string" }
+ },
+ "testarrayoftables" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Monster" }
+ },
+ "enemy" : {
+ "$ref" : "#/definitions/MyGame_Example_Monster"
+ },
+ "testnestedflatbuffer" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "testempty" : {
+ "$ref" : "#/definitions/MyGame_Example_Stat"
+ },
+ "testbool" : {
+ "type" : "boolean"
+ },
+ "testhashs32_fnv1" : {
+ "type" : "number"
+ },
+ "testhashu32_fnv1" : {
+ "type" : "number"
+ },
+ "testhashs64_fnv1" : {
+ "type" : "number"
+ },
+ "testhashu64_fnv1" : {
+ "type" : "number"
+ },
+ "testhashs32_fnv1a" : {
+ "type" : "number"
+ },
+ "testhashu32_fnv1a" : {
+ "type" : "number"
+ },
+ "testhashs64_fnv1a" : {
+ "type" : "number"
+ },
+ "testhashu64_fnv1a" : {
+ "type" : "number"
+ },
+ "testarrayofbools" : {
+ "type" : "array", "items" : { "type" : "boolean" }
+ },
+ "testf" : {
+ "type" : "number"
+ },
+ "testf2" : {
+ "type" : "number"
+ },
+ "testf3" : {
+ "type" : "number"
+ },
+ "testarrayofstring2" : {
+ "type" : "array", "items" : { "type" : "string" }
+ },
+ "testarrayofsortedstruct" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Ability" }
+ },
+ "flex" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "test5" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Test" }
+ },
+ "vector_of_longs" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "vector_of_doubles" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "parent_namespace_test" : {
+ "$ref" : "#/definitions/MyGame_InParentNamespace"
+ },
+ "vector_of_referrables" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Referrable" }
+ },
+ "single_weak_reference" : {
+ "type" : "number"
+ },
+ "vector_of_weak_references" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "vector_of_strong_referrables" : {
+ "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Referrable" }
+ },
+ "co_owning_reference" : {
+ "type" : "number"
+ },
+ "vector_of_co_owning_references" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "non_owning_reference" : {
+ "type" : "number"
+ },
+ "vector_of_non_owning_references" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "any_unique_type" : {
+ "$ref" : "#/definitions/MyGame_Example_AnyUniqueAliases"
+ },
+ "any_unique" : {
+ "anyOf": [{ "$ref" : "#/definitions/MyGame_Example_Monster" },{ "$ref" : "#/definitions/MyGame_Example_TestSimpleTableWithEnum" },{ "$ref" : "#/definitions/MyGame_Example2_Monster" }]
+ },
+ "any_ambiguous_type" : {
+ "$ref" : "#/definitions/MyGame_Example_AnyAmbiguousAliases"
+ },
+ "any_ambiguous" : {
+ "anyOf": [{ "$ref" : "#/definitions/MyGame_Example_Monster" },{ "$ref" : "#/definitions/MyGame_Example_Monster" },{ "$ref" : "#/definitions/MyGame_Example_Monster" }]
+ },
+ "vector_of_enums" : {
+ "$ref" : "#/definitions/MyGame_Example_Color"
+ }
+ },
+ "required" : ["name"],
+ "additionalProperties" : false
+ },
+ "MyGame_Example_TypeAliases" : {
+ "type" : "object",
+ "properties" : {
+ "i8" : {
+ "type" : "number"
+ },
+ "u8" : {
+ "type" : "number"
+ },
+ "i16" : {
+ "type" : "number"
+ },
+ "u16" : {
+ "type" : "number"
+ },
+ "i32" : {
+ "type" : "number"
+ },
+ "u32" : {
+ "type" : "number"
+ },
+ "i64" : {
+ "type" : "number"
+ },
+ "u64" : {
+ "type" : "number"
+ },
+ "f32" : {
+ "type" : "number"
+ },
+ "f64" : {
+ "type" : "number"
+ },
+ "v8" : {
+ "type" : "array", "items" : { "type" : "number" }
+ },
+ "vf64" : {
+ "type" : "array", "items" : { "type" : "number" }
+ }
+ },
+ "additionalProperties" : false
+ }
+ },
+ "$ref" : "#/definitions/MyGame_Example_Monster"
+}
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
new file mode 100644
index 0000000..4016ce9
--- /dev/null
+++ b/tests/monster_test_generated.h
@@ -0,0 +1,3499 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_
+#define FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flexbuffers.h"
+
+namespace MyGame {
+
+struct InParentNamespace;
+struct InParentNamespaceT;
+
+namespace Example2 {
+
+struct Monster;
+struct MonsterT;
+
+} // namespace Example2
+
+namespace Example {
+
+struct Test;
+
+struct TestSimpleTableWithEnum;
+struct TestSimpleTableWithEnumT;
+
+struct Vec3;
+
+struct Ability;
+
+struct Stat;
+struct StatT;
+
+struct Referrable;
+struct ReferrableT;
+
+struct Monster;
+struct MonsterT;
+
+struct TypeAliases;
+struct TypeAliasesT;
+
+} // namespace Example
+
+bool operator==(const InParentNamespaceT &lhs, const InParentNamespaceT &rhs);
+bool operator!=(const InParentNamespaceT &lhs, const InParentNamespaceT &rhs);
+namespace Example2 {
+
+bool operator==(const MonsterT &lhs, const MonsterT &rhs);
+bool operator!=(const MonsterT &lhs, const MonsterT &rhs);
+} // namespace Example2
+
+namespace Example {
+
+bool operator==(const Test &lhs, const Test &rhs);
+bool operator!=(const Test &lhs, const Test &rhs);
+bool operator==(const TestSimpleTableWithEnumT &lhs, const TestSimpleTableWithEnumT &rhs);
+bool operator!=(const TestSimpleTableWithEnumT &lhs, const TestSimpleTableWithEnumT &rhs);
+bool operator==(const Vec3 &lhs, const Vec3 &rhs);
+bool operator!=(const Vec3 &lhs, const Vec3 &rhs);
+bool operator==(const Ability &lhs, const Ability &rhs);
+bool operator!=(const Ability &lhs, const Ability &rhs);
+bool operator==(const StatT &lhs, const StatT &rhs);
+bool operator!=(const StatT &lhs, const StatT &rhs);
+bool operator==(const ReferrableT &lhs, const ReferrableT &rhs);
+bool operator!=(const ReferrableT &lhs, const ReferrableT &rhs);
+bool operator==(const MonsterT &lhs, const MonsterT &rhs);
+bool operator!=(const MonsterT &lhs, const MonsterT &rhs);
+bool operator==(const TypeAliasesT &lhs, const TypeAliasesT &rhs);
+bool operator!=(const TypeAliasesT &lhs, const TypeAliasesT &rhs);
+
+} // namespace Example
+
+inline const flatbuffers::TypeTable *InParentNamespaceTypeTable();
+
+namespace Example2 {
+
+inline const flatbuffers::TypeTable *MonsterTypeTable();
+
+} // namespace Example2
+
+namespace Example {
+
+inline const flatbuffers::TypeTable *TestTypeTable();
+
+inline const flatbuffers::TypeTable *TestSimpleTableWithEnumTypeTable();
+
+inline const flatbuffers::TypeTable *Vec3TypeTable();
+
+inline const flatbuffers::TypeTable *AbilityTypeTable();
+
+inline const flatbuffers::TypeTable *StatTypeTable();
+
+inline const flatbuffers::TypeTable *ReferrableTypeTable();
+
+inline const flatbuffers::TypeTable *MonsterTypeTable();
+
+inline const flatbuffers::TypeTable *TypeAliasesTypeTable();
+
+/// Composite components of Monster color.
+enum Color {
+ Color_Red = 1,
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ Color_Green = 2,
+ /// \brief color Blue (1u << 3)
+ Color_Blue = 8,
+ Color_NONE = 0,
+ Color_ANY = 11
+};
+
+inline const Color (&EnumValuesColor())[3] {
+ static const Color values[] = {
+ Color_Red,
+ Color_Green,
+ Color_Blue
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesColor() {
+ static const char * const names[9] = {
+ "Red",
+ "Green",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Blue",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameColor(Color e) {
+ if (e < Color_Red || e > Color_Blue) return "";
+ const size_t index = static_cast<size_t>(e) - static_cast<size_t>(Color_Red);
+ return EnumNamesColor()[index];
+}
+
+enum Any {
+ Any_NONE = 0,
+ Any_Monster = 1,
+ Any_TestSimpleTableWithEnum = 2,
+ Any_MyGame_Example2_Monster = 3,
+ Any_MIN = Any_NONE,
+ Any_MAX = Any_MyGame_Example2_Monster
+};
+
+inline const Any (&EnumValuesAny())[4] {
+ static const Any values[] = {
+ Any_NONE,
+ Any_Monster,
+ Any_TestSimpleTableWithEnum,
+ Any_MyGame_Example2_Monster
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesAny() {
+ static const char * const names[5] = {
+ "NONE",
+ "Monster",
+ "TestSimpleTableWithEnum",
+ "MyGame_Example2_Monster",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameAny(Any e) {
+ if (e < Any_NONE || e > Any_MyGame_Example2_Monster) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesAny()[index];
+}
+
+template<typename T> struct AnyTraits {
+ static const Any enum_value = Any_NONE;
+};
+
+template<> struct AnyTraits<MyGame::Example::Monster> {
+ static const Any enum_value = Any_Monster;
+};
+
+template<> struct AnyTraits<MyGame::Example::TestSimpleTableWithEnum> {
+ static const Any enum_value = Any_TestSimpleTableWithEnum;
+};
+
+template<> struct AnyTraits<MyGame::Example2::Monster> {
+ static const Any enum_value = Any_MyGame_Example2_Monster;
+};
+
+struct AnyUnion {
+ Any type;
+ void *value;
+
+ AnyUnion() : type(Any_NONE), value(nullptr) {}
+ AnyUnion(AnyUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(Any_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ AnyUnion(const AnyUnion &) FLATBUFFERS_NOEXCEPT;
+ AnyUnion &operator=(const AnyUnion &u) FLATBUFFERS_NOEXCEPT
+ { AnyUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+ AnyUnion &operator=(AnyUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~AnyUnion() { Reset(); }
+
+ void Reset();
+
+#ifndef FLATBUFFERS_CPP98_STL
+ template <typename T>
+ void Set(T&& val) {
+ using RT = typename std::remove_reference<T>::type;
+ Reset();
+ type = AnyTraits<typename RT::TableType>::enum_value;
+ if (type != Any_NONE) {
+ value = new RT(std::forward<T>(val));
+ }
+ }
+#endif // FLATBUFFERS_CPP98_STL
+
+ static void *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+ MyGame::Example::MonsterT *AsMonster() {
+ return type == Any_Monster ?
+ reinterpret_cast<MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example::MonsterT *AsMonster() const {
+ return type == Any_Monster ?
+ reinterpret_cast<const MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ MyGame::Example::TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() {
+ return type == Any_TestSimpleTableWithEnum ?
+ reinterpret_cast<MyGame::Example::TestSimpleTableWithEnumT *>(value) : nullptr;
+ }
+ const MyGame::Example::TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() const {
+ return type == Any_TestSimpleTableWithEnum ?
+ reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(value) : nullptr;
+ }
+ MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() {
+ return type == Any_MyGame_Example2_Monster ?
+ reinterpret_cast<MyGame::Example2::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() const {
+ return type == Any_MyGame_Example2_Monster ?
+ reinterpret_cast<const MyGame::Example2::MonsterT *>(value) : nullptr;
+ }
+};
+
+
+inline bool operator==(const AnyUnion &lhs, const AnyUnion &rhs) {
+ if (lhs.type != rhs.type) return false;
+ switch (lhs.type) {
+ case Any_NONE: {
+ return true;
+ }
+ case Any_Monster: {
+ return *(reinterpret_cast<const MyGame::Example::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::MonsterT *>(rhs.value));
+ }
+ case Any_TestSimpleTableWithEnum: {
+ return *(reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(rhs.value));
+ }
+ case Any_MyGame_Example2_Monster: {
+ return *(reinterpret_cast<const MyGame::Example2::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example2::MonsterT *>(rhs.value));
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+inline bool operator!=(const AnyUnion &lhs, const AnyUnion &rhs) {
+ return !(lhs == rhs);
+}
+
+bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type);
+bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+
+enum AnyUniqueAliases {
+ AnyUniqueAliases_NONE = 0,
+ AnyUniqueAliases_M = 1,
+ AnyUniqueAliases_TS = 2,
+ AnyUniqueAliases_M2 = 3,
+ AnyUniqueAliases_MIN = AnyUniqueAliases_NONE,
+ AnyUniqueAliases_MAX = AnyUniqueAliases_M2
+};
+
+inline const AnyUniqueAliases (&EnumValuesAnyUniqueAliases())[4] {
+ static const AnyUniqueAliases values[] = {
+ AnyUniqueAliases_NONE,
+ AnyUniqueAliases_M,
+ AnyUniqueAliases_TS,
+ AnyUniqueAliases_M2
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesAnyUniqueAliases() {
+ static const char * const names[5] = {
+ "NONE",
+ "M",
+ "TS",
+ "M2",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameAnyUniqueAliases(AnyUniqueAliases e) {
+ if (e < AnyUniqueAliases_NONE || e > AnyUniqueAliases_M2) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesAnyUniqueAliases()[index];
+}
+
+template<typename T> struct AnyUniqueAliasesTraits {
+ static const AnyUniqueAliases enum_value = AnyUniqueAliases_NONE;
+};
+
+template<> struct AnyUniqueAliasesTraits<MyGame::Example::Monster> {
+ static const AnyUniqueAliases enum_value = AnyUniqueAliases_M;
+};
+
+template<> struct AnyUniqueAliasesTraits<MyGame::Example::TestSimpleTableWithEnum> {
+ static const AnyUniqueAliases enum_value = AnyUniqueAliases_TS;
+};
+
+template<> struct AnyUniqueAliasesTraits<MyGame::Example2::Monster> {
+ static const AnyUniqueAliases enum_value = AnyUniqueAliases_M2;
+};
+
+struct AnyUniqueAliasesUnion {
+ AnyUniqueAliases type;
+ void *value;
+
+ AnyUniqueAliasesUnion() : type(AnyUniqueAliases_NONE), value(nullptr) {}
+ AnyUniqueAliasesUnion(AnyUniqueAliasesUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(AnyUniqueAliases_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ AnyUniqueAliasesUnion(const AnyUniqueAliasesUnion &) FLATBUFFERS_NOEXCEPT;
+ AnyUniqueAliasesUnion &operator=(const AnyUniqueAliasesUnion &u) FLATBUFFERS_NOEXCEPT
+ { AnyUniqueAliasesUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+ AnyUniqueAliasesUnion &operator=(AnyUniqueAliasesUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~AnyUniqueAliasesUnion() { Reset(); }
+
+ void Reset();
+
+#ifndef FLATBUFFERS_CPP98_STL
+ template <typename T>
+ void Set(T&& val) {
+ using RT = typename std::remove_reference<T>::type;
+ Reset();
+ type = AnyUniqueAliasesTraits<typename RT::TableType>::enum_value;
+ if (type != AnyUniqueAliases_NONE) {
+ value = new RT(std::forward<T>(val));
+ }
+ }
+#endif // FLATBUFFERS_CPP98_STL
+
+ static void *UnPack(const void *obj, AnyUniqueAliases type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+ MyGame::Example::MonsterT *AsM() {
+ return type == AnyUniqueAliases_M ?
+ reinterpret_cast<MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example::MonsterT *AsM() const {
+ return type == AnyUniqueAliases_M ?
+ reinterpret_cast<const MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ MyGame::Example::TestSimpleTableWithEnumT *AsTS() {
+ return type == AnyUniqueAliases_TS ?
+ reinterpret_cast<MyGame::Example::TestSimpleTableWithEnumT *>(value) : nullptr;
+ }
+ const MyGame::Example::TestSimpleTableWithEnumT *AsTS() const {
+ return type == AnyUniqueAliases_TS ?
+ reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(value) : nullptr;
+ }
+ MyGame::Example2::MonsterT *AsM2() {
+ return type == AnyUniqueAliases_M2 ?
+ reinterpret_cast<MyGame::Example2::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example2::MonsterT *AsM2() const {
+ return type == AnyUniqueAliases_M2 ?
+ reinterpret_cast<const MyGame::Example2::MonsterT *>(value) : nullptr;
+ }
+};
+
+
+inline bool operator==(const AnyUniqueAliasesUnion &lhs, const AnyUniqueAliasesUnion &rhs) {
+ if (lhs.type != rhs.type) return false;
+ switch (lhs.type) {
+ case AnyUniqueAliases_NONE: {
+ return true;
+ }
+ case AnyUniqueAliases_M: {
+ return *(reinterpret_cast<const MyGame::Example::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::MonsterT *>(rhs.value));
+ }
+ case AnyUniqueAliases_TS: {
+ return *(reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(rhs.value));
+ }
+ case AnyUniqueAliases_M2: {
+ return *(reinterpret_cast<const MyGame::Example2::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example2::MonsterT *>(rhs.value));
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+inline bool operator!=(const AnyUniqueAliasesUnion &lhs, const AnyUniqueAliasesUnion &rhs) {
+ return !(lhs == rhs);
+}
+
+bool VerifyAnyUniqueAliases(flatbuffers::Verifier &verifier, const void *obj, AnyUniqueAliases type);
+bool VerifyAnyUniqueAliasesVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+
+enum AnyAmbiguousAliases {
+ AnyAmbiguousAliases_NONE = 0,
+ AnyAmbiguousAliases_M1 = 1,
+ AnyAmbiguousAliases_M2 = 2,
+ AnyAmbiguousAliases_M3 = 3,
+ AnyAmbiguousAliases_MIN = AnyAmbiguousAliases_NONE,
+ AnyAmbiguousAliases_MAX = AnyAmbiguousAliases_M3
+};
+
+inline const AnyAmbiguousAliases (&EnumValuesAnyAmbiguousAliases())[4] {
+ static const AnyAmbiguousAliases values[] = {
+ AnyAmbiguousAliases_NONE,
+ AnyAmbiguousAliases_M1,
+ AnyAmbiguousAliases_M2,
+ AnyAmbiguousAliases_M3
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesAnyAmbiguousAliases() {
+ static const char * const names[5] = {
+ "NONE",
+ "M1",
+ "M2",
+ "M3",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameAnyAmbiguousAliases(AnyAmbiguousAliases e) {
+ if (e < AnyAmbiguousAliases_NONE || e > AnyAmbiguousAliases_M3) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesAnyAmbiguousAliases()[index];
+}
+
+struct AnyAmbiguousAliasesUnion {
+ AnyAmbiguousAliases type;
+ void *value;
+
+ AnyAmbiguousAliasesUnion() : type(AnyAmbiguousAliases_NONE), value(nullptr) {}
+ AnyAmbiguousAliasesUnion(AnyAmbiguousAliasesUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(AnyAmbiguousAliases_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ AnyAmbiguousAliasesUnion(const AnyAmbiguousAliasesUnion &) FLATBUFFERS_NOEXCEPT;
+ AnyAmbiguousAliasesUnion &operator=(const AnyAmbiguousAliasesUnion &u) FLATBUFFERS_NOEXCEPT
+ { AnyAmbiguousAliasesUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+ AnyAmbiguousAliasesUnion &operator=(AnyAmbiguousAliasesUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~AnyAmbiguousAliasesUnion() { Reset(); }
+
+ void Reset();
+
+ static void *UnPack(const void *obj, AnyAmbiguousAliases type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+ MyGame::Example::MonsterT *AsM1() {
+ return type == AnyAmbiguousAliases_M1 ?
+ reinterpret_cast<MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example::MonsterT *AsM1() const {
+ return type == AnyAmbiguousAliases_M1 ?
+ reinterpret_cast<const MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ MyGame::Example::MonsterT *AsM2() {
+ return type == AnyAmbiguousAliases_M2 ?
+ reinterpret_cast<MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example::MonsterT *AsM2() const {
+ return type == AnyAmbiguousAliases_M2 ?
+ reinterpret_cast<const MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ MyGame::Example::MonsterT *AsM3() {
+ return type == AnyAmbiguousAliases_M3 ?
+ reinterpret_cast<MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+ const MyGame::Example::MonsterT *AsM3() const {
+ return type == AnyAmbiguousAliases_M3 ?
+ reinterpret_cast<const MyGame::Example::MonsterT *>(value) : nullptr;
+ }
+};
+
+
+inline bool operator==(const AnyAmbiguousAliasesUnion &lhs, const AnyAmbiguousAliasesUnion &rhs) {
+ if (lhs.type != rhs.type) return false;
+ switch (lhs.type) {
+ case AnyAmbiguousAliases_NONE: {
+ return true;
+ }
+ case AnyAmbiguousAliases_M1: {
+ return *(reinterpret_cast<const MyGame::Example::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::MonsterT *>(rhs.value));
+ }
+ case AnyAmbiguousAliases_M2: {
+ return *(reinterpret_cast<const MyGame::Example::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::MonsterT *>(rhs.value));
+ }
+ case AnyAmbiguousAliases_M3: {
+ return *(reinterpret_cast<const MyGame::Example::MonsterT *>(lhs.value)) ==
+ *(reinterpret_cast<const MyGame::Example::MonsterT *>(rhs.value));
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+inline bool operator!=(const AnyAmbiguousAliasesUnion &lhs, const AnyAmbiguousAliasesUnion &rhs) {
+ return !(lhs == rhs);
+}
+
+bool VerifyAnyAmbiguousAliases(flatbuffers::Verifier &verifier, const void *obj, AnyAmbiguousAliases type);
+bool VerifyAnyAmbiguousAliasesVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
+ private:
+ int16_t a_;
+ int8_t b_;
+ int8_t padding0__;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return TestTypeTable();
+ }
+ Test() {
+ memset(static_cast<void *>(this), 0, sizeof(Test));
+ }
+ Test(int16_t _a, int8_t _b)
+ : a_(flatbuffers::EndianScalar(_a)),
+ b_(flatbuffers::EndianScalar(_b)),
+ padding0__(0) {
+ (void)padding0__;
+ }
+ int16_t a() const {
+ return flatbuffers::EndianScalar(a_);
+ }
+ void mutate_a(int16_t _a) {
+ flatbuffers::WriteScalar(&a_, _a);
+ }
+ int8_t b() const {
+ return flatbuffers::EndianScalar(b_);
+ }
+ void mutate_b(int8_t _b) {
+ flatbuffers::WriteScalar(&b_, _b);
+ }
+};
+FLATBUFFERS_STRUCT_END(Test, 4);
+
+inline bool operator==(const Test &lhs, const Test &rhs) {
+ return
+ (lhs.a() == rhs.a()) &&
+ (lhs.b() == rhs.b());
+}
+
+inline bool operator!=(const Test &lhs, const Test &rhs) {
+ return !(lhs == rhs);
+}
+
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Vec3 FLATBUFFERS_FINAL_CLASS {
+ private:
+ float x_;
+ float y_;
+ float z_;
+ int32_t padding0__;
+ double test1_;
+ uint8_t test2_;
+ int8_t padding1__;
+ MyGame::Example::Test test3_;
+ int16_t padding2__;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return Vec3TypeTable();
+ }
+ Vec3() {
+ memset(static_cast<void *>(this), 0, sizeof(Vec3));
+ }
+ Vec3(float _x, float _y, float _z, double _test1, MyGame::Example::Color _test2, const MyGame::Example::Test &_test3)
+ : x_(flatbuffers::EndianScalar(_x)),
+ y_(flatbuffers::EndianScalar(_y)),
+ z_(flatbuffers::EndianScalar(_z)),
+ padding0__(0),
+ test1_(flatbuffers::EndianScalar(_test1)),
+ test2_(flatbuffers::EndianScalar(static_cast<uint8_t>(_test2))),
+ padding1__(0),
+ test3_(_test3),
+ padding2__(0) {
+ (void)padding0__;
+ (void)padding1__;
+ (void)padding2__;
+ }
+ float x() const {
+ return flatbuffers::EndianScalar(x_);
+ }
+ void mutate_x(float _x) {
+ flatbuffers::WriteScalar(&x_, _x);
+ }
+ float y() const {
+ return flatbuffers::EndianScalar(y_);
+ }
+ void mutate_y(float _y) {
+ flatbuffers::WriteScalar(&y_, _y);
+ }
+ float z() const {
+ return flatbuffers::EndianScalar(z_);
+ }
+ void mutate_z(float _z) {
+ flatbuffers::WriteScalar(&z_, _z);
+ }
+ double test1() const {
+ return flatbuffers::EndianScalar(test1_);
+ }
+ void mutate_test1(double _test1) {
+ flatbuffers::WriteScalar(&test1_, _test1);
+ }
+ MyGame::Example::Color test2() const {
+ return static_cast<MyGame::Example::Color>(flatbuffers::EndianScalar(test2_));
+ }
+ void mutate_test2(MyGame::Example::Color _test2) {
+ flatbuffers::WriteScalar(&test2_, static_cast<uint8_t>(_test2));
+ }
+ const MyGame::Example::Test &test3() const {
+ return test3_;
+ }
+ MyGame::Example::Test &mutable_test3() {
+ return test3_;
+ }
+};
+FLATBUFFERS_STRUCT_END(Vec3, 32);
+
+inline bool operator==(const Vec3 &lhs, const Vec3 &rhs) {
+ return
+ (lhs.x() == rhs.x()) &&
+ (lhs.y() == rhs.y()) &&
+ (lhs.z() == rhs.z()) &&
+ (lhs.test1() == rhs.test1()) &&
+ (lhs.test2() == rhs.test2()) &&
+ (lhs.test3() == rhs.test3());
+}
+
+inline bool operator!=(const Vec3 &lhs, const Vec3 &rhs) {
+ return !(lhs == rhs);
+}
+
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS {
+ private:
+ uint32_t id_;
+ uint32_t distance_;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return AbilityTypeTable();
+ }
+ Ability() {
+ memset(static_cast<void *>(this), 0, sizeof(Ability));
+ }
+ Ability(uint32_t _id, uint32_t _distance)
+ : id_(flatbuffers::EndianScalar(_id)),
+ distance_(flatbuffers::EndianScalar(_distance)) {
+ }
+ uint32_t id() const {
+ return flatbuffers::EndianScalar(id_);
+ }
+ void mutate_id(uint32_t _id) {
+ flatbuffers::WriteScalar(&id_, _id);
+ }
+ bool KeyCompareLessThan(const Ability *o) const {
+ return id() < o->id();
+ }
+ int KeyCompareWithValue(uint32_t val) const {
+ return static_cast<int>(id() > val) - static_cast<int>(id() < val);
+ }
+ uint32_t distance() const {
+ return flatbuffers::EndianScalar(distance_);
+ }
+ void mutate_distance(uint32_t _distance) {
+ flatbuffers::WriteScalar(&distance_, _distance);
+ }
+};
+FLATBUFFERS_STRUCT_END(Ability, 8);
+
+inline bool operator==(const Ability &lhs, const Ability &rhs) {
+ return
+ (lhs.id() == rhs.id()) &&
+ (lhs.distance() == rhs.distance());
+}
+
+inline bool operator!=(const Ability &lhs, const Ability &rhs) {
+ return !(lhs == rhs);
+}
+
+
+} // namespace Example
+
+struct InParentNamespaceT : public flatbuffers::NativeTable {
+ typedef InParentNamespace TableType;
+ InParentNamespaceT() {
+ }
+};
+
+inline bool operator==(const InParentNamespaceT &, const InParentNamespaceT &) {
+ return true;
+}
+
+inline bool operator!=(const InParentNamespaceT &lhs, const InParentNamespaceT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef InParentNamespaceT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return InParentNamespaceTypeTable();
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ verifier.EndTable();
+ }
+ InParentNamespaceT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(InParentNamespaceT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<InParentNamespace> Pack(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct InParentNamespaceBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit InParentNamespaceBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ InParentNamespaceBuilder &operator=(const InParentNamespaceBuilder &);
+ flatbuffers::Offset<InParentNamespace> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<InParentNamespace>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(
+ flatbuffers::FlatBufferBuilder &_fbb) {
+ InParentNamespaceBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+namespace Example2 {
+
+struct MonsterT : public flatbuffers::NativeTable {
+ typedef Monster TableType;
+ MonsterT() {
+ }
+};
+
+inline bool operator==(const MonsterT &, const MonsterT &) {
+ return true;
+}
+
+inline bool operator!=(const MonsterT &lhs, const MonsterT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return MonsterTypeTable();
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ verifier.EndTable();
+ }
+ MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct MonsterBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ MonsterBuilder &operator=(const MonsterBuilder &);
+ flatbuffers::Offset<Monster> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Monster>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Monster> CreateMonster(
+ flatbuffers::FlatBufferBuilder &_fbb) {
+ MonsterBuilder builder_(_fbb);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+} // namespace Example2
+
+namespace Example {
+
+struct TestSimpleTableWithEnumT : public flatbuffers::NativeTable {
+ typedef TestSimpleTableWithEnum TableType;
+ MyGame::Example::Color color;
+ TestSimpleTableWithEnumT()
+ : color(MyGame::Example::Color_Green) {
+ }
+};
+
+inline bool operator==(const TestSimpleTableWithEnumT &lhs, const TestSimpleTableWithEnumT &rhs) {
+ return
+ (lhs.color == rhs.color);
+}
+
+inline bool operator!=(const TestSimpleTableWithEnumT &lhs, const TestSimpleTableWithEnumT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef TestSimpleTableWithEnumT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return TestSimpleTableWithEnumTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_COLOR = 4
+ };
+ MyGame::Example::Color color() const {
+ return static_cast<MyGame::Example::Color>(GetField<uint8_t>(VT_COLOR, 2));
+ }
+ bool mutate_color(MyGame::Example::Color _color) {
+ return SetField<uint8_t>(VT_COLOR, static_cast<uint8_t>(_color), 2);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint8_t>(verifier, VT_COLOR) &&
+ verifier.EndTable();
+ }
+ TestSimpleTableWithEnumT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(TestSimpleTableWithEnumT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<TestSimpleTableWithEnum> Pack(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct TestSimpleTableWithEnumBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_color(MyGame::Example::Color color) {
+ fbb_.AddElement<uint8_t>(TestSimpleTableWithEnum::VT_COLOR, static_cast<uint8_t>(color), 2);
+ }
+ explicit TestSimpleTableWithEnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ TestSimpleTableWithEnumBuilder &operator=(const TestSimpleTableWithEnumBuilder &);
+ flatbuffers::Offset<TestSimpleTableWithEnum> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TestSimpleTableWithEnum>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ MyGame::Example::Color color = MyGame::Example::Color_Green) {
+ TestSimpleTableWithEnumBuilder builder_(_fbb);
+ builder_.add_color(color);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct StatT : public flatbuffers::NativeTable {
+ typedef Stat TableType;
+ std::string id;
+ int64_t val;
+ uint16_t count;
+ StatT()
+ : val(0),
+ count(0) {
+ }
+};
+
+inline bool operator==(const StatT &lhs, const StatT &rhs) {
+ return
+ (lhs.id == rhs.id) &&
+ (lhs.val == rhs.val) &&
+ (lhs.count == rhs.count);
+}
+
+inline bool operator!=(const StatT &lhs, const StatT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef StatT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return StatTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_ID = 4,
+ VT_VAL = 6,
+ VT_COUNT = 8
+ };
+ const flatbuffers::String *id() const {
+ return GetPointer<const flatbuffers::String *>(VT_ID);
+ }
+ flatbuffers::String *mutable_id() {
+ return GetPointer<flatbuffers::String *>(VT_ID);
+ }
+ int64_t val() const {
+ return GetField<int64_t>(VT_VAL, 0);
+ }
+ bool mutate_val(int64_t _val) {
+ return SetField<int64_t>(VT_VAL, _val, 0);
+ }
+ uint16_t count() const {
+ return GetField<uint16_t>(VT_COUNT, 0);
+ }
+ bool mutate_count(uint16_t _count) {
+ return SetField<uint16_t>(VT_COUNT, _count, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_ID) &&
+ verifier.VerifyString(id()) &&
+ VerifyField<int64_t>(verifier, VT_VAL) &&
+ VerifyField<uint16_t>(verifier, VT_COUNT) &&
+ verifier.EndTable();
+ }
+ StatT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(StatT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Stat> Pack(flatbuffers::FlatBufferBuilder &_fbb, const StatT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct StatBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_id(flatbuffers::Offset<flatbuffers::String> id) {
+ fbb_.AddOffset(Stat::VT_ID, id);
+ }
+ void add_val(int64_t val) {
+ fbb_.AddElement<int64_t>(Stat::VT_VAL, val, 0);
+ }
+ void add_count(uint16_t count) {
+ fbb_.AddElement<uint16_t>(Stat::VT_COUNT, count, 0);
+ }
+ explicit StatBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ StatBuilder &operator=(const StatBuilder &);
+ flatbuffers::Offset<Stat> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Stat>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Stat> CreateStat(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::String> id = 0,
+ int64_t val = 0,
+ uint16_t count = 0) {
+ StatBuilder builder_(_fbb);
+ builder_.add_val(val);
+ builder_.add_id(id);
+ builder_.add_count(count);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Stat> CreateStatDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const char *id = nullptr,
+ int64_t val = 0,
+ uint16_t count = 0) {
+ auto id__ = id ? _fbb.CreateString(id) : 0;
+ return MyGame::Example::CreateStat(
+ _fbb,
+ id__,
+ val,
+ count);
+}
+
+flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct ReferrableT : public flatbuffers::NativeTable {
+ typedef Referrable TableType;
+ uint64_t id;
+ ReferrableT()
+ : id(0) {
+ }
+};
+
+inline bool operator==(const ReferrableT &lhs, const ReferrableT &rhs) {
+ return
+ (lhs.id == rhs.id);
+}
+
+inline bool operator!=(const ReferrableT &lhs, const ReferrableT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Referrable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef ReferrableT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return ReferrableTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_ID = 4
+ };
+ uint64_t id() const {
+ return GetField<uint64_t>(VT_ID, 0);
+ }
+ bool mutate_id(uint64_t _id) {
+ return SetField<uint64_t>(VT_ID, _id, 0);
+ }
+ bool KeyCompareLessThan(const Referrable *o) const {
+ return id() < o->id();
+ }
+ int KeyCompareWithValue(uint64_t val) const {
+ return static_cast<int>(id() > val) - static_cast<int>(id() < val);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint64_t>(verifier, VT_ID) &&
+ verifier.EndTable();
+ }
+ ReferrableT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(ReferrableT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Referrable> Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReferrableT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct ReferrableBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_id(uint64_t id) {
+ fbb_.AddElement<uint64_t>(Referrable::VT_ID, id, 0);
+ }
+ explicit ReferrableBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ ReferrableBuilder &operator=(const ReferrableBuilder &);
+ flatbuffers::Offset<Referrable> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Referrable>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Referrable> CreateReferrable(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint64_t id = 0) {
+ ReferrableBuilder builder_(_fbb);
+ builder_.add_id(id);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<Referrable> CreateReferrable(flatbuffers::FlatBufferBuilder &_fbb, const ReferrableT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct MonsterT : public flatbuffers::NativeTable {
+ typedef Monster TableType;
+ flatbuffers::unique_ptr<MyGame::Example::Vec3> pos;
+ int16_t mana;
+ int16_t hp;
+ std::string name;
+ std::vector<uint8_t> inventory;
+ MyGame::Example::Color color;
+ AnyUnion test;
+ std::vector<MyGame::Example::Test> test4;
+ std::vector<std::string> testarrayofstring;
+ std::vector<flatbuffers::unique_ptr<MyGame::Example::MonsterT>> testarrayoftables;
+ flatbuffers::unique_ptr<MyGame::Example::MonsterT> enemy;
+ std::vector<uint8_t> testnestedflatbuffer;
+ flatbuffers::unique_ptr<MyGame::Example::StatT> testempty;
+ bool testbool;
+ int32_t testhashs32_fnv1;
+ uint32_t testhashu32_fnv1;
+ int64_t testhashs64_fnv1;
+ uint64_t testhashu64_fnv1;
+ int32_t testhashs32_fnv1a;
+ Stat *testhashu32_fnv1a;
+ int64_t testhashs64_fnv1a;
+ uint64_t testhashu64_fnv1a;
+ std::vector<bool> testarrayofbools;
+ float testf;
+ float testf2;
+ float testf3;
+ std::vector<std::string> testarrayofstring2;
+ std::vector<MyGame::Example::Ability> testarrayofsortedstruct;
+ std::vector<uint8_t> flex;
+ std::vector<MyGame::Example::Test> test5;
+ std::vector<int64_t> vector_of_longs;
+ std::vector<double> vector_of_doubles;
+ flatbuffers::unique_ptr<MyGame::InParentNamespaceT> parent_namespace_test;
+ std::vector<flatbuffers::unique_ptr<MyGame::Example::ReferrableT>> vector_of_referrables;
+ ReferrableT *single_weak_reference;
+ std::vector<ReferrableT *> vector_of_weak_references;
+ std::vector<flatbuffers::unique_ptr<MyGame::Example::ReferrableT>> vector_of_strong_referrables;
+ ReferrableT *co_owning_reference;
+ std::vector<flatbuffers::unique_ptr<ReferrableT>> vector_of_co_owning_references;
+ ReferrableT *non_owning_reference;
+ std::vector<ReferrableT *> vector_of_non_owning_references;
+ AnyUniqueAliasesUnion any_unique;
+ AnyAmbiguousAliasesUnion any_ambiguous;
+ std::vector<MyGame::Example::Color> vector_of_enums;
+ MonsterT()
+ : mana(150),
+ hp(100),
+ color(MyGame::Example::Color_Blue),
+ testbool(false),
+ testhashs32_fnv1(0),
+ testhashu32_fnv1(0),
+ testhashs64_fnv1(0),
+ testhashu64_fnv1(0),
+ testhashs32_fnv1a(0),
+ testhashu32_fnv1a(nullptr),
+ testhashs64_fnv1a(0),
+ testhashu64_fnv1a(0),
+ testf(3.14159f),
+ testf2(3.0f),
+ testf3(0.0f),
+ single_weak_reference(nullptr),
+ co_owning_reference(nullptr),
+ non_owning_reference(nullptr) {
+ }
+};
+
+inline bool operator==(const MonsterT &lhs, const MonsterT &rhs) {
+ return
+ (lhs.pos == rhs.pos) &&
+ (lhs.mana == rhs.mana) &&
+ (lhs.hp == rhs.hp) &&
+ (lhs.name == rhs.name) &&
+ (lhs.inventory == rhs.inventory) &&
+ (lhs.color == rhs.color) &&
+ (lhs.test == rhs.test) &&
+ (lhs.test4 == rhs.test4) &&
+ (lhs.testarrayofstring == rhs.testarrayofstring) &&
+ (lhs.testarrayoftables == rhs.testarrayoftables) &&
+ (lhs.enemy == rhs.enemy) &&
+ (lhs.testnestedflatbuffer == rhs.testnestedflatbuffer) &&
+ (lhs.testempty == rhs.testempty) &&
+ (lhs.testbool == rhs.testbool) &&
+ (lhs.testhashs32_fnv1 == rhs.testhashs32_fnv1) &&
+ (lhs.testhashu32_fnv1 == rhs.testhashu32_fnv1) &&
+ (lhs.testhashs64_fnv1 == rhs.testhashs64_fnv1) &&
+ (lhs.testhashu64_fnv1 == rhs.testhashu64_fnv1) &&
+ (lhs.testhashs32_fnv1a == rhs.testhashs32_fnv1a) &&
+ (lhs.testhashu32_fnv1a == rhs.testhashu32_fnv1a) &&
+ (lhs.testhashs64_fnv1a == rhs.testhashs64_fnv1a) &&
+ (lhs.testhashu64_fnv1a == rhs.testhashu64_fnv1a) &&
+ (lhs.testarrayofbools == rhs.testarrayofbools) &&
+ (lhs.testf == rhs.testf) &&
+ (lhs.testf2 == rhs.testf2) &&
+ (lhs.testf3 == rhs.testf3) &&
+ (lhs.testarrayofstring2 == rhs.testarrayofstring2) &&
+ (lhs.testarrayofsortedstruct == rhs.testarrayofsortedstruct) &&
+ (lhs.flex == rhs.flex) &&
+ (lhs.test5 == rhs.test5) &&
+ (lhs.vector_of_longs == rhs.vector_of_longs) &&
+ (lhs.vector_of_doubles == rhs.vector_of_doubles) &&
+ (lhs.parent_namespace_test == rhs.parent_namespace_test) &&
+ (lhs.vector_of_referrables == rhs.vector_of_referrables) &&
+ (lhs.single_weak_reference == rhs.single_weak_reference) &&
+ (lhs.vector_of_weak_references == rhs.vector_of_weak_references) &&
+ (lhs.vector_of_strong_referrables == rhs.vector_of_strong_referrables) &&
+ (lhs.co_owning_reference == rhs.co_owning_reference) &&
+ (lhs.vector_of_co_owning_references == rhs.vector_of_co_owning_references) &&
+ (lhs.non_owning_reference == rhs.non_owning_reference) &&
+ (lhs.vector_of_non_owning_references == rhs.vector_of_non_owning_references) &&
+ (lhs.any_unique == rhs.any_unique) &&
+ (lhs.any_ambiguous == rhs.any_ambiguous) &&
+ (lhs.vector_of_enums == rhs.vector_of_enums);
+}
+
+inline bool operator!=(const MonsterT &lhs, const MonsterT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+/// an example documentation comment: monster object
+struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MonsterT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return MonsterTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_POS = 4,
+ VT_MANA = 6,
+ VT_HP = 8,
+ VT_NAME = 10,
+ VT_INVENTORY = 14,
+ VT_COLOR = 16,
+ VT_TEST_TYPE = 18,
+ VT_TEST = 20,
+ VT_TEST4 = 22,
+ VT_TESTARRAYOFSTRING = 24,
+ VT_TESTARRAYOFTABLES = 26,
+ VT_ENEMY = 28,
+ VT_TESTNESTEDFLATBUFFER = 30,
+ VT_TESTEMPTY = 32,
+ VT_TESTBOOL = 34,
+ VT_TESTHASHS32_FNV1 = 36,
+ VT_TESTHASHU32_FNV1 = 38,
+ VT_TESTHASHS64_FNV1 = 40,
+ VT_TESTHASHU64_FNV1 = 42,
+ VT_TESTHASHS32_FNV1A = 44,
+ VT_TESTHASHU32_FNV1A = 46,
+ VT_TESTHASHS64_FNV1A = 48,
+ VT_TESTHASHU64_FNV1A = 50,
+ VT_TESTARRAYOFBOOLS = 52,
+ VT_TESTF = 54,
+ VT_TESTF2 = 56,
+ VT_TESTF3 = 58,
+ VT_TESTARRAYOFSTRING2 = 60,
+ VT_TESTARRAYOFSORTEDSTRUCT = 62,
+ VT_FLEX = 64,
+ VT_TEST5 = 66,
+ VT_VECTOR_OF_LONGS = 68,
+ VT_VECTOR_OF_DOUBLES = 70,
+ VT_PARENT_NAMESPACE_TEST = 72,
+ VT_VECTOR_OF_REFERRABLES = 74,
+ VT_SINGLE_WEAK_REFERENCE = 76,
+ VT_VECTOR_OF_WEAK_REFERENCES = 78,
+ VT_VECTOR_OF_STRONG_REFERRABLES = 80,
+ VT_CO_OWNING_REFERENCE = 82,
+ VT_VECTOR_OF_CO_OWNING_REFERENCES = 84,
+ VT_NON_OWNING_REFERENCE = 86,
+ VT_VECTOR_OF_NON_OWNING_REFERENCES = 88,
+ VT_ANY_UNIQUE_TYPE = 90,
+ VT_ANY_UNIQUE = 92,
+ VT_ANY_AMBIGUOUS_TYPE = 94,
+ VT_ANY_AMBIGUOUS = 96,
+ VT_VECTOR_OF_ENUMS = 98
+ };
+ const MyGame::Example::Vec3 *pos() const {
+ return GetStruct<const MyGame::Example::Vec3 *>(VT_POS);
+ }
+ MyGame::Example::Vec3 *mutable_pos() {
+ return GetStruct<MyGame::Example::Vec3 *>(VT_POS);
+ }
+ int16_t mana() const {
+ return GetField<int16_t>(VT_MANA, 150);
+ }
+ bool mutate_mana(int16_t _mana) {
+ return SetField<int16_t>(VT_MANA, _mana, 150);
+ }
+ int16_t hp() const {
+ return GetField<int16_t>(VT_HP, 100);
+ }
+ bool mutate_hp(int16_t _hp) {
+ return SetField<int16_t>(VT_HP, _hp, 100);
+ }
+ const flatbuffers::String *name() const {
+ return GetPointer<const flatbuffers::String *>(VT_NAME);
+ }
+ flatbuffers::String *mutable_name() {
+ return GetPointer<flatbuffers::String *>(VT_NAME);
+ }
+ bool KeyCompareLessThan(const Monster *o) const {
+ return *name() < *o->name();
+ }
+ int KeyCompareWithValue(const char *val) const {
+ return strcmp(name()->c_str(), val);
+ }
+ const flatbuffers::Vector<uint8_t> *inventory() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_INVENTORY);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_inventory() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_INVENTORY);
+ }
+ MyGame::Example::Color color() const {
+ return static_cast<MyGame::Example::Color>(GetField<uint8_t>(VT_COLOR, 8));
+ }
+ bool mutate_color(MyGame::Example::Color _color) {
+ return SetField<uint8_t>(VT_COLOR, static_cast<uint8_t>(_color), 8);
+ }
+ MyGame::Example::Any test_type() const {
+ return static_cast<MyGame::Example::Any>(GetField<uint8_t>(VT_TEST_TYPE, 0));
+ }
+ bool mutate_test_type(MyGame::Example::Any _test_type) {
+ return SetField<uint8_t>(VT_TEST_TYPE, static_cast<uint8_t>(_test_type), 0);
+ }
+ const void *test() const {
+ return GetPointer<const void *>(VT_TEST);
+ }
+ template<typename T> const T *test_as() const;
+ const MyGame::Example::Monster *test_as_Monster() const {
+ return test_type() == MyGame::Example::Any_Monster ? static_cast<const MyGame::Example::Monster *>(test()) : nullptr;
+ }
+ const MyGame::Example::TestSimpleTableWithEnum *test_as_TestSimpleTableWithEnum() const {
+ return test_type() == MyGame::Example::Any_TestSimpleTableWithEnum ? static_cast<const MyGame::Example::TestSimpleTableWithEnum *>(test()) : nullptr;
+ }
+ const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const {
+ return test_type() == MyGame::Example::Any_MyGame_Example2_Monster ? static_cast<const MyGame::Example2::Monster *>(test()) : nullptr;
+ }
+ void *mutable_test() {
+ return GetPointer<void *>(VT_TEST);
+ }
+ const flatbuffers::Vector<const MyGame::Example::Test *> *test4() const {
+ return GetPointer<const flatbuffers::Vector<const MyGame::Example::Test *> *>(VT_TEST4);
+ }
+ flatbuffers::Vector<const MyGame::Example::Test *> *mutable_test4() {
+ return GetPointer<flatbuffers::Vector<const MyGame::Example::Test *> *>(VT_TEST4);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING);
+ }
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ const flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Monster>> *testarrayoftables() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Monster>> *>(VT_TESTARRAYOFTABLES);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Monster>> *mutable_testarrayoftables() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Monster>> *>(VT_TESTARRAYOFTABLES);
+ }
+ const MyGame::Example::Monster *enemy() const {
+ return GetPointer<const MyGame::Example::Monster *>(VT_ENEMY);
+ }
+ MyGame::Example::Monster *mutable_enemy() {
+ return GetPointer<MyGame::Example::Monster *>(VT_ENEMY);
+ }
+ const flatbuffers::Vector<uint8_t> *testnestedflatbuffer() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_TESTNESTEDFLATBUFFER);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_testnestedflatbuffer() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_TESTNESTEDFLATBUFFER);
+ }
+ const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const {
+ return flatbuffers::GetRoot<MyGame::Example::Monster>(testnestedflatbuffer()->Data());
+ }
+ const MyGame::Example::Stat *testempty() const {
+ return GetPointer<const MyGame::Example::Stat *>(VT_TESTEMPTY);
+ }
+ MyGame::Example::Stat *mutable_testempty() {
+ return GetPointer<MyGame::Example::Stat *>(VT_TESTEMPTY);
+ }
+ bool testbool() const {
+ return GetField<uint8_t>(VT_TESTBOOL, 0) != 0;
+ }
+ bool mutate_testbool(bool _testbool) {
+ return SetField<uint8_t>(VT_TESTBOOL, static_cast<uint8_t>(_testbool), 0);
+ }
+ int32_t testhashs32_fnv1() const {
+ return GetField<int32_t>(VT_TESTHASHS32_FNV1, 0);
+ }
+ bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) {
+ return SetField<int32_t>(VT_TESTHASHS32_FNV1, _testhashs32_fnv1, 0);
+ }
+ uint32_t testhashu32_fnv1() const {
+ return GetField<uint32_t>(VT_TESTHASHU32_FNV1, 0);
+ }
+ bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) {
+ return SetField<uint32_t>(VT_TESTHASHU32_FNV1, _testhashu32_fnv1, 0);
+ }
+ int64_t testhashs64_fnv1() const {
+ return GetField<int64_t>(VT_TESTHASHS64_FNV1, 0);
+ }
+ bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) {
+ return SetField<int64_t>(VT_TESTHASHS64_FNV1, _testhashs64_fnv1, 0);
+ }
+ uint64_t testhashu64_fnv1() const {
+ return GetField<uint64_t>(VT_TESTHASHU64_FNV1, 0);
+ }
+ bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) {
+ return SetField<uint64_t>(VT_TESTHASHU64_FNV1, _testhashu64_fnv1, 0);
+ }
+ int32_t testhashs32_fnv1a() const {
+ return GetField<int32_t>(VT_TESTHASHS32_FNV1A, 0);
+ }
+ bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) {
+ return SetField<int32_t>(VT_TESTHASHS32_FNV1A, _testhashs32_fnv1a, 0);
+ }
+ uint32_t testhashu32_fnv1a() const {
+ return GetField<uint32_t>(VT_TESTHASHU32_FNV1A, 0);
+ }
+ bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) {
+ return SetField<uint32_t>(VT_TESTHASHU32_FNV1A, _testhashu32_fnv1a, 0);
+ }
+ int64_t testhashs64_fnv1a() const {
+ return GetField<int64_t>(VT_TESTHASHS64_FNV1A, 0);
+ }
+ bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) {
+ return SetField<int64_t>(VT_TESTHASHS64_FNV1A, _testhashs64_fnv1a, 0);
+ }
+ uint64_t testhashu64_fnv1a() const {
+ return GetField<uint64_t>(VT_TESTHASHU64_FNV1A, 0);
+ }
+ bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) {
+ return SetField<uint64_t>(VT_TESTHASHU64_FNV1A, _testhashu64_fnv1a, 0);
+ }
+ const flatbuffers::Vector<uint8_t> *testarrayofbools() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_TESTARRAYOFBOOLS);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_testarrayofbools() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_TESTARRAYOFBOOLS);
+ }
+ float testf() const {
+ return GetField<float>(VT_TESTF, 3.14159f);
+ }
+ bool mutate_testf(float _testf) {
+ return SetField<float>(VT_TESTF, _testf, 3.14159f);
+ }
+ float testf2() const {
+ return GetField<float>(VT_TESTF2, 3.0f);
+ }
+ bool mutate_testf2(float _testf2) {
+ return SetField<float>(VT_TESTF2, _testf2, 3.0f);
+ }
+ float testf3() const {
+ return GetField<float>(VT_TESTF3, 0.0f);
+ }
+ bool mutate_testf3(float _testf3) {
+ return SetField<float>(VT_TESTF3, _testf3, 0.0f);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring2() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2);
+ }
+ const flatbuffers::Vector<const MyGame::Example::Ability *> *testarrayofsortedstruct() const {
+ return GetPointer<const flatbuffers::Vector<const MyGame::Example::Ability *> *>(VT_TESTARRAYOFSORTEDSTRUCT);
+ }
+ flatbuffers::Vector<const MyGame::Example::Ability *> *mutable_testarrayofsortedstruct() {
+ return GetPointer<flatbuffers::Vector<const MyGame::Example::Ability *> *>(VT_TESTARRAYOFSORTEDSTRUCT);
+ }
+ const flatbuffers::Vector<uint8_t> *flex() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_FLEX);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_flex() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_FLEX);
+ }
+ flexbuffers::Reference flex_flexbuffer_root() const {
+ return flexbuffers::GetRoot(flex()->Data(), flex()->size());
+ }
+ const flatbuffers::Vector<const MyGame::Example::Test *> *test5() const {
+ return GetPointer<const flatbuffers::Vector<const MyGame::Example::Test *> *>(VT_TEST5);
+ }
+ flatbuffers::Vector<const MyGame::Example::Test *> *mutable_test5() {
+ return GetPointer<flatbuffers::Vector<const MyGame::Example::Test *> *>(VT_TEST5);
+ }
+ const flatbuffers::Vector<int64_t> *vector_of_longs() const {
+ return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_VECTOR_OF_LONGS);
+ }
+ flatbuffers::Vector<int64_t> *mutable_vector_of_longs() {
+ return GetPointer<flatbuffers::Vector<int64_t> *>(VT_VECTOR_OF_LONGS);
+ }
+ const flatbuffers::Vector<double> *vector_of_doubles() const {
+ return GetPointer<const flatbuffers::Vector<double> *>(VT_VECTOR_OF_DOUBLES);
+ }
+ flatbuffers::Vector<double> *mutable_vector_of_doubles() {
+ return GetPointer<flatbuffers::Vector<double> *>(VT_VECTOR_OF_DOUBLES);
+ }
+ const MyGame::InParentNamespace *parent_namespace_test() const {
+ return GetPointer<const MyGame::InParentNamespace *>(VT_PARENT_NAMESPACE_TEST);
+ }
+ MyGame::InParentNamespace *mutable_parent_namespace_test() {
+ return GetPointer<MyGame::InParentNamespace *>(VT_PARENT_NAMESPACE_TEST);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *vector_of_referrables() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *>(VT_VECTOR_OF_REFERRABLES);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *mutable_vector_of_referrables() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *>(VT_VECTOR_OF_REFERRABLES);
+ }
+ uint64_t single_weak_reference() const {
+ return GetField<uint64_t>(VT_SINGLE_WEAK_REFERENCE, 0);
+ }
+ bool mutate_single_weak_reference(uint64_t _single_weak_reference) {
+ return SetField<uint64_t>(VT_SINGLE_WEAK_REFERENCE, _single_weak_reference, 0);
+ }
+ const flatbuffers::Vector<uint64_t> *vector_of_weak_references() const {
+ return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VECTOR_OF_WEAK_REFERENCES);
+ }
+ flatbuffers::Vector<uint64_t> *mutable_vector_of_weak_references() {
+ return GetPointer<flatbuffers::Vector<uint64_t> *>(VT_VECTOR_OF_WEAK_REFERENCES);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *vector_of_strong_referrables() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *>(VT_VECTOR_OF_STRONG_REFERRABLES);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *mutable_vector_of_strong_referrables() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>> *>(VT_VECTOR_OF_STRONG_REFERRABLES);
+ }
+ uint64_t co_owning_reference() const {
+ return GetField<uint64_t>(VT_CO_OWNING_REFERENCE, 0);
+ }
+ bool mutate_co_owning_reference(uint64_t _co_owning_reference) {
+ return SetField<uint64_t>(VT_CO_OWNING_REFERENCE, _co_owning_reference, 0);
+ }
+ const flatbuffers::Vector<uint64_t> *vector_of_co_owning_references() const {
+ return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VECTOR_OF_CO_OWNING_REFERENCES);
+ }
+ flatbuffers::Vector<uint64_t> *mutable_vector_of_co_owning_references() {
+ return GetPointer<flatbuffers::Vector<uint64_t> *>(VT_VECTOR_OF_CO_OWNING_REFERENCES);
+ }
+ uint64_t non_owning_reference() const {
+ return GetField<uint64_t>(VT_NON_OWNING_REFERENCE, 0);
+ }
+ bool mutate_non_owning_reference(uint64_t _non_owning_reference) {
+ return SetField<uint64_t>(VT_NON_OWNING_REFERENCE, _non_owning_reference, 0);
+ }
+ const flatbuffers::Vector<uint64_t> *vector_of_non_owning_references() const {
+ return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_VECTOR_OF_NON_OWNING_REFERENCES);
+ }
+ flatbuffers::Vector<uint64_t> *mutable_vector_of_non_owning_references() {
+ return GetPointer<flatbuffers::Vector<uint64_t> *>(VT_VECTOR_OF_NON_OWNING_REFERENCES);
+ }
+ MyGame::Example::AnyUniqueAliases any_unique_type() const {
+ return static_cast<MyGame::Example::AnyUniqueAliases>(GetField<uint8_t>(VT_ANY_UNIQUE_TYPE, 0));
+ }
+ bool mutate_any_unique_type(MyGame::Example::AnyUniqueAliases _any_unique_type) {
+ return SetField<uint8_t>(VT_ANY_UNIQUE_TYPE, static_cast<uint8_t>(_any_unique_type), 0);
+ }
+ const void *any_unique() const {
+ return GetPointer<const void *>(VT_ANY_UNIQUE);
+ }
+ template<typename T> const T *any_unique_as() const;
+ const MyGame::Example::Monster *any_unique_as_M() const {
+ return any_unique_type() == MyGame::Example::AnyUniqueAliases_M ? static_cast<const MyGame::Example::Monster *>(any_unique()) : nullptr;
+ }
+ const MyGame::Example::TestSimpleTableWithEnum *any_unique_as_TS() const {
+ return any_unique_type() == MyGame::Example::AnyUniqueAliases_TS ? static_cast<const MyGame::Example::TestSimpleTableWithEnum *>(any_unique()) : nullptr;
+ }
+ const MyGame::Example2::Monster *any_unique_as_M2() const {
+ return any_unique_type() == MyGame::Example::AnyUniqueAliases_M2 ? static_cast<const MyGame::Example2::Monster *>(any_unique()) : nullptr;
+ }
+ void *mutable_any_unique() {
+ return GetPointer<void *>(VT_ANY_UNIQUE);
+ }
+ MyGame::Example::AnyAmbiguousAliases any_ambiguous_type() const {
+ return static_cast<MyGame::Example::AnyAmbiguousAliases>(GetField<uint8_t>(VT_ANY_AMBIGUOUS_TYPE, 0));
+ }
+ bool mutate_any_ambiguous_type(MyGame::Example::AnyAmbiguousAliases _any_ambiguous_type) {
+ return SetField<uint8_t>(VT_ANY_AMBIGUOUS_TYPE, static_cast<uint8_t>(_any_ambiguous_type), 0);
+ }
+ const void *any_ambiguous() const {
+ return GetPointer<const void *>(VT_ANY_AMBIGUOUS);
+ }
+ const MyGame::Example::Monster *any_ambiguous_as_M1() const {
+ return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M1 ? static_cast<const MyGame::Example::Monster *>(any_ambiguous()) : nullptr;
+ }
+ const MyGame::Example::Monster *any_ambiguous_as_M2() const {
+ return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M2 ? static_cast<const MyGame::Example::Monster *>(any_ambiguous()) : nullptr;
+ }
+ const MyGame::Example::Monster *any_ambiguous_as_M3() const {
+ return any_ambiguous_type() == MyGame::Example::AnyAmbiguousAliases_M3 ? static_cast<const MyGame::Example::Monster *>(any_ambiguous()) : nullptr;
+ }
+ void *mutable_any_ambiguous() {
+ return GetPointer<void *>(VT_ANY_AMBIGUOUS);
+ }
+ const flatbuffers::Vector<uint8_t> *vector_of_enums() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_VECTOR_OF_ENUMS);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_vector_of_enums() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_VECTOR_OF_ENUMS);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<MyGame::Example::Vec3>(verifier, VT_POS) &&
+ VerifyField<int16_t>(verifier, VT_MANA) &&
+ VerifyField<int16_t>(verifier, VT_HP) &&
+ VerifyOffsetRequired(verifier, VT_NAME) &&
+ verifier.VerifyString(name()) &&
+ VerifyOffset(verifier, VT_INVENTORY) &&
+ verifier.VerifyVector(inventory()) &&
+ VerifyField<uint8_t>(verifier, VT_COLOR) &&
+ VerifyField<uint8_t>(verifier, VT_TEST_TYPE) &&
+ VerifyOffset(verifier, VT_TEST) &&
+ VerifyAny(verifier, test(), test_type()) &&
+ VerifyOffset(verifier, VT_TEST4) &&
+ verifier.VerifyVector(test4()) &&
+ VerifyOffset(verifier, VT_TESTARRAYOFSTRING) &&
+ verifier.VerifyVector(testarrayofstring()) &&
+ verifier.VerifyVectorOfStrings(testarrayofstring()) &&
+ VerifyOffset(verifier, VT_TESTARRAYOFTABLES) &&
+ verifier.VerifyVector(testarrayoftables()) &&
+ verifier.VerifyVectorOfTables(testarrayoftables()) &&
+ VerifyOffset(verifier, VT_ENEMY) &&
+ verifier.VerifyTable(enemy()) &&
+ VerifyOffset(verifier, VT_TESTNESTEDFLATBUFFER) &&
+ verifier.VerifyVector(testnestedflatbuffer()) &&
+ VerifyOffset(verifier, VT_TESTEMPTY) &&
+ verifier.VerifyTable(testempty()) &&
+ VerifyField<uint8_t>(verifier, VT_TESTBOOL) &&
+ VerifyField<int32_t>(verifier, VT_TESTHASHS32_FNV1) &&
+ VerifyField<uint32_t>(verifier, VT_TESTHASHU32_FNV1) &&
+ VerifyField<int64_t>(verifier, VT_TESTHASHS64_FNV1) &&
+ VerifyField<uint64_t>(verifier, VT_TESTHASHU64_FNV1) &&
+ VerifyField<int32_t>(verifier, VT_TESTHASHS32_FNV1A) &&
+ VerifyField<uint32_t>(verifier, VT_TESTHASHU32_FNV1A) &&
+ VerifyField<int64_t>(verifier, VT_TESTHASHS64_FNV1A) &&
+ VerifyField<uint64_t>(verifier, VT_TESTHASHU64_FNV1A) &&
+ VerifyOffset(verifier, VT_TESTARRAYOFBOOLS) &&
+ verifier.VerifyVector(testarrayofbools()) &&
+ VerifyField<float>(verifier, VT_TESTF) &&
+ VerifyField<float>(verifier, VT_TESTF2) &&
+ VerifyField<float>(verifier, VT_TESTF3) &&
+ VerifyOffset(verifier, VT_TESTARRAYOFSTRING2) &&
+ verifier.VerifyVector(testarrayofstring2()) &&
+ verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
+ VerifyOffset(verifier, VT_TESTARRAYOFSORTEDSTRUCT) &&
+ verifier.VerifyVector(testarrayofsortedstruct()) &&
+ VerifyOffset(verifier, VT_FLEX) &&
+ verifier.VerifyVector(flex()) &&
+ VerifyOffset(verifier, VT_TEST5) &&
+ verifier.VerifyVector(test5()) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_LONGS) &&
+ verifier.VerifyVector(vector_of_longs()) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_DOUBLES) &&
+ verifier.VerifyVector(vector_of_doubles()) &&
+ VerifyOffset(verifier, VT_PARENT_NAMESPACE_TEST) &&
+ verifier.VerifyTable(parent_namespace_test()) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_REFERRABLES) &&
+ verifier.VerifyVector(vector_of_referrables()) &&
+ verifier.VerifyVectorOfTables(vector_of_referrables()) &&
+ VerifyField<uint64_t>(verifier, VT_SINGLE_WEAK_REFERENCE) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_WEAK_REFERENCES) &&
+ verifier.VerifyVector(vector_of_weak_references()) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_STRONG_REFERRABLES) &&
+ verifier.VerifyVector(vector_of_strong_referrables()) &&
+ verifier.VerifyVectorOfTables(vector_of_strong_referrables()) &&
+ VerifyField<uint64_t>(verifier, VT_CO_OWNING_REFERENCE) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_CO_OWNING_REFERENCES) &&
+ verifier.VerifyVector(vector_of_co_owning_references()) &&
+ VerifyField<uint64_t>(verifier, VT_NON_OWNING_REFERENCE) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_NON_OWNING_REFERENCES) &&
+ verifier.VerifyVector(vector_of_non_owning_references()) &&
+ VerifyField<uint8_t>(verifier, VT_ANY_UNIQUE_TYPE) &&
+ VerifyOffset(verifier, VT_ANY_UNIQUE) &&
+ VerifyAnyUniqueAliases(verifier, any_unique(), any_unique_type()) &&
+ VerifyField<uint8_t>(verifier, VT_ANY_AMBIGUOUS_TYPE) &&
+ VerifyOffset(verifier, VT_ANY_AMBIGUOUS) &&
+ VerifyAnyAmbiguousAliases(verifier, any_ambiguous(), any_ambiguous_type()) &&
+ VerifyOffset(verifier, VT_VECTOR_OF_ENUMS) &&
+ verifier.VerifyVector(vector_of_enums()) &&
+ verifier.EndTable();
+ }
+ MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+template<> inline const MyGame::Example::Monster *Monster::test_as<MyGame::Example::Monster>() const {
+ return test_as_Monster();
+}
+
+template<> inline const MyGame::Example::TestSimpleTableWithEnum *Monster::test_as<MyGame::Example::TestSimpleTableWithEnum>() const {
+ return test_as_TestSimpleTableWithEnum();
+}
+
+template<> inline const MyGame::Example2::Monster *Monster::test_as<MyGame::Example2::Monster>() const {
+ return test_as_MyGame_Example2_Monster();
+}
+
+template<> inline const MyGame::Example::Monster *Monster::any_unique_as<MyGame::Example::Monster>() const {
+ return any_unique_as_M();
+}
+
+template<> inline const MyGame::Example::TestSimpleTableWithEnum *Monster::any_unique_as<MyGame::Example::TestSimpleTableWithEnum>() const {
+ return any_unique_as_TS();
+}
+
+template<> inline const MyGame::Example2::Monster *Monster::any_unique_as<MyGame::Example2::Monster>() const {
+ return any_unique_as_M2();
+}
+
+struct MonsterBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_pos(const MyGame::Example::Vec3 *pos) {
+ fbb_.AddStruct(Monster::VT_POS, pos);
+ }
+ void add_mana(int16_t mana) {
+ fbb_.AddElement<int16_t>(Monster::VT_MANA, mana, 150);
+ }
+ void add_hp(int16_t hp) {
+ fbb_.AddElement<int16_t>(Monster::VT_HP, hp, 100);
+ }
+ void add_name(flatbuffers::Offset<flatbuffers::String> name) {
+ fbb_.AddOffset(Monster::VT_NAME, name);
+ }
+ void add_inventory(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory) {
+ fbb_.AddOffset(Monster::VT_INVENTORY, inventory);
+ }
+ void add_color(MyGame::Example::Color color) {
+ fbb_.AddElement<uint8_t>(Monster::VT_COLOR, static_cast<uint8_t>(color), 8);
+ }
+ void add_test_type(MyGame::Example::Any test_type) {
+ fbb_.AddElement<uint8_t>(Monster::VT_TEST_TYPE, static_cast<uint8_t>(test_type), 0);
+ }
+ void add_test(flatbuffers::Offset<void> test) {
+ fbb_.AddOffset(Monster::VT_TEST, test);
+ }
+ void add_test4(flatbuffers::Offset<flatbuffers::Vector<const MyGame::Example::Test *>> test4) {
+ fbb_.AddOffset(Monster::VT_TEST4, test4);
+ }
+ void add_testarrayofstring(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring) {
+ fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING, testarrayofstring);
+ }
+ void add_testarrayoftables(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Monster>>> testarrayoftables) {
+ fbb_.AddOffset(Monster::VT_TESTARRAYOFTABLES, testarrayoftables);
+ }
+ void add_enemy(flatbuffers::Offset<MyGame::Example::Monster> enemy) {
+ fbb_.AddOffset(Monster::VT_ENEMY, enemy);
+ }
+ void add_testnestedflatbuffer(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testnestedflatbuffer) {
+ fbb_.AddOffset(Monster::VT_TESTNESTEDFLATBUFFER, testnestedflatbuffer);
+ }
+ void add_testempty(flatbuffers::Offset<MyGame::Example::Stat> testempty) {
+ fbb_.AddOffset(Monster::VT_TESTEMPTY, testempty);
+ }
+ void add_testbool(bool testbool) {
+ fbb_.AddElement<uint8_t>(Monster::VT_TESTBOOL, static_cast<uint8_t>(testbool), 0);
+ }
+ void add_testhashs32_fnv1(int32_t testhashs32_fnv1) {
+ fbb_.AddElement<int32_t>(Monster::VT_TESTHASHS32_FNV1, testhashs32_fnv1, 0);
+ }
+ void add_testhashu32_fnv1(uint32_t testhashu32_fnv1) {
+ fbb_.AddElement<uint32_t>(Monster::VT_TESTHASHU32_FNV1, testhashu32_fnv1, 0);
+ }
+ void add_testhashs64_fnv1(int64_t testhashs64_fnv1) {
+ fbb_.AddElement<int64_t>(Monster::VT_TESTHASHS64_FNV1, testhashs64_fnv1, 0);
+ }
+ void add_testhashu64_fnv1(uint64_t testhashu64_fnv1) {
+ fbb_.AddElement<uint64_t>(Monster::VT_TESTHASHU64_FNV1, testhashu64_fnv1, 0);
+ }
+ void add_testhashs32_fnv1a(int32_t testhashs32_fnv1a) {
+ fbb_.AddElement<int32_t>(Monster::VT_TESTHASHS32_FNV1A, testhashs32_fnv1a, 0);
+ }
+ void add_testhashu32_fnv1a(uint32_t testhashu32_fnv1a) {
+ fbb_.AddElement<uint32_t>(Monster::VT_TESTHASHU32_FNV1A, testhashu32_fnv1a, 0);
+ }
+ void add_testhashs64_fnv1a(int64_t testhashs64_fnv1a) {
+ fbb_.AddElement<int64_t>(Monster::VT_TESTHASHS64_FNV1A, testhashs64_fnv1a, 0);
+ }
+ void add_testhashu64_fnv1a(uint64_t testhashu64_fnv1a) {
+ fbb_.AddElement<uint64_t>(Monster::VT_TESTHASHU64_FNV1A, testhashu64_fnv1a, 0);
+ }
+ void add_testarrayofbools(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testarrayofbools) {
+ fbb_.AddOffset(Monster::VT_TESTARRAYOFBOOLS, testarrayofbools);
+ }
+ void add_testf(float testf) {
+ fbb_.AddElement<float>(Monster::VT_TESTF, testf, 3.14159f);
+ }
+ void add_testf2(float testf2) {
+ fbb_.AddElement<float>(Monster::VT_TESTF2, testf2, 3.0f);
+ }
+ void add_testf3(float testf3) {
+ fbb_.AddElement<float>(Monster::VT_TESTF3, testf3, 0.0f);
+ }
+ void add_testarrayofstring2(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2) {
+ fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2);
+ }
+ void add_testarrayofsortedstruct(flatbuffers::Offset<flatbuffers::Vector<const MyGame::Example::Ability *>> testarrayofsortedstruct) {
+ fbb_.AddOffset(Monster::VT_TESTARRAYOFSORTEDSTRUCT, testarrayofsortedstruct);
+ }
+ void add_flex(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex) {
+ fbb_.AddOffset(Monster::VT_FLEX, flex);
+ }
+ void add_test5(flatbuffers::Offset<flatbuffers::Vector<const MyGame::Example::Test *>> test5) {
+ fbb_.AddOffset(Monster::VT_TEST5, test5);
+ }
+ void add_vector_of_longs(flatbuffers::Offset<flatbuffers::Vector<int64_t>> vector_of_longs) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_LONGS, vector_of_longs);
+ }
+ void add_vector_of_doubles(flatbuffers::Offset<flatbuffers::Vector<double>> vector_of_doubles) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_DOUBLES, vector_of_doubles);
+ }
+ void add_parent_namespace_test(flatbuffers::Offset<MyGame::InParentNamespace> parent_namespace_test) {
+ fbb_.AddOffset(Monster::VT_PARENT_NAMESPACE_TEST, parent_namespace_test);
+ }
+ void add_vector_of_referrables(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>>> vector_of_referrables) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_REFERRABLES, vector_of_referrables);
+ }
+ void add_single_weak_reference(uint64_t single_weak_reference) {
+ fbb_.AddElement<uint64_t>(Monster::VT_SINGLE_WEAK_REFERENCE, single_weak_reference, 0);
+ }
+ void add_vector_of_weak_references(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> vector_of_weak_references) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_WEAK_REFERENCES, vector_of_weak_references);
+ }
+ void add_vector_of_strong_referrables(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>>> vector_of_strong_referrables) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_STRONG_REFERRABLES, vector_of_strong_referrables);
+ }
+ void add_co_owning_reference(uint64_t co_owning_reference) {
+ fbb_.AddElement<uint64_t>(Monster::VT_CO_OWNING_REFERENCE, co_owning_reference, 0);
+ }
+ void add_vector_of_co_owning_references(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> vector_of_co_owning_references) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_CO_OWNING_REFERENCES, vector_of_co_owning_references);
+ }
+ void add_non_owning_reference(uint64_t non_owning_reference) {
+ fbb_.AddElement<uint64_t>(Monster::VT_NON_OWNING_REFERENCE, non_owning_reference, 0);
+ }
+ void add_vector_of_non_owning_references(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> vector_of_non_owning_references) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_NON_OWNING_REFERENCES, vector_of_non_owning_references);
+ }
+ void add_any_unique_type(MyGame::Example::AnyUniqueAliases any_unique_type) {
+ fbb_.AddElement<uint8_t>(Monster::VT_ANY_UNIQUE_TYPE, static_cast<uint8_t>(any_unique_type), 0);
+ }
+ void add_any_unique(flatbuffers::Offset<void> any_unique) {
+ fbb_.AddOffset(Monster::VT_ANY_UNIQUE, any_unique);
+ }
+ void add_any_ambiguous_type(MyGame::Example::AnyAmbiguousAliases any_ambiguous_type) {
+ fbb_.AddElement<uint8_t>(Monster::VT_ANY_AMBIGUOUS_TYPE, static_cast<uint8_t>(any_ambiguous_type), 0);
+ }
+ void add_any_ambiguous(flatbuffers::Offset<void> any_ambiguous) {
+ fbb_.AddOffset(Monster::VT_ANY_AMBIGUOUS, any_ambiguous);
+ }
+ void add_vector_of_enums(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> vector_of_enums) {
+ fbb_.AddOffset(Monster::VT_VECTOR_OF_ENUMS, vector_of_enums);
+ }
+ explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ MonsterBuilder &operator=(const MonsterBuilder &);
+ flatbuffers::Offset<Monster> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Monster>(end);
+ fbb_.Required(o, Monster::VT_NAME);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Monster> CreateMonster(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const MyGame::Example::Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ flatbuffers::Offset<flatbuffers::String> name = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> inventory = 0,
+ MyGame::Example::Color color = MyGame::Example::Color_Blue,
+ MyGame::Example::Any test_type = MyGame::Example::Any_NONE,
+ flatbuffers::Offset<void> test = 0,
+ flatbuffers::Offset<flatbuffers::Vector<const MyGame::Example::Test *>> test4 = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Monster>>> testarrayoftables = 0,
+ flatbuffers::Offset<MyGame::Example::Monster> enemy = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testnestedflatbuffer = 0,
+ flatbuffers::Offset<MyGame::Example::Stat> testempty = 0,
+ bool testbool = false,
+ int32_t testhashs32_fnv1 = 0,
+ uint32_t testhashu32_fnv1 = 0,
+ int64_t testhashs64_fnv1 = 0,
+ uint64_t testhashu64_fnv1 = 0,
+ int32_t testhashs32_fnv1a = 0,
+ uint32_t testhashu32_fnv1a = 0,
+ int64_t testhashs64_fnv1a = 0,
+ uint64_t testhashu64_fnv1a = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testarrayofbools = 0,
+ float testf = 3.14159f,
+ float testf2 = 3.0f,
+ float testf3 = 0.0f,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0,
+ flatbuffers::Offset<flatbuffers::Vector<const MyGame::Example::Ability *>> testarrayofsortedstruct = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex = 0,
+ flatbuffers::Offset<flatbuffers::Vector<const MyGame::Example::Test *>> test5 = 0,
+ flatbuffers::Offset<flatbuffers::Vector<int64_t>> vector_of_longs = 0,
+ flatbuffers::Offset<flatbuffers::Vector<double>> vector_of_doubles = 0,
+ flatbuffers::Offset<MyGame::InParentNamespace> parent_namespace_test = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>>> vector_of_referrables = 0,
+ uint64_t single_weak_reference = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint64_t>> vector_of_weak_references = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<MyGame::Example::Referrable>>> vector_of_strong_referrables = 0,
+ uint64_t co_owning_reference = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint64_t>> vector_of_co_owning_references = 0,
+ uint64_t non_owning_reference = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint64_t>> vector_of_non_owning_references = 0,
+ MyGame::Example::AnyUniqueAliases any_unique_type = MyGame::Example::AnyUniqueAliases_NONE,
+ flatbuffers::Offset<void> any_unique = 0,
+ MyGame::Example::AnyAmbiguousAliases any_ambiguous_type = MyGame::Example::AnyAmbiguousAliases_NONE,
+ flatbuffers::Offset<void> any_ambiguous = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> vector_of_enums = 0) {
+ MonsterBuilder builder_(_fbb);
+ builder_.add_non_owning_reference(non_owning_reference);
+ builder_.add_co_owning_reference(co_owning_reference);
+ builder_.add_single_weak_reference(single_weak_reference);
+ builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
+ builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
+ builder_.add_testhashu64_fnv1(testhashu64_fnv1);
+ builder_.add_testhashs64_fnv1(testhashs64_fnv1);
+ builder_.add_vector_of_enums(vector_of_enums);
+ builder_.add_any_ambiguous(any_ambiguous);
+ builder_.add_any_unique(any_unique);
+ builder_.add_vector_of_non_owning_references(vector_of_non_owning_references);
+ builder_.add_vector_of_co_owning_references(vector_of_co_owning_references);
+ builder_.add_vector_of_strong_referrables(vector_of_strong_referrables);
+ builder_.add_vector_of_weak_references(vector_of_weak_references);
+ builder_.add_vector_of_referrables(vector_of_referrables);
+ builder_.add_parent_namespace_test(parent_namespace_test);
+ builder_.add_vector_of_doubles(vector_of_doubles);
+ builder_.add_vector_of_longs(vector_of_longs);
+ builder_.add_test5(test5);
+ builder_.add_flex(flex);
+ builder_.add_testarrayofsortedstruct(testarrayofsortedstruct);
+ builder_.add_testarrayofstring2(testarrayofstring2);
+ builder_.add_testf3(testf3);
+ builder_.add_testf2(testf2);
+ builder_.add_testf(testf);
+ builder_.add_testarrayofbools(testarrayofbools);
+ builder_.add_testhashu32_fnv1a(testhashu32_fnv1a);
+ builder_.add_testhashs32_fnv1a(testhashs32_fnv1a);
+ builder_.add_testhashu32_fnv1(testhashu32_fnv1);
+ builder_.add_testhashs32_fnv1(testhashs32_fnv1);
+ builder_.add_testempty(testempty);
+ builder_.add_testnestedflatbuffer(testnestedflatbuffer);
+ builder_.add_enemy(enemy);
+ builder_.add_testarrayoftables(testarrayoftables);
+ builder_.add_testarrayofstring(testarrayofstring);
+ builder_.add_test4(test4);
+ builder_.add_test(test);
+ builder_.add_inventory(inventory);
+ builder_.add_name(name);
+ builder_.add_pos(pos);
+ builder_.add_hp(hp);
+ builder_.add_mana(mana);
+ builder_.add_any_ambiguous_type(any_ambiguous_type);
+ builder_.add_any_unique_type(any_unique_type);
+ builder_.add_testbool(testbool);
+ builder_.add_test_type(test_type);
+ builder_.add_color(color);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Monster> CreateMonsterDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const MyGame::Example::Vec3 *pos = 0,
+ int16_t mana = 150,
+ int16_t hp = 100,
+ const char *name = nullptr,
+ const std::vector<uint8_t> *inventory = nullptr,
+ MyGame::Example::Color color = MyGame::Example::Color_Blue,
+ MyGame::Example::Any test_type = MyGame::Example::Any_NONE,
+ flatbuffers::Offset<void> test = 0,
+ const std::vector<MyGame::Example::Test> *test4 = nullptr,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring = nullptr,
+ const std::vector<flatbuffers::Offset<MyGame::Example::Monster>> *testarrayoftables = nullptr,
+ flatbuffers::Offset<MyGame::Example::Monster> enemy = 0,
+ const std::vector<uint8_t> *testnestedflatbuffer = nullptr,
+ flatbuffers::Offset<MyGame::Example::Stat> testempty = 0,
+ bool testbool = false,
+ int32_t testhashs32_fnv1 = 0,
+ uint32_t testhashu32_fnv1 = 0,
+ int64_t testhashs64_fnv1 = 0,
+ uint64_t testhashu64_fnv1 = 0,
+ int32_t testhashs32_fnv1a = 0,
+ uint32_t testhashu32_fnv1a = 0,
+ int64_t testhashs64_fnv1a = 0,
+ uint64_t testhashu64_fnv1a = 0,
+ const std::vector<uint8_t> *testarrayofbools = nullptr,
+ float testf = 3.14159f,
+ float testf2 = 3.0f,
+ float testf3 = 0.0f,
+ const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr,
+ const std::vector<MyGame::Example::Ability> *testarrayofsortedstruct = nullptr,
+ const std::vector<uint8_t> *flex = nullptr,
+ const std::vector<MyGame::Example::Test> *test5 = nullptr,
+ const std::vector<int64_t> *vector_of_longs = nullptr,
+ const std::vector<double> *vector_of_doubles = nullptr,
+ flatbuffers::Offset<MyGame::InParentNamespace> parent_namespace_test = 0,
+ const std::vector<flatbuffers::Offset<MyGame::Example::Referrable>> *vector_of_referrables = nullptr,
+ uint64_t single_weak_reference = 0,
+ const std::vector<uint64_t> *vector_of_weak_references = nullptr,
+ const std::vector<flatbuffers::Offset<MyGame::Example::Referrable>> *vector_of_strong_referrables = nullptr,
+ uint64_t co_owning_reference = 0,
+ const std::vector<uint64_t> *vector_of_co_owning_references = nullptr,
+ uint64_t non_owning_reference = 0,
+ const std::vector<uint64_t> *vector_of_non_owning_references = nullptr,
+ MyGame::Example::AnyUniqueAliases any_unique_type = MyGame::Example::AnyUniqueAliases_NONE,
+ flatbuffers::Offset<void> any_unique = 0,
+ MyGame::Example::AnyAmbiguousAliases any_ambiguous_type = MyGame::Example::AnyAmbiguousAliases_NONE,
+ flatbuffers::Offset<void> any_ambiguous = 0,
+ const std::vector<uint8_t> *vector_of_enums = nullptr) {
+ auto name__ = name ? _fbb.CreateString(name) : 0;
+ auto inventory__ = inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0;
+ auto test4__ = test4 ? _fbb.CreateVectorOfStructs<MyGame::Example::Test>(*test4) : 0;
+ auto testarrayofstring__ = testarrayofstring ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring) : 0;
+ auto testarrayoftables__ = testarrayoftables ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Example::Monster>>(*testarrayoftables) : 0;
+ auto testnestedflatbuffer__ = testnestedflatbuffer ? _fbb.CreateVector<uint8_t>(*testnestedflatbuffer) : 0;
+ auto testarrayofbools__ = testarrayofbools ? _fbb.CreateVector<uint8_t>(*testarrayofbools) : 0;
+ auto testarrayofstring2__ = testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0;
+ auto testarrayofsortedstruct__ = testarrayofsortedstruct ? _fbb.CreateVectorOfStructs<MyGame::Example::Ability>(*testarrayofsortedstruct) : 0;
+ auto flex__ = flex ? _fbb.CreateVector<uint8_t>(*flex) : 0;
+ auto test5__ = test5 ? _fbb.CreateVectorOfStructs<MyGame::Example::Test>(*test5) : 0;
+ auto vector_of_longs__ = vector_of_longs ? _fbb.CreateVector<int64_t>(*vector_of_longs) : 0;
+ auto vector_of_doubles__ = vector_of_doubles ? _fbb.CreateVector<double>(*vector_of_doubles) : 0;
+ auto vector_of_referrables__ = vector_of_referrables ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Example::Referrable>>(*vector_of_referrables) : 0;
+ auto vector_of_weak_references__ = vector_of_weak_references ? _fbb.CreateVector<uint64_t>(*vector_of_weak_references) : 0;
+ auto vector_of_strong_referrables__ = vector_of_strong_referrables ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Example::Referrable>>(*vector_of_strong_referrables) : 0;
+ auto vector_of_co_owning_references__ = vector_of_co_owning_references ? _fbb.CreateVector<uint64_t>(*vector_of_co_owning_references) : 0;
+ auto vector_of_non_owning_references__ = vector_of_non_owning_references ? _fbb.CreateVector<uint64_t>(*vector_of_non_owning_references) : 0;
+ auto vector_of_enums__ = vector_of_enums ? _fbb.CreateVector<uint8_t>(*vector_of_enums) : 0;
+ return MyGame::Example::CreateMonster(
+ _fbb,
+ pos,
+ mana,
+ hp,
+ name__,
+ inventory__,
+ color,
+ test_type,
+ test,
+ test4__,
+ testarrayofstring__,
+ testarrayoftables__,
+ enemy,
+ testnestedflatbuffer__,
+ testempty,
+ testbool,
+ testhashs32_fnv1,
+ testhashu32_fnv1,
+ testhashs64_fnv1,
+ testhashu64_fnv1,
+ testhashs32_fnv1a,
+ testhashu32_fnv1a,
+ testhashs64_fnv1a,
+ testhashu64_fnv1a,
+ testarrayofbools__,
+ testf,
+ testf2,
+ testf3,
+ testarrayofstring2__,
+ testarrayofsortedstruct__,
+ flex__,
+ test5__,
+ vector_of_longs__,
+ vector_of_doubles__,
+ parent_namespace_test,
+ vector_of_referrables__,
+ single_weak_reference,
+ vector_of_weak_references__,
+ vector_of_strong_referrables__,
+ co_owning_reference,
+ vector_of_co_owning_references__,
+ non_owning_reference,
+ vector_of_non_owning_references__,
+ any_unique_type,
+ any_unique,
+ any_ambiguous_type,
+ any_ambiguous,
+ vector_of_enums__);
+}
+
+flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct TypeAliasesT : public flatbuffers::NativeTable {
+ typedef TypeAliases TableType;
+ int8_t i8;
+ uint8_t u8;
+ int16_t i16;
+ uint16_t u16;
+ int32_t i32;
+ uint32_t u32;
+ int64_t i64;
+ uint64_t u64;
+ float f32;
+ double f64;
+ std::vector<int8_t> v8;
+ std::vector<double> vf64;
+ TypeAliasesT()
+ : i8(0),
+ u8(0),
+ i16(0),
+ u16(0),
+ i32(0),
+ u32(0),
+ i64(0),
+ u64(0),
+ f32(0.0f),
+ f64(0.0) {
+ }
+};
+
+inline bool operator==(const TypeAliasesT &lhs, const TypeAliasesT &rhs) {
+ return
+ (lhs.i8 == rhs.i8) &&
+ (lhs.u8 == rhs.u8) &&
+ (lhs.i16 == rhs.i16) &&
+ (lhs.u16 == rhs.u16) &&
+ (lhs.i32 == rhs.i32) &&
+ (lhs.u32 == rhs.u32) &&
+ (lhs.i64 == rhs.i64) &&
+ (lhs.u64 == rhs.u64) &&
+ (lhs.f32 == rhs.f32) &&
+ (lhs.f64 == rhs.f64) &&
+ (lhs.v8 == rhs.v8) &&
+ (lhs.vf64 == rhs.vf64);
+}
+
+inline bool operator!=(const TypeAliasesT &lhs, const TypeAliasesT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct TypeAliases FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef TypeAliasesT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return TypeAliasesTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_I8 = 4,
+ VT_U8 = 6,
+ VT_I16 = 8,
+ VT_U16 = 10,
+ VT_I32 = 12,
+ VT_U32 = 14,
+ VT_I64 = 16,
+ VT_U64 = 18,
+ VT_F32 = 20,
+ VT_F64 = 22,
+ VT_V8 = 24,
+ VT_VF64 = 26
+ };
+ int8_t i8() const {
+ return GetField<int8_t>(VT_I8, 0);
+ }
+ bool mutate_i8(int8_t _i8) {
+ return SetField<int8_t>(VT_I8, _i8, 0);
+ }
+ uint8_t u8() const {
+ return GetField<uint8_t>(VT_U8, 0);
+ }
+ bool mutate_u8(uint8_t _u8) {
+ return SetField<uint8_t>(VT_U8, _u8, 0);
+ }
+ int16_t i16() const {
+ return GetField<int16_t>(VT_I16, 0);
+ }
+ bool mutate_i16(int16_t _i16) {
+ return SetField<int16_t>(VT_I16, _i16, 0);
+ }
+ uint16_t u16() const {
+ return GetField<uint16_t>(VT_U16, 0);
+ }
+ bool mutate_u16(uint16_t _u16) {
+ return SetField<uint16_t>(VT_U16, _u16, 0);
+ }
+ int32_t i32() const {
+ return GetField<int32_t>(VT_I32, 0);
+ }
+ bool mutate_i32(int32_t _i32) {
+ return SetField<int32_t>(VT_I32, _i32, 0);
+ }
+ uint32_t u32() const {
+ return GetField<uint32_t>(VT_U32, 0);
+ }
+ bool mutate_u32(uint32_t _u32) {
+ return SetField<uint32_t>(VT_U32, _u32, 0);
+ }
+ int64_t i64() const {
+ return GetField<int64_t>(VT_I64, 0);
+ }
+ bool mutate_i64(int64_t _i64) {
+ return SetField<int64_t>(VT_I64, _i64, 0);
+ }
+ uint64_t u64() const {
+ return GetField<uint64_t>(VT_U64, 0);
+ }
+ bool mutate_u64(uint64_t _u64) {
+ return SetField<uint64_t>(VT_U64, _u64, 0);
+ }
+ float f32() const {
+ return GetField<float>(VT_F32, 0.0f);
+ }
+ bool mutate_f32(float _f32) {
+ return SetField<float>(VT_F32, _f32, 0.0f);
+ }
+ double f64() const {
+ return GetField<double>(VT_F64, 0.0);
+ }
+ bool mutate_f64(double _f64) {
+ return SetField<double>(VT_F64, _f64, 0.0);
+ }
+ const flatbuffers::Vector<int8_t> *v8() const {
+ return GetPointer<const flatbuffers::Vector<int8_t> *>(VT_V8);
+ }
+ flatbuffers::Vector<int8_t> *mutable_v8() {
+ return GetPointer<flatbuffers::Vector<int8_t> *>(VT_V8);
+ }
+ const flatbuffers::Vector<double> *vf64() const {
+ return GetPointer<const flatbuffers::Vector<double> *>(VT_VF64);
+ }
+ flatbuffers::Vector<double> *mutable_vf64() {
+ return GetPointer<flatbuffers::Vector<double> *>(VT_VF64);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int8_t>(verifier, VT_I8) &&
+ VerifyField<uint8_t>(verifier, VT_U8) &&
+ VerifyField<int16_t>(verifier, VT_I16) &&
+ VerifyField<uint16_t>(verifier, VT_U16) &&
+ VerifyField<int32_t>(verifier, VT_I32) &&
+ VerifyField<uint32_t>(verifier, VT_U32) &&
+ VerifyField<int64_t>(verifier, VT_I64) &&
+ VerifyField<uint64_t>(verifier, VT_U64) &&
+ VerifyField<float>(verifier, VT_F32) &&
+ VerifyField<double>(verifier, VT_F64) &&
+ VerifyOffset(verifier, VT_V8) &&
+ verifier.VerifyVector(v8()) &&
+ VerifyOffset(verifier, VT_VF64) &&
+ verifier.VerifyVector(vf64()) &&
+ verifier.EndTable();
+ }
+ TypeAliasesT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(TypeAliasesT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<TypeAliases> Pack(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct TypeAliasesBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_i8(int8_t i8) {
+ fbb_.AddElement<int8_t>(TypeAliases::VT_I8, i8, 0);
+ }
+ void add_u8(uint8_t u8) {
+ fbb_.AddElement<uint8_t>(TypeAliases::VT_U8, u8, 0);
+ }
+ void add_i16(int16_t i16) {
+ fbb_.AddElement<int16_t>(TypeAliases::VT_I16, i16, 0);
+ }
+ void add_u16(uint16_t u16) {
+ fbb_.AddElement<uint16_t>(TypeAliases::VT_U16, u16, 0);
+ }
+ void add_i32(int32_t i32) {
+ fbb_.AddElement<int32_t>(TypeAliases::VT_I32, i32, 0);
+ }
+ void add_u32(uint32_t u32) {
+ fbb_.AddElement<uint32_t>(TypeAliases::VT_U32, u32, 0);
+ }
+ void add_i64(int64_t i64) {
+ fbb_.AddElement<int64_t>(TypeAliases::VT_I64, i64, 0);
+ }
+ void add_u64(uint64_t u64) {
+ fbb_.AddElement<uint64_t>(TypeAliases::VT_U64, u64, 0);
+ }
+ void add_f32(float f32) {
+ fbb_.AddElement<float>(TypeAliases::VT_F32, f32, 0.0f);
+ }
+ void add_f64(double f64) {
+ fbb_.AddElement<double>(TypeAliases::VT_F64, f64, 0.0);
+ }
+ void add_v8(flatbuffers::Offset<flatbuffers::Vector<int8_t>> v8) {
+ fbb_.AddOffset(TypeAliases::VT_V8, v8);
+ }
+ void add_vf64(flatbuffers::Offset<flatbuffers::Vector<double>> vf64) {
+ fbb_.AddOffset(TypeAliases::VT_VF64, vf64);
+ }
+ explicit TypeAliasesBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ TypeAliasesBuilder &operator=(const TypeAliasesBuilder &);
+ flatbuffers::Offset<TypeAliases> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TypeAliases>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TypeAliases> CreateTypeAliases(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ int8_t i8 = 0,
+ uint8_t u8 = 0,
+ int16_t i16 = 0,
+ uint16_t u16 = 0,
+ int32_t i32 = 0,
+ uint32_t u32 = 0,
+ int64_t i64 = 0,
+ uint64_t u64 = 0,
+ float f32 = 0.0f,
+ double f64 = 0.0,
+ flatbuffers::Offset<flatbuffers::Vector<int8_t>> v8 = 0,
+ flatbuffers::Offset<flatbuffers::Vector<double>> vf64 = 0) {
+ TypeAliasesBuilder builder_(_fbb);
+ builder_.add_f64(f64);
+ builder_.add_u64(u64);
+ builder_.add_i64(i64);
+ builder_.add_vf64(vf64);
+ builder_.add_v8(v8);
+ builder_.add_f32(f32);
+ builder_.add_u32(u32);
+ builder_.add_i32(i32);
+ builder_.add_u16(u16);
+ builder_.add_i16(i16);
+ builder_.add_u8(u8);
+ builder_.add_i8(i8);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<TypeAliases> CreateTypeAliasesDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ int8_t i8 = 0,
+ uint8_t u8 = 0,
+ int16_t i16 = 0,
+ uint16_t u16 = 0,
+ int32_t i32 = 0,
+ uint32_t u32 = 0,
+ int64_t i64 = 0,
+ uint64_t u64 = 0,
+ float f32 = 0.0f,
+ double f64 = 0.0,
+ const std::vector<int8_t> *v8 = nullptr,
+ const std::vector<double> *vf64 = nullptr) {
+ auto v8__ = v8 ? _fbb.CreateVector<int8_t>(*v8) : 0;
+ auto vf64__ = vf64 ? _fbb.CreateVector<double>(*vf64) : 0;
+ return MyGame::Example::CreateTypeAliases(
+ _fbb,
+ i8,
+ u8,
+ i16,
+ u16,
+ i32,
+ u32,
+ i64,
+ u64,
+ f32,
+ f64,
+ v8__,
+ vf64__);
+}
+
+flatbuffers::Offset<TypeAliases> CreateTypeAliases(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+} // namespace Example
+
+inline InParentNamespaceT *InParentNamespace::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new InParentNamespaceT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void InParentNamespace::UnPackTo(InParentNamespaceT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+}
+
+inline flatbuffers::Offset<InParentNamespace> InParentNamespace::Pack(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateInParentNamespace(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const InParentNamespaceT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ return MyGame::CreateInParentNamespace(
+ _fbb);
+}
+
+namespace Example2 {
+
+inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new MonsterT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+}
+
+inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonster(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ return MyGame::Example2::CreateMonster(
+ _fbb);
+}
+
+} // namespace Example2
+
+namespace Example {
+
+inline TestSimpleTableWithEnumT *TestSimpleTableWithEnum::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new TestSimpleTableWithEnumT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void TestSimpleTableWithEnum::UnPackTo(TestSimpleTableWithEnumT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = color(); _o->color = _e; };
+}
+
+inline flatbuffers::Offset<TestSimpleTableWithEnum> TestSimpleTableWithEnum::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateTestSimpleTableWithEnum(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TestSimpleTableWithEnumT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _color = _o->color;
+ return MyGame::Example::CreateTestSimpleTableWithEnum(
+ _fbb,
+ _color);
+}
+
+inline StatT *Stat::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new StatT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Stat::UnPackTo(StatT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = id(); if (_e) _o->id = _e->str(); };
+ { auto _e = val(); _o->val = _e; };
+ { auto _e = count(); _o->count = _e; };
+}
+
+inline flatbuffers::Offset<Stat> Stat::Pack(flatbuffers::FlatBufferBuilder &_fbb, const StatT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateStat(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const StatT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _id = _o->id.empty() ? 0 : _fbb.CreateString(_o->id);
+ auto _val = _o->val;
+ auto _count = _o->count;
+ return MyGame::Example::CreateStat(
+ _fbb,
+ _id,
+ _val,
+ _count);
+}
+
+inline ReferrableT *Referrable::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new ReferrableT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Referrable::UnPackTo(ReferrableT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = id(); _o->id = _e; };
+}
+
+inline flatbuffers::Offset<Referrable> Referrable::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ReferrableT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateReferrable(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Referrable> CreateReferrable(flatbuffers::FlatBufferBuilder &_fbb, const ReferrableT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ReferrableT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _id = _o->id;
+ return MyGame::Example::CreateReferrable(
+ _fbb,
+ _id);
+}
+
+inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new MonsterT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = pos(); if (_e) _o->pos = flatbuffers::unique_ptr<MyGame::Example::Vec3>(new MyGame::Example::Vec3(*_e)); };
+ { auto _e = mana(); _o->mana = _e; };
+ { auto _e = hp(); _o->hp = _e; };
+ { auto _e = name(); if (_e) _o->name = _e->str(); };
+ { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
+ { auto _e = color(); _o->color = _e; };
+ { auto _e = test_type(); _o->test.type = _e; };
+ { auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); };
+ { auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } };
+ { auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } };
+ { auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = flatbuffers::unique_ptr<MyGame::Example::MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
+ { auto _e = enemy(); if (_e) _o->enemy = flatbuffers::unique_ptr<MyGame::Example::MonsterT>(_e->UnPack(_resolver)); };
+ { auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer[_i] = _e->Get(_i); } } };
+ { auto _e = testempty(); if (_e) _o->testempty = flatbuffers::unique_ptr<MyGame::Example::StatT>(_e->UnPack(_resolver)); };
+ { auto _e = testbool(); _o->testbool = _e; };
+ { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; };
+ { auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; };
+ { auto _e = testhashs64_fnv1(); _o->testhashs64_fnv1 = _e; };
+ { auto _e = testhashu64_fnv1(); _o->testhashu64_fnv1 = _e; };
+ { auto _e = testhashs32_fnv1a(); _o->testhashs32_fnv1a = _e; };
+ { auto _e = testhashu32_fnv1a(); //scalar resolver, naked
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->testhashu32_fnv1a), static_cast<flatbuffers::hash_value_t>(_e)); else _o->testhashu32_fnv1a = nullptr; };
+ { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; };
+ { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; };
+ { auto _e = testarrayofbools(); if (_e) { _o->testarrayofbools.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools[_i] = _e->Get(_i) != 0; } } };
+ { auto _e = testf(); _o->testf = _e; };
+ { auto _e = testf2(); _o->testf2 = _e; };
+ { auto _e = testf3(); _o->testf3 = _e; };
+ { auto _e = testarrayofstring2(); if (_e) { _o->testarrayofstring2.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2[_i] = _e->Get(_i)->str(); } } };
+ { auto _e = testarrayofsortedstruct(); if (_e) { _o->testarrayofsortedstruct.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofsortedstruct[_i] = *_e->Get(_i); } } };
+ { auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->flex[_i] = _e->Get(_i); } } };
+ { auto _e = test5(); if (_e) { _o->test5.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test5[_i] = *_e->Get(_i); } } };
+ { auto _e = vector_of_longs(); if (_e) { _o->vector_of_longs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_longs[_i] = _e->Get(_i); } } };
+ { auto _e = vector_of_doubles(); if (_e) { _o->vector_of_doubles.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_doubles[_i] = _e->Get(_i); } } };
+ { auto _e = parent_namespace_test(); if (_e) _o->parent_namespace_test = flatbuffers::unique_ptr<MyGame::InParentNamespaceT>(_e->UnPack(_resolver)); };
+ { auto _e = vector_of_referrables(); if (_e) { _o->vector_of_referrables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_referrables[_i] = flatbuffers::unique_ptr<MyGame::Example::ReferrableT>(_e->Get(_i)->UnPack(_resolver)); } } };
+ { auto _e = single_weak_reference(); //scalar resolver, naked
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->single_weak_reference), static_cast<flatbuffers::hash_value_t>(_e)); else _o->single_weak_reference = nullptr; };
+ { auto _e = vector_of_weak_references(); if (_e) { _o->vector_of_weak_references.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { //vector resolver, naked
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->vector_of_weak_references[_i]), static_cast<flatbuffers::hash_value_t>(_e->Get(_i))); else _o->vector_of_weak_references[_i] = nullptr; } } };
+ { auto _e = vector_of_strong_referrables(); if (_e) { _o->vector_of_strong_referrables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_strong_referrables[_i] = flatbuffers::unique_ptr<MyGame::Example::ReferrableT>(_e->Get(_i)->UnPack(_resolver)); } } };
+ { auto _e = co_owning_reference(); //scalar resolver, naked
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->co_owning_reference), static_cast<flatbuffers::hash_value_t>(_e)); else _o->co_owning_reference = nullptr; };
+ { auto _e = vector_of_co_owning_references(); if (_e) { _o->vector_of_co_owning_references.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { //vector resolver, default_ptr_type
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->vector_of_co_owning_references[_i]), static_cast<flatbuffers::hash_value_t>(_e->Get(_i)));/* else do nothing */; } } };
+ { auto _e = non_owning_reference(); //scalar resolver, naked
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->non_owning_reference), static_cast<flatbuffers::hash_value_t>(_e)); else _o->non_owning_reference = nullptr; };
+ { auto _e = vector_of_non_owning_references(); if (_e) { _o->vector_of_non_owning_references.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { //vector resolver, naked
+if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->vector_of_non_owning_references[_i]), static_cast<flatbuffers::hash_value_t>(_e->Get(_i))); else _o->vector_of_non_owning_references[_i] = nullptr; } } };
+ { auto _e = any_unique_type(); _o->any_unique.type = _e; };
+ { auto _e = any_unique(); if (_e) _o->any_unique.value = AnyUniqueAliasesUnion::UnPack(_e, any_unique_type(), _resolver); };
+ { auto _e = any_ambiguous_type(); _o->any_ambiguous.type = _e; };
+ { auto _e = any_ambiguous(); if (_e) _o->any_ambiguous.value = AnyAmbiguousAliasesUnion::UnPack(_e, any_ambiguous_type(), _resolver); };
+ { auto _e = vector_of_enums(); if (_e) { _o->vector_of_enums.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_enums[_i] = static_cast<MyGame::Example::Color>(_e->Get(_i)); } } };
+}
+
+inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMonster(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _pos = _o->pos ? _o->pos.get() : 0;
+ auto _mana = _o->mana;
+ auto _hp = _o->hp;
+ auto _name = _fbb.CreateString(_o->name);
+ auto _inventory = _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0;
+ auto _color = _o->color;
+ auto _test_type = _o->test.type;
+ auto _test = _o->test.Pack(_fbb);
+ auto _test4 = _o->test4.size() ? _fbb.CreateVectorOfStructs(_o->test4) : 0;
+ auto _testarrayofstring = _o->testarrayofstring.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring) : 0;
+ auto _testarrayoftables = _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Example::Monster>> (_o->testarrayoftables.size(), [](size_t i, _VectorArgs *__va) { return CreateMonster(*__va->__fbb, __va->__o->testarrayoftables[i].get(), __va->__rehasher); }, &_va ) : 0;
+ auto _enemy = _o->enemy ? CreateMonster(_fbb, _o->enemy.get(), _rehasher) : 0;
+ auto _testnestedflatbuffer = _o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0;
+ auto _testempty = _o->testempty ? CreateStat(_fbb, _o->testempty.get(), _rehasher) : 0;
+ auto _testbool = _o->testbool;
+ auto _testhashs32_fnv1 = _o->testhashs32_fnv1;
+ auto _testhashu32_fnv1 = _o->testhashu32_fnv1;
+ auto _testhashs64_fnv1 = _o->testhashs64_fnv1;
+ auto _testhashu64_fnv1 = _o->testhashu64_fnv1;
+ auto _testhashs32_fnv1a = _o->testhashs32_fnv1a;
+ auto _testhashu32_fnv1a = _rehasher ? static_cast<uint32_t>((*_rehasher)(_o->testhashu32_fnv1a)) : 0;
+ auto _testhashs64_fnv1a = _o->testhashs64_fnv1a;
+ auto _testhashu64_fnv1a = _o->testhashu64_fnv1a;
+ auto _testarrayofbools = _o->testarrayofbools.size() ? _fbb.CreateVector(_o->testarrayofbools) : 0;
+ auto _testf = _o->testf;
+ auto _testf2 = _o->testf2;
+ auto _testf3 = _o->testf3;
+ auto _testarrayofstring2 = _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0;
+ auto _testarrayofsortedstruct = _o->testarrayofsortedstruct.size() ? _fbb.CreateVectorOfStructs(_o->testarrayofsortedstruct) : 0;
+ auto _flex = _o->flex.size() ? _fbb.CreateVector(_o->flex) : 0;
+ auto _test5 = _o->test5.size() ? _fbb.CreateVectorOfStructs(_o->test5) : 0;
+ auto _vector_of_longs = _o->vector_of_longs.size() ? _fbb.CreateVector(_o->vector_of_longs) : 0;
+ auto _vector_of_doubles = _o->vector_of_doubles.size() ? _fbb.CreateVector(_o->vector_of_doubles) : 0;
+ auto _parent_namespace_test = _o->parent_namespace_test ? CreateInParentNamespace(_fbb, _o->parent_namespace_test.get(), _rehasher) : 0;
+ auto _vector_of_referrables = _o->vector_of_referrables.size() ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Example::Referrable>> (_o->vector_of_referrables.size(), [](size_t i, _VectorArgs *__va) { return CreateReferrable(*__va->__fbb, __va->__o->vector_of_referrables[i].get(), __va->__rehasher); }, &_va ) : 0;
+ auto _single_weak_reference = _rehasher ? static_cast<uint64_t>((*_rehasher)(_o->single_weak_reference)) : 0;
+ auto _vector_of_weak_references = _o->vector_of_weak_references.size() ? _fbb.CreateVector<uint64_t>(_o->vector_of_weak_references.size(), [](size_t i, _VectorArgs *__va) { return __va->__rehasher ? static_cast<uint64_t>((*__va->__rehasher)(__va->__o->vector_of_weak_references[i])) : 0; }, &_va ) : 0;
+ auto _vector_of_strong_referrables = _o->vector_of_strong_referrables.size() ? _fbb.CreateVector<flatbuffers::Offset<MyGame::Example::Referrable>> (_o->vector_of_strong_referrables.size(), [](size_t i, _VectorArgs *__va) { return CreateReferrable(*__va->__fbb, __va->__o->vector_of_strong_referrables[i].get(), __va->__rehasher); }, &_va ) : 0;
+ auto _co_owning_reference = _rehasher ? static_cast<uint64_t>((*_rehasher)(_o->co_owning_reference)) : 0;
+ auto _vector_of_co_owning_references = _o->vector_of_co_owning_references.size() ? _fbb.CreateVector<uint64_t>(_o->vector_of_co_owning_references.size(), [](size_t i, _VectorArgs *__va) { return __va->__rehasher ? static_cast<uint64_t>((*__va->__rehasher)(__va->__o->vector_of_co_owning_references[i].get())) : 0; }, &_va ) : 0;
+ auto _non_owning_reference = _rehasher ? static_cast<uint64_t>((*_rehasher)(_o->non_owning_reference)) : 0;
+ auto _vector_of_non_owning_references = _o->vector_of_non_owning_references.size() ? _fbb.CreateVector<uint64_t>(_o->vector_of_non_owning_references.size(), [](size_t i, _VectorArgs *__va) { return __va->__rehasher ? static_cast<uint64_t>((*__va->__rehasher)(__va->__o->vector_of_non_owning_references[i])) : 0; }, &_va ) : 0;
+ auto _any_unique_type = _o->any_unique.type;
+ auto _any_unique = _o->any_unique.Pack(_fbb);
+ auto _any_ambiguous_type = _o->any_ambiguous.type;
+ auto _any_ambiguous = _o->any_ambiguous.Pack(_fbb);
+ auto _vector_of_enums = _o->vector_of_enums.size() ? _fbb.CreateVectorScalarCast<uint8_t>(flatbuffers::data(_o->vector_of_enums), _o->vector_of_enums.size()) : 0;
+ return MyGame::Example::CreateMonster(
+ _fbb,
+ _pos,
+ _mana,
+ _hp,
+ _name,
+ _inventory,
+ _color,
+ _test_type,
+ _test,
+ _test4,
+ _testarrayofstring,
+ _testarrayoftables,
+ _enemy,
+ _testnestedflatbuffer,
+ _testempty,
+ _testbool,
+ _testhashs32_fnv1,
+ _testhashu32_fnv1,
+ _testhashs64_fnv1,
+ _testhashu64_fnv1,
+ _testhashs32_fnv1a,
+ _testhashu32_fnv1a,
+ _testhashs64_fnv1a,
+ _testhashu64_fnv1a,
+ _testarrayofbools,
+ _testf,
+ _testf2,
+ _testf3,
+ _testarrayofstring2,
+ _testarrayofsortedstruct,
+ _flex,
+ _test5,
+ _vector_of_longs,
+ _vector_of_doubles,
+ _parent_namespace_test,
+ _vector_of_referrables,
+ _single_weak_reference,
+ _vector_of_weak_references,
+ _vector_of_strong_referrables,
+ _co_owning_reference,
+ _vector_of_co_owning_references,
+ _non_owning_reference,
+ _vector_of_non_owning_references,
+ _any_unique_type,
+ _any_unique,
+ _any_ambiguous_type,
+ _any_ambiguous,
+ _vector_of_enums);
+}
+
+inline TypeAliasesT *TypeAliases::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new TypeAliasesT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void TypeAliases::UnPackTo(TypeAliasesT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = i8(); _o->i8 = _e; };
+ { auto _e = u8(); _o->u8 = _e; };
+ { auto _e = i16(); _o->i16 = _e; };
+ { auto _e = u16(); _o->u16 = _e; };
+ { auto _e = i32(); _o->i32 = _e; };
+ { auto _e = u32(); _o->u32 = _e; };
+ { auto _e = i64(); _o->i64 = _e; };
+ { auto _e = u64(); _o->u64 = _e; };
+ { auto _e = f32(); _o->f32 = _e; };
+ { auto _e = f64(); _o->f64 = _e; };
+ { auto _e = v8(); if (_e) { _o->v8.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->v8[_i] = _e->Get(_i); } } };
+ { auto _e = vf64(); if (_e) { _o->vf64.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vf64[_i] = _e->Get(_i); } } };
+}
+
+inline flatbuffers::Offset<TypeAliases> TypeAliases::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateTypeAliases(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<TypeAliases> CreateTypeAliases(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TypeAliasesT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _i8 = _o->i8;
+ auto _u8 = _o->u8;
+ auto _i16 = _o->i16;
+ auto _u16 = _o->u16;
+ auto _i32 = _o->i32;
+ auto _u32 = _o->u32;
+ auto _i64 = _o->i64;
+ auto _u64 = _o->u64;
+ auto _f32 = _o->f32;
+ auto _f64 = _o->f64;
+ auto _v8 = _o->v8.size() ? _fbb.CreateVector(_o->v8) : 0;
+ auto _vf64 = _o->vf64.size() ? _fbb.CreateVector(_o->vf64) : 0;
+ return MyGame::Example::CreateTypeAliases(
+ _fbb,
+ _i8,
+ _u8,
+ _i16,
+ _u16,
+ _i32,
+ _u32,
+ _i64,
+ _u64,
+ _f32,
+ _f64,
+ _v8,
+ _vf64);
+}
+
+inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type) {
+ switch (type) {
+ case Any_NONE: {
+ return true;
+ }
+ case Any_Monster: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case Any_TestSimpleTableWithEnum: {
+ auto ptr = reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnum *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case Any_MyGame_Example2_Monster: {
+ auto ptr = reinterpret_cast<const MyGame::Example2::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default: return false;
+ }
+}
+
+inline bool VerifyAnyVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
+ if (!values || !types) return !values && !types;
+ if (values->size() != types->size()) return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
+ if (!VerifyAny(
+ verifier, values->Get(i), types->GetEnum<Any>(i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline void *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) {
+ switch (type) {
+ case Any_Monster: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case Any_TestSimpleTableWithEnum: {
+ auto ptr = reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnum *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case Any_MyGame_Example2_Monster: {
+ auto ptr = reinterpret_cast<const MyGame::Example2::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+ switch (type) {
+ case Any_Monster: {
+ auto ptr = reinterpret_cast<const MyGame::Example::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ case Any_TestSimpleTableWithEnum: {
+ auto ptr = reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(value);
+ return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union();
+ }
+ case Any_MyGame_Example2_Monster: {
+ auto ptr = reinterpret_cast<const MyGame::Example2::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ default: return 0;
+ }
+}
+
+inline AnyUnion::AnyUnion(const AnyUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+ switch (type) {
+ case Any_Monster: {
+ FLATBUFFERS_ASSERT(false); // MyGame::Example::MonsterT not copyable.
+ break;
+ }
+ case Any_TestSimpleTableWithEnum: {
+ value = new MyGame::Example::TestSimpleTableWithEnumT(*reinterpret_cast<MyGame::Example::TestSimpleTableWithEnumT *>(u.value));
+ break;
+ }
+ case Any_MyGame_Example2_Monster: {
+ value = new MyGame::Example2::MonsterT(*reinterpret_cast<MyGame::Example2::MonsterT *>(u.value));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+inline void AnyUnion::Reset() {
+ switch (type) {
+ case Any_Monster: {
+ auto ptr = reinterpret_cast<MyGame::Example::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ case Any_TestSimpleTableWithEnum: {
+ auto ptr = reinterpret_cast<MyGame::Example::TestSimpleTableWithEnumT *>(value);
+ delete ptr;
+ break;
+ }
+ case Any_MyGame_Example2_Monster: {
+ auto ptr = reinterpret_cast<MyGame::Example2::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ default: break;
+ }
+ value = nullptr;
+ type = Any_NONE;
+}
+
+inline bool VerifyAnyUniqueAliases(flatbuffers::Verifier &verifier, const void *obj, AnyUniqueAliases type) {
+ switch (type) {
+ case AnyUniqueAliases_NONE: {
+ return true;
+ }
+ case AnyUniqueAliases_M: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case AnyUniqueAliases_TS: {
+ auto ptr = reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnum *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case AnyUniqueAliases_M2: {
+ auto ptr = reinterpret_cast<const MyGame::Example2::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default: return false;
+ }
+}
+
+inline bool VerifyAnyUniqueAliasesVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
+ if (!values || !types) return !values && !types;
+ if (values->size() != types->size()) return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
+ if (!VerifyAnyUniqueAliases(
+ verifier, values->Get(i), types->GetEnum<AnyUniqueAliases>(i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline void *AnyUniqueAliasesUnion::UnPack(const void *obj, AnyUniqueAliases type, const flatbuffers::resolver_function_t *resolver) {
+ switch (type) {
+ case AnyUniqueAliases_M: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case AnyUniqueAliases_TS: {
+ auto ptr = reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnum *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case AnyUniqueAliases_M2: {
+ auto ptr = reinterpret_cast<const MyGame::Example2::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> AnyUniqueAliasesUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+ switch (type) {
+ case AnyUniqueAliases_M: {
+ auto ptr = reinterpret_cast<const MyGame::Example::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ case AnyUniqueAliases_TS: {
+ auto ptr = reinterpret_cast<const MyGame::Example::TestSimpleTableWithEnumT *>(value);
+ return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union();
+ }
+ case AnyUniqueAliases_M2: {
+ auto ptr = reinterpret_cast<const MyGame::Example2::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ default: return 0;
+ }
+}
+
+inline AnyUniqueAliasesUnion::AnyUniqueAliasesUnion(const AnyUniqueAliasesUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+ switch (type) {
+ case AnyUniqueAliases_M: {
+ FLATBUFFERS_ASSERT(false); // MyGame::Example::MonsterT not copyable.
+ break;
+ }
+ case AnyUniqueAliases_TS: {
+ value = new MyGame::Example::TestSimpleTableWithEnumT(*reinterpret_cast<MyGame::Example::TestSimpleTableWithEnumT *>(u.value));
+ break;
+ }
+ case AnyUniqueAliases_M2: {
+ value = new MyGame::Example2::MonsterT(*reinterpret_cast<MyGame::Example2::MonsterT *>(u.value));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+inline void AnyUniqueAliasesUnion::Reset() {
+ switch (type) {
+ case AnyUniqueAliases_M: {
+ auto ptr = reinterpret_cast<MyGame::Example::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ case AnyUniqueAliases_TS: {
+ auto ptr = reinterpret_cast<MyGame::Example::TestSimpleTableWithEnumT *>(value);
+ delete ptr;
+ break;
+ }
+ case AnyUniqueAliases_M2: {
+ auto ptr = reinterpret_cast<MyGame::Example2::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ default: break;
+ }
+ value = nullptr;
+ type = AnyUniqueAliases_NONE;
+}
+
+inline bool VerifyAnyAmbiguousAliases(flatbuffers::Verifier &verifier, const void *obj, AnyAmbiguousAliases type) {
+ switch (type) {
+ case AnyAmbiguousAliases_NONE: {
+ return true;
+ }
+ case AnyAmbiguousAliases_M1: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case AnyAmbiguousAliases_M2: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case AnyAmbiguousAliases_M3: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ default: return false;
+ }
+}
+
+inline bool VerifyAnyAmbiguousAliasesVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
+ if (!values || !types) return !values && !types;
+ if (values->size() != types->size()) return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
+ if (!VerifyAnyAmbiguousAliases(
+ verifier, values->Get(i), types->GetEnum<AnyAmbiguousAliases>(i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline void *AnyAmbiguousAliasesUnion::UnPack(const void *obj, AnyAmbiguousAliases type, const flatbuffers::resolver_function_t *resolver) {
+ switch (type) {
+ case AnyAmbiguousAliases_M1: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case AnyAmbiguousAliases_M2: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case AnyAmbiguousAliases_M3: {
+ auto ptr = reinterpret_cast<const MyGame::Example::Monster *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> AnyAmbiguousAliasesUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+ switch (type) {
+ case AnyAmbiguousAliases_M1: {
+ auto ptr = reinterpret_cast<const MyGame::Example::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ case AnyAmbiguousAliases_M2: {
+ auto ptr = reinterpret_cast<const MyGame::Example::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ case AnyAmbiguousAliases_M3: {
+ auto ptr = reinterpret_cast<const MyGame::Example::MonsterT *>(value);
+ return CreateMonster(_fbb, ptr, _rehasher).Union();
+ }
+ default: return 0;
+ }
+}
+
+inline AnyAmbiguousAliasesUnion::AnyAmbiguousAliasesUnion(const AnyAmbiguousAliasesUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+ switch (type) {
+ case AnyAmbiguousAliases_M1: {
+ FLATBUFFERS_ASSERT(false); // MyGame::Example::MonsterT not copyable.
+ break;
+ }
+ case AnyAmbiguousAliases_M2: {
+ FLATBUFFERS_ASSERT(false); // MyGame::Example::MonsterT not copyable.
+ break;
+ }
+ case AnyAmbiguousAliases_M3: {
+ FLATBUFFERS_ASSERT(false); // MyGame::Example::MonsterT not copyable.
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+inline void AnyAmbiguousAliasesUnion::Reset() {
+ switch (type) {
+ case AnyAmbiguousAliases_M1: {
+ auto ptr = reinterpret_cast<MyGame::Example::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ case AnyAmbiguousAliases_M2: {
+ auto ptr = reinterpret_cast<MyGame::Example::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ case AnyAmbiguousAliases_M3: {
+ auto ptr = reinterpret_cast<MyGame::Example::MonsterT *>(value);
+ delete ptr;
+ break;
+ }
+ default: break;
+ }
+ value = nullptr;
+ type = AnyAmbiguousAliases_NONE;
+}
+
+inline const flatbuffers::TypeTable *ColorTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_UCHAR, 0, 0 },
+ { flatbuffers::ET_UCHAR, 0, 0 },
+ { flatbuffers::ET_UCHAR, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::ColorTypeTable
+ };
+ static const int64_t values[] = { 1, 2, 8 };
+ static const char * const names[] = {
+ "Red",
+ "Green",
+ "Blue"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_ENUM, 3, type_codes, type_refs, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *AnyTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 1 },
+ { flatbuffers::ET_SEQUENCE, 0, 2 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::MonsterTypeTable,
+ MyGame::Example::TestSimpleTableWithEnumTypeTable,
+ MyGame::Example2::MonsterTypeTable
+ };
+ static const char * const names[] = {
+ "NONE",
+ "Monster",
+ "TestSimpleTableWithEnum",
+ "MyGame_Example2_Monster"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_UNION, 4, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *AnyUniqueAliasesTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 1 },
+ { flatbuffers::ET_SEQUENCE, 0, 2 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::MonsterTypeTable,
+ MyGame::Example::TestSimpleTableWithEnumTypeTable,
+ MyGame::Example2::MonsterTypeTable
+ };
+ static const char * const names[] = {
+ "NONE",
+ "M",
+ "TS",
+ "M2"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_UNION, 4, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *AnyAmbiguousAliasesTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::MonsterTypeTable
+ };
+ static const char * const names[] = {
+ "NONE",
+ "M1",
+ "M2",
+ "M3"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_UNION, 4, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+} // namespace Example
+
+inline const flatbuffers::TypeTable *InParentNamespaceTypeTable() {
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr
+ };
+ return &tt;
+}
+
+namespace Example2 {
+
+inline const flatbuffers::TypeTable *MonsterTypeTable() {
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr
+ };
+ return &tt;
+}
+
+} // namespace Example2
+
+namespace Example {
+
+inline const flatbuffers::TypeTable *TestTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SHORT, 0, -1 },
+ { flatbuffers::ET_CHAR, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 2, 4 };
+ static const char * const names[] = {
+ "a",
+ "b"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *TestSimpleTableWithEnumTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_UCHAR, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::ColorTypeTable
+ };
+ static const char * const names[] = {
+ "color"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *Vec3TypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_DOUBLE, 0, -1 },
+ { flatbuffers::ET_UCHAR, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 1 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::ColorTypeTable,
+ MyGame::Example::TestTypeTable
+ };
+ static const int64_t values[] = { 0, 4, 8, 16, 24, 26, 32 };
+ static const char * const names[] = {
+ "x",
+ "y",
+ "z",
+ "test1",
+ "test2",
+ "test3"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 6, type_codes, type_refs, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *AbilityTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_UINT, 0, -1 },
+ { flatbuffers::ET_UINT, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 4, 8 };
+ static const char * const names[] = {
+ "id",
+ "distance"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *StatTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_STRING, 0, -1 },
+ { flatbuffers::ET_LONG, 0, -1 },
+ { flatbuffers::ET_USHORT, 0, -1 }
+ };
+ static const char * const names[] = {
+ "id",
+ "val",
+ "count"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 3, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *ReferrableTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_ULONG, 0, -1 }
+ };
+ static const char * const names[] = {
+ "id"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *MonsterTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SHORT, 0, -1 },
+ { flatbuffers::ET_SHORT, 0, -1 },
+ { flatbuffers::ET_STRING, 0, -1 },
+ { flatbuffers::ET_BOOL, 0, -1 },
+ { flatbuffers::ET_UCHAR, 1, -1 },
+ { flatbuffers::ET_UCHAR, 0, 1 },
+ { flatbuffers::ET_UTYPE, 0, 2 },
+ { flatbuffers::ET_SEQUENCE, 0, 2 },
+ { flatbuffers::ET_SEQUENCE, 1, 3 },
+ { flatbuffers::ET_STRING, 1, -1 },
+ { flatbuffers::ET_SEQUENCE, 1, 4 },
+ { flatbuffers::ET_SEQUENCE, 0, 4 },
+ { flatbuffers::ET_UCHAR, 1, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 5 },
+ { flatbuffers::ET_BOOL, 0, -1 },
+ { flatbuffers::ET_INT, 0, -1 },
+ { flatbuffers::ET_UINT, 0, -1 },
+ { flatbuffers::ET_LONG, 0, -1 },
+ { flatbuffers::ET_ULONG, 0, -1 },
+ { flatbuffers::ET_INT, 0, -1 },
+ { flatbuffers::ET_UINT, 0, -1 },
+ { flatbuffers::ET_LONG, 0, -1 },
+ { flatbuffers::ET_ULONG, 0, -1 },
+ { flatbuffers::ET_BOOL, 1, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_STRING, 1, -1 },
+ { flatbuffers::ET_SEQUENCE, 1, 6 },
+ { flatbuffers::ET_UCHAR, 1, -1 },
+ { flatbuffers::ET_SEQUENCE, 1, 3 },
+ { flatbuffers::ET_LONG, 1, -1 },
+ { flatbuffers::ET_DOUBLE, 1, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 7 },
+ { flatbuffers::ET_SEQUENCE, 1, 8 },
+ { flatbuffers::ET_ULONG, 0, -1 },
+ { flatbuffers::ET_ULONG, 1, -1 },
+ { flatbuffers::ET_SEQUENCE, 1, 8 },
+ { flatbuffers::ET_ULONG, 0, -1 },
+ { flatbuffers::ET_ULONG, 1, -1 },
+ { flatbuffers::ET_ULONG, 0, -1 },
+ { flatbuffers::ET_ULONG, 1, -1 },
+ { flatbuffers::ET_UTYPE, 0, 9 },
+ { flatbuffers::ET_SEQUENCE, 0, 9 },
+ { flatbuffers::ET_UTYPE, 0, 10 },
+ { flatbuffers::ET_SEQUENCE, 0, 10 },
+ { flatbuffers::ET_UCHAR, 1, 1 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ MyGame::Example::Vec3TypeTable,
+ MyGame::Example::ColorTypeTable,
+ MyGame::Example::AnyTypeTable,
+ MyGame::Example::TestTypeTable,
+ MyGame::Example::MonsterTypeTable,
+ MyGame::Example::StatTypeTable,
+ MyGame::Example::AbilityTypeTable,
+ MyGame::InParentNamespaceTypeTable,
+ MyGame::Example::ReferrableTypeTable,
+ MyGame::Example::AnyUniqueAliasesTypeTable,
+ MyGame::Example::AnyAmbiguousAliasesTypeTable
+ };
+ static const char * const names[] = {
+ "pos",
+ "mana",
+ "hp",
+ "name",
+ "friendly",
+ "inventory",
+ "color",
+ "test_type",
+ "test",
+ "test4",
+ "testarrayofstring",
+ "testarrayoftables",
+ "enemy",
+ "testnestedflatbuffer",
+ "testempty",
+ "testbool",
+ "testhashs32_fnv1",
+ "testhashu32_fnv1",
+ "testhashs64_fnv1",
+ "testhashu64_fnv1",
+ "testhashs32_fnv1a",
+ "testhashu32_fnv1a",
+ "testhashs64_fnv1a",
+ "testhashu64_fnv1a",
+ "testarrayofbools",
+ "testf",
+ "testf2",
+ "testf3",
+ "testarrayofstring2",
+ "testarrayofsortedstruct",
+ "flex",
+ "test5",
+ "vector_of_longs",
+ "vector_of_doubles",
+ "parent_namespace_test",
+ "vector_of_referrables",
+ "single_weak_reference",
+ "vector_of_weak_references",
+ "vector_of_strong_referrables",
+ "co_owning_reference",
+ "vector_of_co_owning_references",
+ "non_owning_reference",
+ "vector_of_non_owning_references",
+ "any_unique_type",
+ "any_unique",
+ "any_ambiguous_type",
+ "any_ambiguous",
+ "vector_of_enums"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 48, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *TypeAliasesTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_CHAR, 0, -1 },
+ { flatbuffers::ET_UCHAR, 0, -1 },
+ { flatbuffers::ET_SHORT, 0, -1 },
+ { flatbuffers::ET_USHORT, 0, -1 },
+ { flatbuffers::ET_INT, 0, -1 },
+ { flatbuffers::ET_UINT, 0, -1 },
+ { flatbuffers::ET_LONG, 0, -1 },
+ { flatbuffers::ET_ULONG, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_DOUBLE, 0, -1 },
+ { flatbuffers::ET_CHAR, 1, -1 },
+ { flatbuffers::ET_DOUBLE, 1, -1 }
+ };
+ static const char * const names[] = {
+ "i8",
+ "u8",
+ "i16",
+ "u16",
+ "i32",
+ "u32",
+ "i64",
+ "u64",
+ "f32",
+ "f64",
+ "v8",
+ "vf64"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 12, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const MyGame::Example::Monster *GetMonster(const void *buf) {
+ return flatbuffers::GetRoot<MyGame::Example::Monster>(buf);
+}
+
+inline const MyGame::Example::Monster *GetSizePrefixedMonster(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<MyGame::Example::Monster>(buf);
+}
+
+inline Monster *GetMutableMonster(void *buf) {
+ return flatbuffers::GetMutableRoot<Monster>(buf);
+}
+
+inline const char *MonsterIdentifier() {
+ return "MONS";
+}
+
+inline bool MonsterBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(
+ buf, MonsterIdentifier());
+}
+
+inline bool VerifyMonsterBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<MyGame::Example::Monster>(MonsterIdentifier());
+}
+
+inline bool VerifySizePrefixedMonsterBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<MyGame::Example::Monster>(MonsterIdentifier());
+}
+
+inline const char *MonsterExtension() {
+ return "mon";
+}
+
+inline void FinishMonsterBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::Example::Monster> root) {
+ fbb.Finish(root, MonsterIdentifier());
+}
+
+inline void FinishSizePrefixedMonsterBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<MyGame::Example::Monster> root) {
+ fbb.FinishSizePrefixed(root, MonsterIdentifier());
+}
+
+inline flatbuffers::unique_ptr<MyGame::Example::MonsterT> UnPackMonster(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MyGame::Example::MonsterT>(GetMonster(buf)->UnPack(res));
+}
+
+inline flatbuffers::unique_ptr<MyGame::Example::MonsterT> UnPackSizePrefixedMonster(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MyGame::Example::MonsterT>(GetSizePrefixedMonster(buf)->UnPack(res));
+}
+
+} // namespace Example
+} // namespace MyGame
+
+#endif // FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
new file mode 100644
index 0000000..2a68288
--- /dev/null
+++ b/tests/monster_test_generated.js
@@ -0,0 +1,3299 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @const
+ * @namespace
+ */
+var MyGame = MyGame || {};
+
+/**
+ * @const
+ * @namespace
+ */
+MyGame.Example = MyGame.Example || {};
+
+/**
+ * @const
+ * @namespace
+ */
+MyGame.Example2 = MyGame.Example2 || {};
+
+/**
+ * @const
+ * @namespace
+ */
+MyGame.OtherNameSpace = MyGame.OtherNameSpace || {};
+
+/**
+ * Composite components of Monster color.
+ *
+ * @enum {number}
+ */
+MyGame.Example.Color = {
+ Red: 1,
+
+ /**
+ * \brief color Green
+ * Green is bit_flag with value (1u << 1)
+ */
+ Green: 2,
+
+ /**
+ * \brief color Blue (1u << 3)
+ */
+ Blue: 8
+};
+
+/**
+ * Composite components of Monster color.
+ *
+ * @enum {string}
+ */
+MyGame.Example.ColorName = {
+ 1: 'Red',
+
+ /**
+ * \brief color Green
+ * Green is bit_flag with value (1u << 1)
+ */
+ 2: 'Green',
+
+ /**
+ * \brief color Blue (1u << 3)
+ */
+ 8: 'Blue'
+};
+
+/**
+ * @enum {number}
+ */
+MyGame.Example.Any = {
+ NONE: 0,
+ Monster: 1,
+ TestSimpleTableWithEnum: 2,
+ MyGame_Example2_Monster: 3
+};
+
+/**
+ * @enum {string}
+ */
+MyGame.Example.AnyName = {
+ 0: 'NONE',
+ 1: 'Monster',
+ 2: 'TestSimpleTableWithEnum',
+ 3: 'MyGame_Example2_Monster'
+};
+
+/**
+ * @enum {number}
+ */
+MyGame.Example.AnyUniqueAliases = {
+ NONE: 0,
+ M: 1,
+ TS: 2,
+ M2: 3
+};
+
+/**
+ * @enum {string}
+ */
+MyGame.Example.AnyUniqueAliasesName = {
+ 0: 'NONE',
+ 1: 'M',
+ 2: 'TS',
+ 3: 'M2'
+};
+
+/**
+ * @enum {number}
+ */
+MyGame.Example.AnyAmbiguousAliases = {
+ NONE: 0,
+ M1: 1,
+ M2: 2,
+ M3: 3
+};
+
+/**
+ * @enum {string}
+ */
+MyGame.Example.AnyAmbiguousAliasesName = {
+ 0: 'NONE',
+ 1: 'M1',
+ 2: 'M2',
+ 3: 'M3'
+};
+
+/**
+ * @constructor
+ */
+MyGame.InParentNamespace = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.InParentNamespace}
+ */
+MyGame.InParentNamespace.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.InParentNamespace=} obj
+ * @returns {MyGame.InParentNamespace}
+ */
+MyGame.InParentNamespace.getRootAsInParentNamespace = function(bb, obj) {
+ return (obj || new MyGame.InParentNamespace).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.InParentNamespace=} obj
+ * @returns {MyGame.InParentNamespace}
+ */
+MyGame.InParentNamespace.getSizePrefixedRootAsInParentNamespace = function(bb, obj) {
+ return (obj || new MyGame.InParentNamespace).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.InParentNamespace.startInParentNamespace = function(builder) {
+ builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.InParentNamespace.endInParentNamespace = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.InParentNamespace.createInParentNamespace = function(builder) {
+ MyGame.InParentNamespace.startInParentNamespace(builder);
+ return MyGame.InParentNamespace.endInParentNamespace(builder);
+}
+
+/**
+ * @constructor
+ */
+MyGame.Example2.Monster = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example2.Monster}
+ */
+MyGame.Example2.Monster.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example2.Monster=} obj
+ * @returns {MyGame.Example2.Monster}
+ */
+MyGame.Example2.Monster.getRootAsMonster = function(bb, obj) {
+ return (obj || new MyGame.Example2.Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example2.Monster=} obj
+ * @returns {MyGame.Example2.Monster}
+ */
+MyGame.Example2.Monster.getSizePrefixedRootAsMonster = function(bb, obj) {
+ return (obj || new MyGame.Example2.Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example2.Monster.startMonster = function(builder) {
+ builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example2.Monster.endMonster = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example2.Monster.createMonster = function(builder) {
+ MyGame.Example2.Monster.startMonster(builder);
+ return MyGame.Example2.Monster.endMonster(builder);
+}
+
+/**
+ * @constructor
+ */
+MyGame.Example.Test = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Test}
+ */
+MyGame.Example.Test.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Test.prototype.a = function() {
+ return this.bb.readInt16(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Test.prototype.mutate_a = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Test.prototype.b = function() {
+ return this.bb.readInt8(this.bb_pos + 2);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Test.prototype.mutate_b = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 2);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} a
+ * @param {number} b
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Test.createTest = function(builder, a, b) {
+ builder.prep(2, 4);
+ builder.pad(1);
+ builder.writeInt8(b);
+ builder.writeInt16(a);
+ return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+MyGame.Example.TestSimpleTableWithEnum = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.TestSimpleTableWithEnum}
+ */
+MyGame.Example.TestSimpleTableWithEnum.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.TestSimpleTableWithEnum=} obj
+ * @returns {MyGame.Example.TestSimpleTableWithEnum}
+ */
+MyGame.Example.TestSimpleTableWithEnum.getRootAsTestSimpleTableWithEnum = function(bb, obj) {
+ return (obj || new MyGame.Example.TestSimpleTableWithEnum).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.TestSimpleTableWithEnum=} obj
+ * @returns {MyGame.Example.TestSimpleTableWithEnum}
+ */
+MyGame.Example.TestSimpleTableWithEnum.getSizePrefixedRootAsTestSimpleTableWithEnum = function(bb, obj) {
+ return (obj || new MyGame.Example.TestSimpleTableWithEnum).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+MyGame.Example.TestSimpleTableWithEnum.prototype.color = function() {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.Color.Green;
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+MyGame.Example.TestSimpleTableWithEnum.prototype.mutate_color = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example.TestSimpleTableWithEnum.startTestSimpleTableWithEnum = function(builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ */
+MyGame.Example.TestSimpleTableWithEnum.addColor = function(builder, color) {
+ builder.addFieldInt8(0, color, MyGame.Example.Color.Green);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TestSimpleTableWithEnum.endTestSimpleTableWithEnum = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TestSimpleTableWithEnum.createTestSimpleTableWithEnum = function(builder, color) {
+ MyGame.Example.TestSimpleTableWithEnum.startTestSimpleTableWithEnum(builder);
+ MyGame.Example.TestSimpleTableWithEnum.addColor(builder, color);
+ return MyGame.Example.TestSimpleTableWithEnum.endTestSimpleTableWithEnum(builder);
+}
+
+/**
+ * @constructor
+ */
+MyGame.Example.Vec3 = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Vec3}
+ */
+MyGame.Example.Vec3.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Vec3.prototype.x = function() {
+ return this.bb.readFloat32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Vec3.prototype.mutate_x = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Vec3.prototype.y = function() {
+ return this.bb.readFloat32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Vec3.prototype.mutate_y = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Vec3.prototype.z = function() {
+ return this.bb.readFloat32(this.bb_pos + 8);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Vec3.prototype.mutate_z = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Vec3.prototype.test1 = function() {
+ return this.bb.readFloat64(this.bb_pos + 16);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Vec3.prototype.mutate_test1 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 16);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+MyGame.Example.Vec3.prototype.test2 = function() {
+ return /** @type {MyGame.Example.Color} */ (this.bb.readUint8(this.bb_pos + 24));
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+MyGame.Example.Vec3.prototype.mutate_test2 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 24);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test|null}
+ */
+MyGame.Example.Vec3.prototype.test3 = function(obj) {
+ return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} test1
+ * @param {MyGame.Example.Color} test2
+ * @param {number} test3_a
+ * @param {number} test3_b
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Vec3.createVec3 = function(builder, x, y, z, test1, test2, test3_a, test3_b) {
+ builder.prep(8, 32);
+ builder.pad(2);
+ builder.prep(2, 4);
+ builder.pad(1);
+ builder.writeInt8(test3_b);
+ builder.writeInt16(test3_a);
+ builder.pad(1);
+ builder.writeInt8(test2);
+ builder.writeFloat64(test1);
+ builder.pad(4);
+ builder.writeFloat32(z);
+ builder.writeFloat32(y);
+ builder.writeFloat32(x);
+ return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+MyGame.Example.Ability = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Ability}
+ */
+MyGame.Example.Ability.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Ability.prototype.id = function() {
+ return this.bb.readUint32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Ability.prototype.mutate_id = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Ability.prototype.distance = function() {
+ return this.bb.readUint32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Ability.prototype.mutate_distance = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} id
+ * @param {number} distance
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Ability.createAbility = function(builder, id, distance) {
+ builder.prep(4, 8);
+ builder.writeInt32(distance);
+ builder.writeInt32(id);
+ return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+MyGame.Example.Stat = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Stat}
+ */
+MyGame.Example.Stat.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.Stat=} obj
+ * @returns {MyGame.Example.Stat}
+ */
+MyGame.Example.Stat.getRootAsStat = function(bb, obj) {
+ return (obj || new MyGame.Example.Stat).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.Stat=} obj
+ * @returns {MyGame.Example.Stat}
+ */
+MyGame.Example.Stat.getSizePrefixedRootAsStat = function(bb, obj) {
+ return (obj || new MyGame.Example.Stat).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array|null}
+ */
+MyGame.Example.Stat.prototype.id = function(optionalEncoding) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Stat.prototype.val = function() {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Stat.prototype.mutate_val = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Stat.prototype.count = function() {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? this.bb.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Stat.prototype.mutate_count = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example.Stat.startStat = function(builder) {
+ builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} idOffset
+ */
+MyGame.Example.Stat.addId = function(builder, idOffset) {
+ builder.addFieldOffset(0, idOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} val
+ */
+MyGame.Example.Stat.addVal = function(builder, val) {
+ builder.addFieldInt64(1, val, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} count
+ */
+MyGame.Example.Stat.addCount = function(builder, count) {
+ builder.addFieldInt16(2, count, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Stat.endStat = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} idOffset
+ * @param {flatbuffers.Long} val
+ * @param {number} count
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Stat.createStat = function(builder, idOffset, val, count) {
+ MyGame.Example.Stat.startStat(builder);
+ MyGame.Example.Stat.addId(builder, idOffset);
+ MyGame.Example.Stat.addVal(builder, val);
+ MyGame.Example.Stat.addCount(builder, count);
+ return MyGame.Example.Stat.endStat(builder);
+}
+
+/**
+ * @constructor
+ */
+MyGame.Example.Referrable = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Referrable}
+ */
+MyGame.Example.Referrable.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.Referrable=} obj
+ * @returns {MyGame.Example.Referrable}
+ */
+MyGame.Example.Referrable.getRootAsReferrable = function(bb, obj) {
+ return (obj || new MyGame.Example.Referrable).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.Referrable=} obj
+ * @returns {MyGame.Example.Referrable}
+ */
+MyGame.Example.Referrable.getSizePrefixedRootAsReferrable = function(bb, obj) {
+ return (obj || new MyGame.Example.Referrable).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Referrable.prototype.id = function() {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Referrable.prototype.mutate_id = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example.Referrable.startReferrable = function(builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} id
+ */
+MyGame.Example.Referrable.addId = function(builder, id) {
+ builder.addFieldInt64(0, id, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Referrable.endReferrable = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} id
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Referrable.createReferrable = function(builder, id) {
+ MyGame.Example.Referrable.startReferrable(builder);
+ MyGame.Example.Referrable.addId(builder, id);
+ return MyGame.Example.Referrable.endReferrable(builder);
+}
+
+/**
+ * an example documentation comment: monster object
+ *
+ * @constructor
+ */
+MyGame.Example.Monster = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Monster}
+ */
+MyGame.Example.Monster.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster}
+ */
+MyGame.Example.Monster.getRootAsMonster = function(bb, obj) {
+ return (obj || new MyGame.Example.Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster}
+ */
+MyGame.Example.Monster.getSizePrefixedRootAsMonster = function(bb, obj) {
+ return (obj || new MyGame.Example.Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.bufferHasIdentifier = function(bb) {
+ return bb.__has_identifier('MONS');
+};
+
+/**
+ * @param {MyGame.Example.Vec3=} obj
+ * @returns {MyGame.Example.Vec3|null}
+ */
+MyGame.Example.Monster.prototype.pos = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? (obj || new MyGame.Example.Vec3).__init(this.bb_pos + offset, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.mana = function() {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? this.bb.readInt16(this.bb_pos + offset) : 150;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_mana = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.hp = function() {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? this.bb.readInt16(this.bb_pos + offset) : 100;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_hp = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array|null}
+ */
+MyGame.Example.Monster.prototype.name = function(optionalEncoding) {
+ var offset = this.bb.__offset(this.bb_pos, 10);
+ return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.inventory = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 14);
+ return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.inventoryLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 14);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+MyGame.Example.Monster.prototype.inventoryArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 14);
+ return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+MyGame.Example.Monster.prototype.color = function() {
+ var offset = this.bb.__offset(this.bb_pos, 16);
+ return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.Color.Blue;
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_color = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 16);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {MyGame.Example.Any}
+ */
+MyGame.Example.Monster.prototype.testType = function() {
+ var offset = this.bb.__offset(this.bb_pos, 18);
+ return offset ? /** @type {MyGame.Example.Any} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.Any.NONE;
+};
+
+/**
+ * @param {MyGame.Example.Any} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_test_type = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 18);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+MyGame.Example.Monster.prototype.test = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 20);
+ return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+MyGame.Example.Monster.prototype.test4 = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 22);
+ return offset ? (obj || new MyGame.Example.Test).__init(this.bb.__vector(this.bb_pos + offset) + index * 4, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.test4Length = function() {
+ var offset = this.bb.__offset(this.bb_pos, 22);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+MyGame.Example.Monster.prototype.testarrayofstring = function(index, optionalEncoding) {
+ var offset = this.bb.__offset(this.bb_pos, 24);
+ return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayofstringLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 24);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * an example documentation comment: this will end up in the generated code
+ * multiline too
+ *
+ * @param {number} index
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster}
+ */
+MyGame.Example.Monster.prototype.testarrayoftables = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 26);
+ return offset ? (obj || new MyGame.Example.Monster).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayoftablesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 26);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster|null}
+ */
+MyGame.Example.Monster.prototype.enemy = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 28);
+ return offset ? (obj || new MyGame.Example.Monster).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testnestedflatbuffer = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 30);
+ return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testnestedflatbufferLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 30);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+MyGame.Example.Monster.prototype.testnestedflatbufferArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 30);
+ return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {MyGame.Example.Stat=} obj
+ * @returns {MyGame.Example.Stat|null}
+ */
+MyGame.Example.Monster.prototype.testempty = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 32);
+ return offset ? (obj || new MyGame.Example.Stat).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.testbool = function() {
+ var offset = this.bb.__offset(this.bb_pos, 34);
+ return offset ? !!this.bb.readInt8(this.bb_pos + offset) : false;
+};
+
+/**
+ * @param {boolean} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testbool = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 34);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testhashs32Fnv1 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 36);
+ return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashs32_fnv1 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 36);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testhashu32Fnv1 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 38);
+ return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashu32_fnv1 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 38);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.testhashs64Fnv1 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 40);
+ return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashs64_fnv1 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 40);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.testhashu64Fnv1 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 42);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashu64_fnv1 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 42);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testhashs32Fnv1a = function() {
+ var offset = this.bb.__offset(this.bb_pos, 44);
+ return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashs32_fnv1a = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 44);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testhashu32Fnv1a = function() {
+ var offset = this.bb.__offset(this.bb_pos, 46);
+ return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashu32_fnv1a = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 46);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.testhashs64Fnv1a = function() {
+ var offset = this.bb.__offset(this.bb_pos, 48);
+ return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashs64_fnv1a = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 48);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.testhashu64Fnv1a = function() {
+ var offset = this.bb.__offset(this.bb_pos, 50);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testhashu64_fnv1a = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 50);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.testarrayofbools = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 52);
+ return offset ? !!this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : false;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayofboolsLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 52);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int8Array}
+ */
+MyGame.Example.Monster.prototype.testarrayofboolsArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 52);
+ return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testf = function() {
+ var offset = this.bb.__offset(this.bb_pos, 54);
+ return offset ? this.bb.readFloat32(this.bb_pos + offset) : 3.14159;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testf = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 54);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testf2 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 56);
+ return offset ? this.bb.readFloat32(this.bb_pos + offset) : 3.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testf2 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 56);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testf3 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 58);
+ return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_testf3 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 58);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+MyGame.Example.Monster.prototype.testarrayofstring2 = function(index, optionalEncoding) {
+ var offset = this.bb.__offset(this.bb_pos, 60);
+ return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayofstring2Length = function() {
+ var offset = this.bb.__offset(this.bb_pos, 60);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Ability=} obj
+ * @returns {MyGame.Example.Ability}
+ */
+MyGame.Example.Monster.prototype.testarrayofsortedstruct = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 62);
+ return offset ? (obj || new MyGame.Example.Ability).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayofsortedstructLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 62);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.flex = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 64);
+ return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.flexLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 64);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+MyGame.Example.Monster.prototype.flexArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 64);
+ return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+MyGame.Example.Monster.prototype.test5 = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 66);
+ return offset ? (obj || new MyGame.Example.Test).__init(this.bb.__vector(this.bb_pos + offset) + index * 4, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.test5Length = function() {
+ var offset = this.bb.__offset(this.bb_pos, 66);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.vectorOfLongs = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 68);
+ return offset ? this.bb.readInt64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfLongsLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 68);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoubles = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 70);
+ return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoublesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 70);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoublesArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 70);
+ return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {MyGame.InParentNamespace=} obj
+ * @returns {MyGame.InParentNamespace|null}
+ */
+MyGame.Example.Monster.prototype.parentNamespaceTest = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 72);
+ return offset ? (obj || new MyGame.InParentNamespace).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Referrable=} obj
+ * @returns {MyGame.Example.Referrable}
+ */
+MyGame.Example.Monster.prototype.vectorOfReferrables = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 74);
+ return offset ? (obj || new MyGame.Example.Referrable).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfReferrablesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 74);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.singleWeakReference = function() {
+ var offset = this.bb.__offset(this.bb_pos, 76);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_single_weak_reference = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 76);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.vectorOfWeakReferences = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 78);
+ return offset ? this.bb.readUint64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfWeakReferencesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 78);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Referrable=} obj
+ * @returns {MyGame.Example.Referrable}
+ */
+MyGame.Example.Monster.prototype.vectorOfStrongReferrables = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 80);
+ return offset ? (obj || new MyGame.Example.Referrable).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfStrongReferrablesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 80);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.coOwningReference = function() {
+ var offset = this.bb.__offset(this.bb_pos, 82);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_co_owning_reference = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 82);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.vectorOfCoOwningReferences = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 84);
+ return offset ? this.bb.readUint64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfCoOwningReferencesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 84);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.nonOwningReference = function() {
+ var offset = this.bb.__offset(this.bb_pos, 86);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_non_owning_reference = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 86);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.vectorOfNonOwningReferences = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 88);
+ return offset ? this.bb.readUint64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfNonOwningReferencesLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 88);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {MyGame.Example.AnyUniqueAliases}
+ */
+MyGame.Example.Monster.prototype.anyUniqueType = function() {
+ var offset = this.bb.__offset(this.bb_pos, 90);
+ return offset ? /** @type {MyGame.Example.AnyUniqueAliases} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.AnyUniqueAliases.NONE;
+};
+
+/**
+ * @param {MyGame.Example.AnyUniqueAliases} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_any_unique_type = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 90);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+MyGame.Example.Monster.prototype.anyUnique = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 92);
+ return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @returns {MyGame.Example.AnyAmbiguousAliases}
+ */
+MyGame.Example.Monster.prototype.anyAmbiguousType = function() {
+ var offset = this.bb.__offset(this.bb_pos, 94);
+ return offset ? /** @type {MyGame.Example.AnyAmbiguousAliases} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.AnyAmbiguousAliases.NONE;
+};
+
+/**
+ * @param {MyGame.Example.AnyAmbiguousAliases} value
+ * @returns {boolean}
+ */
+MyGame.Example.Monster.prototype.mutate_any_ambiguous_type = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 94);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+MyGame.Example.Monster.prototype.anyAmbiguous = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 96);
+ return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {MyGame.Example.Color}
+ */
+MyGame.Example.Monster.prototype.vectorOfEnums = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 98);
+ return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index)) : /** @type {MyGame.Example.Color} */ (0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfEnumsLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 98);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+MyGame.Example.Monster.prototype.vectorOfEnumsArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 98);
+ return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example.Monster.startMonster = function(builder) {
+ builder.startObject(48);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} posOffset
+ */
+MyGame.Example.Monster.addPos = function(builder, posOffset) {
+ builder.addFieldStruct(0, posOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} mana
+ */
+MyGame.Example.Monster.addMana = function(builder, mana) {
+ builder.addFieldInt16(1, mana, 150);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} hp
+ */
+MyGame.Example.Monster.addHp = function(builder, hp) {
+ builder.addFieldInt16(2, hp, 100);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} nameOffset
+ */
+MyGame.Example.Monster.addName = function(builder, nameOffset) {
+ builder.addFieldOffset(3, nameOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} inventoryOffset
+ */
+MyGame.Example.Monster.addInventory = function(builder, inventoryOffset) {
+ builder.addFieldOffset(5, inventoryOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createInventoryVector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startInventoryVector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ */
+MyGame.Example.Monster.addColor = function(builder, color) {
+ builder.addFieldInt8(6, color, MyGame.Example.Color.Blue);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Any} testType
+ */
+MyGame.Example.Monster.addTestType = function(builder, testType) {
+ builder.addFieldInt8(7, testType, MyGame.Example.Any.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testOffset
+ */
+MyGame.Example.Monster.addTest = function(builder, testOffset) {
+ builder.addFieldOffset(8, testOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} test4Offset
+ */
+MyGame.Example.Monster.addTest4 = function(builder, test4Offset) {
+ builder.addFieldOffset(9, test4Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTest4Vector = function(builder, numElems) {
+ builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstringOffset
+ */
+MyGame.Example.Monster.addTestarrayofstring = function(builder, testarrayofstringOffset) {
+ builder.addFieldOffset(10, testarrayofstringOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createTestarrayofstringVector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayofstringVector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayoftablesOffset
+ */
+MyGame.Example.Monster.addTestarrayoftables = function(builder, testarrayoftablesOffset) {
+ builder.addFieldOffset(11, testarrayoftablesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createTestarrayoftablesVector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayoftablesVector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} enemyOffset
+ */
+MyGame.Example.Monster.addEnemy = function(builder, enemyOffset) {
+ builder.addFieldOffset(12, enemyOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testnestedflatbufferOffset
+ */
+MyGame.Example.Monster.addTestnestedflatbuffer = function(builder, testnestedflatbufferOffset) {
+ builder.addFieldOffset(13, testnestedflatbufferOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createTestnestedflatbufferVector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestnestedflatbufferVector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testemptyOffset
+ */
+MyGame.Example.Monster.addTestempty = function(builder, testemptyOffset) {
+ builder.addFieldOffset(14, testemptyOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {boolean} testbool
+ */
+MyGame.Example.Monster.addTestbool = function(builder, testbool) {
+ builder.addFieldInt8(15, +testbool, +false);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashs32Fnv1
+ */
+MyGame.Example.Monster.addTesthashs32Fnv1 = function(builder, testhashs32Fnv1) {
+ builder.addFieldInt32(16, testhashs32Fnv1, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashu32Fnv1
+ */
+MyGame.Example.Monster.addTesthashu32Fnv1 = function(builder, testhashu32Fnv1) {
+ builder.addFieldInt32(17, testhashu32Fnv1, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashs64Fnv1
+ */
+MyGame.Example.Monster.addTesthashs64Fnv1 = function(builder, testhashs64Fnv1) {
+ builder.addFieldInt64(18, testhashs64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashu64Fnv1
+ */
+MyGame.Example.Monster.addTesthashu64Fnv1 = function(builder, testhashu64Fnv1) {
+ builder.addFieldInt64(19, testhashu64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashs32Fnv1a
+ */
+MyGame.Example.Monster.addTesthashs32Fnv1a = function(builder, testhashs32Fnv1a) {
+ builder.addFieldInt32(20, testhashs32Fnv1a, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashu32Fnv1a
+ */
+MyGame.Example.Monster.addTesthashu32Fnv1a = function(builder, testhashu32Fnv1a) {
+ builder.addFieldInt32(21, testhashu32Fnv1a, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashs64Fnv1a
+ */
+MyGame.Example.Monster.addTesthashs64Fnv1a = function(builder, testhashs64Fnv1a) {
+ builder.addFieldInt64(22, testhashs64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashu64Fnv1a
+ */
+MyGame.Example.Monster.addTesthashu64Fnv1a = function(builder, testhashu64Fnv1a) {
+ builder.addFieldInt64(23, testhashu64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofboolsOffset
+ */
+MyGame.Example.Monster.addTestarrayofbools = function(builder, testarrayofboolsOffset) {
+ builder.addFieldOffset(24, testarrayofboolsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<boolean>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createTestarrayofboolsVector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(+data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayofboolsVector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf
+ */
+MyGame.Example.Monster.addTestf = function(builder, testf) {
+ builder.addFieldFloat32(25, testf, 3.14159);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf2
+ */
+MyGame.Example.Monster.addTestf2 = function(builder, testf2) {
+ builder.addFieldFloat32(26, testf2, 3.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf3
+ */
+MyGame.Example.Monster.addTestf3 = function(builder, testf3) {
+ builder.addFieldFloat32(27, testf3, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstring2Offset
+ */
+MyGame.Example.Monster.addTestarrayofstring2 = function(builder, testarrayofstring2Offset) {
+ builder.addFieldOffset(28, testarrayofstring2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createTestarrayofstring2Vector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayofstring2Vector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofsortedstructOffset
+ */
+MyGame.Example.Monster.addTestarrayofsortedstruct = function(builder, testarrayofsortedstructOffset) {
+ builder.addFieldOffset(29, testarrayofsortedstructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayofsortedstructVector = function(builder, numElems) {
+ builder.startVector(8, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} flexOffset
+ */
+MyGame.Example.Monster.addFlex = function(builder, flexOffset) {
+ builder.addFieldOffset(30, flexOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createFlexVector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startFlexVector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} test5Offset
+ */
+MyGame.Example.Monster.addTest5 = function(builder, test5Offset) {
+ builder.addFieldOffset(31, test5Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTest5Vector = function(builder, numElems) {
+ builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfLongsOffset
+ */
+MyGame.Example.Monster.addVectorOfLongs = function(builder, vectorOfLongsOffset) {
+ builder.addFieldOffset(32, vectorOfLongsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfLongsVector = function(builder, data) {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfLongsVector = function(builder, numElems) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfDoublesOffset
+ */
+MyGame.Example.Monster.addVectorOfDoubles = function(builder, vectorOfDoublesOffset) {
+ builder.addFieldOffset(33, vectorOfDoublesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfDoublesVector = function(builder, data) {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addFloat64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfDoublesVector = function(builder, numElems) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} parentNamespaceTestOffset
+ */
+MyGame.Example.Monster.addParentNamespaceTest = function(builder, parentNamespaceTestOffset) {
+ builder.addFieldOffset(34, parentNamespaceTestOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfReferrablesOffset
+ */
+MyGame.Example.Monster.addVectorOfReferrables = function(builder, vectorOfReferrablesOffset) {
+ builder.addFieldOffset(35, vectorOfReferrablesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfReferrablesVector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfReferrablesVector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} singleWeakReference
+ */
+MyGame.Example.Monster.addSingleWeakReference = function(builder, singleWeakReference) {
+ builder.addFieldInt64(36, singleWeakReference, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfWeakReferencesOffset
+ */
+MyGame.Example.Monster.addVectorOfWeakReferences = function(builder, vectorOfWeakReferencesOffset) {
+ builder.addFieldOffset(37, vectorOfWeakReferencesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfWeakReferencesVector = function(builder, data) {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfWeakReferencesVector = function(builder, numElems) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfStrongReferrablesOffset
+ */
+MyGame.Example.Monster.addVectorOfStrongReferrables = function(builder, vectorOfStrongReferrablesOffset) {
+ builder.addFieldOffset(38, vectorOfStrongReferrablesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfStrongReferrablesVector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfStrongReferrablesVector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} coOwningReference
+ */
+MyGame.Example.Monster.addCoOwningReference = function(builder, coOwningReference) {
+ builder.addFieldInt64(39, coOwningReference, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfCoOwningReferencesOffset
+ */
+MyGame.Example.Monster.addVectorOfCoOwningReferences = function(builder, vectorOfCoOwningReferencesOffset) {
+ builder.addFieldOffset(40, vectorOfCoOwningReferencesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfCoOwningReferencesVector = function(builder, data) {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfCoOwningReferencesVector = function(builder, numElems) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} nonOwningReference
+ */
+MyGame.Example.Monster.addNonOwningReference = function(builder, nonOwningReference) {
+ builder.addFieldInt64(41, nonOwningReference, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfNonOwningReferencesOffset
+ */
+MyGame.Example.Monster.addVectorOfNonOwningReferences = function(builder, vectorOfNonOwningReferencesOffset) {
+ builder.addFieldOffset(42, vectorOfNonOwningReferencesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfNonOwningReferencesVector = function(builder, data) {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfNonOwningReferencesVector = function(builder, numElems) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.AnyUniqueAliases} anyUniqueType
+ */
+MyGame.Example.Monster.addAnyUniqueType = function(builder, anyUniqueType) {
+ builder.addFieldInt8(43, anyUniqueType, MyGame.Example.AnyUniqueAliases.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} anyUniqueOffset
+ */
+MyGame.Example.Monster.addAnyUnique = function(builder, anyUniqueOffset) {
+ builder.addFieldOffset(44, anyUniqueOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.AnyAmbiguousAliases} anyAmbiguousType
+ */
+MyGame.Example.Monster.addAnyAmbiguousType = function(builder, anyAmbiguousType) {
+ builder.addFieldInt8(45, anyAmbiguousType, MyGame.Example.AnyAmbiguousAliases.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} anyAmbiguousOffset
+ */
+MyGame.Example.Monster.addAnyAmbiguous = function(builder, anyAmbiguousOffset) {
+ builder.addFieldOffset(46, anyAmbiguousOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfEnumsOffset
+ */
+MyGame.Example.Monster.addVectorOfEnums = function(builder, vectorOfEnumsOffset) {
+ builder.addFieldOffset(47, vectorOfEnumsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<MyGame.Example.Color>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfEnumsVector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfEnumsVector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.endMonster = function(builder) {
+ var offset = builder.endObject();
+ builder.requiredField(offset, 10); // name
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+MyGame.Example.Monster.finishMonsterBuffer = function(builder, offset) {
+ builder.finish(offset, 'MONS');
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+MyGame.Example.Monster.finishSizePrefixedMonsterBuffer = function(builder, offset) {
+ builder.finish(offset, 'MONS', true);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} posOffset
+ * @param {number} mana
+ * @param {number} hp
+ * @param {flatbuffers.Offset} nameOffset
+ * @param {flatbuffers.Offset} inventoryOffset
+ * @param {MyGame.Example.Color} color
+ * @param {MyGame.Example.Any} testType
+ * @param {flatbuffers.Offset} testOffset
+ * @param {flatbuffers.Offset} test4Offset
+ * @param {flatbuffers.Offset} testarrayofstringOffset
+ * @param {flatbuffers.Offset} testarrayoftablesOffset
+ * @param {flatbuffers.Offset} enemyOffset
+ * @param {flatbuffers.Offset} testnestedflatbufferOffset
+ * @param {flatbuffers.Offset} testemptyOffset
+ * @param {boolean} testbool
+ * @param {number} testhashs32Fnv1
+ * @param {number} testhashu32Fnv1
+ * @param {flatbuffers.Long} testhashs64Fnv1
+ * @param {flatbuffers.Long} testhashu64Fnv1
+ * @param {number} testhashs32Fnv1a
+ * @param {number} testhashu32Fnv1a
+ * @param {flatbuffers.Long} testhashs64Fnv1a
+ * @param {flatbuffers.Long} testhashu64Fnv1a
+ * @param {flatbuffers.Offset} testarrayofboolsOffset
+ * @param {number} testf
+ * @param {number} testf2
+ * @param {number} testf3
+ * @param {flatbuffers.Offset} testarrayofstring2Offset
+ * @param {flatbuffers.Offset} testarrayofsortedstructOffset
+ * @param {flatbuffers.Offset} flexOffset
+ * @param {flatbuffers.Offset} test5Offset
+ * @param {flatbuffers.Offset} vectorOfLongsOffset
+ * @param {flatbuffers.Offset} vectorOfDoublesOffset
+ * @param {flatbuffers.Offset} parentNamespaceTestOffset
+ * @param {flatbuffers.Offset} vectorOfReferrablesOffset
+ * @param {flatbuffers.Long} singleWeakReference
+ * @param {flatbuffers.Offset} vectorOfWeakReferencesOffset
+ * @param {flatbuffers.Offset} vectorOfStrongReferrablesOffset
+ * @param {flatbuffers.Long} coOwningReference
+ * @param {flatbuffers.Offset} vectorOfCoOwningReferencesOffset
+ * @param {flatbuffers.Long} nonOwningReference
+ * @param {flatbuffers.Offset} vectorOfNonOwningReferencesOffset
+ * @param {MyGame.Example.AnyUniqueAliases} anyUniqueType
+ * @param {flatbuffers.Offset} anyUniqueOffset
+ * @param {MyGame.Example.AnyAmbiguousAliases} anyAmbiguousType
+ * @param {flatbuffers.Offset} anyAmbiguousOffset
+ * @param {flatbuffers.Offset} vectorOfEnumsOffset
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createMonster = function(builder, posOffset, mana, hp, nameOffset, inventoryOffset, color, testType, testOffset, test4Offset, testarrayofstringOffset, testarrayoftablesOffset, enemyOffset, testnestedflatbufferOffset, testemptyOffset, testbool, testhashs32Fnv1, testhashu32Fnv1, testhashs64Fnv1, testhashu64Fnv1, testhashs32Fnv1a, testhashu32Fnv1a, testhashs64Fnv1a, testhashu64Fnv1a, testarrayofboolsOffset, testf, testf2, testf3, testarrayofstring2Offset, testarrayofsortedstructOffset, flexOffset, test5Offset, vectorOfLongsOffset, vectorOfDoublesOffset, parentNamespaceTestOffset, vectorOfReferrablesOffset, singleWeakReference, vectorOfWeakReferencesOffset, vectorOfStrongReferrablesOffset, coOwningReference, vectorOfCoOwningReferencesOffset, nonOwningReference, vectorOfNonOwningReferencesOffset, anyUniqueType, anyUniqueOffset, anyAmbiguousType, anyAmbiguousOffset, vectorOfEnumsOffset) {
+ MyGame.Example.Monster.startMonster(builder);
+ MyGame.Example.Monster.addPos(builder, posOffset);
+ MyGame.Example.Monster.addMana(builder, mana);
+ MyGame.Example.Monster.addHp(builder, hp);
+ MyGame.Example.Monster.addName(builder, nameOffset);
+ MyGame.Example.Monster.addInventory(builder, inventoryOffset);
+ MyGame.Example.Monster.addColor(builder, color);
+ MyGame.Example.Monster.addTestType(builder, testType);
+ MyGame.Example.Monster.addTest(builder, testOffset);
+ MyGame.Example.Monster.addTest4(builder, test4Offset);
+ MyGame.Example.Monster.addTestarrayofstring(builder, testarrayofstringOffset);
+ MyGame.Example.Monster.addTestarrayoftables(builder, testarrayoftablesOffset);
+ MyGame.Example.Monster.addEnemy(builder, enemyOffset);
+ MyGame.Example.Monster.addTestnestedflatbuffer(builder, testnestedflatbufferOffset);
+ MyGame.Example.Monster.addTestempty(builder, testemptyOffset);
+ MyGame.Example.Monster.addTestbool(builder, testbool);
+ MyGame.Example.Monster.addTesthashs32Fnv1(builder, testhashs32Fnv1);
+ MyGame.Example.Monster.addTesthashu32Fnv1(builder, testhashu32Fnv1);
+ MyGame.Example.Monster.addTesthashs64Fnv1(builder, testhashs64Fnv1);
+ MyGame.Example.Monster.addTesthashu64Fnv1(builder, testhashu64Fnv1);
+ MyGame.Example.Monster.addTesthashs32Fnv1a(builder, testhashs32Fnv1a);
+ MyGame.Example.Monster.addTesthashu32Fnv1a(builder, testhashu32Fnv1a);
+ MyGame.Example.Monster.addTesthashs64Fnv1a(builder, testhashs64Fnv1a);
+ MyGame.Example.Monster.addTesthashu64Fnv1a(builder, testhashu64Fnv1a);
+ MyGame.Example.Monster.addTestarrayofbools(builder, testarrayofboolsOffset);
+ MyGame.Example.Monster.addTestf(builder, testf);
+ MyGame.Example.Monster.addTestf2(builder, testf2);
+ MyGame.Example.Monster.addTestf3(builder, testf3);
+ MyGame.Example.Monster.addTestarrayofstring2(builder, testarrayofstring2Offset);
+ MyGame.Example.Monster.addTestarrayofsortedstruct(builder, testarrayofsortedstructOffset);
+ MyGame.Example.Monster.addFlex(builder, flexOffset);
+ MyGame.Example.Monster.addTest5(builder, test5Offset);
+ MyGame.Example.Monster.addVectorOfLongs(builder, vectorOfLongsOffset);
+ MyGame.Example.Monster.addVectorOfDoubles(builder, vectorOfDoublesOffset);
+ MyGame.Example.Monster.addParentNamespaceTest(builder, parentNamespaceTestOffset);
+ MyGame.Example.Monster.addVectorOfReferrables(builder, vectorOfReferrablesOffset);
+ MyGame.Example.Monster.addSingleWeakReference(builder, singleWeakReference);
+ MyGame.Example.Monster.addVectorOfWeakReferences(builder, vectorOfWeakReferencesOffset);
+ MyGame.Example.Monster.addVectorOfStrongReferrables(builder, vectorOfStrongReferrablesOffset);
+ MyGame.Example.Monster.addCoOwningReference(builder, coOwningReference);
+ MyGame.Example.Monster.addVectorOfCoOwningReferences(builder, vectorOfCoOwningReferencesOffset);
+ MyGame.Example.Monster.addNonOwningReference(builder, nonOwningReference);
+ MyGame.Example.Monster.addVectorOfNonOwningReferences(builder, vectorOfNonOwningReferencesOffset);
+ MyGame.Example.Monster.addAnyUniqueType(builder, anyUniqueType);
+ MyGame.Example.Monster.addAnyUnique(builder, anyUniqueOffset);
+ MyGame.Example.Monster.addAnyAmbiguousType(builder, anyAmbiguousType);
+ MyGame.Example.Monster.addAnyAmbiguous(builder, anyAmbiguousOffset);
+ MyGame.Example.Monster.addVectorOfEnums(builder, vectorOfEnumsOffset);
+ return MyGame.Example.Monster.endMonster(builder);
+}
+
+/**
+ * @constructor
+ */
+MyGame.Example.TypeAliases = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.TypeAliases}
+ */
+MyGame.Example.TypeAliases.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.TypeAliases=} obj
+ * @returns {MyGame.Example.TypeAliases}
+ */
+MyGame.Example.TypeAliases.getRootAsTypeAliases = function(bb, obj) {
+ return (obj || new MyGame.Example.TypeAliases).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.TypeAliases=} obj
+ * @returns {MyGame.Example.TypeAliases}
+ */
+MyGame.Example.TypeAliases.getSizePrefixedRootAsTypeAliases = function(bb, obj) {
+ return (obj || new MyGame.Example.TypeAliases).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.i8 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? this.bb.readInt8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i8 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.u8 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? this.bb.readUint8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u8 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.i16 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? this.bb.readInt16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i16 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.u16 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 10);
+ return offset ? this.bb.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u16 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 10);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.i32 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 12);
+ return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i32 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 12);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.u32 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 14);
+ return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u32 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 14);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.TypeAliases.prototype.i64 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 16);
+ return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i64 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 16);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.TypeAliases.prototype.u64 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 18);
+ return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u64 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 18);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.f32 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 20);
+ return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_f32 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 20);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.f64 = function() {
+ var offset = this.bb.__offset(this.bb_pos, 22);
+ return offset ? this.bb.readFloat64(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_f64 = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 22);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeFloat64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.v8 = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 24);
+ return offset ? this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.v8Length = function() {
+ var offset = this.bb.__offset(this.bb_pos, 24);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int8Array}
+ */
+MyGame.Example.TypeAliases.prototype.v8Array = function() {
+ var offset = this.bb.__offset(this.bb_pos, 24);
+ return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.vf64 = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 26);
+ return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.vf64Length = function() {
+ var offset = this.bb.__offset(this.bb_pos, 26);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+MyGame.Example.TypeAliases.prototype.vf64Array = function() {
+ var offset = this.bb.__offset(this.bb_pos, 26);
+ return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example.TypeAliases.startTypeAliases = function(builder) {
+ builder.startObject(12);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i8
+ */
+MyGame.Example.TypeAliases.addI8 = function(builder, i8) {
+ builder.addFieldInt8(0, i8, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u8
+ */
+MyGame.Example.TypeAliases.addU8 = function(builder, u8) {
+ builder.addFieldInt8(1, u8, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i16
+ */
+MyGame.Example.TypeAliases.addI16 = function(builder, i16) {
+ builder.addFieldInt16(2, i16, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u16
+ */
+MyGame.Example.TypeAliases.addU16 = function(builder, u16) {
+ builder.addFieldInt16(3, u16, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i32
+ */
+MyGame.Example.TypeAliases.addI32 = function(builder, i32) {
+ builder.addFieldInt32(4, i32, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u32
+ */
+MyGame.Example.TypeAliases.addU32 = function(builder, u32) {
+ builder.addFieldInt32(5, u32, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} i64
+ */
+MyGame.Example.TypeAliases.addI64 = function(builder, i64) {
+ builder.addFieldInt64(6, i64, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} u64
+ */
+MyGame.Example.TypeAliases.addU64 = function(builder, u64) {
+ builder.addFieldInt64(7, u64, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} f32
+ */
+MyGame.Example.TypeAliases.addF32 = function(builder, f32) {
+ builder.addFieldFloat32(8, f32, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} f64
+ */
+MyGame.Example.TypeAliases.addF64 = function(builder, f64) {
+ builder.addFieldFloat64(9, f64, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} v8Offset
+ */
+MyGame.Example.TypeAliases.addV8 = function(builder, v8Offset) {
+ builder.addFieldOffset(10, v8Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.createV8Vector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.TypeAliases.startV8Vector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vf64Offset
+ */
+MyGame.Example.TypeAliases.addVf64 = function(builder, vf64Offset) {
+ builder.addFieldOffset(11, vf64Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.createVf64Vector = function(builder, data) {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addFloat64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.TypeAliases.startVf64Vector = function(builder, numElems) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.endTypeAliases = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i8
+ * @param {number} u8
+ * @param {number} i16
+ * @param {number} u16
+ * @param {number} i32
+ * @param {number} u32
+ * @param {flatbuffers.Long} i64
+ * @param {flatbuffers.Long} u64
+ * @param {number} f32
+ * @param {number} f64
+ * @param {flatbuffers.Offset} v8Offset
+ * @param {flatbuffers.Offset} vf64Offset
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.createTypeAliases = function(builder, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, v8Offset, vf64Offset) {
+ MyGame.Example.TypeAliases.startTypeAliases(builder);
+ MyGame.Example.TypeAliases.addI8(builder, i8);
+ MyGame.Example.TypeAliases.addU8(builder, u8);
+ MyGame.Example.TypeAliases.addI16(builder, i16);
+ MyGame.Example.TypeAliases.addU16(builder, u16);
+ MyGame.Example.TypeAliases.addI32(builder, i32);
+ MyGame.Example.TypeAliases.addU32(builder, u32);
+ MyGame.Example.TypeAliases.addI64(builder, i64);
+ MyGame.Example.TypeAliases.addU64(builder, u64);
+ MyGame.Example.TypeAliases.addF32(builder, f32);
+ MyGame.Example.TypeAliases.addF64(builder, f64);
+ MyGame.Example.TypeAliases.addV8(builder, v8Offset);
+ MyGame.Example.TypeAliases.addVf64(builder, vf64Offset);
+ return MyGame.Example.TypeAliases.endTypeAliases(builder);
+}
+
+// Exports for Node.js and RequireJS
+this.MyGame = MyGame;
diff --git a/tests/monster_test_generated.lobster b/tests/monster_test_generated.lobster
new file mode 100644
index 0000000..05e9cbe
--- /dev/null
+++ b/tests/monster_test_generated.lobster
@@ -0,0 +1,710 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+import flatbuffers
+
+namespace MyGame_Example
+
+/// Composite components of Monster color.
+enum Color:
+ Color_Red = 1
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ Color_Green = 2
+ /// \brief color Blue (1u << 3)
+ Color_Blue = 8
+
+enum Any:
+ Any_NONE = 0
+ Any_Monster = 1
+ Any_TestSimpleTableWithEnum = 2
+ Any_MyGame_Example2_Monster = 3
+
+enum AnyUniqueAliases:
+ AnyUniqueAliases_NONE = 0
+ AnyUniqueAliases_M = 1
+ AnyUniqueAliases_TS = 2
+ AnyUniqueAliases_M2 = 3
+
+enum AnyAmbiguousAliases:
+ AnyAmbiguousAliases_NONE = 0
+ AnyAmbiguousAliases_M1 = 1
+ AnyAmbiguousAliases_M2 = 2
+ AnyAmbiguousAliases_M3 = 3
+
+namespace MyGame
+
+class InParentNamespace
+
+namespace MyGame_Example2
+
+class Monster
+
+namespace MyGame_Example
+
+class Test
+
+class TestSimpleTableWithEnum
+
+class Vec3
+
+class Ability
+
+class Stat
+
+class Referrable
+
+class Monster
+
+class TypeAliases
+
+namespace MyGame
+
+class InParentNamespace : flatbuffers_handle
+
+def GetRootAsInParentNamespace(buf:string): return InParentNamespace { buf, buf.flatbuffers_indirect(0) }
+
+struct InParentNamespaceBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(0)
+ return this
+ def end():
+ return b_.EndObject()
+
+namespace MyGame_Example2
+
+class Monster : flatbuffers_handle
+
+def GetRootAsMonster(buf:string): return Monster { buf, buf.flatbuffers_indirect(0) }
+
+struct MonsterBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(0)
+ return this
+ def end():
+ return b_.EndObject()
+
+namespace MyGame_Example
+
+class Test : flatbuffers_handle
+ def a():
+ return buf_.read_int16_le(pos_ + 0)
+ def b():
+ return buf_.read_int8_le(pos_ + 2)
+
+def CreateTest(b_:flatbuffers_builder, a:int, b:int):
+ b_.Prep(2, 4)
+ b_.Pad(1)
+ b_.PrependInt8(b)
+ b_.PrependInt16(a)
+ return b_.Offset()
+
+class TestSimpleTableWithEnum : flatbuffers_handle
+ def color():
+ return Color(buf_.flatbuffers_field_int8(pos_, 4, 2))
+
+def GetRootAsTestSimpleTableWithEnum(buf:string): return TestSimpleTableWithEnum { buf, buf.flatbuffers_indirect(0) }
+
+struct TestSimpleTableWithEnumBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(1)
+ return this
+ def add_color(color:Color):
+ b_.PrependUint8Slot(0, color, 2)
+ return this
+ def end():
+ return b_.EndObject()
+
+class Vec3 : flatbuffers_handle
+ def x():
+ return buf_.read_float32_le(pos_ + 0)
+ def y():
+ return buf_.read_float32_le(pos_ + 4)
+ def z():
+ return buf_.read_float32_le(pos_ + 8)
+ def test1():
+ return buf_.read_float64_le(pos_ + 16)
+ def test2():
+ return Color(buf_.read_int8_le(pos_ + 24))
+ def test3():
+ return MyGame_Example_Test{ buf_, pos_ + 26 }
+
+def CreateVec3(b_:flatbuffers_builder, x:float, y:float, z:float, test1:float, test2:Color, test3_a:int, test3_b:int):
+ b_.Prep(8, 32)
+ b_.Pad(2)
+ b_.Prep(2, 4)
+ b_.Pad(1)
+ b_.PrependInt8(test3_b)
+ b_.PrependInt16(test3_a)
+ b_.Pad(1)
+ b_.PrependUint8(test2)
+ b_.PrependFloat64(test1)
+ b_.Pad(4)
+ b_.PrependFloat32(z)
+ b_.PrependFloat32(y)
+ b_.PrependFloat32(x)
+ return b_.Offset()
+
+class Ability : flatbuffers_handle
+ def id():
+ return buf_.read_int32_le(pos_ + 0)
+ def distance():
+ return buf_.read_int32_le(pos_ + 4)
+
+def CreateAbility(b_:flatbuffers_builder, id:int, distance:int):
+ b_.Prep(4, 8)
+ b_.PrependUint32(distance)
+ b_.PrependUint32(id)
+ return b_.Offset()
+
+class Stat : flatbuffers_handle
+ def id():
+ return buf_.flatbuffers_field_string(pos_, 4)
+ def val():
+ return buf_.flatbuffers_field_int64(pos_, 6, 0)
+ def count():
+ return buf_.flatbuffers_field_int16(pos_, 8, 0)
+
+def GetRootAsStat(buf:string): return Stat { buf, buf.flatbuffers_indirect(0) }
+
+struct StatBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(3)
+ return this
+ def add_id(id:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(0, id)
+ return this
+ def add_val(val:int):
+ b_.PrependInt64Slot(1, val, 0)
+ return this
+ def add_count(count:int):
+ b_.PrependUint16Slot(2, count, 0)
+ return this
+ def end():
+ return b_.EndObject()
+
+class Referrable : flatbuffers_handle
+ def id():
+ return buf_.flatbuffers_field_int64(pos_, 4, 0)
+
+def GetRootAsReferrable(buf:string): return Referrable { buf, buf.flatbuffers_indirect(0) }
+
+struct ReferrableBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(1)
+ return this
+ def add_id(id:int):
+ b_.PrependUint64Slot(0, id, 0)
+ return this
+ def end():
+ return b_.EndObject()
+
+/// an example documentation comment: monster object
+class Monster : flatbuffers_handle
+ def pos():
+ let o = buf_.flatbuffers_field_struct(pos_, 4)
+ return if o: MyGame_Example_Vec3 { buf_, o } else: nil
+ def mana():
+ return buf_.flatbuffers_field_int16(pos_, 6, 150)
+ def hp():
+ return buf_.flatbuffers_field_int16(pos_, 8, 100)
+ def name():
+ return buf_.flatbuffers_field_string(pos_, 10)
+ def inventory(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 14) + i * 1)
+ def inventory_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 14)
+ def color():
+ return Color(buf_.flatbuffers_field_int8(pos_, 16, 8))
+ def test_type():
+ return Any(buf_.flatbuffers_field_int8(pos_, 18, 0))
+ def test_as_Monster():
+ return MyGame_Example_Monster { buf_, buf_.flatbuffers_field_table(pos_, 20) }
+ def test_as_TestSimpleTableWithEnum():
+ return MyGame_Example_TestSimpleTableWithEnum { buf_, buf_.flatbuffers_field_table(pos_, 20) }
+ def test_as_MyGame_Example2_Monster():
+ return MyGame_Example2_Monster { buf_, buf_.flatbuffers_field_table(pos_, 20) }
+ def test4(i:int):
+ return MyGame_Example_Test { buf_, buf_.flatbuffers_field_vector(pos_, 22) + i * 4 }
+ def test4_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 22)
+ def testarrayofstring(i:int):
+ return buf_.flatbuffers_string(buf_.flatbuffers_field_vector(pos_, 24) + i * 4)
+ def testarrayofstring_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 24)
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ def testarrayoftables(i:int):
+ return MyGame_Example_Monster { buf_, buf_.flatbuffers_indirect(buf_.flatbuffers_field_vector(pos_, 26) + i * 4) }
+ def testarrayoftables_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 26)
+ def enemy():
+ let o = buf_.flatbuffers_field_table(pos_, 28)
+ return if o: MyGame_Example_Monster { buf_, o } else: nil
+ def testnestedflatbuffer(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 30) + i * 1)
+ def testnestedflatbuffer_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 30)
+ def testempty():
+ let o = buf_.flatbuffers_field_table(pos_, 32)
+ return if o: MyGame_Example_Stat { buf_, o } else: nil
+ def testbool():
+ return buf_.flatbuffers_field_int8(pos_, 34, 0)
+ def testhashs32_fnv1():
+ return buf_.flatbuffers_field_int32(pos_, 36, 0)
+ def testhashu32_fnv1():
+ return buf_.flatbuffers_field_int32(pos_, 38, 0)
+ def testhashs64_fnv1():
+ return buf_.flatbuffers_field_int64(pos_, 40, 0)
+ def testhashu64_fnv1():
+ return buf_.flatbuffers_field_int64(pos_, 42, 0)
+ def testhashs32_fnv1a():
+ return buf_.flatbuffers_field_int32(pos_, 44, 0)
+ def testhashu32_fnv1a():
+ return buf_.flatbuffers_field_int32(pos_, 46, 0)
+ def testhashs64_fnv1a():
+ return buf_.flatbuffers_field_int64(pos_, 48, 0)
+ def testhashu64_fnv1a():
+ return buf_.flatbuffers_field_int64(pos_, 50, 0)
+ def testarrayofbools(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 52) + i * 1)
+ def testarrayofbools_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 52)
+ def testf():
+ return buf_.flatbuffers_field_float32(pos_, 54, 3.14159)
+ def testf2():
+ return buf_.flatbuffers_field_float32(pos_, 56, 3.0)
+ def testf3():
+ return buf_.flatbuffers_field_float32(pos_, 58, 0.0)
+ def testarrayofstring2(i:int):
+ return buf_.flatbuffers_string(buf_.flatbuffers_field_vector(pos_, 60) + i * 4)
+ def testarrayofstring2_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 60)
+ def testarrayofsortedstruct(i:int):
+ return MyGame_Example_Ability { buf_, buf_.flatbuffers_field_vector(pos_, 62) + i * 8 }
+ def testarrayofsortedstruct_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 62)
+ def flex(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 64) + i * 1)
+ def flex_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 64)
+ def test5(i:int):
+ return MyGame_Example_Test { buf_, buf_.flatbuffers_field_vector(pos_, 66) + i * 4 }
+ def test5_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 66)
+ def vector_of_longs(i:int):
+ return buf_.read_int64_le(buf_.flatbuffers_field_vector(pos_, 68) + i * 8)
+ def vector_of_longs_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 68)
+ def vector_of_doubles(i:int):
+ return buf_.read_float64_le(buf_.flatbuffers_field_vector(pos_, 70) + i * 8)
+ def vector_of_doubles_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 70)
+ def parent_namespace_test():
+ let o = buf_.flatbuffers_field_table(pos_, 72)
+ return if o: MyGame_InParentNamespace { buf_, o } else: nil
+ def vector_of_referrables(i:int):
+ return MyGame_Example_Referrable { buf_, buf_.flatbuffers_indirect(buf_.flatbuffers_field_vector(pos_, 74) + i * 4) }
+ def vector_of_referrables_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 74)
+ def single_weak_reference():
+ return buf_.flatbuffers_field_int64(pos_, 76, 0)
+ def vector_of_weak_references(i:int):
+ return buf_.read_int64_le(buf_.flatbuffers_field_vector(pos_, 78) + i * 8)
+ def vector_of_weak_references_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 78)
+ def vector_of_strong_referrables(i:int):
+ return MyGame_Example_Referrable { buf_, buf_.flatbuffers_indirect(buf_.flatbuffers_field_vector(pos_, 80) + i * 4) }
+ def vector_of_strong_referrables_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 80)
+ def co_owning_reference():
+ return buf_.flatbuffers_field_int64(pos_, 82, 0)
+ def vector_of_co_owning_references(i:int):
+ return buf_.read_int64_le(buf_.flatbuffers_field_vector(pos_, 84) + i * 8)
+ def vector_of_co_owning_references_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 84)
+ def non_owning_reference():
+ return buf_.flatbuffers_field_int64(pos_, 86, 0)
+ def vector_of_non_owning_references(i:int):
+ return buf_.read_int64_le(buf_.flatbuffers_field_vector(pos_, 88) + i * 8)
+ def vector_of_non_owning_references_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 88)
+ def any_unique_type():
+ return AnyUniqueAliases(buf_.flatbuffers_field_int8(pos_, 90, 0))
+ def any_unique_as_M():
+ return MyGame_Example_Monster { buf_, buf_.flatbuffers_field_table(pos_, 92) }
+ def any_unique_as_TS():
+ return MyGame_Example_TestSimpleTableWithEnum { buf_, buf_.flatbuffers_field_table(pos_, 92) }
+ def any_unique_as_M2():
+ return MyGame_Example2_Monster { buf_, buf_.flatbuffers_field_table(pos_, 92) }
+ def any_ambiguous_type():
+ return AnyAmbiguousAliases(buf_.flatbuffers_field_int8(pos_, 94, 0))
+ def any_ambiguous_as_M1():
+ return MyGame_Example_Monster { buf_, buf_.flatbuffers_field_table(pos_, 96) }
+ def any_ambiguous_as_M2():
+ return MyGame_Example_Monster { buf_, buf_.flatbuffers_field_table(pos_, 96) }
+ def any_ambiguous_as_M3():
+ return MyGame_Example_Monster { buf_, buf_.flatbuffers_field_table(pos_, 96) }
+ def vector_of_enums(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 98) + i * 1)
+ def vector_of_enums_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 98)
+
+def GetRootAsMonster(buf:string): return Monster { buf, buf.flatbuffers_indirect(0) }
+
+struct MonsterBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(48)
+ return this
+ def add_pos(pos:flatbuffers_offset):
+ b_.PrependStructSlot(0, pos)
+ return this
+ def add_mana(mana:int):
+ b_.PrependInt16Slot(1, mana, 150)
+ return this
+ def add_hp(hp:int):
+ b_.PrependInt16Slot(2, hp, 100)
+ return this
+ def add_name(name:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(3, name)
+ return this
+ def add_inventory(inventory:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(5, inventory)
+ return this
+ def add_color(color:Color):
+ b_.PrependUint8Slot(6, color, 8)
+ return this
+ def add_test_type(test_type:Any):
+ b_.PrependUint8Slot(7, test_type, 0)
+ return this
+ def add_test(test:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(8, test)
+ return this
+ def add_test4(test4:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(9, test4)
+ return this
+ def add_testarrayofstring(testarrayofstring:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(10, testarrayofstring)
+ return this
+ def add_testarrayoftables(testarrayoftables:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(11, testarrayoftables)
+ return this
+ def add_enemy(enemy:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(12, enemy)
+ return this
+ def add_testnestedflatbuffer(testnestedflatbuffer:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(13, testnestedflatbuffer)
+ return this
+ def add_testempty(testempty:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(14, testempty)
+ return this
+ def add_testbool(testbool:int):
+ b_.PrependBoolSlot(15, testbool, 0)
+ return this
+ def add_testhashs32_fnv1(testhashs32_fnv1:int):
+ b_.PrependInt32Slot(16, testhashs32_fnv1, 0)
+ return this
+ def add_testhashu32_fnv1(testhashu32_fnv1:int):
+ b_.PrependUint32Slot(17, testhashu32_fnv1, 0)
+ return this
+ def add_testhashs64_fnv1(testhashs64_fnv1:int):
+ b_.PrependInt64Slot(18, testhashs64_fnv1, 0)
+ return this
+ def add_testhashu64_fnv1(testhashu64_fnv1:int):
+ b_.PrependUint64Slot(19, testhashu64_fnv1, 0)
+ return this
+ def add_testhashs32_fnv1a(testhashs32_fnv1a:int):
+ b_.PrependInt32Slot(20, testhashs32_fnv1a, 0)
+ return this
+ def add_testhashu32_fnv1a(testhashu32_fnv1a:int):
+ b_.PrependUint32Slot(21, testhashu32_fnv1a, 0)
+ return this
+ def add_testhashs64_fnv1a(testhashs64_fnv1a:int):
+ b_.PrependInt64Slot(22, testhashs64_fnv1a, 0)
+ return this
+ def add_testhashu64_fnv1a(testhashu64_fnv1a:int):
+ b_.PrependUint64Slot(23, testhashu64_fnv1a, 0)
+ return this
+ def add_testarrayofbools(testarrayofbools:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(24, testarrayofbools)
+ return this
+ def add_testf(testf:float):
+ b_.PrependFloat32Slot(25, testf, 3.14159)
+ return this
+ def add_testf2(testf2:float):
+ b_.PrependFloat32Slot(26, testf2, 3.0)
+ return this
+ def add_testf3(testf3:float):
+ b_.PrependFloat32Slot(27, testf3, 0.0)
+ return this
+ def add_testarrayofstring2(testarrayofstring2:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(28, testarrayofstring2)
+ return this
+ def add_testarrayofsortedstruct(testarrayofsortedstruct:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(29, testarrayofsortedstruct)
+ return this
+ def add_flex(flex:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(30, flex)
+ return this
+ def add_test5(test5:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(31, test5)
+ return this
+ def add_vector_of_longs(vector_of_longs:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(32, vector_of_longs)
+ return this
+ def add_vector_of_doubles(vector_of_doubles:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(33, vector_of_doubles)
+ return this
+ def add_parent_namespace_test(parent_namespace_test:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(34, parent_namespace_test)
+ return this
+ def add_vector_of_referrables(vector_of_referrables:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(35, vector_of_referrables)
+ return this
+ def add_single_weak_reference(single_weak_reference:int):
+ b_.PrependUint64Slot(36, single_weak_reference, 0)
+ return this
+ def add_vector_of_weak_references(vector_of_weak_references:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(37, vector_of_weak_references)
+ return this
+ def add_vector_of_strong_referrables(vector_of_strong_referrables:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(38, vector_of_strong_referrables)
+ return this
+ def add_co_owning_reference(co_owning_reference:int):
+ b_.PrependUint64Slot(39, co_owning_reference, 0)
+ return this
+ def add_vector_of_co_owning_references(vector_of_co_owning_references:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(40, vector_of_co_owning_references)
+ return this
+ def add_non_owning_reference(non_owning_reference:int):
+ b_.PrependUint64Slot(41, non_owning_reference, 0)
+ return this
+ def add_vector_of_non_owning_references(vector_of_non_owning_references:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(42, vector_of_non_owning_references)
+ return this
+ def add_any_unique_type(any_unique_type:AnyUniqueAliases):
+ b_.PrependUint8Slot(43, any_unique_type, 0)
+ return this
+ def add_any_unique(any_unique:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(44, any_unique)
+ return this
+ def add_any_ambiguous_type(any_ambiguous_type:AnyAmbiguousAliases):
+ b_.PrependUint8Slot(45, any_ambiguous_type, 0)
+ return this
+ def add_any_ambiguous(any_ambiguous:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(46, any_ambiguous)
+ return this
+ def add_vector_of_enums(vector_of_enums:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(47, vector_of_enums)
+ return this
+ def end():
+ return b_.EndObject()
+
+def MonsterStartInventoryVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def MonsterCreateInventoryVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependUint8(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTest4Vector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 2)
+
+def MonsterStartTestarrayofstringVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 4)
+def MonsterCreateTestarrayofstringVector(b_:flatbuffers_builder, v_:[flatbuffers_offset]):
+ b_.StartVector(4, v_.length, 4)
+ reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTestarrayoftablesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 4)
+def MonsterCreateTestarrayoftablesVector(b_:flatbuffers_builder, v_:[flatbuffers_offset]):
+ b_.StartVector(4, v_.length, 4)
+ reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTestnestedflatbufferVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def MonsterCreateTestnestedflatbufferVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependUint8(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTestarrayofboolsVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def MonsterCreateTestarrayofboolsVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependBool(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTestarrayofstring2Vector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 4)
+def MonsterCreateTestarrayofstring2Vector(b_:flatbuffers_builder, v_:[flatbuffers_offset]):
+ b_.StartVector(4, v_.length, 4)
+ reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTestarrayofsortedstructVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 4)
+
+def MonsterStartFlexVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def MonsterCreateFlexVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependUint8(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartTest5Vector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 2)
+
+def MonsterStartVectorOfLongsVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 8)
+def MonsterCreateVectorOfLongsVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(8, v_.length, 8)
+ reverse(v_) e_: b_.PrependInt64(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfDoublesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 8)
+def MonsterCreateVectorOfDoublesVector(b_:flatbuffers_builder, v_:[float]):
+ b_.StartVector(8, v_.length, 8)
+ reverse(v_) e_: b_.PrependFloat64(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfReferrablesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 4)
+def MonsterCreateVectorOfReferrablesVector(b_:flatbuffers_builder, v_:[flatbuffers_offset]):
+ b_.StartVector(4, v_.length, 4)
+ reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfWeakReferencesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 8)
+def MonsterCreateVectorOfWeakReferencesVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(8, v_.length, 8)
+ reverse(v_) e_: b_.PrependUint64(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfStrongReferrablesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(4, n_, 4)
+def MonsterCreateVectorOfStrongReferrablesVector(b_:flatbuffers_builder, v_:[flatbuffers_offset]):
+ b_.StartVector(4, v_.length, 4)
+ reverse(v_) e_: b_.PrependUOffsetTRelative(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfCoOwningReferencesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 8)
+def MonsterCreateVectorOfCoOwningReferencesVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(8, v_.length, 8)
+ reverse(v_) e_: b_.PrependUint64(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfNonOwningReferencesVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 8)
+def MonsterCreateVectorOfNonOwningReferencesVector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(8, v_.length, 8)
+ reverse(v_) e_: b_.PrependUint64(e_)
+ return b_.EndVector(v_.length)
+
+def MonsterStartVectorOfEnumsVector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def MonsterCreateVectorOfEnumsVector(b_:flatbuffers_builder, v_:[Color]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependUint8(e_)
+ return b_.EndVector(v_.length)
+
+class TypeAliases : flatbuffers_handle
+ def i8():
+ return buf_.flatbuffers_field_int8(pos_, 4, 0)
+ def u8():
+ return buf_.flatbuffers_field_int8(pos_, 6, 0)
+ def i16():
+ return buf_.flatbuffers_field_int16(pos_, 8, 0)
+ def u16():
+ return buf_.flatbuffers_field_int16(pos_, 10, 0)
+ def i32():
+ return buf_.flatbuffers_field_int32(pos_, 12, 0)
+ def u32():
+ return buf_.flatbuffers_field_int32(pos_, 14, 0)
+ def i64():
+ return buf_.flatbuffers_field_int64(pos_, 16, 0)
+ def u64():
+ return buf_.flatbuffers_field_int64(pos_, 18, 0)
+ def f32():
+ return buf_.flatbuffers_field_float32(pos_, 20, 0.0)
+ def f64():
+ return buf_.flatbuffers_field_float64(pos_, 22, 0.0)
+ def v8(i:int):
+ return buf_.read_int8_le(buf_.flatbuffers_field_vector(pos_, 24) + i * 1)
+ def v8_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 24)
+ def vf64(i:int):
+ return buf_.read_float64_le(buf_.flatbuffers_field_vector(pos_, 26) + i * 8)
+ def vf64_length():
+ return buf_.flatbuffers_field_vector_len(pos_, 26)
+
+def GetRootAsTypeAliases(buf:string): return TypeAliases { buf, buf.flatbuffers_indirect(0) }
+
+struct TypeAliasesBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(12)
+ return this
+ def add_i8(i8:int):
+ b_.PrependInt8Slot(0, i8, 0)
+ return this
+ def add_u8(u8:int):
+ b_.PrependUint8Slot(1, u8, 0)
+ return this
+ def add_i16(i16:int):
+ b_.PrependInt16Slot(2, i16, 0)
+ return this
+ def add_u16(u16:int):
+ b_.PrependUint16Slot(3, u16, 0)
+ return this
+ def add_i32(i32:int):
+ b_.PrependInt32Slot(4, i32, 0)
+ return this
+ def add_u32(u32:int):
+ b_.PrependUint32Slot(5, u32, 0)
+ return this
+ def add_i64(i64:int):
+ b_.PrependInt64Slot(6, i64, 0)
+ return this
+ def add_u64(u64:int):
+ b_.PrependUint64Slot(7, u64, 0)
+ return this
+ def add_f32(f32:float):
+ b_.PrependFloat32Slot(8, f32, 0.0)
+ return this
+ def add_f64(f64:float):
+ b_.PrependFloat64Slot(9, f64, 0.0)
+ return this
+ def add_v8(v8:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(10, v8)
+ return this
+ def add_vf64(vf64:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(11, vf64)
+ return this
+ def end():
+ return b_.EndObject()
+
+def TypeAliasesStartV8Vector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(1, n_, 1)
+def TypeAliasesCreateV8Vector(b_:flatbuffers_builder, v_:[int]):
+ b_.StartVector(1, v_.length, 1)
+ reverse(v_) e_: b_.PrependInt8(e_)
+ return b_.EndVector(v_.length)
+
+def TypeAliasesStartVf64Vector(b_:flatbuffers_builder, n_:int):
+ b_.StartVector(8, n_, 8)
+def TypeAliasesCreateVf64Vector(b_:flatbuffers_builder, v_:[float]):
+ b_.StartVector(8, v_.length, 8)
+ reverse(v_) e_: b_.PrependFloat64(e_)
+ return b_.EndVector(v_.length)
+
diff --git a/tests/monster_test_generated.rs b/tests/monster_test_generated.rs
new file mode 100644
index 0000000..59bbf37
--- /dev/null
+++ b/tests/monster_test_generated.rs
@@ -0,0 +1,1908 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+
+use std::mem;
+use std::cmp::Ordering;
+
+extern crate flatbuffers;
+use self::flatbuffers::EndianScalar;
+
+#[allow(unused_imports, dead_code)]
+pub mod my_game {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+
+pub enum InParentNamespaceOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct InParentNamespace<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for InParentNamespace<'a> {
+ type Inner = InParentNamespace<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> InParentNamespace<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ InParentNamespace {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ _args: &'args InParentNamespaceArgs) -> flatbuffers::WIPOffset<InParentNamespace<'bldr>> {
+ let mut builder = InParentNamespaceBuilder::new(_fbb);
+ builder.finish()
+ }
+
+}
+
+pub struct InParentNamespaceArgs {
+}
+impl<'a> Default for InParentNamespaceArgs {
+ #[inline]
+ fn default() -> Self {
+ InParentNamespaceArgs {
+ }
+ }
+}
+pub struct InParentNamespaceBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> InParentNamespaceBuilder<'a, 'b> {
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> InParentNamespaceBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ InParentNamespaceBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<InParentNamespace<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+#[allow(unused_imports, dead_code)]
+pub mod example_2 {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+
+pub enum MonsterOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct Monster<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for Monster<'a> {
+ type Inner = Monster<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> Monster<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ Monster {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ _args: &'args MonsterArgs) -> flatbuffers::WIPOffset<Monster<'bldr>> {
+ let mut builder = MonsterBuilder::new(_fbb);
+ builder.finish()
+ }
+
+}
+
+pub struct MonsterArgs {
+}
+impl<'a> Default for MonsterArgs {
+ #[inline]
+ fn default() -> Self {
+ MonsterArgs {
+ }
+ }
+}
+pub struct MonsterBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> MonsterBuilder<'a, 'b> {
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> MonsterBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ MonsterBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<Monster<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+} // pub mod Example2
+
+#[allow(unused_imports, dead_code)]
+pub mod example {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+
+/// Composite components of Monster color.
+#[allow(non_camel_case_types)]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum Color {
+ Red = 1,
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ Green = 2,
+ /// \brief color Blue (1u << 3)
+ Blue = 8,
+
+}
+
+const ENUM_MIN_COLOR: u8 = 1;
+const ENUM_MAX_COLOR: u8 = 8;
+
+impl<'a> flatbuffers::Follow<'a> for Color {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for Color {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = u8::to_le(self as u8);
+ let p = &n as *const u8 as *const Color;
+ unsafe { *p }
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ let n = u8::from_le(self as u8);
+ let p = &n as *const u8 as *const Color;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for Color {
+ type Output = Color;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<Color>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_COLOR:[Color; 3] = [
+ Color::Red,
+ Color::Green,
+ Color::Blue
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_COLOR:[&'static str; 8] = [
+ "Red",
+ "Green",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "Blue"
+];
+
+pub fn enum_name_color(e: Color) -> &'static str {
+ let index = e as u8 - Color::Red as u8;
+ ENUM_NAMES_COLOR[index as usize]
+}
+
+#[allow(non_camel_case_types)]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum Any {
+ NONE = 0,
+ Monster = 1,
+ TestSimpleTableWithEnum = 2,
+ MyGame_Example2_Monster = 3,
+
+}
+
+const ENUM_MIN_ANY: u8 = 0;
+const ENUM_MAX_ANY: u8 = 3;
+
+impl<'a> flatbuffers::Follow<'a> for Any {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for Any {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = u8::to_le(self as u8);
+ let p = &n as *const u8 as *const Any;
+ unsafe { *p }
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ let n = u8::from_le(self as u8);
+ let p = &n as *const u8 as *const Any;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for Any {
+ type Output = Any;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<Any>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_ANY:[Any; 4] = [
+ Any::NONE,
+ Any::Monster,
+ Any::TestSimpleTableWithEnum,
+ Any::MyGame_Example2_Monster
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_ANY:[&'static str; 4] = [
+ "NONE",
+ "Monster",
+ "TestSimpleTableWithEnum",
+ "MyGame_Example2_Monster"
+];
+
+pub fn enum_name_any(e: Any) -> &'static str {
+ let index = e as u8;
+ ENUM_NAMES_ANY[index as usize]
+}
+
+pub struct AnyUnionTableOffset {}
+#[allow(non_camel_case_types)]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum AnyUniqueAliases {
+ NONE = 0,
+ M = 1,
+ TS = 2,
+ M2 = 3,
+
+}
+
+const ENUM_MIN_ANY_UNIQUE_ALIASES: u8 = 0;
+const ENUM_MAX_ANY_UNIQUE_ALIASES: u8 = 3;
+
+impl<'a> flatbuffers::Follow<'a> for AnyUniqueAliases {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for AnyUniqueAliases {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = u8::to_le(self as u8);
+ let p = &n as *const u8 as *const AnyUniqueAliases;
+ unsafe { *p }
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ let n = u8::from_le(self as u8);
+ let p = &n as *const u8 as *const AnyUniqueAliases;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for AnyUniqueAliases {
+ type Output = AnyUniqueAliases;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<AnyUniqueAliases>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_ANY_UNIQUE_ALIASES:[AnyUniqueAliases; 4] = [
+ AnyUniqueAliases::NONE,
+ AnyUniqueAliases::M,
+ AnyUniqueAliases::TS,
+ AnyUniqueAliases::M2
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_ANY_UNIQUE_ALIASES:[&'static str; 4] = [
+ "NONE",
+ "M",
+ "TS",
+ "M2"
+];
+
+pub fn enum_name_any_unique_aliases(e: AnyUniqueAliases) -> &'static str {
+ let index = e as u8;
+ ENUM_NAMES_ANY_UNIQUE_ALIASES[index as usize]
+}
+
+pub struct AnyUniqueAliasesUnionTableOffset {}
+#[allow(non_camel_case_types)]
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub enum AnyAmbiguousAliases {
+ NONE = 0,
+ M1 = 1,
+ M2 = 2,
+ M3 = 3,
+
+}
+
+const ENUM_MIN_ANY_AMBIGUOUS_ALIASES: u8 = 0;
+const ENUM_MAX_ANY_AMBIGUOUS_ALIASES: u8 = 3;
+
+impl<'a> flatbuffers::Follow<'a> for AnyAmbiguousAliases {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for AnyAmbiguousAliases {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = u8::to_le(self as u8);
+ let p = &n as *const u8 as *const AnyAmbiguousAliases;
+ unsafe { *p }
+ }
+ #[inline]
+ fn from_little_endian(self) -> Self {
+ let n = u8::from_le(self as u8);
+ let p = &n as *const u8 as *const AnyAmbiguousAliases;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for AnyAmbiguousAliases {
+ type Output = AnyAmbiguousAliases;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<AnyAmbiguousAliases>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_ANY_AMBIGUOUS_ALIASES:[AnyAmbiguousAliases; 4] = [
+ AnyAmbiguousAliases::NONE,
+ AnyAmbiguousAliases::M1,
+ AnyAmbiguousAliases::M2,
+ AnyAmbiguousAliases::M3
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_ANY_AMBIGUOUS_ALIASES:[&'static str; 4] = [
+ "NONE",
+ "M1",
+ "M2",
+ "M3"
+];
+
+pub fn enum_name_any_ambiguous_aliases(e: AnyAmbiguousAliases) -> &'static str {
+ let index = e as u8;
+ ENUM_NAMES_ANY_AMBIGUOUS_ALIASES[index as usize]
+}
+
+pub struct AnyAmbiguousAliasesUnionTableOffset {}
+// struct Test, aligned to 2
+#[repr(C, align(2))]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Test {
+ a_: i16,
+ b_: i8,
+ padding0__: u8,
+} // pub struct Test
+impl flatbuffers::SafeSliceAccess for Test {}
+impl<'a> flatbuffers::Follow<'a> for Test {
+ type Inner = &'a Test;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ <&'a Test>::follow(buf, loc)
+ }
+}
+impl<'a> flatbuffers::Follow<'a> for &'a Test {
+ type Inner = &'a Test;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::follow_cast_ref::<Test>(buf, loc)
+ }
+}
+impl<'b> flatbuffers::Push for Test {
+ type Output = Test;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(self as *const Test as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+impl<'b> flatbuffers::Push for &'b Test {
+ type Output = Test;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(*self as *const Test as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+
+
+impl Test {
+ pub fn new<'a>(_a: i16, _b: i8) -> Self {
+ Test {
+ a_: _a.to_little_endian(),
+ b_: _b.to_little_endian(),
+
+ padding0__: 0,
+ }
+ }
+ pub fn a<'a>(&'a self) -> i16 {
+ self.a_.from_little_endian()
+ }
+ pub fn b<'a>(&'a self) -> i8 {
+ self.b_.from_little_endian()
+ }
+}
+
+// struct Vec3, aligned to 8
+#[repr(C, align(8))]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Vec3 {
+ x_: f32,
+ y_: f32,
+ z_: f32,
+ padding0__: u32,
+ test1_: f64,
+ test2_: Color,
+ padding1__: u8,
+ test3_: Test,
+ padding2__: u16,
+} // pub struct Vec3
+impl flatbuffers::SafeSliceAccess for Vec3 {}
+impl<'a> flatbuffers::Follow<'a> for Vec3 {
+ type Inner = &'a Vec3;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ <&'a Vec3>::follow(buf, loc)
+ }
+}
+impl<'a> flatbuffers::Follow<'a> for &'a Vec3 {
+ type Inner = &'a Vec3;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::follow_cast_ref::<Vec3>(buf, loc)
+ }
+}
+impl<'b> flatbuffers::Push for Vec3 {
+ type Output = Vec3;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(self as *const Vec3 as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+impl<'b> flatbuffers::Push for &'b Vec3 {
+ type Output = Vec3;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(*self as *const Vec3 as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+
+
+impl Vec3 {
+ pub fn new<'a>(_x: f32, _y: f32, _z: f32, _test1: f64, _test2: Color, _test3: &'a Test) -> Self {
+ Vec3 {
+ x_: _x.to_little_endian(),
+ y_: _y.to_little_endian(),
+ z_: _z.to_little_endian(),
+ test1_: _test1.to_little_endian(),
+ test2_: _test2.to_little_endian(),
+ test3_: *_test3,
+
+ padding0__: 0,
+ padding1__: 0,
+ padding2__: 0,
+ }
+ }
+ pub fn x<'a>(&'a self) -> f32 {
+ self.x_.from_little_endian()
+ }
+ pub fn y<'a>(&'a self) -> f32 {
+ self.y_.from_little_endian()
+ }
+ pub fn z<'a>(&'a self) -> f32 {
+ self.z_.from_little_endian()
+ }
+ pub fn test1<'a>(&'a self) -> f64 {
+ self.test1_.from_little_endian()
+ }
+ pub fn test2<'a>(&'a self) -> Color {
+ self.test2_.from_little_endian()
+ }
+ pub fn test3<'a>(&'a self) -> &'a Test {
+ &self.test3_
+ }
+}
+
+// struct Ability, aligned to 4
+#[repr(C, align(4))]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct Ability {
+ id_: u32,
+ distance_: u32,
+} // pub struct Ability
+impl flatbuffers::SafeSliceAccess for Ability {}
+impl<'a> flatbuffers::Follow<'a> for Ability {
+ type Inner = &'a Ability;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ <&'a Ability>::follow(buf, loc)
+ }
+}
+impl<'a> flatbuffers::Follow<'a> for &'a Ability {
+ type Inner = &'a Ability;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::follow_cast_ref::<Ability>(buf, loc)
+ }
+}
+impl<'b> flatbuffers::Push for Ability {
+ type Output = Ability;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(self as *const Ability as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+impl<'b> flatbuffers::Push for &'b Ability {
+ type Output = Ability;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(*self as *const Ability as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+
+
+impl Ability {
+ pub fn new<'a>(_id: u32, _distance: u32) -> Self {
+ Ability {
+ id_: _id.to_little_endian(),
+ distance_: _distance.to_little_endian(),
+
+ }
+ }
+ pub fn id<'a>(&'a self) -> u32 {
+ self.id_.from_little_endian()
+ }
+ #[inline]
+ pub fn key_compare_less_than(&self, o: &Ability) -> bool {
+ self.id() < o.id()
+ }
+
+ #[inline]
+ pub fn key_compare_with_value(&self, val: u32) -> ::std::cmp::Ordering {
+ let key = self.id();
+ key.cmp(&val)
+ }
+ pub fn distance<'a>(&'a self) -> u32 {
+ self.distance_.from_little_endian()
+ }
+}
+
+pub enum TestSimpleTableWithEnumOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct TestSimpleTableWithEnum<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for TestSimpleTableWithEnum<'a> {
+ type Inner = TestSimpleTableWithEnum<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> TestSimpleTableWithEnum<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ TestSimpleTableWithEnum {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args TestSimpleTableWithEnumArgs) -> flatbuffers::WIPOffset<TestSimpleTableWithEnum<'bldr>> {
+ let mut builder = TestSimpleTableWithEnumBuilder::new(_fbb);
+ builder.add_color(args.color);
+ builder.finish()
+ }
+
+ pub const VT_COLOR: flatbuffers::VOffsetT = 4;
+
+ #[inline]
+ pub fn color(&self) -> Color {
+ self._tab.get::<Color>(TestSimpleTableWithEnum::VT_COLOR, Some(Color::Green)).unwrap()
+ }
+}
+
+pub struct TestSimpleTableWithEnumArgs {
+ pub color: Color,
+}
+impl<'a> Default for TestSimpleTableWithEnumArgs {
+ #[inline]
+ fn default() -> Self {
+ TestSimpleTableWithEnumArgs {
+ color: Color::Green,
+ }
+ }
+}
+pub struct TestSimpleTableWithEnumBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> TestSimpleTableWithEnumBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_color(&mut self, color: Color) {
+ self.fbb_.push_slot::<Color>(TestSimpleTableWithEnum::VT_COLOR, color, Color::Green);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TestSimpleTableWithEnumBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ TestSimpleTableWithEnumBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<TestSimpleTableWithEnum<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+pub enum StatOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct Stat<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for Stat<'a> {
+ type Inner = Stat<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> Stat<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ Stat {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args StatArgs<'args>) -> flatbuffers::WIPOffset<Stat<'bldr>> {
+ let mut builder = StatBuilder::new(_fbb);
+ builder.add_val(args.val);
+ if let Some(x) = args.id { builder.add_id(x); }
+ builder.add_count(args.count);
+ builder.finish()
+ }
+
+ pub const VT_ID: flatbuffers::VOffsetT = 4;
+ pub const VT_VAL: flatbuffers::VOffsetT = 6;
+ pub const VT_COUNT: flatbuffers::VOffsetT = 8;
+
+ #[inline]
+ pub fn id(&self) -> Option<&'a str> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Stat::VT_ID, None)
+ }
+ #[inline]
+ pub fn val(&self) -> i64 {
+ self._tab.get::<i64>(Stat::VT_VAL, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn count(&self) -> u16 {
+ self._tab.get::<u16>(Stat::VT_COUNT, Some(0)).unwrap()
+ }
+}
+
+pub struct StatArgs<'a> {
+ pub id: Option<flatbuffers::WIPOffset<&'a str>>,
+ pub val: i64,
+ pub count: u16,
+}
+impl<'a> Default for StatArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ StatArgs {
+ id: None,
+ val: 0,
+ count: 0,
+ }
+ }
+}
+pub struct StatBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> StatBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_id(&mut self, id: flatbuffers::WIPOffset<&'b str>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Stat::VT_ID, id);
+ }
+ #[inline]
+ pub fn add_val(&mut self, val: i64) {
+ self.fbb_.push_slot::<i64>(Stat::VT_VAL, val, 0);
+ }
+ #[inline]
+ pub fn add_count(&mut self, count: u16) {
+ self.fbb_.push_slot::<u16>(Stat::VT_COUNT, count, 0);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> StatBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ StatBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<Stat<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+pub enum ReferrableOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct Referrable<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for Referrable<'a> {
+ type Inner = Referrable<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> Referrable<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ Referrable {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args ReferrableArgs) -> flatbuffers::WIPOffset<Referrable<'bldr>> {
+ let mut builder = ReferrableBuilder::new(_fbb);
+ builder.add_id(args.id);
+ builder.finish()
+ }
+
+ pub const VT_ID: flatbuffers::VOffsetT = 4;
+
+ #[inline]
+ pub fn id(&self) -> u64 {
+ self._tab.get::<u64>(Referrable::VT_ID, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn key_compare_less_than(&self, o: &Referrable) -> bool {
+ self.id() < o.id()
+ }
+
+ #[inline]
+ pub fn key_compare_with_value(&self, val: u64) -> ::std::cmp::Ordering {
+ let key = self.id();
+ key.cmp(&val)
+ }
+}
+
+pub struct ReferrableArgs {
+ pub id: u64,
+}
+impl<'a> Default for ReferrableArgs {
+ #[inline]
+ fn default() -> Self {
+ ReferrableArgs {
+ id: 0,
+ }
+ }
+}
+pub struct ReferrableBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> ReferrableBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_id(&mut self, id: u64) {
+ self.fbb_.push_slot::<u64>(Referrable::VT_ID, id, 0);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> ReferrableBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ ReferrableBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<Referrable<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+pub enum MonsterOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+/// an example documentation comment: monster object
+pub struct Monster<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for Monster<'a> {
+ type Inner = Monster<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> Monster<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ Monster {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args MonsterArgs<'args>) -> flatbuffers::WIPOffset<Monster<'bldr>> {
+ let mut builder = MonsterBuilder::new(_fbb);
+ builder.add_non_owning_reference(args.non_owning_reference);
+ builder.add_co_owning_reference(args.co_owning_reference);
+ builder.add_single_weak_reference(args.single_weak_reference);
+ builder.add_testhashu64_fnv1a(args.testhashu64_fnv1a);
+ builder.add_testhashs64_fnv1a(args.testhashs64_fnv1a);
+ builder.add_testhashu64_fnv1(args.testhashu64_fnv1);
+ builder.add_testhashs64_fnv1(args.testhashs64_fnv1);
+ if let Some(x) = args.vector_of_enums { builder.add_vector_of_enums(x); }
+ if let Some(x) = args.any_ambiguous { builder.add_any_ambiguous(x); }
+ if let Some(x) = args.any_unique { builder.add_any_unique(x); }
+ if let Some(x) = args.vector_of_non_owning_references { builder.add_vector_of_non_owning_references(x); }
+ if let Some(x) = args.vector_of_co_owning_references { builder.add_vector_of_co_owning_references(x); }
+ if let Some(x) = args.vector_of_strong_referrables { builder.add_vector_of_strong_referrables(x); }
+ if let Some(x) = args.vector_of_weak_references { builder.add_vector_of_weak_references(x); }
+ if let Some(x) = args.vector_of_referrables { builder.add_vector_of_referrables(x); }
+ if let Some(x) = args.parent_namespace_test { builder.add_parent_namespace_test(x); }
+ if let Some(x) = args.vector_of_doubles { builder.add_vector_of_doubles(x); }
+ if let Some(x) = args.vector_of_longs { builder.add_vector_of_longs(x); }
+ if let Some(x) = args.test5 { builder.add_test5(x); }
+ if let Some(x) = args.flex { builder.add_flex(x); }
+ if let Some(x) = args.testarrayofsortedstruct { builder.add_testarrayofsortedstruct(x); }
+ if let Some(x) = args.testarrayofstring2 { builder.add_testarrayofstring2(x); }
+ builder.add_testf3(args.testf3);
+ builder.add_testf2(args.testf2);
+ builder.add_testf(args.testf);
+ if let Some(x) = args.testarrayofbools { builder.add_testarrayofbools(x); }
+ builder.add_testhashu32_fnv1a(args.testhashu32_fnv1a);
+ builder.add_testhashs32_fnv1a(args.testhashs32_fnv1a);
+ builder.add_testhashu32_fnv1(args.testhashu32_fnv1);
+ builder.add_testhashs32_fnv1(args.testhashs32_fnv1);
+ if let Some(x) = args.testempty { builder.add_testempty(x); }
+ if let Some(x) = args.testnestedflatbuffer { builder.add_testnestedflatbuffer(x); }
+ if let Some(x) = args.enemy { builder.add_enemy(x); }
+ if let Some(x) = args.testarrayoftables { builder.add_testarrayoftables(x); }
+ if let Some(x) = args.testarrayofstring { builder.add_testarrayofstring(x); }
+ if let Some(x) = args.test4 { builder.add_test4(x); }
+ if let Some(x) = args.test { builder.add_test(x); }
+ if let Some(x) = args.inventory { builder.add_inventory(x); }
+ if let Some(x) = args.name { builder.add_name(x); }
+ if let Some(x) = args.pos { builder.add_pos(x); }
+ builder.add_hp(args.hp);
+ builder.add_mana(args.mana);
+ builder.add_any_ambiguous_type(args.any_ambiguous_type);
+ builder.add_any_unique_type(args.any_unique_type);
+ builder.add_testbool(args.testbool);
+ builder.add_test_type(args.test_type);
+ builder.add_color(args.color);
+ builder.finish()
+ }
+
+ pub const VT_POS: flatbuffers::VOffsetT = 4;
+ pub const VT_MANA: flatbuffers::VOffsetT = 6;
+ pub const VT_HP: flatbuffers::VOffsetT = 8;
+ pub const VT_NAME: flatbuffers::VOffsetT = 10;
+ pub const VT_INVENTORY: flatbuffers::VOffsetT = 14;
+ pub const VT_COLOR: flatbuffers::VOffsetT = 16;
+ pub const VT_TEST_TYPE: flatbuffers::VOffsetT = 18;
+ pub const VT_TEST: flatbuffers::VOffsetT = 20;
+ pub const VT_TEST4: flatbuffers::VOffsetT = 22;
+ pub const VT_TESTARRAYOFSTRING: flatbuffers::VOffsetT = 24;
+ pub const VT_TESTARRAYOFTABLES: flatbuffers::VOffsetT = 26;
+ pub const VT_ENEMY: flatbuffers::VOffsetT = 28;
+ pub const VT_TESTNESTEDFLATBUFFER: flatbuffers::VOffsetT = 30;
+ pub const VT_TESTEMPTY: flatbuffers::VOffsetT = 32;
+ pub const VT_TESTBOOL: flatbuffers::VOffsetT = 34;
+ pub const VT_TESTHASHS32_FNV1: flatbuffers::VOffsetT = 36;
+ pub const VT_TESTHASHU32_FNV1: flatbuffers::VOffsetT = 38;
+ pub const VT_TESTHASHS64_FNV1: flatbuffers::VOffsetT = 40;
+ pub const VT_TESTHASHU64_FNV1: flatbuffers::VOffsetT = 42;
+ pub const VT_TESTHASHS32_FNV1A: flatbuffers::VOffsetT = 44;
+ pub const VT_TESTHASHU32_FNV1A: flatbuffers::VOffsetT = 46;
+ pub const VT_TESTHASHS64_FNV1A: flatbuffers::VOffsetT = 48;
+ pub const VT_TESTHASHU64_FNV1A: flatbuffers::VOffsetT = 50;
+ pub const VT_TESTARRAYOFBOOLS: flatbuffers::VOffsetT = 52;
+ pub const VT_TESTF: flatbuffers::VOffsetT = 54;
+ pub const VT_TESTF2: flatbuffers::VOffsetT = 56;
+ pub const VT_TESTF3: flatbuffers::VOffsetT = 58;
+ pub const VT_TESTARRAYOFSTRING2: flatbuffers::VOffsetT = 60;
+ pub const VT_TESTARRAYOFSORTEDSTRUCT: flatbuffers::VOffsetT = 62;
+ pub const VT_FLEX: flatbuffers::VOffsetT = 64;
+ pub const VT_TEST5: flatbuffers::VOffsetT = 66;
+ pub const VT_VECTOR_OF_LONGS: flatbuffers::VOffsetT = 68;
+ pub const VT_VECTOR_OF_DOUBLES: flatbuffers::VOffsetT = 70;
+ pub const VT_PARENT_NAMESPACE_TEST: flatbuffers::VOffsetT = 72;
+ pub const VT_VECTOR_OF_REFERRABLES: flatbuffers::VOffsetT = 74;
+ pub const VT_SINGLE_WEAK_REFERENCE: flatbuffers::VOffsetT = 76;
+ pub const VT_VECTOR_OF_WEAK_REFERENCES: flatbuffers::VOffsetT = 78;
+ pub const VT_VECTOR_OF_STRONG_REFERRABLES: flatbuffers::VOffsetT = 80;
+ pub const VT_CO_OWNING_REFERENCE: flatbuffers::VOffsetT = 82;
+ pub const VT_VECTOR_OF_CO_OWNING_REFERENCES: flatbuffers::VOffsetT = 84;
+ pub const VT_NON_OWNING_REFERENCE: flatbuffers::VOffsetT = 86;
+ pub const VT_VECTOR_OF_NON_OWNING_REFERENCES: flatbuffers::VOffsetT = 88;
+ pub const VT_ANY_UNIQUE_TYPE: flatbuffers::VOffsetT = 90;
+ pub const VT_ANY_UNIQUE: flatbuffers::VOffsetT = 92;
+ pub const VT_ANY_AMBIGUOUS_TYPE: flatbuffers::VOffsetT = 94;
+ pub const VT_ANY_AMBIGUOUS: flatbuffers::VOffsetT = 96;
+ pub const VT_VECTOR_OF_ENUMS: flatbuffers::VOffsetT = 98;
+
+ #[inline]
+ pub fn pos(&self) -> Option<&'a Vec3> {
+ self._tab.get::<Vec3>(Monster::VT_POS, None)
+ }
+ #[inline]
+ pub fn mana(&self) -> i16 {
+ self._tab.get::<i16>(Monster::VT_MANA, Some(150)).unwrap()
+ }
+ #[inline]
+ pub fn hp(&self) -> i16 {
+ self._tab.get::<i16>(Monster::VT_HP, Some(100)).unwrap()
+ }
+ #[inline]
+ pub fn name(&self) -> &'a str {
+ self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(Monster::VT_NAME, None).unwrap()
+ }
+ #[inline]
+ pub fn key_compare_less_than(&self, o: &Monster) -> bool {
+ self.name() < o.name()
+ }
+
+ #[inline]
+ pub fn key_compare_with_value(&self, val: & str) -> ::std::cmp::Ordering {
+ let key = self.name();
+ key.cmp(&val)
+ }
+ #[inline]
+ pub fn inventory(&self) -> Option<&'a [u8]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u8>>>(Monster::VT_INVENTORY, None).map(|v| v.safe_slice())
+ }
+ #[inline]
+ pub fn color(&self) -> Color {
+ self._tab.get::<Color>(Monster::VT_COLOR, Some(Color::Blue)).unwrap()
+ }
+ #[inline]
+ pub fn test_type(&self) -> Any {
+ self._tab.get::<Any>(Monster::VT_TEST_TYPE, Some(Any::NONE)).unwrap()
+ }
+ #[inline]
+ pub fn test(&self) -> Option<flatbuffers::Table<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Table<'a>>>(Monster::VT_TEST, None)
+ }
+ #[inline]
+ pub fn test4(&self) -> Option<&'a [Test]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Test>>>(Monster::VT_TEST4, None).map(|v| v.safe_slice() )
+ }
+ #[inline]
+ pub fn testarrayofstring(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&'a str>>>>(Monster::VT_TESTARRAYOFSTRING, None)
+ }
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ #[inline]
+ pub fn testarrayoftables(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Monster<'a>>>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Monster<'a>>>>>(Monster::VT_TESTARRAYOFTABLES, None)
+ }
+ #[inline]
+ pub fn enemy(&self) -> Option<Monster<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<Monster<'a>>>(Monster::VT_ENEMY, None)
+ }
+ #[inline]
+ pub fn testnestedflatbuffer(&self) -> Option<&'a [u8]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u8>>>(Monster::VT_TESTNESTEDFLATBUFFER, None).map(|v| v.safe_slice())
+ }
+ pub fn testnestedflatbuffer_nested_flatbuffer(&'a self) -> Option<Monster<'a>> {
+ match self.testnestedflatbuffer() {
+ None => { None }
+ Some(data) => {
+ use self::flatbuffers::Follow;
+ Some(<flatbuffers::ForwardsUOffset<Monster<'a>>>::follow(data, 0))
+ },
+ }
+ }
+ #[inline]
+ pub fn testempty(&self) -> Option<Stat<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<Stat<'a>>>(Monster::VT_TESTEMPTY, None)
+ }
+ #[inline]
+ pub fn testbool(&self) -> bool {
+ self._tab.get::<bool>(Monster::VT_TESTBOOL, Some(false)).unwrap()
+ }
+ #[inline]
+ pub fn testhashs32_fnv1(&self) -> i32 {
+ self._tab.get::<i32>(Monster::VT_TESTHASHS32_FNV1, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashu32_fnv1(&self) -> u32 {
+ self._tab.get::<u32>(Monster::VT_TESTHASHU32_FNV1, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashs64_fnv1(&self) -> i64 {
+ self._tab.get::<i64>(Monster::VT_TESTHASHS64_FNV1, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashu64_fnv1(&self) -> u64 {
+ self._tab.get::<u64>(Monster::VT_TESTHASHU64_FNV1, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashs32_fnv1a(&self) -> i32 {
+ self._tab.get::<i32>(Monster::VT_TESTHASHS32_FNV1A, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashu32_fnv1a(&self) -> u32 {
+ self._tab.get::<u32>(Monster::VT_TESTHASHU32_FNV1A, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashs64_fnv1a(&self) -> i64 {
+ self._tab.get::<i64>(Monster::VT_TESTHASHS64_FNV1A, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testhashu64_fnv1a(&self) -> u64 {
+ self._tab.get::<u64>(Monster::VT_TESTHASHU64_FNV1A, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn testarrayofbools(&self) -> Option<&'a [bool]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, bool>>>(Monster::VT_TESTARRAYOFBOOLS, None).map(|v| v.safe_slice())
+ }
+ #[inline]
+ pub fn testf(&self) -> f32 {
+ self._tab.get::<f32>(Monster::VT_TESTF, Some(3.14159)).unwrap()
+ }
+ #[inline]
+ pub fn testf2(&self) -> f32 {
+ self._tab.get::<f32>(Monster::VT_TESTF2, Some(3.0)).unwrap()
+ }
+ #[inline]
+ pub fn testf3(&self) -> f32 {
+ self._tab.get::<f32>(Monster::VT_TESTF3, Some(0.0)).unwrap()
+ }
+ #[inline]
+ pub fn testarrayofstring2(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<&'a str>>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&'a str>>>>(Monster::VT_TESTARRAYOFSTRING2, None)
+ }
+ #[inline]
+ pub fn testarrayofsortedstruct(&self) -> Option<&'a [Ability]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Ability>>>(Monster::VT_TESTARRAYOFSORTEDSTRUCT, None).map(|v| v.safe_slice() )
+ }
+ #[inline]
+ pub fn flex(&self) -> Option<&'a [u8]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u8>>>(Monster::VT_FLEX, None).map(|v| v.safe_slice())
+ }
+ #[inline]
+ pub fn test5(&self) -> Option<&'a [Test]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<Test>>>(Monster::VT_TEST5, None).map(|v| v.safe_slice() )
+ }
+ #[inline]
+ pub fn vector_of_longs(&self) -> Option<flatbuffers::Vector<'a, i64>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, i64>>>(Monster::VT_VECTOR_OF_LONGS, None)
+ }
+ #[inline]
+ pub fn vector_of_doubles(&self) -> Option<flatbuffers::Vector<'a, f64>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, f64>>>(Monster::VT_VECTOR_OF_DOUBLES, None)
+ }
+ #[inline]
+ pub fn parent_namespace_test(&self) -> Option<super::InParentNamespace<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::InParentNamespace<'a>>>(Monster::VT_PARENT_NAMESPACE_TEST, None)
+ }
+ #[inline]
+ pub fn vector_of_referrables(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Referrable<'a>>>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Referrable<'a>>>>>(Monster::VT_VECTOR_OF_REFERRABLES, None)
+ }
+ #[inline]
+ pub fn single_weak_reference(&self) -> u64 {
+ self._tab.get::<u64>(Monster::VT_SINGLE_WEAK_REFERENCE, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn vector_of_weak_references(&self) -> Option<flatbuffers::Vector<'a, u64>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u64>>>(Monster::VT_VECTOR_OF_WEAK_REFERENCES, None)
+ }
+ #[inline]
+ pub fn vector_of_strong_referrables(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<Referrable<'a>>>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<Referrable<'a>>>>>(Monster::VT_VECTOR_OF_STRONG_REFERRABLES, None)
+ }
+ #[inline]
+ pub fn co_owning_reference(&self) -> u64 {
+ self._tab.get::<u64>(Monster::VT_CO_OWNING_REFERENCE, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn vector_of_co_owning_references(&self) -> Option<flatbuffers::Vector<'a, u64>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u64>>>(Monster::VT_VECTOR_OF_CO_OWNING_REFERENCES, None)
+ }
+ #[inline]
+ pub fn non_owning_reference(&self) -> u64 {
+ self._tab.get::<u64>(Monster::VT_NON_OWNING_REFERENCE, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn vector_of_non_owning_references(&self) -> Option<flatbuffers::Vector<'a, u64>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, u64>>>(Monster::VT_VECTOR_OF_NON_OWNING_REFERENCES, None)
+ }
+ #[inline]
+ pub fn any_unique_type(&self) -> AnyUniqueAliases {
+ self._tab.get::<AnyUniqueAliases>(Monster::VT_ANY_UNIQUE_TYPE, Some(AnyUniqueAliases::NONE)).unwrap()
+ }
+ #[inline]
+ pub fn any_unique(&self) -> Option<flatbuffers::Table<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Table<'a>>>(Monster::VT_ANY_UNIQUE, None)
+ }
+ #[inline]
+ pub fn any_ambiguous_type(&self) -> AnyAmbiguousAliases {
+ self._tab.get::<AnyAmbiguousAliases>(Monster::VT_ANY_AMBIGUOUS_TYPE, Some(AnyAmbiguousAliases::NONE)).unwrap()
+ }
+ #[inline]
+ pub fn any_ambiguous(&self) -> Option<flatbuffers::Table<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Table<'a>>>(Monster::VT_ANY_AMBIGUOUS, None)
+ }
+ #[inline]
+ pub fn vector_of_enums(&self) -> Option<flatbuffers::Vector<'a, Color>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, Color>>>(Monster::VT_VECTOR_OF_ENUMS, None)
+ }
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn test_as_monster(&self) -> Option<Monster<'a>> {
+ if self.test_type() == Any::Monster {
+ self.test().map(|u| Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn test_as_test_simple_table_with_enum(&self) -> Option<TestSimpleTableWithEnum<'a>> {
+ if self.test_type() == Any::TestSimpleTableWithEnum {
+ self.test().map(|u| TestSimpleTableWithEnum::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn test_as_my_game_example_2_monster(&self) -> Option<super::example_2::Monster<'a>> {
+ if self.test_type() == Any::MyGame_Example2_Monster {
+ self.test().map(|u| super::example_2::Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn any_unique_as_m(&self) -> Option<Monster<'a>> {
+ if self.any_unique_type() == AnyUniqueAliases::M {
+ self.any_unique().map(|u| Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn any_unique_as_ts(&self) -> Option<TestSimpleTableWithEnum<'a>> {
+ if self.any_unique_type() == AnyUniqueAliases::TS {
+ self.any_unique().map(|u| TestSimpleTableWithEnum::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn any_unique_as_m2(&self) -> Option<super::example_2::Monster<'a>> {
+ if self.any_unique_type() == AnyUniqueAliases::M2 {
+ self.any_unique().map(|u| super::example_2::Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn any_ambiguous_as_m1(&self) -> Option<Monster<'a>> {
+ if self.any_ambiguous_type() == AnyAmbiguousAliases::M1 {
+ self.any_ambiguous().map(|u| Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn any_ambiguous_as_m2(&self) -> Option<Monster<'a>> {
+ if self.any_ambiguous_type() == AnyAmbiguousAliases::M2 {
+ self.any_ambiguous().map(|u| Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ #[allow(non_snake_case)]
+ pub fn any_ambiguous_as_m3(&self) -> Option<Monster<'a>> {
+ if self.any_ambiguous_type() == AnyAmbiguousAliases::M3 {
+ self.any_ambiguous().map(|u| Monster::init_from_table(u))
+ } else {
+ None
+ }
+ }
+
+}
+
+pub struct MonsterArgs<'a> {
+ pub pos: Option<&'a Vec3>,
+ pub mana: i16,
+ pub hp: i16,
+ pub name: Option<flatbuffers::WIPOffset<&'a str>>,
+ pub inventory: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u8>>>,
+ pub color: Color,
+ pub test_type: Any,
+ pub test: Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
+ pub test4: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , Test>>>,
+ pub testarrayofstring: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<&'a str>>>>,
+ pub testarrayoftables: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<Monster<'a >>>>>,
+ pub enemy: Option<flatbuffers::WIPOffset<Monster<'a >>>,
+ pub testnestedflatbuffer: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u8>>>,
+ pub testempty: Option<flatbuffers::WIPOffset<Stat<'a >>>,
+ pub testbool: bool,
+ pub testhashs32_fnv1: i32,
+ pub testhashu32_fnv1: u32,
+ pub testhashs64_fnv1: i64,
+ pub testhashu64_fnv1: u64,
+ pub testhashs32_fnv1a: i32,
+ pub testhashu32_fnv1a: u32,
+ pub testhashs64_fnv1a: i64,
+ pub testhashu64_fnv1a: u64,
+ pub testarrayofbools: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , bool>>>,
+ pub testf: f32,
+ pub testf2: f32,
+ pub testf3: f32,
+ pub testarrayofstring2: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<&'a str>>>>,
+ pub testarrayofsortedstruct: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , Ability>>>,
+ pub flex: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u8>>>,
+ pub test5: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , Test>>>,
+ pub vector_of_longs: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , i64>>>,
+ pub vector_of_doubles: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , f64>>>,
+ pub parent_namespace_test: Option<flatbuffers::WIPOffset<super::InParentNamespace<'a >>>,
+ pub vector_of_referrables: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<Referrable<'a >>>>>,
+ pub single_weak_reference: u64,
+ pub vector_of_weak_references: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u64>>>,
+ pub vector_of_strong_referrables: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , flatbuffers::ForwardsUOffset<Referrable<'a >>>>>,
+ pub co_owning_reference: u64,
+ pub vector_of_co_owning_references: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u64>>>,
+ pub non_owning_reference: u64,
+ pub vector_of_non_owning_references: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , u64>>>,
+ pub any_unique_type: AnyUniqueAliases,
+ pub any_unique: Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
+ pub any_ambiguous_type: AnyAmbiguousAliases,
+ pub any_ambiguous: Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>,
+ pub vector_of_enums: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , Color>>>,
+}
+impl<'a> Default for MonsterArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ MonsterArgs {
+ pos: None,
+ mana: 150,
+ hp: 100,
+ name: None, // required field
+ inventory: None,
+ color: Color::Blue,
+ test_type: Any::NONE,
+ test: None,
+ test4: None,
+ testarrayofstring: None,
+ testarrayoftables: None,
+ enemy: None,
+ testnestedflatbuffer: None,
+ testempty: None,
+ testbool: false,
+ testhashs32_fnv1: 0,
+ testhashu32_fnv1: 0,
+ testhashs64_fnv1: 0,
+ testhashu64_fnv1: 0,
+ testhashs32_fnv1a: 0,
+ testhashu32_fnv1a: 0,
+ testhashs64_fnv1a: 0,
+ testhashu64_fnv1a: 0,
+ testarrayofbools: None,
+ testf: 3.14159,
+ testf2: 3.0,
+ testf3: 0.0,
+ testarrayofstring2: None,
+ testarrayofsortedstruct: None,
+ flex: None,
+ test5: None,
+ vector_of_longs: None,
+ vector_of_doubles: None,
+ parent_namespace_test: None,
+ vector_of_referrables: None,
+ single_weak_reference: 0,
+ vector_of_weak_references: None,
+ vector_of_strong_referrables: None,
+ co_owning_reference: 0,
+ vector_of_co_owning_references: None,
+ non_owning_reference: 0,
+ vector_of_non_owning_references: None,
+ any_unique_type: AnyUniqueAliases::NONE,
+ any_unique: None,
+ any_ambiguous_type: AnyAmbiguousAliases::NONE,
+ any_ambiguous: None,
+ vector_of_enums: None,
+ }
+ }
+}
+pub struct MonsterBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> MonsterBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_pos(&mut self, pos: &'b Vec3) {
+ self.fbb_.push_slot_always::<&Vec3>(Monster::VT_POS, pos);
+ }
+ #[inline]
+ pub fn add_mana(&mut self, mana: i16) {
+ self.fbb_.push_slot::<i16>(Monster::VT_MANA, mana, 150);
+ }
+ #[inline]
+ pub fn add_hp(&mut self, hp: i16) {
+ self.fbb_.push_slot::<i16>(Monster::VT_HP, hp, 100);
+ }
+ #[inline]
+ pub fn add_name(&mut self, name: flatbuffers::WIPOffset<&'b str>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_NAME, name);
+ }
+ #[inline]
+ pub fn add_inventory(&mut self, inventory: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u8>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_INVENTORY, inventory);
+ }
+ #[inline]
+ pub fn add_color(&mut self, color: Color) {
+ self.fbb_.push_slot::<Color>(Monster::VT_COLOR, color, Color::Blue);
+ }
+ #[inline]
+ pub fn add_test_type(&mut self, test_type: Any) {
+ self.fbb_.push_slot::<Any>(Monster::VT_TEST_TYPE, test_type, Any::NONE);
+ }
+ #[inline]
+ pub fn add_test(&mut self, test: flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TEST, test);
+ }
+ #[inline]
+ pub fn add_test4(&mut self, test4: flatbuffers::WIPOffset<flatbuffers::Vector<'b , Test>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TEST4, test4);
+ }
+ #[inline]
+ pub fn add_testarrayofstring(&mut self, testarrayofstring: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<&'b str>>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TESTARRAYOFSTRING, testarrayofstring);
+ }
+ #[inline]
+ pub fn add_testarrayoftables(&mut self, testarrayoftables: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<Monster<'b >>>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TESTARRAYOFTABLES, testarrayoftables);
+ }
+ #[inline]
+ pub fn add_enemy(&mut self, enemy: flatbuffers::WIPOffset<Monster<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<Monster>>(Monster::VT_ENEMY, enemy);
+ }
+ #[inline]
+ pub fn add_testnestedflatbuffer(&mut self, testnestedflatbuffer: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u8>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TESTNESTEDFLATBUFFER, testnestedflatbuffer);
+ }
+ #[inline]
+ pub fn add_testempty(&mut self, testempty: flatbuffers::WIPOffset<Stat<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<Stat>>(Monster::VT_TESTEMPTY, testempty);
+ }
+ #[inline]
+ pub fn add_testbool(&mut self, testbool: bool) {
+ self.fbb_.push_slot::<bool>(Monster::VT_TESTBOOL, testbool, false);
+ }
+ #[inline]
+ pub fn add_testhashs32_fnv1(&mut self, testhashs32_fnv1: i32) {
+ self.fbb_.push_slot::<i32>(Monster::VT_TESTHASHS32_FNV1, testhashs32_fnv1, 0);
+ }
+ #[inline]
+ pub fn add_testhashu32_fnv1(&mut self, testhashu32_fnv1: u32) {
+ self.fbb_.push_slot::<u32>(Monster::VT_TESTHASHU32_FNV1, testhashu32_fnv1, 0);
+ }
+ #[inline]
+ pub fn add_testhashs64_fnv1(&mut self, testhashs64_fnv1: i64) {
+ self.fbb_.push_slot::<i64>(Monster::VT_TESTHASHS64_FNV1, testhashs64_fnv1, 0);
+ }
+ #[inline]
+ pub fn add_testhashu64_fnv1(&mut self, testhashu64_fnv1: u64) {
+ self.fbb_.push_slot::<u64>(Monster::VT_TESTHASHU64_FNV1, testhashu64_fnv1, 0);
+ }
+ #[inline]
+ pub fn add_testhashs32_fnv1a(&mut self, testhashs32_fnv1a: i32) {
+ self.fbb_.push_slot::<i32>(Monster::VT_TESTHASHS32_FNV1A, testhashs32_fnv1a, 0);
+ }
+ #[inline]
+ pub fn add_testhashu32_fnv1a(&mut self, testhashu32_fnv1a: u32) {
+ self.fbb_.push_slot::<u32>(Monster::VT_TESTHASHU32_FNV1A, testhashu32_fnv1a, 0);
+ }
+ #[inline]
+ pub fn add_testhashs64_fnv1a(&mut self, testhashs64_fnv1a: i64) {
+ self.fbb_.push_slot::<i64>(Monster::VT_TESTHASHS64_FNV1A, testhashs64_fnv1a, 0);
+ }
+ #[inline]
+ pub fn add_testhashu64_fnv1a(&mut self, testhashu64_fnv1a: u64) {
+ self.fbb_.push_slot::<u64>(Monster::VT_TESTHASHU64_FNV1A, testhashu64_fnv1a, 0);
+ }
+ #[inline]
+ pub fn add_testarrayofbools(&mut self, testarrayofbools: flatbuffers::WIPOffset<flatbuffers::Vector<'b , bool>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TESTARRAYOFBOOLS, testarrayofbools);
+ }
+ #[inline]
+ pub fn add_testf(&mut self, testf: f32) {
+ self.fbb_.push_slot::<f32>(Monster::VT_TESTF, testf, 3.14159);
+ }
+ #[inline]
+ pub fn add_testf2(&mut self, testf2: f32) {
+ self.fbb_.push_slot::<f32>(Monster::VT_TESTF2, testf2, 3.0);
+ }
+ #[inline]
+ pub fn add_testf3(&mut self, testf3: f32) {
+ self.fbb_.push_slot::<f32>(Monster::VT_TESTF3, testf3, 0.0);
+ }
+ #[inline]
+ pub fn add_testarrayofstring2(&mut self, testarrayofstring2: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<&'b str>>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2);
+ }
+ #[inline]
+ pub fn add_testarrayofsortedstruct(&mut self, testarrayofsortedstruct: flatbuffers::WIPOffset<flatbuffers::Vector<'b , Ability>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TESTARRAYOFSORTEDSTRUCT, testarrayofsortedstruct);
+ }
+ #[inline]
+ pub fn add_flex(&mut self, flex: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u8>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_FLEX, flex);
+ }
+ #[inline]
+ pub fn add_test5(&mut self, test5: flatbuffers::WIPOffset<flatbuffers::Vector<'b , Test>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_TEST5, test5);
+ }
+ #[inline]
+ pub fn add_vector_of_longs(&mut self, vector_of_longs: flatbuffers::WIPOffset<flatbuffers::Vector<'b , i64>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_LONGS, vector_of_longs);
+ }
+ #[inline]
+ pub fn add_vector_of_doubles(&mut self, vector_of_doubles: flatbuffers::WIPOffset<flatbuffers::Vector<'b , f64>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_DOUBLES, vector_of_doubles);
+ }
+ #[inline]
+ pub fn add_parent_namespace_test(&mut self, parent_namespace_test: flatbuffers::WIPOffset<super::InParentNamespace<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<super::InParentNamespace>>(Monster::VT_PARENT_NAMESPACE_TEST, parent_namespace_test);
+ }
+ #[inline]
+ pub fn add_vector_of_referrables(&mut self, vector_of_referrables: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<Referrable<'b >>>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_REFERRABLES, vector_of_referrables);
+ }
+ #[inline]
+ pub fn add_single_weak_reference(&mut self, single_weak_reference: u64) {
+ self.fbb_.push_slot::<u64>(Monster::VT_SINGLE_WEAK_REFERENCE, single_weak_reference, 0);
+ }
+ #[inline]
+ pub fn add_vector_of_weak_references(&mut self, vector_of_weak_references: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u64>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_WEAK_REFERENCES, vector_of_weak_references);
+ }
+ #[inline]
+ pub fn add_vector_of_strong_referrables(&mut self, vector_of_strong_referrables: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<Referrable<'b >>>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_STRONG_REFERRABLES, vector_of_strong_referrables);
+ }
+ #[inline]
+ pub fn add_co_owning_reference(&mut self, co_owning_reference: u64) {
+ self.fbb_.push_slot::<u64>(Monster::VT_CO_OWNING_REFERENCE, co_owning_reference, 0);
+ }
+ #[inline]
+ pub fn add_vector_of_co_owning_references(&mut self, vector_of_co_owning_references: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u64>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_CO_OWNING_REFERENCES, vector_of_co_owning_references);
+ }
+ #[inline]
+ pub fn add_non_owning_reference(&mut self, non_owning_reference: u64) {
+ self.fbb_.push_slot::<u64>(Monster::VT_NON_OWNING_REFERENCE, non_owning_reference, 0);
+ }
+ #[inline]
+ pub fn add_vector_of_non_owning_references(&mut self, vector_of_non_owning_references: flatbuffers::WIPOffset<flatbuffers::Vector<'b , u64>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_NON_OWNING_REFERENCES, vector_of_non_owning_references);
+ }
+ #[inline]
+ pub fn add_any_unique_type(&mut self, any_unique_type: AnyUniqueAliases) {
+ self.fbb_.push_slot::<AnyUniqueAliases>(Monster::VT_ANY_UNIQUE_TYPE, any_unique_type, AnyUniqueAliases::NONE);
+ }
+ #[inline]
+ pub fn add_any_unique(&mut self, any_unique: flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_ANY_UNIQUE, any_unique);
+ }
+ #[inline]
+ pub fn add_any_ambiguous_type(&mut self, any_ambiguous_type: AnyAmbiguousAliases) {
+ self.fbb_.push_slot::<AnyAmbiguousAliases>(Monster::VT_ANY_AMBIGUOUS_TYPE, any_ambiguous_type, AnyAmbiguousAliases::NONE);
+ }
+ #[inline]
+ pub fn add_any_ambiguous(&mut self, any_ambiguous: flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_ANY_AMBIGUOUS, any_ambiguous);
+ }
+ #[inline]
+ pub fn add_vector_of_enums(&mut self, vector_of_enums: flatbuffers::WIPOffset<flatbuffers::Vector<'b , Color>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(Monster::VT_VECTOR_OF_ENUMS, vector_of_enums);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> MonsterBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ MonsterBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<Monster<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ self.fbb_.required(o, Monster::VT_NAME,"name");
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+pub enum TypeAliasesOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct TypeAliases<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for TypeAliases<'a> {
+ type Inner = TypeAliases<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> TypeAliases<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ TypeAliases {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args TypeAliasesArgs<'args>) -> flatbuffers::WIPOffset<TypeAliases<'bldr>> {
+ let mut builder = TypeAliasesBuilder::new(_fbb);
+ builder.add_f64_(args.f64_);
+ builder.add_u64_(args.u64_);
+ builder.add_i64_(args.i64_);
+ if let Some(x) = args.vf64 { builder.add_vf64(x); }
+ if let Some(x) = args.v8 { builder.add_v8(x); }
+ builder.add_f32_(args.f32_);
+ builder.add_u32_(args.u32_);
+ builder.add_i32_(args.i32_);
+ builder.add_u16_(args.u16_);
+ builder.add_i16_(args.i16_);
+ builder.add_u8_(args.u8_);
+ builder.add_i8_(args.i8_);
+ builder.finish()
+ }
+
+ pub const VT_I8_: flatbuffers::VOffsetT = 4;
+ pub const VT_U8_: flatbuffers::VOffsetT = 6;
+ pub const VT_I16_: flatbuffers::VOffsetT = 8;
+ pub const VT_U16_: flatbuffers::VOffsetT = 10;
+ pub const VT_I32_: flatbuffers::VOffsetT = 12;
+ pub const VT_U32_: flatbuffers::VOffsetT = 14;
+ pub const VT_I64_: flatbuffers::VOffsetT = 16;
+ pub const VT_U64_: flatbuffers::VOffsetT = 18;
+ pub const VT_F32_: flatbuffers::VOffsetT = 20;
+ pub const VT_F64_: flatbuffers::VOffsetT = 22;
+ pub const VT_V8: flatbuffers::VOffsetT = 24;
+ pub const VT_VF64: flatbuffers::VOffsetT = 26;
+
+ #[inline]
+ pub fn i8_(&self) -> i8 {
+ self._tab.get::<i8>(TypeAliases::VT_I8_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn u8_(&self) -> u8 {
+ self._tab.get::<u8>(TypeAliases::VT_U8_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn i16_(&self) -> i16 {
+ self._tab.get::<i16>(TypeAliases::VT_I16_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn u16_(&self) -> u16 {
+ self._tab.get::<u16>(TypeAliases::VT_U16_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn i32_(&self) -> i32 {
+ self._tab.get::<i32>(TypeAliases::VT_I32_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn u32_(&self) -> u32 {
+ self._tab.get::<u32>(TypeAliases::VT_U32_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn i64_(&self) -> i64 {
+ self._tab.get::<i64>(TypeAliases::VT_I64_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn u64_(&self) -> u64 {
+ self._tab.get::<u64>(TypeAliases::VT_U64_, Some(0)).unwrap()
+ }
+ #[inline]
+ pub fn f32_(&self) -> f32 {
+ self._tab.get::<f32>(TypeAliases::VT_F32_, Some(0.0)).unwrap()
+ }
+ #[inline]
+ pub fn f64_(&self) -> f64 {
+ self._tab.get::<f64>(TypeAliases::VT_F64_, Some(0.0)).unwrap()
+ }
+ #[inline]
+ pub fn v8(&self) -> Option<&'a [i8]> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, i8>>>(TypeAliases::VT_V8, None).map(|v| v.safe_slice())
+ }
+ #[inline]
+ pub fn vf64(&self) -> Option<flatbuffers::Vector<'a, f64>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, f64>>>(TypeAliases::VT_VF64, None)
+ }
+}
+
+pub struct TypeAliasesArgs<'a> {
+ pub i8_: i8,
+ pub u8_: u8,
+ pub i16_: i16,
+ pub u16_: u16,
+ pub i32_: i32,
+ pub u32_: u32,
+ pub i64_: i64,
+ pub u64_: u64,
+ pub f32_: f32,
+ pub f64_: f64,
+ pub v8: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , i8>>>,
+ pub vf64: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a , f64>>>,
+}
+impl<'a> Default for TypeAliasesArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ TypeAliasesArgs {
+ i8_: 0,
+ u8_: 0,
+ i16_: 0,
+ u16_: 0,
+ i32_: 0,
+ u32_: 0,
+ i64_: 0,
+ u64_: 0,
+ f32_: 0.0,
+ f64_: 0.0,
+ v8: None,
+ vf64: None,
+ }
+ }
+}
+pub struct TypeAliasesBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> TypeAliasesBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_i8_(&mut self, i8_: i8) {
+ self.fbb_.push_slot::<i8>(TypeAliases::VT_I8_, i8_, 0);
+ }
+ #[inline]
+ pub fn add_u8_(&mut self, u8_: u8) {
+ self.fbb_.push_slot::<u8>(TypeAliases::VT_U8_, u8_, 0);
+ }
+ #[inline]
+ pub fn add_i16_(&mut self, i16_: i16) {
+ self.fbb_.push_slot::<i16>(TypeAliases::VT_I16_, i16_, 0);
+ }
+ #[inline]
+ pub fn add_u16_(&mut self, u16_: u16) {
+ self.fbb_.push_slot::<u16>(TypeAliases::VT_U16_, u16_, 0);
+ }
+ #[inline]
+ pub fn add_i32_(&mut self, i32_: i32) {
+ self.fbb_.push_slot::<i32>(TypeAliases::VT_I32_, i32_, 0);
+ }
+ #[inline]
+ pub fn add_u32_(&mut self, u32_: u32) {
+ self.fbb_.push_slot::<u32>(TypeAliases::VT_U32_, u32_, 0);
+ }
+ #[inline]
+ pub fn add_i64_(&mut self, i64_: i64) {
+ self.fbb_.push_slot::<i64>(TypeAliases::VT_I64_, i64_, 0);
+ }
+ #[inline]
+ pub fn add_u64_(&mut self, u64_: u64) {
+ self.fbb_.push_slot::<u64>(TypeAliases::VT_U64_, u64_, 0);
+ }
+ #[inline]
+ pub fn add_f32_(&mut self, f32_: f32) {
+ self.fbb_.push_slot::<f32>(TypeAliases::VT_F32_, f32_, 0.0);
+ }
+ #[inline]
+ pub fn add_f64_(&mut self, f64_: f64) {
+ self.fbb_.push_slot::<f64>(TypeAliases::VT_F64_, f64_, 0.0);
+ }
+ #[inline]
+ pub fn add_v8(&mut self, v8: flatbuffers::WIPOffset<flatbuffers::Vector<'b , i8>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(TypeAliases::VT_V8, v8);
+ }
+ #[inline]
+ pub fn add_vf64(&mut self, vf64: flatbuffers::WIPOffset<flatbuffers::Vector<'b , f64>>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(TypeAliases::VT_VF64, vf64);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TypeAliasesBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ TypeAliasesBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<TypeAliases<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+#[inline]
+pub fn get_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
+ flatbuffers::get_root::<Monster<'a>>(buf)
+}
+
+#[inline]
+pub fn get_size_prefixed_root_as_monster<'a>(buf: &'a [u8]) -> Monster<'a> {
+ flatbuffers::get_size_prefixed_root::<Monster<'a>>(buf)
+}
+
+pub const MONSTER_IDENTIFIER: &'static str = "MONS";
+
+#[inline]
+pub fn monster_buffer_has_identifier(buf: &[u8]) -> bool {
+ return flatbuffers::buffer_has_identifier(buf, MONSTER_IDENTIFIER, false);
+}
+
+#[inline]
+pub fn monster_size_prefixed_buffer_has_identifier(buf: &[u8]) -> bool {
+ return flatbuffers::buffer_has_identifier(buf, MONSTER_IDENTIFIER, true);
+}
+
+pub const MONSTER_EXTENSION: &'static str = "mon";
+
+#[inline]
+pub fn finish_monster_buffer<'a, 'b>(
+ fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ root: flatbuffers::WIPOffset<Monster<'a>>) {
+ fbb.finish(root, Some(MONSTER_IDENTIFIER));
+}
+
+#[inline]
+pub fn finish_size_prefixed_monster_buffer<'a, 'b>(fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, root: flatbuffers::WIPOffset<Monster<'a>>) {
+ fbb.finish_size_prefixed(root, Some(MONSTER_IDENTIFIER));
+}
+} // pub mod Example
+} // pub mod MyGame
+
diff --git a/tests/monster_test_generated.ts b/tests/monster_test_generated.ts
new file mode 100644
index 0000000..5f51589
--- /dev/null
+++ b/tests/monster_test_generated.ts
@@ -0,0 +1,3086 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * Composite components of Monster color.
+ *
+ * @enum {number}
+ */
+export namespace MyGame.Example{
+export enum Color{
+ Red= 1,
+
+ /**
+ * \brief color Green
+ * Green is bit_flag with value (1u << 1)
+ */
+ Green= 2,
+
+ /**
+ * \brief color Blue (1u << 3)
+ */
+ Blue= 8
+}};
+
+/**
+ * @enum {number}
+ */
+export namespace MyGame.Example{
+export enum Any{
+ NONE= 0,
+ Monster= 1,
+ TestSimpleTableWithEnum= 2,
+ MyGame_Example2_Monster= 3
+}};
+
+/**
+ * @enum {number}
+ */
+export namespace MyGame.Example{
+export enum AnyUniqueAliases{
+ NONE= 0,
+ M= 1,
+ TS= 2,
+ M2= 3
+}};
+
+/**
+ * @enum {number}
+ */
+export namespace MyGame.Example{
+export enum AnyAmbiguousAliases{
+ NONE= 0,
+ M1= 1,
+ M2= 2,
+ M3= 3
+}};
+
+/**
+ * @constructor
+ */
+export namespace MyGame{
+export class InParentNamespace {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns InParentNamespace
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):InParentNamespace {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param InParentNamespace= obj
+ * @returns InParentNamespace
+ */
+static getRootAsInParentNamespace(bb:flatbuffers.ByteBuffer, obj?:InParentNamespace):InParentNamespace {
+ return (obj || new InParentNamespace).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param InParentNamespace= obj
+ * @returns InParentNamespace
+ */
+static getSizePrefixedRootAsInParentNamespace(bb:flatbuffers.ByteBuffer, obj?:InParentNamespace):InParentNamespace {
+ return (obj || new InParentNamespace).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startInParentNamespace(builder:flatbuffers.Builder) {
+ builder.startObject(0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endInParentNamespace(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createInParentNamespace(builder:flatbuffers.Builder):flatbuffers.Offset {
+ InParentNamespace.startInParentNamespace(builder);
+ return InParentNamespace.endInParentNamespace(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example2{
+export class Monster {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Monster
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Monster {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Monster= obj
+ * @returns Monster
+ */
+static getRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+ return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Monster= obj
+ * @returns Monster
+ */
+static getSizePrefixedRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+ return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startMonster(builder:flatbuffers.Builder) {
+ builder.startObject(0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+ Monster.startMonster(builder);
+ return Monster.endMonster(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Test {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Test
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Test {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns number
+ */
+a():number {
+ return this.bb!.readInt16(this.bb_pos);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_a(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+b():number {
+ return this.bb!.readInt8(this.bb_pos + 2);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_b(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 2);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number a
+ * @param number b
+ * @returns flatbuffers.Offset
+ */
+static createTest(builder:flatbuffers.Builder, a: number, b: number):flatbuffers.Offset {
+ builder.prep(2, 4);
+ builder.pad(1);
+ builder.writeInt8(b);
+ builder.writeInt16(a);
+ return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class TestSimpleTableWithEnum {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns TestSimpleTableWithEnum
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TestSimpleTableWithEnum {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TestSimpleTableWithEnum= obj
+ * @returns TestSimpleTableWithEnum
+ */
+static getRootAsTestSimpleTableWithEnum(bb:flatbuffers.ByteBuffer, obj?:TestSimpleTableWithEnum):TestSimpleTableWithEnum {
+ return (obj || new TestSimpleTableWithEnum).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TestSimpleTableWithEnum= obj
+ * @returns TestSimpleTableWithEnum
+ */
+static getSizePrefixedRootAsTestSimpleTableWithEnum(bb:flatbuffers.ByteBuffer, obj?:TestSimpleTableWithEnum):TestSimpleTableWithEnum {
+ return (obj || new TestSimpleTableWithEnum).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns MyGame.Example.Color
+ */
+color():MyGame.Example.Color {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : MyGame.Example.Color.Green;
+};
+
+/**
+ * @param MyGame.Example.Color value
+ * @returns boolean
+ */
+mutate_color(value:MyGame.Example.Color):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startTestSimpleTableWithEnum(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param MyGame.Example.Color color
+ */
+static addColor(builder:flatbuffers.Builder, color:MyGame.Example.Color) {
+ builder.addFieldInt8(0, color, MyGame.Example.Color.Green);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endTestSimpleTableWithEnum(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createTestSimpleTableWithEnum(builder:flatbuffers.Builder, color:MyGame.Example.Color):flatbuffers.Offset {
+ TestSimpleTableWithEnum.startTestSimpleTableWithEnum(builder);
+ TestSimpleTableWithEnum.addColor(builder, color);
+ return TestSimpleTableWithEnum.endTestSimpleTableWithEnum(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Vec3 {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Vec3
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Vec3 {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns number
+ */
+x():number {
+ return this.bb!.readFloat32(this.bb_pos);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_x(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+y():number {
+ return this.bb!.readFloat32(this.bb_pos + 4);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_y(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+z():number {
+ return this.bb!.readFloat32(this.bb_pos + 8);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_z(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+test1():number {
+ return this.bb!.readFloat64(this.bb_pos + 16);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_test1(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 16);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns MyGame.Example.Color
+ */
+test2():MyGame.Example.Color {
+ return /** */ (this.bb!.readUint8(this.bb_pos + 24));
+};
+
+/**
+ * @param MyGame.Example.Color value
+ * @returns boolean
+ */
+mutate_test2(value:MyGame.Example.Color):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 24);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param MyGame.Example.Test= obj
+ * @returns MyGame.Example.Test|null
+ */
+test3(obj?:MyGame.Example.Test):MyGame.Example.Test|null {
+ return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb!);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number x
+ * @param number y
+ * @param number z
+ * @param number test1
+ * @param MyGame.Example.Color test2
+ * @param number test3_a
+ * @param number test3_b
+ * @returns flatbuffers.Offset
+ */
+static createVec3(builder:flatbuffers.Builder, x: number, y: number, z: number, test1: number, test2: MyGame.Example.Color, test3_a: number, test3_b: number):flatbuffers.Offset {
+ builder.prep(8, 32);
+ builder.pad(2);
+ builder.prep(2, 4);
+ builder.pad(1);
+ builder.writeInt8(test3_b);
+ builder.writeInt16(test3_a);
+ builder.pad(1);
+ builder.writeInt8(test2);
+ builder.writeFloat64(test1);
+ builder.pad(4);
+ builder.writeFloat32(z);
+ builder.writeFloat32(y);
+ builder.writeFloat32(x);
+ return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Ability {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Ability
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Ability {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns number
+ */
+id():number {
+ return this.bb!.readUint32(this.bb_pos);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_id(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+distance():number {
+ return this.bb!.readUint32(this.bb_pos + 4);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_distance(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number id
+ * @param number distance
+ * @returns flatbuffers.Offset
+ */
+static createAbility(builder:flatbuffers.Builder, id: number, distance: number):flatbuffers.Offset {
+ builder.prep(4, 8);
+ builder.writeInt32(distance);
+ builder.writeInt32(id);
+ return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Stat {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Stat
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Stat {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Stat= obj
+ * @returns Stat
+ */
+static getRootAsStat(bb:flatbuffers.ByteBuffer, obj?:Stat):Stat {
+ return (obj || new Stat).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Stat= obj
+ * @returns Stat
+ */
+static getSizePrefixedRootAsStat(bb:flatbuffers.ByteBuffer, obj?:Stat):Stat {
+ return (obj || new Stat).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.Encoding= optionalEncoding
+ * @returns string|Uint8Array|null
+ */
+id():string|null
+id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
+id(optionalEncoding?:any):string|Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+val():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readInt64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_val(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+count():number {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_count(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startStat(builder:flatbuffers.Builder) {
+ builder.startObject(3);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset idOffset
+ */
+static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(0, idOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long val
+ */
+static addVal(builder:flatbuffers.Builder, val:flatbuffers.Long) {
+ builder.addFieldInt64(1, val, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number count
+ */
+static addCount(builder:flatbuffers.Builder, count:number) {
+ builder.addFieldInt16(2, count, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endStat(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createStat(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, val:flatbuffers.Long, count:number):flatbuffers.Offset {
+ Stat.startStat(builder);
+ Stat.addId(builder, idOffset);
+ Stat.addVal(builder, val);
+ Stat.addCount(builder, count);
+ return Stat.endStat(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Referrable {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Referrable
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Referrable {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Referrable= obj
+ * @returns Referrable
+ */
+static getRootAsReferrable(bb:flatbuffers.ByteBuffer, obj?:Referrable):Referrable {
+ return (obj || new Referrable).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Referrable= obj
+ * @returns Referrable
+ */
+static getSizePrefixedRootAsReferrable(bb:flatbuffers.ByteBuffer, obj?:Referrable):Referrable {
+ return (obj || new Referrable).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+id():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_id(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startReferrable(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long id
+ */
+static addId(builder:flatbuffers.Builder, id:flatbuffers.Long) {
+ builder.addFieldInt64(0, id, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endReferrable(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createReferrable(builder:flatbuffers.Builder, id:flatbuffers.Long):flatbuffers.Offset {
+ Referrable.startReferrable(builder);
+ Referrable.addId(builder, id);
+ return Referrable.endReferrable(builder);
+}
+}
+}
+/**
+ * an example documentation comment: monster object
+ *
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Monster {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Monster
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Monster {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Monster= obj
+ * @returns Monster
+ */
+static getRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+ return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Monster= obj
+ * @returns Monster
+ */
+static getSizePrefixedRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+ return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @returns boolean
+ */
+static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {
+ return bb.__has_identifier('MONS');
+};
+
+/**
+ * @param MyGame.Example.Vec3= obj
+ * @returns MyGame.Example.Vec3|null
+ */
+pos(obj?:MyGame.Example.Vec3):MyGame.Example.Vec3|null {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? (obj || new MyGame.Example.Vec3).__init(this.bb_pos + offset, this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+mana():number {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readInt16(this.bb_pos + offset) : 150;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_mana(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+hp():number {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? this.bb!.readInt16(this.bb_pos + offset) : 100;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_hp(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Encoding= optionalEncoding
+ * @returns string|Uint8Array|null
+ */
+name():string|null
+name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
+name(optionalEncoding?:any):string|Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 10);
+ return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @param number index
+ * @returns number
+ */
+inventory(index: number):number|null {
+ var offset = this.bb!.__offset(this.bb_pos, 14);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns number
+ */
+inventoryLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 14);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Uint8Array
+ */
+inventoryArray():Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 14);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns MyGame.Example.Color
+ */
+color():MyGame.Example.Color {
+ var offset = this.bb!.__offset(this.bb_pos, 16);
+ return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : MyGame.Example.Color.Blue;
+};
+
+/**
+ * @param MyGame.Example.Color value
+ * @returns boolean
+ */
+mutate_color(value:MyGame.Example.Color):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 16);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns MyGame.Example.Any
+ */
+testType():MyGame.Example.Any {
+ var offset = this.bb!.__offset(this.bb_pos, 18);
+ return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : MyGame.Example.Any.NONE;
+};
+
+/**
+ * @param MyGame.Example.Any value
+ * @returns boolean
+ */
+mutate_test_type(value:MyGame.Example.Any):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 18);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Table obj
+ * @returns ?flatbuffers.Table
+ */
+test<T extends flatbuffers.Table>(obj:T):T|null {
+ var offset = this.bb!.__offset(this.bb_pos, 20);
+ return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param number index
+ * @param MyGame.Example.Test= obj
+ * @returns MyGame.Example.Test
+ */
+test4(index: number, obj?:MyGame.Example.Test):MyGame.Example.Test|null {
+ var offset = this.bb!.__offset(this.bb_pos, 22);
+ return offset ? (obj || new MyGame.Example.Test).__init(this.bb!.__vector(this.bb_pos + offset) + index * 4, this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+test4Length():number {
+ var offset = this.bb!.__offset(this.bb_pos, 22);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number index
+ * @param flatbuffers.Encoding= optionalEncoding
+ * @returns string|Uint8Array
+ */
+testarrayofstring(index: number):string
+testarrayofstring(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+testarrayofstring(index: number,optionalEncoding?:any):string|Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 24);
+ return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns number
+ */
+testarrayofstringLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 24);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * an example documentation comment: this will end up in the generated code
+ * multiline too
+ *
+ * @param number index
+ * @param MyGame.Example.Monster= obj
+ * @returns MyGame.Example.Monster
+ */
+testarrayoftables(index: number, obj?:MyGame.Example.Monster):MyGame.Example.Monster|null {
+ var offset = this.bb!.__offset(this.bb_pos, 26);
+ return offset ? (obj || new MyGame.Example.Monster).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+testarrayoftablesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 26);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param MyGame.Example.Monster= obj
+ * @returns MyGame.Example.Monster|null
+ */
+enemy(obj?:MyGame.Example.Monster):MyGame.Example.Monster|null {
+ var offset = this.bb!.__offset(this.bb_pos, 28);
+ return offset ? (obj || new MyGame.Example.Monster).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @param number index
+ * @returns number
+ */
+testnestedflatbuffer(index: number):number|null {
+ var offset = this.bb!.__offset(this.bb_pos, 30);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns number
+ */
+testnestedflatbufferLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 30);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Uint8Array
+ */
+testnestedflatbufferArray():Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 30);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param MyGame.Example.Stat= obj
+ * @returns MyGame.Example.Stat|null
+ */
+testempty(obj?:MyGame.Example.Stat):MyGame.Example.Stat|null {
+ var offset = this.bb!.__offset(this.bb_pos, 32);
+ return offset ? (obj || new MyGame.Example.Stat).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @returns boolean
+ */
+testbool():boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 34);
+ return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
+};
+
+/**
+ * @param boolean value
+ * @returns boolean
+ */
+mutate_testbool(value:boolean):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 34);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, +value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+testhashs32Fnv1():number {
+ var offset = this.bb!.__offset(this.bb_pos, 36);
+ return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testhashs32_fnv1(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 36);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+testhashu32Fnv1():number {
+ var offset = this.bb!.__offset(this.bb_pos, 38);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testhashu32_fnv1(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 38);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+testhashs64Fnv1():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 40);
+ return offset ? this.bb!.readInt64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_testhashs64_fnv1(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 40);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+testhashu64Fnv1():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 42);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_testhashu64_fnv1(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 42);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+testhashs32Fnv1a():number {
+ var offset = this.bb!.__offset(this.bb_pos, 44);
+ return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testhashs32_fnv1a(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 44);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+testhashu32Fnv1a():number {
+ var offset = this.bb!.__offset(this.bb_pos, 46);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testhashu32_fnv1a(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 46);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+testhashs64Fnv1a():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 48);
+ return offset ? this.bb!.readInt64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_testhashs64_fnv1a(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 48);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+testhashu64Fnv1a():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 50);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_testhashu64_fnv1a(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 50);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param number index
+ * @returns boolean
+ */
+testarrayofbools(index: number):boolean|null {
+ var offset = this.bb!.__offset(this.bb_pos, 52);
+ return offset ? !!this.bb!.readInt8(this.bb!.__vector(this.bb_pos + offset) + index) : false;
+};
+
+/**
+ * @returns number
+ */
+testarrayofboolsLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 52);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Int8Array
+ */
+testarrayofboolsArray():Int8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 52);
+ return offset ? new Int8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns number
+ */
+testf():number {
+ var offset = this.bb!.__offset(this.bb_pos, 54);
+ return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 3.14159;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testf(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 54);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+testf2():number {
+ var offset = this.bb!.__offset(this.bb_pos, 56);
+ return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 3.0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testf2(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 56);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+testf3():number {
+ var offset = this.bb!.__offset(this.bb_pos, 58);
+ return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_testf3(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 58);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param number index
+ * @param flatbuffers.Encoding= optionalEncoding
+ * @returns string|Uint8Array
+ */
+testarrayofstring2(index: number):string
+testarrayofstring2(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+testarrayofstring2(index: number,optionalEncoding?:any):string|Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 60);
+ return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns number
+ */
+testarrayofstring2Length():number {
+ var offset = this.bb!.__offset(this.bb_pos, 60);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number index
+ * @param MyGame.Example.Ability= obj
+ * @returns MyGame.Example.Ability
+ */
+testarrayofsortedstruct(index: number, obj?:MyGame.Example.Ability):MyGame.Example.Ability|null {
+ var offset = this.bb!.__offset(this.bb_pos, 62);
+ return offset ? (obj || new MyGame.Example.Ability).__init(this.bb!.__vector(this.bb_pos + offset) + index * 8, this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+testarrayofsortedstructLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 62);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number index
+ * @returns number
+ */
+flex(index: number):number|null {
+ var offset = this.bb!.__offset(this.bb_pos, 64);
+ return offset ? this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns number
+ */
+flexLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 64);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Uint8Array
+ */
+flexArray():Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 64);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param number index
+ * @param MyGame.Example.Test= obj
+ * @returns MyGame.Example.Test
+ */
+test5(index: number, obj?:MyGame.Example.Test):MyGame.Example.Test|null {
+ var offset = this.bb!.__offset(this.bb_pos, 66);
+ return offset ? (obj || new MyGame.Example.Test).__init(this.bb!.__vector(this.bb_pos + offset) + index * 4, this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+test5Length():number {
+ var offset = this.bb!.__offset(this.bb_pos, 66);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number index
+ * @returns flatbuffers.Long
+ */
+vectorOfLongs(index: number):flatbuffers.Long|null {
+ var offset = this.bb!.__offset(this.bb_pos, 68);
+ return offset ? this.bb!.readInt64(this.bb!.__vector(this.bb_pos + offset) + index * 8) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @returns number
+ */
+vectorOfLongsLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 68);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number index
+ * @returns number
+ */
+vectorOfDoubles(index: number):number|null {
+ var offset = this.bb!.__offset(this.bb_pos, 70);
+ return offset ? this.bb!.readFloat64(this.bb!.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns number
+ */
+vectorOfDoublesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 70);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Float64Array
+ */
+vectorOfDoublesArray():Float64Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 70);
+ return offset ? new Float64Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param MyGame.InParentNamespace= obj
+ * @returns MyGame.InParentNamespace|null
+ */
+parentNamespaceTest(obj?:MyGame.InParentNamespace):MyGame.InParentNamespace|null {
+ var offset = this.bb!.__offset(this.bb_pos, 72);
+ return offset ? (obj || new MyGame.InParentNamespace).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @param number index
+ * @param MyGame.Example.Referrable= obj
+ * @returns MyGame.Example.Referrable
+ */
+vectorOfReferrables(index: number, obj?:MyGame.Example.Referrable):MyGame.Example.Referrable|null {
+ var offset = this.bb!.__offset(this.bb_pos, 74);
+ return offset ? (obj || new MyGame.Example.Referrable).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+vectorOfReferrablesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 74);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+singleWeakReference():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 76);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_single_weak_reference(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 76);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param number index
+ * @returns flatbuffers.Long
+ */
+vectorOfWeakReferences(index: number):flatbuffers.Long|null {
+ var offset = this.bb!.__offset(this.bb_pos, 78);
+ return offset ? this.bb!.readUint64(this.bb!.__vector(this.bb_pos + offset) + index * 8) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @returns number
+ */
+vectorOfWeakReferencesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 78);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number index
+ * @param MyGame.Example.Referrable= obj
+ * @returns MyGame.Example.Referrable
+ */
+vectorOfStrongReferrables(index: number, obj?:MyGame.Example.Referrable):MyGame.Example.Referrable|null {
+ var offset = this.bb!.__offset(this.bb_pos, 80);
+ return offset ? (obj || new MyGame.Example.Referrable).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
+};
+
+/**
+ * @returns number
+ */
+vectorOfStrongReferrablesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 80);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+coOwningReference():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 82);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_co_owning_reference(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 82);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param number index
+ * @returns flatbuffers.Long
+ */
+vectorOfCoOwningReferences(index: number):flatbuffers.Long|null {
+ var offset = this.bb!.__offset(this.bb_pos, 84);
+ return offset ? this.bb!.readUint64(this.bb!.__vector(this.bb_pos + offset) + index * 8) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @returns number
+ */
+vectorOfCoOwningReferencesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 84);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+nonOwningReference():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 86);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_non_owning_reference(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 86);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param number index
+ * @returns flatbuffers.Long
+ */
+vectorOfNonOwningReferences(index: number):flatbuffers.Long|null {
+ var offset = this.bb!.__offset(this.bb_pos, 88);
+ return offset ? this.bb!.readUint64(this.bb!.__vector(this.bb_pos + offset) + index * 8) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @returns number
+ */
+vectorOfNonOwningReferencesLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 88);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns MyGame.Example.AnyUniqueAliases
+ */
+anyUniqueType():MyGame.Example.AnyUniqueAliases {
+ var offset = this.bb!.__offset(this.bb_pos, 90);
+ return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : MyGame.Example.AnyUniqueAliases.NONE;
+};
+
+/**
+ * @param MyGame.Example.AnyUniqueAliases value
+ * @returns boolean
+ */
+mutate_any_unique_type(value:MyGame.Example.AnyUniqueAliases):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 90);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Table obj
+ * @returns ?flatbuffers.Table
+ */
+anyUnique<T extends flatbuffers.Table>(obj:T):T|null {
+ var offset = this.bb!.__offset(this.bb_pos, 92);
+ return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @returns MyGame.Example.AnyAmbiguousAliases
+ */
+anyAmbiguousType():MyGame.Example.AnyAmbiguousAliases {
+ var offset = this.bb!.__offset(this.bb_pos, 94);
+ return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : MyGame.Example.AnyAmbiguousAliases.NONE;
+};
+
+/**
+ * @param MyGame.Example.AnyAmbiguousAliases value
+ * @returns boolean
+ */
+mutate_any_ambiguous_type(value:MyGame.Example.AnyAmbiguousAliases):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 94);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Table obj
+ * @returns ?flatbuffers.Table
+ */
+anyAmbiguous<T extends flatbuffers.Table>(obj:T):T|null {
+ var offset = this.bb!.__offset(this.bb_pos, 96);
+ return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param number index
+ * @returns MyGame.Example.Color
+ */
+vectorOfEnums(index: number):MyGame.Example.Color|null {
+ var offset = this.bb!.__offset(this.bb_pos, 98);
+ return offset ? /** */ (this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index)) : /** */ (0);
+};
+
+/**
+ * @returns number
+ */
+vectorOfEnumsLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 98);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Uint8Array
+ */
+vectorOfEnumsArray():Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 98);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startMonster(builder:flatbuffers.Builder) {
+ builder.startObject(48);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset posOffset
+ */
+static addPos(builder:flatbuffers.Builder, posOffset:flatbuffers.Offset) {
+ builder.addFieldStruct(0, posOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number mana
+ */
+static addMana(builder:flatbuffers.Builder, mana:number) {
+ builder.addFieldInt16(1, mana, 150);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number hp
+ */
+static addHp(builder:flatbuffers.Builder, hp:number) {
+ builder.addFieldInt16(2, hp, 100);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset nameOffset
+ */
+static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(3, nameOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset inventoryOffset
+ */
+static addInventory(builder:flatbuffers.Builder, inventoryOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(5, inventoryOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<number> data
+ * @returns flatbuffers.Offset
+ */
+static createInventoryVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startInventoryVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param MyGame.Example.Color color
+ */
+static addColor(builder:flatbuffers.Builder, color:MyGame.Example.Color) {
+ builder.addFieldInt8(6, color, MyGame.Example.Color.Blue);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param MyGame.Example.Any testType
+ */
+static addTestType(builder:flatbuffers.Builder, testType:MyGame.Example.Any) {
+ builder.addFieldInt8(7, testType, MyGame.Example.Any.NONE);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testOffset
+ */
+static addTest(builder:flatbuffers.Builder, testOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(8, testOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset test4Offset
+ */
+static addTest4(builder:flatbuffers.Builder, test4Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(9, test4Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTest4Vector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testarrayofstringOffset
+ */
+static addTestarrayofstring(builder:flatbuffers.Builder, testarrayofstringOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(10, testarrayofstringOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Offset> data
+ * @returns flatbuffers.Offset
+ */
+static createTestarrayofstringVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTestarrayofstringVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testarrayoftablesOffset
+ */
+static addTestarrayoftables(builder:flatbuffers.Builder, testarrayoftablesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(11, testarrayoftablesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Offset> data
+ * @returns flatbuffers.Offset
+ */
+static createTestarrayoftablesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTestarrayoftablesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset enemyOffset
+ */
+static addEnemy(builder:flatbuffers.Builder, enemyOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(12, enemyOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testnestedflatbufferOffset
+ */
+static addTestnestedflatbuffer(builder:flatbuffers.Builder, testnestedflatbufferOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(13, testnestedflatbufferOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<number> data
+ * @returns flatbuffers.Offset
+ */
+static createTestnestedflatbufferVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTestnestedflatbufferVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testemptyOffset
+ */
+static addTestempty(builder:flatbuffers.Builder, testemptyOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(14, testemptyOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param boolean testbool
+ */
+static addTestbool(builder:flatbuffers.Builder, testbool:boolean) {
+ builder.addFieldInt8(15, +testbool, +false);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testhashs32Fnv1
+ */
+static addTesthashs32Fnv1(builder:flatbuffers.Builder, testhashs32Fnv1:number) {
+ builder.addFieldInt32(16, testhashs32Fnv1, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testhashu32Fnv1
+ */
+static addTesthashu32Fnv1(builder:flatbuffers.Builder, testhashu32Fnv1:number) {
+ builder.addFieldInt32(17, testhashu32Fnv1, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long testhashs64Fnv1
+ */
+static addTesthashs64Fnv1(builder:flatbuffers.Builder, testhashs64Fnv1:flatbuffers.Long) {
+ builder.addFieldInt64(18, testhashs64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long testhashu64Fnv1
+ */
+static addTesthashu64Fnv1(builder:flatbuffers.Builder, testhashu64Fnv1:flatbuffers.Long) {
+ builder.addFieldInt64(19, testhashu64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testhashs32Fnv1a
+ */
+static addTesthashs32Fnv1a(builder:flatbuffers.Builder, testhashs32Fnv1a:number) {
+ builder.addFieldInt32(20, testhashs32Fnv1a, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testhashu32Fnv1a
+ */
+static addTesthashu32Fnv1a(builder:flatbuffers.Builder, testhashu32Fnv1a:number) {
+ builder.addFieldInt32(21, testhashu32Fnv1a, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long testhashs64Fnv1a
+ */
+static addTesthashs64Fnv1a(builder:flatbuffers.Builder, testhashs64Fnv1a:flatbuffers.Long) {
+ builder.addFieldInt64(22, testhashs64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long testhashu64Fnv1a
+ */
+static addTesthashu64Fnv1a(builder:flatbuffers.Builder, testhashu64Fnv1a:flatbuffers.Long) {
+ builder.addFieldInt64(23, testhashu64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testarrayofboolsOffset
+ */
+static addTestarrayofbools(builder:flatbuffers.Builder, testarrayofboolsOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(24, testarrayofboolsOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<boolean> data
+ * @returns flatbuffers.Offset
+ */
+static createTestarrayofboolsVector(builder:flatbuffers.Builder, data:boolean[]):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(+data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTestarrayofboolsVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testf
+ */
+static addTestf(builder:flatbuffers.Builder, testf:number) {
+ builder.addFieldFloat32(25, testf, 3.14159);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testf2
+ */
+static addTestf2(builder:flatbuffers.Builder, testf2:number) {
+ builder.addFieldFloat32(26, testf2, 3.0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number testf3
+ */
+static addTestf3(builder:flatbuffers.Builder, testf3:number) {
+ builder.addFieldFloat32(27, testf3, 0.0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testarrayofstring2Offset
+ */
+static addTestarrayofstring2(builder:flatbuffers.Builder, testarrayofstring2Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(28, testarrayofstring2Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Offset> data
+ * @returns flatbuffers.Offset
+ */
+static createTestarrayofstring2Vector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTestarrayofstring2Vector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset testarrayofsortedstructOffset
+ */
+static addTestarrayofsortedstruct(builder:flatbuffers.Builder, testarrayofsortedstructOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(29, testarrayofsortedstructOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTestarrayofsortedstructVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset flexOffset
+ */
+static addFlex(builder:flatbuffers.Builder, flexOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(30, flexOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<number> data
+ * @returns flatbuffers.Offset
+ */
+static createFlexVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startFlexVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset test5Offset
+ */
+static addTest5(builder:flatbuffers.Builder, test5Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(31, test5Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startTest5Vector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfLongsOffset
+ */
+static addVectorOfLongs(builder:flatbuffers.Builder, vectorOfLongsOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(32, vectorOfLongsOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Long> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfLongsVector(builder:flatbuffers.Builder, data:flatbuffers.Long[]):flatbuffers.Offset {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfLongsVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfDoublesOffset
+ */
+static addVectorOfDoubles(builder:flatbuffers.Builder, vectorOfDoublesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(33, vectorOfDoublesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<number> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfDoublesVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addFloat64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfDoublesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset parentNamespaceTestOffset
+ */
+static addParentNamespaceTest(builder:flatbuffers.Builder, parentNamespaceTestOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(34, parentNamespaceTestOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfReferrablesOffset
+ */
+static addVectorOfReferrables(builder:flatbuffers.Builder, vectorOfReferrablesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(35, vectorOfReferrablesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Offset> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfReferrablesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfReferrablesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long singleWeakReference
+ */
+static addSingleWeakReference(builder:flatbuffers.Builder, singleWeakReference:flatbuffers.Long) {
+ builder.addFieldInt64(36, singleWeakReference, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfWeakReferencesOffset
+ */
+static addVectorOfWeakReferences(builder:flatbuffers.Builder, vectorOfWeakReferencesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(37, vectorOfWeakReferencesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Long> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfWeakReferencesVector(builder:flatbuffers.Builder, data:flatbuffers.Long[]):flatbuffers.Offset {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfWeakReferencesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfStrongReferrablesOffset
+ */
+static addVectorOfStrongReferrables(builder:flatbuffers.Builder, vectorOfStrongReferrablesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(38, vectorOfStrongReferrablesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Offset> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfStrongReferrablesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfStrongReferrablesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long coOwningReference
+ */
+static addCoOwningReference(builder:flatbuffers.Builder, coOwningReference:flatbuffers.Long) {
+ builder.addFieldInt64(39, coOwningReference, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfCoOwningReferencesOffset
+ */
+static addVectorOfCoOwningReferences(builder:flatbuffers.Builder, vectorOfCoOwningReferencesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(40, vectorOfCoOwningReferencesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Long> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfCoOwningReferencesVector(builder:flatbuffers.Builder, data:flatbuffers.Long[]):flatbuffers.Offset {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfCoOwningReferencesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long nonOwningReference
+ */
+static addNonOwningReference(builder:flatbuffers.Builder, nonOwningReference:flatbuffers.Long) {
+ builder.addFieldInt64(41, nonOwningReference, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfNonOwningReferencesOffset
+ */
+static addVectorOfNonOwningReferences(builder:flatbuffers.Builder, vectorOfNonOwningReferencesOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(42, vectorOfNonOwningReferencesOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Long> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfNonOwningReferencesVector(builder:flatbuffers.Builder, data:flatbuffers.Long[]):flatbuffers.Offset {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfNonOwningReferencesVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param MyGame.Example.AnyUniqueAliases anyUniqueType
+ */
+static addAnyUniqueType(builder:flatbuffers.Builder, anyUniqueType:MyGame.Example.AnyUniqueAliases) {
+ builder.addFieldInt8(43, anyUniqueType, MyGame.Example.AnyUniqueAliases.NONE);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset anyUniqueOffset
+ */
+static addAnyUnique(builder:flatbuffers.Builder, anyUniqueOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(44, anyUniqueOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param MyGame.Example.AnyAmbiguousAliases anyAmbiguousType
+ */
+static addAnyAmbiguousType(builder:flatbuffers.Builder, anyAmbiguousType:MyGame.Example.AnyAmbiguousAliases) {
+ builder.addFieldInt8(45, anyAmbiguousType, MyGame.Example.AnyAmbiguousAliases.NONE);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset anyAmbiguousOffset
+ */
+static addAnyAmbiguous(builder:flatbuffers.Builder, anyAmbiguousOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(46, anyAmbiguousOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vectorOfEnumsOffset
+ */
+static addVectorOfEnums(builder:flatbuffers.Builder, vectorOfEnumsOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(47, vectorOfEnumsOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<MyGame.Example.Color> data
+ * @returns flatbuffers.Offset
+ */
+static createVectorOfEnumsVector(builder:flatbuffers.Builder, data:MyGame.Example.Color[]):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVectorOfEnumsVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ builder.requiredField(offset, 10); // name
+ return offset;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset offset
+ */
+static finishMonsterBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+ builder.finish(offset, 'MONS');
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset offset
+ */
+static finishSizePrefixedMonsterBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+ builder.finish(offset, 'MONS', true);
+};
+
+static createMonster(builder:flatbuffers.Builder, posOffset:flatbuffers.Offset, mana:number, hp:number, nameOffset:flatbuffers.Offset, inventoryOffset:flatbuffers.Offset, color:MyGame.Example.Color, testType:MyGame.Example.Any, testOffset:flatbuffers.Offset, test4Offset:flatbuffers.Offset, testarrayofstringOffset:flatbuffers.Offset, testarrayoftablesOffset:flatbuffers.Offset, enemyOffset:flatbuffers.Offset, testnestedflatbufferOffset:flatbuffers.Offset, testemptyOffset:flatbuffers.Offset, testbool:boolean, testhashs32Fnv1:number, testhashu32Fnv1:number, testhashs64Fnv1:flatbuffers.Long, testhashu64Fnv1:flatbuffers.Long, testhashs32Fnv1a:number, testhashu32Fnv1a:number, testhashs64Fnv1a:flatbuffers.Long, testhashu64Fnv1a:flatbuffers.Long, testarrayofboolsOffset:flatbuffers.Offset, testf:number, testf2:number, testf3:number, testarrayofstring2Offset:flatbuffers.Offset, testarrayofsortedstructOffset:flatbuffers.Offset, flexOffset:flatbuffers.Offset, test5Offset:flatbuffers.Offset, vectorOfLongsOffset:flatbuffers.Offset, vectorOfDoublesOffset:flatbuffers.Offset, parentNamespaceTestOffset:flatbuffers.Offset, vectorOfReferrablesOffset:flatbuffers.Offset, singleWeakReference:flatbuffers.Long, vectorOfWeakReferencesOffset:flatbuffers.Offset, vectorOfStrongReferrablesOffset:flatbuffers.Offset, coOwningReference:flatbuffers.Long, vectorOfCoOwningReferencesOffset:flatbuffers.Offset, nonOwningReference:flatbuffers.Long, vectorOfNonOwningReferencesOffset:flatbuffers.Offset, anyUniqueType:MyGame.Example.AnyUniqueAliases, anyUniqueOffset:flatbuffers.Offset, anyAmbiguousType:MyGame.Example.AnyAmbiguousAliases, anyAmbiguousOffset:flatbuffers.Offset, vectorOfEnumsOffset:flatbuffers.Offset):flatbuffers.Offset {
+ Monster.startMonster(builder);
+ Monster.addPos(builder, posOffset);
+ Monster.addMana(builder, mana);
+ Monster.addHp(builder, hp);
+ Monster.addName(builder, nameOffset);
+ Monster.addInventory(builder, inventoryOffset);
+ Monster.addColor(builder, color);
+ Monster.addTestType(builder, testType);
+ Monster.addTest(builder, testOffset);
+ Monster.addTest4(builder, test4Offset);
+ Monster.addTestarrayofstring(builder, testarrayofstringOffset);
+ Monster.addTestarrayoftables(builder, testarrayoftablesOffset);
+ Monster.addEnemy(builder, enemyOffset);
+ Monster.addTestnestedflatbuffer(builder, testnestedflatbufferOffset);
+ Monster.addTestempty(builder, testemptyOffset);
+ Monster.addTestbool(builder, testbool);
+ Monster.addTesthashs32Fnv1(builder, testhashs32Fnv1);
+ Monster.addTesthashu32Fnv1(builder, testhashu32Fnv1);
+ Monster.addTesthashs64Fnv1(builder, testhashs64Fnv1);
+ Monster.addTesthashu64Fnv1(builder, testhashu64Fnv1);
+ Monster.addTesthashs32Fnv1a(builder, testhashs32Fnv1a);
+ Monster.addTesthashu32Fnv1a(builder, testhashu32Fnv1a);
+ Monster.addTesthashs64Fnv1a(builder, testhashs64Fnv1a);
+ Monster.addTesthashu64Fnv1a(builder, testhashu64Fnv1a);
+ Monster.addTestarrayofbools(builder, testarrayofboolsOffset);
+ Monster.addTestf(builder, testf);
+ Monster.addTestf2(builder, testf2);
+ Monster.addTestf3(builder, testf3);
+ Monster.addTestarrayofstring2(builder, testarrayofstring2Offset);
+ Monster.addTestarrayofsortedstruct(builder, testarrayofsortedstructOffset);
+ Monster.addFlex(builder, flexOffset);
+ Monster.addTest5(builder, test5Offset);
+ Monster.addVectorOfLongs(builder, vectorOfLongsOffset);
+ Monster.addVectorOfDoubles(builder, vectorOfDoublesOffset);
+ Monster.addParentNamespaceTest(builder, parentNamespaceTestOffset);
+ Monster.addVectorOfReferrables(builder, vectorOfReferrablesOffset);
+ Monster.addSingleWeakReference(builder, singleWeakReference);
+ Monster.addVectorOfWeakReferences(builder, vectorOfWeakReferencesOffset);
+ Monster.addVectorOfStrongReferrables(builder, vectorOfStrongReferrablesOffset);
+ Monster.addCoOwningReference(builder, coOwningReference);
+ Monster.addVectorOfCoOwningReferences(builder, vectorOfCoOwningReferencesOffset);
+ Monster.addNonOwningReference(builder, nonOwningReference);
+ Monster.addVectorOfNonOwningReferences(builder, vectorOfNonOwningReferencesOffset);
+ Monster.addAnyUniqueType(builder, anyUniqueType);
+ Monster.addAnyUnique(builder, anyUniqueOffset);
+ Monster.addAnyAmbiguousType(builder, anyAmbiguousType);
+ Monster.addAnyAmbiguous(builder, anyAmbiguousOffset);
+ Monster.addVectorOfEnums(builder, vectorOfEnumsOffset);
+ return Monster.endMonster(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class TypeAliases {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns TypeAliases
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TypeAliases {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TypeAliases= obj
+ * @returns TypeAliases
+ */
+static getRootAsTypeAliases(bb:flatbuffers.ByteBuffer, obj?:TypeAliases):TypeAliases {
+ return (obj || new TypeAliases).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TypeAliases= obj
+ * @returns TypeAliases
+ */
+static getSizePrefixedRootAsTypeAliases(bb:flatbuffers.ByteBuffer, obj?:TypeAliases):TypeAliases {
+ return (obj || new TypeAliases).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns number
+ */
+i8():number {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readInt8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_i8(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+u8():number {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.readUint8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_u8(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+i16():number {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? this.bb!.readInt16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_i16(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+u16():number {
+ var offset = this.bb!.__offset(this.bb_pos, 10);
+ return offset ? this.bb!.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_u16(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 10);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint16(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+i32():number {
+ var offset = this.bb!.__offset(this.bb_pos, 12);
+ return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_i32(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 12);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+u32():number {
+ var offset = this.bb!.__offset(this.bb_pos, 14);
+ return offset ? this.bb!.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_u32(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 14);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+i64():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 16);
+ return offset ? this.bb!.readInt64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_i64(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 16);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns flatbuffers.Long
+ */
+u64():flatbuffers.Long {
+ var offset = this.bb!.__offset(this.bb_pos, 18);
+ return offset ? this.bb!.readUint64(this.bb_pos + offset) : this.bb!.createLong(0, 0);
+};
+
+/**
+ * @param flatbuffers.Long value
+ * @returns boolean
+ */
+mutate_u64(value:flatbuffers.Long):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 18);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+f32():number {
+ var offset = this.bb!.__offset(this.bb_pos, 20);
+ return offset ? this.bb!.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_f32(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 20);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+f64():number {
+ var offset = this.bb!.__offset(this.bb_pos, 22);
+ return offset ? this.bb!.readFloat64(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_f64(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 22);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeFloat64(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param number index
+ * @returns number
+ */
+v8(index: number):number|null {
+ var offset = this.bb!.__offset(this.bb_pos, 24);
+ return offset ? this.bb!.readInt8(this.bb!.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns number
+ */
+v8Length():number {
+ var offset = this.bb!.__offset(this.bb_pos, 24);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Int8Array
+ */
+v8Array():Int8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 24);
+ return offset ? new Int8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param number index
+ * @returns number
+ */
+vf64(index: number):number|null {
+ var offset = this.bb!.__offset(this.bb_pos, 26);
+ return offset ? this.bb!.readFloat64(this.bb!.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns number
+ */
+vf64Length():number {
+ var offset = this.bb!.__offset(this.bb_pos, 26);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Float64Array
+ */
+vf64Array():Float64Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 26);
+ return offset ? new Float64Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startTypeAliases(builder:flatbuffers.Builder) {
+ builder.startObject(12);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number i8
+ */
+static addI8(builder:flatbuffers.Builder, i8:number) {
+ builder.addFieldInt8(0, i8, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number u8
+ */
+static addU8(builder:flatbuffers.Builder, u8:number) {
+ builder.addFieldInt8(1, u8, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number i16
+ */
+static addI16(builder:flatbuffers.Builder, i16:number) {
+ builder.addFieldInt16(2, i16, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number u16
+ */
+static addU16(builder:flatbuffers.Builder, u16:number) {
+ builder.addFieldInt16(3, u16, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number i32
+ */
+static addI32(builder:flatbuffers.Builder, i32:number) {
+ builder.addFieldInt32(4, i32, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number u32
+ */
+static addU32(builder:flatbuffers.Builder, u32:number) {
+ builder.addFieldInt32(5, u32, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long i64
+ */
+static addI64(builder:flatbuffers.Builder, i64:flatbuffers.Long) {
+ builder.addFieldInt64(6, i64, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Long u64
+ */
+static addU64(builder:flatbuffers.Builder, u64:flatbuffers.Long) {
+ builder.addFieldInt64(7, u64, builder.createLong(0, 0));
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number f32
+ */
+static addF32(builder:flatbuffers.Builder, f32:number) {
+ builder.addFieldFloat32(8, f32, 0.0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number f64
+ */
+static addF64(builder:flatbuffers.Builder, f64:number) {
+ builder.addFieldFloat64(9, f64, 0.0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset v8Offset
+ */
+static addV8(builder:flatbuffers.Builder, v8Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(10, v8Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<number> data
+ * @returns flatbuffers.Offset
+ */
+static createV8Vector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startV8Vector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset vf64Offset
+ */
+static addVf64(builder:flatbuffers.Builder, vf64Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(11, vf64Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<number> data
+ * @returns flatbuffers.Offset
+ */
+static createVf64Vector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+ builder.startVector(8, data.length, 8);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addFloat64(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startVf64Vector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endTypeAliases(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createTypeAliases(builder:flatbuffers.Builder, i8:number, u8:number, i16:number, u16:number, i32:number, u32:number, i64:flatbuffers.Long, u64:flatbuffers.Long, f32:number, f64:number, v8Offset:flatbuffers.Offset, vf64Offset:flatbuffers.Offset):flatbuffers.Offset {
+ TypeAliases.startTypeAliases(builder);
+ TypeAliases.addI8(builder, i8);
+ TypeAliases.addU8(builder, u8);
+ TypeAliases.addI16(builder, i16);
+ TypeAliases.addU16(builder, u16);
+ TypeAliases.addI32(builder, i32);
+ TypeAliases.addU32(builder, u32);
+ TypeAliases.addI64(builder, i64);
+ TypeAliases.addU64(builder, u64);
+ TypeAliases.addF32(builder, f32);
+ TypeAliases.addF64(builder, f64);
+ TypeAliases.addV8(builder, v8Offset);
+ TypeAliases.addVf64(builder, vf64Offset);
+ return TypeAliases.endTypeAliases(builder);
+}
+}
+}
diff --git a/tests/monster_test_my_game.example2_generated.dart b/tests/monster_test_my_game.example2_generated.dart
new file mode 100644
index 0000000..eed14bc
--- /dev/null
+++ b/tests/monster_test_my_game.example2_generated.dart
@@ -0,0 +1,60 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game.example2;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import './monster_test_my_game_generated.dart' as my_game;
+import './monster_test_my_game.example_generated.dart' as my_game_example;
+
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+
+ @override
+ String toString() {
+ return 'Monster{}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+
+ MonsterObjectBuilder();
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/tests/monster_test_my_game.example_generated.dart b/tests/monster_test_my_game.example_generated.dart
new file mode 100644
index 0000000..13b7f4a
--- /dev/null
+++ b/tests/monster_test_my_game.example_generated.dart
@@ -0,0 +1,1490 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game.example;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import './monster_test_my_game_generated.dart' as my_game;
+import './monster_test_my_game.example2_generated.dart' as my_game_example2;
+
+/// Composite components of Monster color.
+class Color {
+ final int value;
+ const Color._(this.value);
+
+ factory Color.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum Color');
+ }
+ return values[value];
+ }
+
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const Color Red = const Color._(1);
+
+ /// \brief color Green
+ /// Green is bit_flag with value (1u << 1)
+ static const Color Green = const Color._(2);
+
+ /// \brief color Blue (1u << 3)
+ static const Color Blue = const Color._(8);
+ static get values => {1: Red,2: Green,8: Blue,};
+
+ static const fb.Reader<Color> reader = const _ColorReader();
+
+ @override
+ String toString() {
+ return 'Color{value: $value}';
+ }
+}
+
+class _ColorReader extends fb.Reader<Color> {
+ const _ColorReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ Color read(fb.BufferContext bc, int offset) =>
+ new Color.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class AnyTypeId {
+ final int value;
+ const AnyTypeId._(this.value);
+
+ factory AnyTypeId.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyTypeId NONE = const AnyTypeId._(0);
+ static const AnyTypeId Monster = const AnyTypeId._(1);
+ static const AnyTypeId TestSimpleTableWithEnum = const AnyTypeId._(2);
+ static const AnyTypeId MyGame_Example2_Monster = const AnyTypeId._(3);
+ static get values => {0: NONE,1: Monster,2: TestSimpleTableWithEnum,3: MyGame_Example2_Monster,};
+
+ static const fb.Reader<AnyTypeId> reader = const _AnyTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyTypeId{value: $value}';
+ }
+}
+
+class _AnyTypeIdReader extends fb.Reader<AnyTypeId> {
+ const _AnyTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class AnyUniqueAliasesTypeId {
+ final int value;
+ const AnyUniqueAliasesTypeId._(this.value);
+
+ factory AnyUniqueAliasesTypeId.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyUniqueAliasesTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyUniqueAliasesTypeId NONE = const AnyUniqueAliasesTypeId._(0);
+ static const AnyUniqueAliasesTypeId M = const AnyUniqueAliasesTypeId._(1);
+ static const AnyUniqueAliasesTypeId TS = const AnyUniqueAliasesTypeId._(2);
+ static const AnyUniqueAliasesTypeId M2 = const AnyUniqueAliasesTypeId._(3);
+ static get values => {0: NONE,1: M,2: TS,3: M2,};
+
+ static const fb.Reader<AnyUniqueAliasesTypeId> reader = const _AnyUniqueAliasesTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyUniqueAliasesTypeId{value: $value}';
+ }
+}
+
+class _AnyUniqueAliasesTypeIdReader extends fb.Reader<AnyUniqueAliasesTypeId> {
+ const _AnyUniqueAliasesTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyUniqueAliasesTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class AnyAmbiguousAliasesTypeId {
+ final int value;
+ const AnyAmbiguousAliasesTypeId._(this.value);
+
+ factory AnyAmbiguousAliasesTypeId.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum AnyAmbiguousAliasesTypeId');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 3;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const AnyAmbiguousAliasesTypeId NONE = const AnyAmbiguousAliasesTypeId._(0);
+ static const AnyAmbiguousAliasesTypeId M1 = const AnyAmbiguousAliasesTypeId._(1);
+ static const AnyAmbiguousAliasesTypeId M2 = const AnyAmbiguousAliasesTypeId._(2);
+ static const AnyAmbiguousAliasesTypeId M3 = const AnyAmbiguousAliasesTypeId._(3);
+ static get values => {0: NONE,1: M1,2: M2,3: M3,};
+
+ static const fb.Reader<AnyAmbiguousAliasesTypeId> reader = const _AnyAmbiguousAliasesTypeIdReader();
+
+ @override
+ String toString() {
+ return 'AnyAmbiguousAliasesTypeId{value: $value}';
+ }
+}
+
+class _AnyAmbiguousAliasesTypeIdReader extends fb.Reader<AnyAmbiguousAliasesTypeId> {
+ const _AnyAmbiguousAliasesTypeIdReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ AnyAmbiguousAliasesTypeId read(fb.BufferContext bc, int offset) =>
+ new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().read(bc, offset));
+}
+
+class Test {
+ Test._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Test> reader = const _TestReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get a => const fb.Int16Reader().read(_bc, _bcOffset + 0);
+ int get b => const fb.Int8Reader().read(_bc, _bcOffset + 2);
+
+ @override
+ String toString() {
+ return 'Test{a: $a, b: $b}';
+ }
+}
+
+class _TestReader extends fb.StructReader<Test> {
+ const _TestReader();
+
+ @override
+ int get size => 4;
+
+ @override
+ Test createObject(fb.BufferContext bc, int offset) =>
+ new Test._(bc, offset);
+}
+
+class TestBuilder {
+ TestBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int a, int b) {
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(b);
+ fbBuilder.putInt16(a);
+ return fbBuilder.offset;
+ }
+
+}
+
+class TestObjectBuilder extends fb.ObjectBuilder {
+ final int _a;
+ final int _b;
+
+ TestObjectBuilder({
+ int a,
+ int b,
+ })
+ : _a = a,
+ _b = b;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.pad(1);
+ fbBuilder.putInt8(_b);
+ fbBuilder.putInt16(_a);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class TestSimpleTableWithEnum {
+ TestSimpleTableWithEnum._(this._bc, this._bcOffset);
+ factory TestSimpleTableWithEnum(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TestSimpleTableWithEnum> reader = const _TestSimpleTableWithEnumReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Color get color => new Color.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 4, 2));
+
+ @override
+ String toString() {
+ return 'TestSimpleTableWithEnum{color: $color}';
+ }
+}
+
+class _TestSimpleTableWithEnumReader extends fb.TableReader<TestSimpleTableWithEnum> {
+ const _TestSimpleTableWithEnumReader();
+
+ @override
+ TestSimpleTableWithEnum createObject(fb.BufferContext bc, int offset) =>
+ new TestSimpleTableWithEnum._(bc, offset);
+}
+
+class TestSimpleTableWithEnumBuilder {
+ TestSimpleTableWithEnumBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addColor(Color color) {
+ fbBuilder.addUint8(0, color?.value);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TestSimpleTableWithEnumObjectBuilder extends fb.ObjectBuilder {
+ final Color _color;
+
+ TestSimpleTableWithEnumObjectBuilder({
+ Color color,
+ })
+ : _color = color;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addUint8(0, _color?.value);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Vec3 {
+ Vec3._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Vec3> reader = const _Vec3Reader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ double get x => const fb.Float32Reader().read(_bc, _bcOffset + 0);
+ double get y => const fb.Float32Reader().read(_bc, _bcOffset + 4);
+ double get z => const fb.Float32Reader().read(_bc, _bcOffset + 8);
+ double get test1 => const fb.Float64Reader().read(_bc, _bcOffset + 16);
+ Color get test2 => new Color.fromValue(const fb.Uint8Reader().read(_bc, _bcOffset + 24));
+ Test get test3 => Test.reader.read(_bc, _bcOffset + 26);
+
+ @override
+ String toString() {
+ return 'Vec3{x: $x, y: $y, z: $z, test1: $test1, test2: $test2, test3: $test3}';
+ }
+}
+
+class _Vec3Reader extends fb.StructReader<Vec3> {
+ const _Vec3Reader();
+
+ @override
+ int get size => 32;
+
+ @override
+ Vec3 createObject(fb.BufferContext bc, int offset) =>
+ new Vec3._(bc, offset);
+}
+
+class Vec3Builder {
+ Vec3Builder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(double x, double y, double z, double test1, Color test2, fb.StructBuilder test3) {
+ fbBuilder.pad(2);
+ test3();
+ fbBuilder.pad(1);
+ fbBuilder.putUint8(test2?.value);
+ fbBuilder.putFloat64(test1);
+ fbBuilder.pad(4);
+ fbBuilder.putFloat32(z);
+ fbBuilder.putFloat32(y);
+ fbBuilder.putFloat32(x);
+ return fbBuilder.offset;
+ }
+
+}
+
+class Vec3ObjectBuilder extends fb.ObjectBuilder {
+ final double _x;
+ final double _y;
+ final double _z;
+ final double _test1;
+ final Color _test2;
+ final TestObjectBuilder _test3;
+
+ Vec3ObjectBuilder({
+ double x,
+ double y,
+ double z,
+ double test1,
+ Color test2,
+ TestObjectBuilder test3,
+ })
+ : _x = x,
+ _y = y,
+ _z = z,
+ _test1 = test1,
+ _test2 = test2,
+ _test3 = test3;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.pad(2);
+ _test3.finish(fbBuilder);
+ fbBuilder.pad(1);
+ fbBuilder.putUint8(_test2?.value);
+ fbBuilder.putFloat64(_test1);
+ fbBuilder.pad(4);
+ fbBuilder.putFloat32(_z);
+ fbBuilder.putFloat32(_y);
+ fbBuilder.putFloat32(_x);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Ability {
+ Ability._(this._bc, this._bcOffset);
+
+ static const fb.Reader<Ability> reader = const _AbilityReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get id => const fb.Uint32Reader().read(_bc, _bcOffset + 0);
+ int get distance => const fb.Uint32Reader().read(_bc, _bcOffset + 4);
+
+ @override
+ String toString() {
+ return 'Ability{id: $id, distance: $distance}';
+ }
+}
+
+class _AbilityReader extends fb.StructReader<Ability> {
+ const _AbilityReader();
+
+ @override
+ int get size => 8;
+
+ @override
+ Ability createObject(fb.BufferContext bc, int offset) =>
+ new Ability._(bc, offset);
+}
+
+class AbilityBuilder {
+ AbilityBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int id, int distance) {
+ fbBuilder.putUint32(distance);
+ fbBuilder.putUint32(id);
+ return fbBuilder.offset;
+ }
+
+}
+
+class AbilityObjectBuilder extends fb.ObjectBuilder {
+ final int _id;
+ final int _distance;
+
+ AbilityObjectBuilder({
+ int id,
+ int distance,
+ })
+ : _id = id,
+ _distance = distance;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.putUint32(_distance);
+ fbBuilder.putUint32(_id);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Stat {
+ Stat._(this._bc, this._bcOffset);
+ factory Stat(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Stat> reader = const _StatReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ String get id => const fb.StringReader().vTableGet(_bc, _bcOffset, 4, null);
+ int get val => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 6, 0);
+ int get count => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 8, 0);
+
+ @override
+ String toString() {
+ return 'Stat{id: $id, val: $val, count: $count}';
+ }
+}
+
+class _StatReader extends fb.TableReader<Stat> {
+ const _StatReader();
+
+ @override
+ Stat createObject(fb.BufferContext bc, int offset) =>
+ new Stat._(bc, offset);
+}
+
+class StatBuilder {
+ StatBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addIdOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addVal(int val) {
+ fbBuilder.addInt64(1, val);
+ return fbBuilder.offset;
+ }
+ int addCount(int count) {
+ fbBuilder.addUint16(2, count);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class StatObjectBuilder extends fb.ObjectBuilder {
+ final String _id;
+ final int _val;
+ final int _count;
+
+ StatObjectBuilder({
+ String id,
+ int val,
+ int count,
+ })
+ : _id = id,
+ _val = val,
+ _count = count;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int idOffset = fbBuilder.writeString(_id);
+
+ fbBuilder.startTable();
+ if (idOffset != null) {
+ fbBuilder.addOffset(0, idOffset);
+ }
+ fbBuilder.addInt64(1, _val);
+ fbBuilder.addUint16(2, _count);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class Referrable {
+ Referrable._(this._bc, this._bcOffset);
+ factory Referrable(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Referrable> reader = const _ReferrableReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get id => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 4, 0);
+
+ @override
+ String toString() {
+ return 'Referrable{id: $id}';
+ }
+}
+
+class _ReferrableReader extends fb.TableReader<Referrable> {
+ const _ReferrableReader();
+
+ @override
+ Referrable createObject(fb.BufferContext bc, int offset) =>
+ new Referrable._(bc, offset);
+}
+
+class ReferrableBuilder {
+ ReferrableBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addId(int id) {
+ fbBuilder.addUint64(0, id);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class ReferrableObjectBuilder extends fb.ObjectBuilder {
+ final int _id;
+
+ ReferrableObjectBuilder({
+ int id,
+ })
+ : _id = id;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addUint64(0, _id);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+/// an example documentation comment: monster object
+class Monster {
+ Monster._(this._bc, this._bcOffset);
+ factory Monster(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<Monster> reader = const _MonsterReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ Vec3 get pos => Vec3.reader.vTableGet(_bc, _bcOffset, 4, null);
+ int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
+ int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
+ String get name => const fb.StringReader().vTableGet(_bc, _bcOffset, 10, null);
+ List<int> get inventory => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 14, null);
+ Color get color => new Color.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 16, 8));
+ AnyTypeId get testType => new AnyTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 18, 0));
+ dynamic get test {
+ switch (testType?.value) {
+ case 1: return Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+ case 2: return TestSimpleTableWithEnum.reader.vTableGet(_bc, _bcOffset, 20, null);
+ case 3: return my_game_example2.Monster.reader.vTableGet(_bc, _bcOffset, 20, null);
+ default: return null;
+ }
+ }
+ List<Test> get test4 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 22, null);
+ List<String> get testarrayofstring => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 24, null);
+ /// an example documentation comment: this will end up in the generated code
+ /// multiline too
+ List<Monster> get testarrayoftables => const fb.ListReader<Monster>(Monster.reader).vTableGet(_bc, _bcOffset, 26, null);
+ Monster get enemy => Monster.reader.vTableGet(_bc, _bcOffset, 28, null);
+ List<int> get testnestedflatbuffer => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 30, null);
+ Stat get testempty => Stat.reader.vTableGet(_bc, _bcOffset, 32, null);
+ bool get testbool => const fb.BoolReader().vTableGet(_bc, _bcOffset, 34, false);
+ int get testhashs32Fnv1 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 36, 0);
+ int get testhashu32Fnv1 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 38, 0);
+ int get testhashs64Fnv1 => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 40, 0);
+ int get testhashu64Fnv1 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 42, 0);
+ int get testhashs32Fnv1a => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 44, 0);
+ int get testhashu32Fnv1a => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 46, 0);
+ int get testhashs64Fnv1a => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 48, 0);
+ int get testhashu64Fnv1a => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 50, 0);
+ List<bool> get testarrayofbools => const fb.ListReader<bool>(const fb.BoolReader()).vTableGet(_bc, _bcOffset, 52, null);
+ double get testf => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 54, 3.14159);
+ double get testf2 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 56, 3.0);
+ double get testf3 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 58, 0.0);
+ List<String> get testarrayofstring2 => const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 60, null);
+ List<Ability> get testarrayofsortedstruct => const fb.ListReader<Ability>(Ability.reader).vTableGet(_bc, _bcOffset, 62, null);
+ List<int> get flex => const fb.ListReader<int>(const fb.Uint8Reader()).vTableGet(_bc, _bcOffset, 64, null);
+ List<Test> get test5 => const fb.ListReader<Test>(Test.reader).vTableGet(_bc, _bcOffset, 66, null);
+ List<int> get vectorOfLongs => const fb.ListReader<int>(const fb.Int64Reader()).vTableGet(_bc, _bcOffset, 68, null);
+ List<double> get vectorOfDoubles => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 70, null);
+ my_game.InParentNamespace get parentNamespaceTest => my_game.InParentNamespace.reader.vTableGet(_bc, _bcOffset, 72, null);
+ List<Referrable> get vectorOfReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 74, null);
+ int get singleWeakReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 76, 0);
+ List<int> get vectorOfWeakReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 78, null);
+ List<Referrable> get vectorOfStrongReferrables => const fb.ListReader<Referrable>(Referrable.reader).vTableGet(_bc, _bcOffset, 80, null);
+ int get coOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 82, 0);
+ List<int> get vectorOfCoOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 84, null);
+ int get nonOwningReference => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 86, 0);
+ List<int> get vectorOfNonOwningReferences => const fb.ListReader<int>(const fb.Uint64Reader()).vTableGet(_bc, _bcOffset, 88, null);
+ AnyUniqueAliasesTypeId get anyUniqueType => new AnyUniqueAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 90, 0));
+ dynamic get anyUnique {
+ switch (anyUniqueType?.value) {
+ case 1: return M.reader.vTableGet(_bc, _bcOffset, 92, null);
+ case 2: return TS.reader.vTableGet(_bc, _bcOffset, 92, null);
+ case 3: return M2.reader.vTableGet(_bc, _bcOffset, 92, null);
+ default: return null;
+ }
+ }
+ AnyAmbiguousAliasesTypeId get anyAmbiguousType => new AnyAmbiguousAliasesTypeId.fromValue(const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 94, 0));
+ dynamic get anyAmbiguous {
+ switch (anyAmbiguousType?.value) {
+ case 1: return M1.reader.vTableGet(_bc, _bcOffset, 96, null);
+ case 2: return M2.reader.vTableGet(_bc, _bcOffset, 96, null);
+ case 3: return M3.reader.vTableGet(_bc, _bcOffset, 96, null);
+ default: return null;
+ }
+ }
+ List<Color> get vectorOfEnums => const fb.ListReader<Color>(Color.reader).vTableGet(_bc, _bcOffset, 98, null);
+
+ @override
+ String toString() {
+ return 'Monster{pos: $pos, mana: $mana, hp: $hp, name: $name, inventory: $inventory, color: $color, testType: $testType, test: $test, test4: $test4, testarrayofstring: $testarrayofstring, testarrayoftables: $testarrayoftables, enemy: $enemy, testnestedflatbuffer: $testnestedflatbuffer, testempty: $testempty, testbool: $testbool, testhashs32Fnv1: $testhashs32Fnv1, testhashu32Fnv1: $testhashu32Fnv1, testhashs64Fnv1: $testhashs64Fnv1, testhashu64Fnv1: $testhashu64Fnv1, testhashs32Fnv1a: $testhashs32Fnv1a, testhashu32Fnv1a: $testhashu32Fnv1a, testhashs64Fnv1a: $testhashs64Fnv1a, testhashu64Fnv1a: $testhashu64Fnv1a, testarrayofbools: $testarrayofbools, testf: $testf, testf2: $testf2, testf3: $testf3, testarrayofstring2: $testarrayofstring2, testarrayofsortedstruct: $testarrayofsortedstruct, flex: $flex, test5: $test5, vectorOfLongs: $vectorOfLongs, vectorOfDoubles: $vectorOfDoubles, parentNamespaceTest: $parentNamespaceTest, vectorOfReferrables: $vectorOfReferrables, singleWeakReference: $singleWeakReference, vectorOfWeakReferences: $vectorOfWeakReferences, vectorOfStrongReferrables: $vectorOfStrongReferrables, coOwningReference: $coOwningReference, vectorOfCoOwningReferences: $vectorOfCoOwningReferences, nonOwningReference: $nonOwningReference, vectorOfNonOwningReferences: $vectorOfNonOwningReferences, anyUniqueType: $anyUniqueType, anyUnique: $anyUnique, anyAmbiguousType: $anyAmbiguousType, anyAmbiguous: $anyAmbiguous, vectorOfEnums: $vectorOfEnums}';
+ }
+}
+
+class _MonsterReader extends fb.TableReader<Monster> {
+ const _MonsterReader();
+
+ @override
+ Monster createObject(fb.BufferContext bc, int offset) =>
+ new Monster._(bc, offset);
+}
+
+class MonsterBuilder {
+ MonsterBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addPos(int offset) {
+ fbBuilder.addStruct(0, offset);
+ return fbBuilder.offset;
+ }
+ int addMana(int mana) {
+ fbBuilder.addInt16(1, mana);
+ return fbBuilder.offset;
+ }
+ int addHp(int hp) {
+ fbBuilder.addInt16(2, hp);
+ return fbBuilder.offset;
+ }
+ int addNameOffset(int offset) {
+ fbBuilder.addOffset(3, offset);
+ return fbBuilder.offset;
+ }
+ int addInventoryOffset(int offset) {
+ fbBuilder.addOffset(5, offset);
+ return fbBuilder.offset;
+ }
+ int addColor(Color color) {
+ fbBuilder.addUint8(6, color?.value);
+ return fbBuilder.offset;
+ }
+ int addTestType(AnyTypeId testType) {
+ fbBuilder.addUint8(7, testType?.value);
+ return fbBuilder.offset;
+ }
+ int addTestOffset(int offset) {
+ fbBuilder.addOffset(8, offset);
+ return fbBuilder.offset;
+ }
+ int addTest4Offset(int offset) {
+ fbBuilder.addOffset(9, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofstringOffset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayoftablesOffset(int offset) {
+ fbBuilder.addOffset(11, offset);
+ return fbBuilder.offset;
+ }
+ int addEnemyOffset(int offset) {
+ fbBuilder.addOffset(12, offset);
+ return fbBuilder.offset;
+ }
+ int addTestnestedflatbufferOffset(int offset) {
+ fbBuilder.addOffset(13, offset);
+ return fbBuilder.offset;
+ }
+ int addTestemptyOffset(int offset) {
+ fbBuilder.addOffset(14, offset);
+ return fbBuilder.offset;
+ }
+ int addTestbool(bool testbool) {
+ fbBuilder.addBool(15, testbool);
+ return fbBuilder.offset;
+ }
+ int addTesthashs32Fnv1(int testhashs32Fnv1) {
+ fbBuilder.addInt32(16, testhashs32Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashu32Fnv1(int testhashu32Fnv1) {
+ fbBuilder.addUint32(17, testhashu32Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashs64Fnv1(int testhashs64Fnv1) {
+ fbBuilder.addInt64(18, testhashs64Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashu64Fnv1(int testhashu64Fnv1) {
+ fbBuilder.addUint64(19, testhashu64Fnv1);
+ return fbBuilder.offset;
+ }
+ int addTesthashs32Fnv1a(int testhashs32Fnv1a) {
+ fbBuilder.addInt32(20, testhashs32Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashu32Fnv1a(int testhashu32Fnv1a) {
+ fbBuilder.addUint32(21, testhashu32Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashs64Fnv1a(int testhashs64Fnv1a) {
+ fbBuilder.addInt64(22, testhashs64Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTesthashu64Fnv1a(int testhashu64Fnv1a) {
+ fbBuilder.addUint64(23, testhashu64Fnv1a);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofboolsOffset(int offset) {
+ fbBuilder.addOffset(24, offset);
+ return fbBuilder.offset;
+ }
+ int addTestf(double testf) {
+ fbBuilder.addFloat32(25, testf);
+ return fbBuilder.offset;
+ }
+ int addTestf2(double testf2) {
+ fbBuilder.addFloat32(26, testf2);
+ return fbBuilder.offset;
+ }
+ int addTestf3(double testf3) {
+ fbBuilder.addFloat32(27, testf3);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofstring2Offset(int offset) {
+ fbBuilder.addOffset(28, offset);
+ return fbBuilder.offset;
+ }
+ int addTestarrayofsortedstructOffset(int offset) {
+ fbBuilder.addOffset(29, offset);
+ return fbBuilder.offset;
+ }
+ int addFlexOffset(int offset) {
+ fbBuilder.addOffset(30, offset);
+ return fbBuilder.offset;
+ }
+ int addTest5Offset(int offset) {
+ fbBuilder.addOffset(31, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfLongsOffset(int offset) {
+ fbBuilder.addOffset(32, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfDoublesOffset(int offset) {
+ fbBuilder.addOffset(33, offset);
+ return fbBuilder.offset;
+ }
+ int addParentNamespaceTestOffset(int offset) {
+ fbBuilder.addOffset(34, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfReferrablesOffset(int offset) {
+ fbBuilder.addOffset(35, offset);
+ return fbBuilder.offset;
+ }
+ int addSingleWeakReference(int singleWeakReference) {
+ fbBuilder.addUint64(36, singleWeakReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfWeakReferencesOffset(int offset) {
+ fbBuilder.addOffset(37, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfStrongReferrablesOffset(int offset) {
+ fbBuilder.addOffset(38, offset);
+ return fbBuilder.offset;
+ }
+ int addCoOwningReference(int coOwningReference) {
+ fbBuilder.addUint64(39, coOwningReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfCoOwningReferencesOffset(int offset) {
+ fbBuilder.addOffset(40, offset);
+ return fbBuilder.offset;
+ }
+ int addNonOwningReference(int nonOwningReference) {
+ fbBuilder.addUint64(41, nonOwningReference);
+ return fbBuilder.offset;
+ }
+ int addVectorOfNonOwningReferencesOffset(int offset) {
+ fbBuilder.addOffset(42, offset);
+ return fbBuilder.offset;
+ }
+ int addAnyUniqueType(AnyUniqueAliasesTypeId anyUniqueType) {
+ fbBuilder.addUint8(43, anyUniqueType?.value);
+ return fbBuilder.offset;
+ }
+ int addAnyUniqueOffset(int offset) {
+ fbBuilder.addOffset(44, offset);
+ return fbBuilder.offset;
+ }
+ int addAnyAmbiguousType(AnyAmbiguousAliasesTypeId anyAmbiguousType) {
+ fbBuilder.addUint8(45, anyAmbiguousType?.value);
+ return fbBuilder.offset;
+ }
+ int addAnyAmbiguousOffset(int offset) {
+ fbBuilder.addOffset(46, offset);
+ return fbBuilder.offset;
+ }
+ int addVectorOfEnumsOffset(int offset) {
+ fbBuilder.addOffset(47, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class MonsterObjectBuilder extends fb.ObjectBuilder {
+ final Vec3ObjectBuilder _pos;
+ final int _mana;
+ final int _hp;
+ final String _name;
+ final List<int> _inventory;
+ final Color _color;
+ final AnyTypeId _testType;
+ final dynamic _test;
+ final List<TestObjectBuilder> _test4;
+ final List<String> _testarrayofstring;
+ final List<MonsterObjectBuilder> _testarrayoftables;
+ final MonsterObjectBuilder _enemy;
+ final List<int> _testnestedflatbuffer;
+ final StatObjectBuilder _testempty;
+ final bool _testbool;
+ final int _testhashs32Fnv1;
+ final int _testhashu32Fnv1;
+ final int _testhashs64Fnv1;
+ final int _testhashu64Fnv1;
+ final int _testhashs32Fnv1a;
+ final int _testhashu32Fnv1a;
+ final int _testhashs64Fnv1a;
+ final int _testhashu64Fnv1a;
+ final List<bool> _testarrayofbools;
+ final double _testf;
+ final double _testf2;
+ final double _testf3;
+ final List<String> _testarrayofstring2;
+ final List<AbilityObjectBuilder> _testarrayofsortedstruct;
+ final List<int> _flex;
+ final List<TestObjectBuilder> _test5;
+ final List<int> _vectorOfLongs;
+ final List<double> _vectorOfDoubles;
+ final my_game.InParentNamespaceObjectBuilder _parentNamespaceTest;
+ final List<ReferrableObjectBuilder> _vectorOfReferrables;
+ final int _singleWeakReference;
+ final List<int> _vectorOfWeakReferences;
+ final List<ReferrableObjectBuilder> _vectorOfStrongReferrables;
+ final int _coOwningReference;
+ final List<int> _vectorOfCoOwningReferences;
+ final int _nonOwningReference;
+ final List<int> _vectorOfNonOwningReferences;
+ final AnyUniqueAliasesTypeId _anyUniqueType;
+ final dynamic _anyUnique;
+ final AnyAmbiguousAliasesTypeId _anyAmbiguousType;
+ final dynamic _anyAmbiguous;
+ final List<Color> _vectorOfEnums;
+
+ MonsterObjectBuilder({
+ Vec3ObjectBuilder pos,
+ int mana,
+ int hp,
+ String name,
+ List<int> inventory,
+ Color color,
+ AnyTypeId testType,
+ dynamic test,
+ List<TestObjectBuilder> test4,
+ List<String> testarrayofstring,
+ List<MonsterObjectBuilder> testarrayoftables,
+ MonsterObjectBuilder enemy,
+ List<int> testnestedflatbuffer,
+ StatObjectBuilder testempty,
+ bool testbool,
+ int testhashs32Fnv1,
+ int testhashu32Fnv1,
+ int testhashs64Fnv1,
+ int testhashu64Fnv1,
+ int testhashs32Fnv1a,
+ int testhashu32Fnv1a,
+ int testhashs64Fnv1a,
+ int testhashu64Fnv1a,
+ List<bool> testarrayofbools,
+ double testf,
+ double testf2,
+ double testf3,
+ List<String> testarrayofstring2,
+ List<AbilityObjectBuilder> testarrayofsortedstruct,
+ List<int> flex,
+ List<TestObjectBuilder> test5,
+ List<int> vectorOfLongs,
+ List<double> vectorOfDoubles,
+ my_game.InParentNamespaceObjectBuilder parentNamespaceTest,
+ List<ReferrableObjectBuilder> vectorOfReferrables,
+ int singleWeakReference,
+ List<int> vectorOfWeakReferences,
+ List<ReferrableObjectBuilder> vectorOfStrongReferrables,
+ int coOwningReference,
+ List<int> vectorOfCoOwningReferences,
+ int nonOwningReference,
+ List<int> vectorOfNonOwningReferences,
+ AnyUniqueAliasesTypeId anyUniqueType,
+ dynamic anyUnique,
+ AnyAmbiguousAliasesTypeId anyAmbiguousType,
+ dynamic anyAmbiguous,
+ List<Color> vectorOfEnums,
+ })
+ : _pos = pos,
+ _mana = mana,
+ _hp = hp,
+ _name = name,
+ _inventory = inventory,
+ _color = color,
+ _testType = testType,
+ _test = test,
+ _test4 = test4,
+ _testarrayofstring = testarrayofstring,
+ _testarrayoftables = testarrayoftables,
+ _enemy = enemy,
+ _testnestedflatbuffer = testnestedflatbuffer,
+ _testempty = testempty,
+ _testbool = testbool,
+ _testhashs32Fnv1 = testhashs32Fnv1,
+ _testhashu32Fnv1 = testhashu32Fnv1,
+ _testhashs64Fnv1 = testhashs64Fnv1,
+ _testhashu64Fnv1 = testhashu64Fnv1,
+ _testhashs32Fnv1a = testhashs32Fnv1a,
+ _testhashu32Fnv1a = testhashu32Fnv1a,
+ _testhashs64Fnv1a = testhashs64Fnv1a,
+ _testhashu64Fnv1a = testhashu64Fnv1a,
+ _testarrayofbools = testarrayofbools,
+ _testf = testf,
+ _testf2 = testf2,
+ _testf3 = testf3,
+ _testarrayofstring2 = testarrayofstring2,
+ _testarrayofsortedstruct = testarrayofsortedstruct,
+ _flex = flex,
+ _test5 = test5,
+ _vectorOfLongs = vectorOfLongs,
+ _vectorOfDoubles = vectorOfDoubles,
+ _parentNamespaceTest = parentNamespaceTest,
+ _vectorOfReferrables = vectorOfReferrables,
+ _singleWeakReference = singleWeakReference,
+ _vectorOfWeakReferences = vectorOfWeakReferences,
+ _vectorOfStrongReferrables = vectorOfStrongReferrables,
+ _coOwningReference = coOwningReference,
+ _vectorOfCoOwningReferences = vectorOfCoOwningReferences,
+ _nonOwningReference = nonOwningReference,
+ _vectorOfNonOwningReferences = vectorOfNonOwningReferences,
+ _anyUniqueType = anyUniqueType,
+ _anyUnique = anyUnique,
+ _anyAmbiguousType = anyAmbiguousType,
+ _anyAmbiguous = anyAmbiguous,
+ _vectorOfEnums = vectorOfEnums;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int nameOffset = fbBuilder.writeString(_name);
+ final int inventoryOffset = _inventory?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_inventory)
+ : null;
+ final int testOffset = _test?.getOrCreateOffset(fbBuilder);
+ final int test4Offset = _test4?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_test4)
+ : null;
+ final int testarrayofstringOffset = _testarrayofstring?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayofstring.map((b) => fbBuilder.writeString(b)).toList())
+ : null;
+ final int testarrayoftablesOffset = _testarrayoftables?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayoftables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int enemyOffset = _enemy?.getOrCreateOffset(fbBuilder);
+ final int testnestedflatbufferOffset = _testnestedflatbuffer?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_testnestedflatbuffer)
+ : null;
+ final int testemptyOffset = _testempty?.getOrCreateOffset(fbBuilder);
+ final int testarrayofboolsOffset = _testarrayofbools?.isNotEmpty == true
+ ? fbBuilder.writeListBool(_testarrayofbools)
+ : null;
+ final int testarrayofstring2Offset = _testarrayofstring2?.isNotEmpty == true
+ ? fbBuilder.writeList(_testarrayofstring2.map((b) => fbBuilder.writeString(b)).toList())
+ : null;
+ final int testarrayofsortedstructOffset = _testarrayofsortedstruct?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_testarrayofsortedstruct)
+ : null;
+ final int flexOffset = _flex?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_flex)
+ : null;
+ final int test5Offset = _test5?.isNotEmpty == true
+ ? fbBuilder.writeListOfStructs(_test5)
+ : null;
+ final int vectorOfLongsOffset = _vectorOfLongs?.isNotEmpty == true
+ ? fbBuilder.writeListInt64(_vectorOfLongs)
+ : null;
+ final int vectorOfDoublesOffset = _vectorOfDoubles?.isNotEmpty == true
+ ? fbBuilder.writeListFloat64(_vectorOfDoubles)
+ : null;
+ final int parentNamespaceTestOffset = _parentNamespaceTest?.getOrCreateOffset(fbBuilder);
+ final int vectorOfReferrablesOffset = _vectorOfReferrables?.isNotEmpty == true
+ ? fbBuilder.writeList(_vectorOfReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int vectorOfWeakReferencesOffset = _vectorOfWeakReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfWeakReferences)
+ : null;
+ final int vectorOfStrongReferrablesOffset = _vectorOfStrongReferrables?.isNotEmpty == true
+ ? fbBuilder.writeList(_vectorOfStrongReferrables.map((b) => b.getOrCreateOffset(fbBuilder)).toList())
+ : null;
+ final int vectorOfCoOwningReferencesOffset = _vectorOfCoOwningReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfCoOwningReferences)
+ : null;
+ final int vectorOfNonOwningReferencesOffset = _vectorOfNonOwningReferences?.isNotEmpty == true
+ ? fbBuilder.writeListUint64(_vectorOfNonOwningReferences)
+ : null;
+ final int anyUniqueOffset = _anyUnique?.getOrCreateOffset(fbBuilder);
+ final int anyAmbiguousOffset = _anyAmbiguous?.getOrCreateOffset(fbBuilder);
+ final int vectorOfEnumsOffset = _vectorOfEnums?.isNotEmpty == true
+ ? fbBuilder.writeListUint8(_vectorOfEnums.map((f) => f.value))
+ : null;
+
+ fbBuilder.startTable();
+ if (_pos != null) {
+ fbBuilder.addStruct(0, _pos.finish(fbBuilder));
+ }
+ fbBuilder.addInt16(1, _mana);
+ fbBuilder.addInt16(2, _hp);
+ if (nameOffset != null) {
+ fbBuilder.addOffset(3, nameOffset);
+ }
+ if (inventoryOffset != null) {
+ fbBuilder.addOffset(5, inventoryOffset);
+ }
+ fbBuilder.addUint8(6, _color?.value);
+ fbBuilder.addUint8(7, _testType?.value);
+ if (testOffset != null) {
+ fbBuilder.addOffset(8, testOffset);
+ }
+ if (test4Offset != null) {
+ fbBuilder.addOffset(9, test4Offset);
+ }
+ if (testarrayofstringOffset != null) {
+ fbBuilder.addOffset(10, testarrayofstringOffset);
+ }
+ if (testarrayoftablesOffset != null) {
+ fbBuilder.addOffset(11, testarrayoftablesOffset);
+ }
+ if (enemyOffset != null) {
+ fbBuilder.addOffset(12, enemyOffset);
+ }
+ if (testnestedflatbufferOffset != null) {
+ fbBuilder.addOffset(13, testnestedflatbufferOffset);
+ }
+ if (testemptyOffset != null) {
+ fbBuilder.addOffset(14, testemptyOffset);
+ }
+ fbBuilder.addBool(15, _testbool);
+ fbBuilder.addInt32(16, _testhashs32Fnv1);
+ fbBuilder.addUint32(17, _testhashu32Fnv1);
+ fbBuilder.addInt64(18, _testhashs64Fnv1);
+ fbBuilder.addUint64(19, _testhashu64Fnv1);
+ fbBuilder.addInt32(20, _testhashs32Fnv1a);
+ fbBuilder.addUint32(21, _testhashu32Fnv1a);
+ fbBuilder.addInt64(22, _testhashs64Fnv1a);
+ fbBuilder.addUint64(23, _testhashu64Fnv1a);
+ if (testarrayofboolsOffset != null) {
+ fbBuilder.addOffset(24, testarrayofboolsOffset);
+ }
+ fbBuilder.addFloat32(25, _testf);
+ fbBuilder.addFloat32(26, _testf2);
+ fbBuilder.addFloat32(27, _testf3);
+ if (testarrayofstring2Offset != null) {
+ fbBuilder.addOffset(28, testarrayofstring2Offset);
+ }
+ if (testarrayofsortedstructOffset != null) {
+ fbBuilder.addOffset(29, testarrayofsortedstructOffset);
+ }
+ if (flexOffset != null) {
+ fbBuilder.addOffset(30, flexOffset);
+ }
+ if (test5Offset != null) {
+ fbBuilder.addOffset(31, test5Offset);
+ }
+ if (vectorOfLongsOffset != null) {
+ fbBuilder.addOffset(32, vectorOfLongsOffset);
+ }
+ if (vectorOfDoublesOffset != null) {
+ fbBuilder.addOffset(33, vectorOfDoublesOffset);
+ }
+ if (parentNamespaceTestOffset != null) {
+ fbBuilder.addOffset(34, parentNamespaceTestOffset);
+ }
+ if (vectorOfReferrablesOffset != null) {
+ fbBuilder.addOffset(35, vectorOfReferrablesOffset);
+ }
+ fbBuilder.addUint64(36, _singleWeakReference);
+ if (vectorOfWeakReferencesOffset != null) {
+ fbBuilder.addOffset(37, vectorOfWeakReferencesOffset);
+ }
+ if (vectorOfStrongReferrablesOffset != null) {
+ fbBuilder.addOffset(38, vectorOfStrongReferrablesOffset);
+ }
+ fbBuilder.addUint64(39, _coOwningReference);
+ if (vectorOfCoOwningReferencesOffset != null) {
+ fbBuilder.addOffset(40, vectorOfCoOwningReferencesOffset);
+ }
+ fbBuilder.addUint64(41, _nonOwningReference);
+ if (vectorOfNonOwningReferencesOffset != null) {
+ fbBuilder.addOffset(42, vectorOfNonOwningReferencesOffset);
+ }
+ fbBuilder.addUint8(43, _anyUniqueType?.value);
+ if (anyUniqueOffset != null) {
+ fbBuilder.addOffset(44, anyUniqueOffset);
+ }
+ fbBuilder.addUint8(45, _anyAmbiguousType?.value);
+ if (anyAmbiguousOffset != null) {
+ fbBuilder.addOffset(46, anyAmbiguousOffset);
+ }
+ if (vectorOfEnumsOffset != null) {
+ fbBuilder.addOffset(47, vectorOfEnumsOffset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class TypeAliases {
+ TypeAliases._(this._bc, this._bcOffset);
+ factory TypeAliases(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TypeAliases> reader = const _TypeAliasesReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get i8 => const fb.Int8Reader().vTableGet(_bc, _bcOffset, 4, 0);
+ int get u8 => const fb.Uint8Reader().vTableGet(_bc, _bcOffset, 6, 0);
+ int get i16 => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 0);
+ int get u16 => const fb.Uint16Reader().vTableGet(_bc, _bcOffset, 10, 0);
+ int get i32 => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 12, 0);
+ int get u32 => const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 14, 0);
+ int get i64 => const fb.Int64Reader().vTableGet(_bc, _bcOffset, 16, 0);
+ int get u64 => const fb.Uint64Reader().vTableGet(_bc, _bcOffset, 18, 0);
+ double get f32 => const fb.Float32Reader().vTableGet(_bc, _bcOffset, 20, 0.0);
+ double get f64 => const fb.Float64Reader().vTableGet(_bc, _bcOffset, 22, 0.0);
+ List<int> get v8 => const fb.ListReader<int>(const fb.Int8Reader()).vTableGet(_bc, _bcOffset, 24, null);
+ List<double> get vf64 => const fb.ListReader<double>(const fb.Float64Reader()).vTableGet(_bc, _bcOffset, 26, null);
+
+ @override
+ String toString() {
+ return 'TypeAliases{i8: $i8, u8: $u8, i16: $i16, u16: $u16, i32: $i32, u32: $u32, i64: $i64, u64: $u64, f32: $f32, f64: $f64, v8: $v8, vf64: $vf64}';
+ }
+}
+
+class _TypeAliasesReader extends fb.TableReader<TypeAliases> {
+ const _TypeAliasesReader();
+
+ @override
+ TypeAliases createObject(fb.BufferContext bc, int offset) =>
+ new TypeAliases._(bc, offset);
+}
+
+class TypeAliasesBuilder {
+ TypeAliasesBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addI8(int i8) {
+ fbBuilder.addInt8(0, i8);
+ return fbBuilder.offset;
+ }
+ int addU8(int u8) {
+ fbBuilder.addUint8(1, u8);
+ return fbBuilder.offset;
+ }
+ int addI16(int i16) {
+ fbBuilder.addInt16(2, i16);
+ return fbBuilder.offset;
+ }
+ int addU16(int u16) {
+ fbBuilder.addUint16(3, u16);
+ return fbBuilder.offset;
+ }
+ int addI32(int i32) {
+ fbBuilder.addInt32(4, i32);
+ return fbBuilder.offset;
+ }
+ int addU32(int u32) {
+ fbBuilder.addUint32(5, u32);
+ return fbBuilder.offset;
+ }
+ int addI64(int i64) {
+ fbBuilder.addInt64(6, i64);
+ return fbBuilder.offset;
+ }
+ int addU64(int u64) {
+ fbBuilder.addUint64(7, u64);
+ return fbBuilder.offset;
+ }
+ int addF32(double f32) {
+ fbBuilder.addFloat32(8, f32);
+ return fbBuilder.offset;
+ }
+ int addF64(double f64) {
+ fbBuilder.addFloat64(9, f64);
+ return fbBuilder.offset;
+ }
+ int addV8Offset(int offset) {
+ fbBuilder.addOffset(10, offset);
+ return fbBuilder.offset;
+ }
+ int addVf64Offset(int offset) {
+ fbBuilder.addOffset(11, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TypeAliasesObjectBuilder extends fb.ObjectBuilder {
+ final int _i8;
+ final int _u8;
+ final int _i16;
+ final int _u16;
+ final int _i32;
+ final int _u32;
+ final int _i64;
+ final int _u64;
+ final double _f32;
+ final double _f64;
+ final List<int> _v8;
+ final List<double> _vf64;
+
+ TypeAliasesObjectBuilder({
+ int i8,
+ int u8,
+ int i16,
+ int u16,
+ int i32,
+ int u32,
+ int i64,
+ int u64,
+ double f32,
+ double f64,
+ List<int> v8,
+ List<double> vf64,
+ })
+ : _i8 = i8,
+ _u8 = u8,
+ _i16 = i16,
+ _u16 = u16,
+ _i32 = i32,
+ _u32 = u32,
+ _i64 = i64,
+ _u64 = u64,
+ _f32 = f32,
+ _f64 = f64,
+ _v8 = v8,
+ _vf64 = vf64;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int v8Offset = _v8?.isNotEmpty == true
+ ? fbBuilder.writeListInt8(_v8)
+ : null;
+ final int vf64Offset = _vf64?.isNotEmpty == true
+ ? fbBuilder.writeListFloat64(_vf64)
+ : null;
+
+ fbBuilder.startTable();
+ fbBuilder.addInt8(0, _i8);
+ fbBuilder.addUint8(1, _u8);
+ fbBuilder.addInt16(2, _i16);
+ fbBuilder.addUint16(3, _u16);
+ fbBuilder.addInt32(4, _i32);
+ fbBuilder.addUint32(5, _u32);
+ fbBuilder.addInt64(6, _i64);
+ fbBuilder.addUint64(7, _u64);
+ fbBuilder.addFloat32(8, _f32);
+ fbBuilder.addFloat64(9, _f64);
+ if (v8Offset != null) {
+ fbBuilder.addOffset(10, v8Offset);
+ }
+ if (vf64Offset != null) {
+ fbBuilder.addOffset(11, vf64Offset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/tests/monster_test_my_game_generated.dart b/tests/monster_test_my_game_generated.dart
new file mode 100644
index 0000000..abd538c
--- /dev/null
+++ b/tests/monster_test_my_game_generated.dart
@@ -0,0 +1,60 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library my_game;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import './monster_test_my_game.example_generated.dart' as my_game_example;
+import './monster_test_my_game.example2_generated.dart' as my_game_example2;
+
+class InParentNamespace {
+ InParentNamespace._(this._bc, this._bcOffset);
+ factory InParentNamespace(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<InParentNamespace> reader = const _InParentNamespaceReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+
+ @override
+ String toString() {
+ return 'InParentNamespace{}';
+ }
+}
+
+class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
+ const _InParentNamespaceReader();
+
+ @override
+ InParentNamespace createObject(fb.BufferContext bc, int offset) =>
+ new InParentNamespace._(bc, offset);
+}
+
+class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
+
+ InParentNamespaceObjectBuilder();
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/tests/monsterdata_extra.json b/tests/monsterdata_extra.json
new file mode 100644
index 0000000..53045cd
--- /dev/null
+++ b/tests/monsterdata_extra.json
@@ -0,0 +1,15 @@
+{
+ // Initialize with non-default values.
+ d0 : -nan, // match with default
+ d1 : +inf,
+ d2 : -inf,
+ d3: nan,
+ f0 : +nan, // match with default
+ f1 : -nan, // match with default
+ f2 : +inf, // match with default
+ f3 : -inf, // match with default
+ // Values should have exact binary representation
+ // to avoid rounding effects in tests.
+ dvec : [2.0, +inf, -inf, nan,],
+ fvec : [1.0, -inf, +inf, nan],
+}
diff --git a/tests/monsterdata_python_wire.mon b/tests/monsterdata_python_wire.mon
new file mode 100644
index 0000000..2fb956d
--- /dev/null
+++ b/tests/monsterdata_python_wire.mon
Binary files differ
diff --git a/tests/monsterdata_test.golden b/tests/monsterdata_test.golden
new file mode 100644
index 0000000..4bead97
--- /dev/null
+++ b/tests/monsterdata_test.golden
@@ -0,0 +1,82 @@
+{
+ pos: {
+ x: 1.0,
+ y: 2.0,
+ z: 3.0,
+ test1: 3.14159265359,
+ test2: "Green",
+ test3: {
+ a: 10,
+ b: 20
+ }
+ },
+ hp: 80,
+ name: "MyMonster",
+ inventory: [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9
+ ],
+ test_type: "Monster",
+ test: {
+ name: "Fred"
+ },
+ test4: [
+ {
+ a: 10,
+ b: 20
+ },
+ {
+ a: 30,
+ b: 40
+ }
+ ],
+ testarrayofstring: [
+ "bob",
+ "fred",
+ "bob",
+ "fred"
+ ],
+ testarrayoftables: [
+ {
+ hp: 1000,
+ name: "Barney"
+ },
+ {
+ name: "Fred"
+ },
+ {
+ name: "Wilma"
+ }
+ ],
+ testnestedflatbuffer: {
+ name: "NestedMonster"
+ },
+ testbool: true,
+ testhashs32_fnv1: -579221183,
+ testhashu32_fnv1: 3715746113,
+ testhashs64_fnv1: 7930699090847568257,
+ testhashu64_fnv1: 7930699090847568257,
+ testhashs32_fnv1a: -1904106383,
+ testhashu32_fnv1a: 2390860913,
+ testhashs64_fnv1a: 4898026182817603057,
+ testhashu64_fnv1a: 4898026182817603057,
+ flex: 1234,
+ test5: [
+ {
+ a: 10,
+ b: 20
+ },
+ {
+ a: 30,
+ b: 40
+ }
+ ]
+}
diff --git a/tests/monsterdata_test.json b/tests/monsterdata_test.json
new file mode 100644
index 0000000..d3028b5
--- /dev/null
+++ b/tests/monsterdata_test.json
@@ -0,0 +1,78 @@
+{
+ pos: {
+ x: 1,
+ y: "2",
+ z: 3,
+ test1: 3,
+ test2: Green,
+ test3: {
+ a: 5,
+ b: 6
+ }
+ },
+ hp: 80,
+ name: "MyMonster",
+ inventory: [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4
+ ],
+ vector_of_longs: [
+ 1,
+ 100,
+ 10000,
+ 1000000,
+ 100000000
+ ],
+ vector_of_doubles: [
+ -1.7976931348623157e+308,
+ 0,
+ 1.7976931348623157e+308
+ ],
+ test_type: Monster,
+ test: {
+ name: "Fred",
+ pos: null
+ },
+ test4: [
+ {
+ a: 10,
+ b: 20
+ },
+ {
+ b: "40",
+ a: 30
+ }
+ ],
+ test5: [
+ {
+ a: 10,
+ b: 20
+ },
+ {
+ b: "40",
+ a: 30
+ }
+ ],
+ testarrayofstring: [
+ "test1",
+ "test2"
+ ],
+ enemy: {
+ name: "Fred"
+ },
+ testarrayofbools:[
+ true, false, true
+ ],
+ testbool: true,
+ testhashs32_fnv1: "This string is being hashed!",
+ testhashu32_fnv1: "This string is being hashed!",
+ testhashs64_fnv1: "This string is being hashed!",
+ testhashu64_fnv1: "This string is being hashed!",
+ testhashs32_fnv1a: "This string is being hashed!",
+ testhashu32_fnv1a: "This string is being hashed!",
+ testhashs64_fnv1a: "This string is being hashed!",
+ testhashu64_fnv1a: "This string is being hashed!",
+}
diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon
new file mode 100644
index 0000000..ba6cf27
--- /dev/null
+++ b/tests/monsterdata_test.mon
Binary files differ
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs
new file mode 100644
index 0000000..ff44023
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs
@@ -0,0 +1,16 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace NamespaceA.NamespaceB
+{
+
+public enum EnumInNestedNS : sbyte
+{
+ A = 0,
+ B = 1,
+ C = 2,
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go
new file mode 100644
index 0000000..6cec5ff
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.go
@@ -0,0 +1,32 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package NamespaceB
+
+import "strconv"
+
+type EnumInNestedNS int8
+
+const (
+ EnumInNestedNSA EnumInNestedNS = 0
+ EnumInNestedNSB EnumInNestedNS = 1
+ EnumInNestedNSC EnumInNestedNS = 2
+)
+
+var EnumNamesEnumInNestedNS = map[EnumInNestedNS]string{
+ EnumInNestedNSA: "A",
+ EnumInNestedNSB: "B",
+ EnumInNestedNSC: "C",
+}
+
+var EnumValuesEnumInNestedNS = map[string]EnumInNestedNS{
+ "A": EnumInNestedNSA,
+ "B": EnumInNestedNSB,
+ "C": EnumInNestedNSC,
+}
+
+func (v EnumInNestedNS) String() string {
+ if s, ok := EnumNamesEnumInNestedNS[v]; ok {
+ return s
+ }
+ return "EnumInNestedNS(" + strconv.FormatInt(int64(v), 10) + ")"
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java
new file mode 100644
index 0000000..e23cecc
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.java
@@ -0,0 +1,15 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA.NamespaceB;
+
+public final class EnumInNestedNS {
+ private EnumInNestedNS() { }
+ public static final byte A = 0;
+ public static final byte B = 1;
+ public static final byte C = 2;
+
+ public static final String[] names = { "A", "B", "C", };
+
+ public static String name(int e) { return names[e]; }
+}
+
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt
new file mode 100644
index 0000000..0ede58c
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.kt
@@ -0,0 +1,15 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA.NamespaceB
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class EnumInNestedNS private constructor() {
+ companion object {
+ const val A: Byte = 0
+ const val B: Byte = 1
+ const val C: Byte = 2
+ val names : Array<String> = arrayOf("A", "B", "C")
+ fun name(e: Int) : String = names[e]
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.lua b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.lua
new file mode 100644
index 0000000..60b1fb1
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.lua
@@ -0,0 +1,11 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: NamespaceB
+
+local EnumInNestedNS = {
+ A = 0,
+ B = 1,
+ C = 2,
+}
+
+return EnumInNestedNS -- return the module
\ No newline at end of file
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php
new file mode 100644
index 0000000..bcb22b7
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.php
@@ -0,0 +1,25 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA\NamespaceB;
+
+class EnumInNestedNS
+{
+ const A = 0;
+ const B = 1;
+ const C = 2;
+
+ private static $names = array(
+ EnumInNestedNS::A=>"A",
+ EnumInNestedNS::B=>"B",
+ EnumInNestedNS::C=>"C",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py
new file mode 100644
index 0000000..cb8218f
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.py
@@ -0,0 +1,9 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceB
+
+class EnumInNestedNS(object):
+ A = 0
+ B = 1
+ C = 2
+
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
new file mode 100644
index 0000000..9aba8db
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
@@ -0,0 +1,32 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace NamespaceA.NamespaceB
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct StructInNestedNS : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public StructInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int A { get { return __p.bb.GetInt(__p.bb_pos + 0); } }
+ public void MutateA(int a) { __p.bb.PutInt(__p.bb_pos + 0, a); }
+ public int B { get { return __p.bb.GetInt(__p.bb_pos + 4); } }
+ public void MutateB(int b) { __p.bb.PutInt(__p.bb_pos + 4, b); }
+
+ public static Offset<NamespaceA.NamespaceB.StructInNestedNS> CreateStructInNestedNS(FlatBufferBuilder builder, int A, int B) {
+ builder.Prep(4, 8);
+ builder.PutInt(B);
+ builder.PutInt(A);
+ return new Offset<NamespaceA.NamespaceB.StructInNestedNS>(builder.Offset);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
new file mode 100644
index 0000000..e985fbf
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.go
@@ -0,0 +1,41 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package NamespaceB
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type StructInNestedNS struct {
+ _tab flatbuffers.Struct
+}
+
+func (rcv *StructInNestedNS) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *StructInNestedNS) Table() flatbuffers.Table {
+ return rcv._tab.Table
+}
+
+func (rcv *StructInNestedNS) A() int32 {
+ return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
+}
+func (rcv *StructInNestedNS) MutateA(n int32) bool {
+ return rcv._tab.MutateInt32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
+}
+
+func (rcv *StructInNestedNS) B() int32 {
+ return rcv._tab.GetInt32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
+}
+func (rcv *StructInNestedNS) MutateB(n int32) bool {
+ return rcv._tab.MutateInt32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
+}
+
+func CreateStructInNestedNS(builder *flatbuffers.Builder, a int32, b int32) flatbuffers.UOffsetT {
+ builder.Prep(4, 8)
+ builder.PrependInt32(b)
+ builder.PrependInt32(a)
+ return builder.Offset()
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
new file mode 100644
index 0000000..284f89a
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.java
@@ -0,0 +1,27 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA.NamespaceB;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class StructInNestedNS extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public StructInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int a() { return bb.getInt(bb_pos + 0); }
+ public void mutateA(int a) { bb.putInt(bb_pos + 0, a); }
+ public int b() { return bb.getInt(bb_pos + 4); }
+ public void mutateB(int b) { bb.putInt(bb_pos + 4, b); }
+
+ public static int createStructInNestedNS(FlatBufferBuilder builder, int a, int b) {
+ builder.prep(4, 8);
+ builder.putInt(b);
+ builder.putInt(a);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt
new file mode 100644
index 0000000..0273bb1
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.kt
@@ -0,0 +1,32 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA.NamespaceB
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class StructInNestedNS : Struct() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : StructInNestedNS {
+ __init(_i, _bb)
+ return this
+ }
+ val a : Int get() = bb.getInt(bb_pos + 0)
+ fun mutateA(a: Int) : ByteBuffer = bb.putInt(bb_pos + 0, a)
+ val b : Int get() = bb.getInt(bb_pos + 4)
+ fun mutateB(b: Int) : ByteBuffer = bb.putInt(bb_pos + 4, b)
+ companion object {
+ fun createStructInNestedNS(builder: FlatBufferBuilder, a: Int, b: Int) : Int {
+ builder.prep(4, 8)
+ builder.putInt(b)
+ builder.putInt(a)
+ return builder.offset()
+ }
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.lua b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.lua
new file mode 100644
index 0000000..9ca7541
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.lua
@@ -0,0 +1,31 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: NamespaceB
+
+local flatbuffers = require('flatbuffers')
+
+local StructInNestedNS = {} -- the module
+local StructInNestedNS_mt = {} -- the class metatable
+
+function StructInNestedNS.New()
+ local o = {}
+ setmetatable(o, {__index = StructInNestedNS_mt})
+ return o
+end
+function StructInNestedNS_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function StructInNestedNS_mt:A()
+ return self.view:Get(flatbuffers.N.Int32, self.view.pos + 0)
+end
+function StructInNestedNS_mt:B()
+ return self.view:Get(flatbuffers.N.Int32, self.view.pos + 4)
+end
+function StructInNestedNS.CreateStructInNestedNS(builder, a, b)
+ builder:Prep(4, 8)
+ builder:PrependInt32(b)
+ builder:PrependInt32(a)
+ return builder:Offset()
+end
+
+return StructInNestedNS -- return the module
\ No newline at end of file
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php
new file mode 100644
index 0000000..d305484
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.php
@@ -0,0 +1,52 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA\NamespaceB;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class StructInNestedNS extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return StructInNestedNS
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function GetA()
+ {
+ return $this->bb->getInt($this->bb_pos + 0);
+ }
+
+ /**
+ * @return int
+ */
+ public function GetB()
+ {
+ return $this->bb->getInt($this->bb_pos + 4);
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createStructInNestedNS(FlatBufferBuilder $builder, $a, $b)
+ {
+ $builder->prep(4, 8);
+ $builder->putInt($b);
+ $builder->putInt($a);
+ return $builder->offset();
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py
new file mode 100644
index 0000000..59cceaa
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.py
@@ -0,0 +1,23 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceB
+
+import flatbuffers
+
+class StructInNestedNS(object):
+ __slots__ = ['_tab']
+
+ # StructInNestedNS
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # StructInNestedNS
+ def A(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
+ # StructInNestedNS
+ def B(self): return self._tab.Get(flatbuffers.number_types.Int32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
+
+def CreateStructInNestedNS(builder, a, b):
+ builder.Prep(4, 8)
+ builder.PrependInt32(b)
+ builder.PrependInt32(a)
+ return builder.Offset()
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
new file mode 100644
index 0000000..f8ea32b
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
@@ -0,0 +1,40 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace NamespaceA.NamespaceB
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct TableInNestedNS : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb) { return GetRootAsTableInNestedNS(_bb, new TableInNestedNS()); }
+ public static TableInNestedNS GetRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public TableInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int Foo { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateFoo(int foo) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, foo); return true; } else { return false; } }
+
+ public static Offset<NamespaceA.NamespaceB.TableInNestedNS> CreateTableInNestedNS(FlatBufferBuilder builder,
+ int foo = 0) {
+ builder.StartTable(1);
+ TableInNestedNS.AddFoo(builder, foo);
+ return TableInNestedNS.EndTableInNestedNS(builder);
+ }
+
+ public static void StartTableInNestedNS(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddFoo(FlatBufferBuilder builder, int foo) { builder.AddInt(0, foo, 0); }
+ public static Offset<NamespaceA.NamespaceB.TableInNestedNS> EndTableInNestedNS(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<NamespaceA.NamespaceB.TableInNestedNS>(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
new file mode 100644
index 0000000..75f7a55
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.go
@@ -0,0 +1,49 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package NamespaceB
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type TableInNestedNS struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsTableInNestedNS(buf []byte, offset flatbuffers.UOffsetT) *TableInNestedNS {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &TableInNestedNS{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *TableInNestedNS) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TableInNestedNS) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *TableInNestedNS) Foo() int32 {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ return rcv._tab.GetInt32(o + rcv._tab.Pos)
+ }
+ return 0
+}
+
+func (rcv *TableInNestedNS) MutateFoo(n int32) bool {
+ return rcv._tab.MutateInt32Slot(4, n)
+}
+
+func TableInNestedNSStart(builder *flatbuffers.Builder) {
+ builder.StartObject(1)
+}
+func TableInNestedNSAddFoo(builder *flatbuffers.Builder, foo int32) {
+ builder.PrependInt32Slot(0, foo, 0)
+}
+func TableInNestedNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
new file mode 100644
index 0000000..af1449b
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.java
@@ -0,0 +1,35 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA.NamespaceB;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TableInNestedNS extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb) { return getRootAsTableInNestedNS(_bb, new TableInNestedNS()); }
+ public static TableInNestedNS getRootAsTableInNestedNS(ByteBuffer _bb, TableInNestedNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public TableInNestedNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int foo() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+ public boolean mutateFoo(int foo) { int o = __offset(4); if (o != 0) { bb.putInt(o + bb_pos, foo); return true; } else { return false; } }
+
+ public static int createTableInNestedNS(FlatBufferBuilder builder,
+ int foo) {
+ builder.startTable(1);
+ TableInNestedNS.addFoo(builder, foo);
+ return TableInNestedNS.endTableInNestedNS(builder);
+ }
+
+ public static void startTableInNestedNS(FlatBufferBuilder builder) { builder.startTable(1); }
+ public static void addFoo(FlatBufferBuilder builder, int foo) { builder.addInt(0, foo, 0); }
+ public static int endTableInNestedNS(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt
new file mode 100644
index 0000000..59ebdc9
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.kt
@@ -0,0 +1,53 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA.NamespaceB
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class TableInNestedNS : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : TableInNestedNS {
+ __init(_i, _bb)
+ return this
+ }
+ val foo : Int
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.getInt(o + bb_pos) else 0
+ }
+ fun mutateFoo(foo: Int) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, foo)
+ true
+ } else {
+ false
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsTableInNestedNS(_bb: ByteBuffer): TableInNestedNS = getRootAsTableInNestedNS(_bb, TableInNestedNS())
+ fun getRootAsTableInNestedNS(_bb: ByteBuffer, obj: TableInNestedNS): TableInNestedNS {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createTableInNestedNS(builder: FlatBufferBuilder, foo: Int) : Int {
+ builder.startTable(1)
+ addFoo(builder, foo)
+ return endTableInNestedNS(builder)
+ }
+ fun startTableInNestedNS(builder: FlatBufferBuilder) = builder.startTable(1)
+ fun addFoo(builder: FlatBufferBuilder, foo: Int) = builder.addInt(0, foo, 0)
+ fun endTableInNestedNS(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.lua b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.lua
new file mode 100644
index 0000000..dd45e58
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: NamespaceB
+
+local flatbuffers = require('flatbuffers')
+
+local TableInNestedNS = {} -- the module
+local TableInNestedNS_mt = {} -- the class metatable
+
+function TableInNestedNS.New()
+ local o = {}
+ setmetatable(o, {__index = TableInNestedNS_mt})
+ return o
+end
+function TableInNestedNS.GetRootAsTableInNestedNS(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TableInNestedNS.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TableInNestedNS_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TableInNestedNS_mt:Foo()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function TableInNestedNS.Start(builder) builder:StartObject(1) end
+function TableInNestedNS.AddFoo(builder, foo) builder:PrependInt32Slot(0, foo, 0) end
+function TableInNestedNS.End(builder) return builder:EndObject() end
+
+return TableInNestedNS -- return the module
\ No newline at end of file
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php
new file mode 100644
index 0000000..d16379d
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.php
@@ -0,0 +1,84 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA\NamespaceB;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TableInNestedNS extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TableInNestedNS
+ */
+ public static function getRootAsTableInNestedNS(ByteBuffer $bb)
+ {
+ $obj = new TableInNestedNS();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TableInNestedNS
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getFoo()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTableInNestedNS(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TableInNestedNS
+ */
+ public static function createTableInNestedNS(FlatBufferBuilder $builder, $foo)
+ {
+ $builder->startObject(1);
+ self::addFoo($builder, $foo);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addFoo(FlatBufferBuilder $builder, $foo)
+ {
+ $builder->addIntX(0, $foo, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTableInNestedNS(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py
new file mode 100644
index 0000000..d6d1674
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.py
@@ -0,0 +1,30 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceB
+
+import flatbuffers
+
+class TableInNestedNS(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsTableInNestedNS(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = TableInNestedNS()
+ x.Init(buf, n + offset)
+ return x
+
+ # TableInNestedNS
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TableInNestedNS
+ def Foo(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
+ return 0
+
+def TableInNestedNSStart(builder): builder.StartObject(1)
+def TableInNestedNSAddFoo(builder, foo): builder.PrependInt32Slot(0, foo, 0)
+def TableInNestedNSEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/__init__.py b/tests/namespace_test/NamespaceA/NamespaceB/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/NamespaceB/__init__.py
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.cs b/tests/namespace_test/NamespaceA/SecondTableInA.cs
new file mode 100644
index 0000000..7e08de8
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.cs
@@ -0,0 +1,39 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace NamespaceA
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct SecondTableInA : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb) { return GetRootAsSecondTableInA(_bb, new SecondTableInA()); }
+ public static SecondTableInA GetRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public SecondTableInA __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public NamespaceC.TableInC? ReferToC { get { int o = __p.__offset(4); return o != 0 ? (NamespaceC.TableInC?)(new NamespaceC.TableInC()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+
+ public static Offset<NamespaceA.SecondTableInA> CreateSecondTableInA(FlatBufferBuilder builder,
+ Offset<NamespaceC.TableInC> refer_to_cOffset = default(Offset<NamespaceC.TableInC>)) {
+ builder.StartTable(1);
+ SecondTableInA.AddReferToC(builder, refer_to_cOffset);
+ return SecondTableInA.EndSecondTableInA(builder);
+ }
+
+ public static void StartSecondTableInA(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddReferToC(FlatBufferBuilder builder, Offset<NamespaceC.TableInC> referToCOffset) { builder.AddOffset(0, referToCOffset.Value, 0); }
+ public static Offset<NamespaceA.SecondTableInA> EndSecondTableInA(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<NamespaceA.SecondTableInA>(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.go b/tests/namespace_test/NamespaceA/SecondTableInA.go
new file mode 100644
index 0000000..6dd1eef
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.go
@@ -0,0 +1,52 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package NamespaceA
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+
+ NamespaceC "NamespaceC"
+)
+
+type SecondTableInA struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsSecondTableInA(buf []byte, offset flatbuffers.UOffsetT) *SecondTableInA {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &SecondTableInA{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *SecondTableInA) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *SecondTableInA) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *SecondTableInA) ReferToC(obj *NamespaceC.TableInC) *NamespaceC.TableInC {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(NamespaceC.TableInC)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func SecondTableInAStart(builder *flatbuffers.Builder) {
+ builder.StartObject(1)
+}
+func SecondTableInAAddReferToC(builder *flatbuffers.Builder, referToC flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToC), 0)
+}
+func SecondTableInAEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.java b/tests/namespace_test/NamespaceA/SecondTableInA.java
new file mode 100644
index 0000000..a655199
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.java
@@ -0,0 +1,35 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class SecondTableInA extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb) { return getRootAsSecondTableInA(_bb, new SecondTableInA()); }
+ public static SecondTableInA getRootAsSecondTableInA(ByteBuffer _bb, SecondTableInA obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public SecondTableInA __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public NamespaceC.TableInC referToC() { return referToC(new NamespaceC.TableInC()); }
+ public NamespaceC.TableInC referToC(NamespaceC.TableInC obj) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+
+ public static int createSecondTableInA(FlatBufferBuilder builder,
+ int refer_to_cOffset) {
+ builder.startTable(1);
+ SecondTableInA.addReferToC(builder, refer_to_cOffset);
+ return SecondTableInA.endSecondTableInA(builder);
+ }
+
+ public static void startSecondTableInA(FlatBufferBuilder builder) { builder.startTable(1); }
+ public static void addReferToC(FlatBufferBuilder builder, int referToCOffset) { builder.addOffset(0, referToCOffset, 0); }
+ public static int endSecondTableInA(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.kt b/tests/namespace_test/NamespaceA/SecondTableInA.kt
new file mode 100644
index 0000000..8261443
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.kt
@@ -0,0 +1,48 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class SecondTableInA : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : SecondTableInA {
+ __init(_i, _bb)
+ return this
+ }
+ val referToC : NamespaceC.TableInC? get() = referToC(NamespaceC.TableInC())
+ fun referToC(obj: NamespaceC.TableInC) : NamespaceC.TableInC? {
+ val o = __offset(4)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsSecondTableInA(_bb: ByteBuffer): SecondTableInA = getRootAsSecondTableInA(_bb, SecondTableInA())
+ fun getRootAsSecondTableInA(_bb: ByteBuffer, obj: SecondTableInA): SecondTableInA {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createSecondTableInA(builder: FlatBufferBuilder, referToCOffset: Int) : Int {
+ builder.startTable(1)
+ addReferToC(builder, referToCOffset)
+ return endSecondTableInA(builder)
+ }
+ fun startSecondTableInA(builder: FlatBufferBuilder) = builder.startTable(1)
+ fun addReferToC(builder: FlatBufferBuilder, referToC: Int) = builder.addOffset(0, referToC, 0)
+ fun endSecondTableInA(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.lua b/tests/namespace_test/NamespaceA/SecondTableInA.lua
new file mode 100644
index 0000000..9a60e4b
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.lua
@@ -0,0 +1,37 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: NamespaceA
+
+local flatbuffers = require('flatbuffers')
+
+local SecondTableInA = {} -- the module
+local SecondTableInA_mt = {} -- the class metatable
+
+function SecondTableInA.New()
+ local o = {}
+ setmetatable(o, {__index = SecondTableInA_mt})
+ return o
+end
+function SecondTableInA.GetRootAsSecondTableInA(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = SecondTableInA.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function SecondTableInA_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function SecondTableInA_mt:ReferToC()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('NamespaceC.TableInC').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function SecondTableInA.Start(builder) builder:StartObject(1) end
+function SecondTableInA.AddReferToC(builder, referToC) builder:PrependUOffsetTRelativeSlot(0, referToC, 0) end
+function SecondTableInA.End(builder) return builder:EndObject() end
+
+return SecondTableInA -- return the module
\ No newline at end of file
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.php b/tests/namespace_test/NamespaceA/SecondTableInA.php
new file mode 100644
index 0000000..c9bc65c
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.php
@@ -0,0 +1,82 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class SecondTableInA extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return SecondTableInA
+ */
+ public static function getRootAsSecondTableInA(ByteBuffer $bb)
+ {
+ $obj = new SecondTableInA();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return SecondTableInA
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getReferToC()
+ {
+ $obj = new TableInC();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startSecondTableInA(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return SecondTableInA
+ */
+ public static function createSecondTableInA(FlatBufferBuilder $builder, $refer_to_c)
+ {
+ $builder->startObject(1);
+ self::addReferToC($builder, $refer_to_c);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToC(FlatBufferBuilder $builder, $referToC)
+ {
+ $builder->addOffsetX(0, $referToC, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endSecondTableInA(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.py b/tests/namespace_test/NamespaceA/SecondTableInA.py
new file mode 100644
index 0000000..20dac3e
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.py
@@ -0,0 +1,34 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceA
+
+import flatbuffers
+
+class SecondTableInA(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsSecondTableInA(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = SecondTableInA()
+ x.Init(buf, n + offset)
+ return x
+
+ # SecondTableInA
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # SecondTableInA
+ def ReferToC(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInC import TableInC
+ obj = TableInC()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def SecondTableInAStart(builder): builder.StartObject(1)
+def SecondTableInAAddReferToC(builder, referToC): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToC), 0)
+def SecondTableInAEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceA/TableInC.cs b/tests/namespace_test/NamespaceA/TableInC.cs
new file mode 100644
index 0000000..98f4e13
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.cs
@@ -0,0 +1,38 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA
+{
+
+using System;
+using FlatBuffers;
+
+public sealed class TableInC : Table {
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb) { return GetRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+ public NamespaceA.TableInFirstNS ReferToA1 { get { return GetReferToA1(new NamespaceA.TableInFirstNS()); } }
+ public NamespaceA.TableInFirstNS GetReferToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+ public SecondTableInA ReferToA2 { get { return GetReferToA2(new SecondTableInA()); } }
+ public SecondTableInA GetReferToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+
+ public static Offset<NamespaceC.TableInC> CreateTableInC(FlatBufferBuilder builder,
+ Offset<NamespaceA.TableInFirstNS> refer_to_a1Offset = default(Offset<NamespaceA.TableInFirstNS>),
+ Offset<SecondTableInA> refer_to_a2Offset = default(Offset<SecondTableInA>)) {
+ builder.StartObject(2);
+ TableInC.AddReferToA2(builder, refer_to_a2Offset);
+ TableInC.AddReferToA1(builder, refer_to_a1Offset);
+ return TableInC.EndTableInC(builder);
+ }
+
+ public static void StartTableInC(FlatBufferBuilder builder) { builder.StartObject(2); }
+ public static void AddReferToA1(FlatBufferBuilder builder, Offset<NamespaceA.TableInFirstNS> referToA1Offset) { builder.AddOffset(0, referToA1Offset.Value, 0); }
+ public static void AddReferToA2(FlatBufferBuilder builder, Offset<SecondTableInA> referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
+ public static Offset<NamespaceC.TableInC> EndTableInC(FlatBufferBuilder builder) {
+ int o = builder.EndObject();
+ return new Offset<NamespaceC.TableInC>(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/TableInC.go b/tests/namespace_test/NamespaceA/TableInC.go
new file mode 100644
index 0000000..6f3d3f2
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.go
@@ -0,0 +1,46 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+)
+type TableInC struct {
+ _tab flatbuffers.Table
+}
+
+func (rcv *TableInC) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TableInC) ReferToA1(obj *TableInFirstNS) *TableInFirstNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(TableInFirstNS)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *TableInC) ReferToA2(obj *SecondTableInA) *SecondTableInA {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(SecondTableInA)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func TableInCStart(builder *flatbuffers.Builder) { builder.StartObject(2) }
+func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0) }
+func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0) }
+func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }
diff --git a/tests/namespace_test/NamespaceA/TableInC.php b/tests/namespace_test/NamespaceA/TableInC.php
new file mode 100644
index 0000000..49705f8
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.php
@@ -0,0 +1,100 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TableInC extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TableInC
+ */
+ public static function getRootAsTableInC(ByteBuffer $bb)
+ {
+ $obj = new TableInC();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TableInC
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getReferToA1()
+ {
+ $obj = new TableInFirstNS();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ public function getReferToA2()
+ {
+ $obj = new SecondTableInA();
+ $o = $this->__offset(6);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTableInC(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TableInC
+ */
+ public static function createTableInC(FlatBufferBuilder $builder, $refer_to_a1, $refer_to_a2)
+ {
+ $builder->startObject(2);
+ self::addReferToA1($builder, $refer_to_a1);
+ self::addReferToA2($builder, $refer_to_a2);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA1(FlatBufferBuilder $builder, $referToA1)
+ {
+ $builder->addOffsetX(0, $referToA1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA2(FlatBufferBuilder $builder, $referToA2)
+ {
+ $builder->addOffsetX(1, $referToA2, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTableInC(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/TableInC.py b/tests/namespace_test/NamespaceA/TableInC.py
new file mode 100644
index 0000000..4afea1a
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInC.py
@@ -0,0 +1,39 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceA
+
+import flatbuffers
+
+class TableInC(object):
+ __slots__ = ['_tab']
+
+ # TableInC
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TableInC
+ def ReferToA1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInFirstNS import TableInFirstNS
+ obj = TableInFirstNS()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # TableInC
+ def ReferToA2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .SecondTableInA import SecondTableInA
+ obj = SecondTableInA()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def TableInCStart(builder): builder.StartObject(2)
+def TableInCAddReferToA1(builder, referToA1): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToA1), 0)
+def TableInCAddReferToA2(builder, referToA2): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(referToA2), 0)
+def TableInCEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.cs b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
new file mode 100644
index 0000000..d0d8ed0
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
@@ -0,0 +1,37 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace NamespaceA
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct TableInFirstNS : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb) { return GetRootAsTableInFirstNS(_bb, new TableInFirstNS()); }
+ public static TableInFirstNS GetRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public TableInFirstNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public NamespaceA.NamespaceB.TableInNestedNS? FooTable { get { int o = __p.__offset(4); return o != 0 ? (NamespaceA.NamespaceB.TableInNestedNS?)(new NamespaceA.NamespaceB.TableInNestedNS()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public NamespaceA.NamespaceB.EnumInNestedNS FooEnum { get { int o = __p.__offset(6); return o != 0 ? (NamespaceA.NamespaceB.EnumInNestedNS)__p.bb.GetSbyte(o + __p.bb_pos) : NamespaceA.NamespaceB.EnumInNestedNS.A; } }
+ public bool MutateFooEnum(NamespaceA.NamespaceB.EnumInNestedNS foo_enum) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, (sbyte)foo_enum); return true; } else { return false; } }
+ public NamespaceA.NamespaceB.StructInNestedNS? FooStruct { get { int o = __p.__offset(8); return o != 0 ? (NamespaceA.NamespaceB.StructInNestedNS?)(new NamespaceA.NamespaceB.StructInNestedNS()).__assign(o + __p.bb_pos, __p.bb) : null; } }
+
+ public static void StartTableInFirstNS(FlatBufferBuilder builder) { builder.StartTable(3); }
+ public static void AddFooTable(FlatBufferBuilder builder, Offset<NamespaceA.NamespaceB.TableInNestedNS> fooTableOffset) { builder.AddOffset(0, fooTableOffset.Value, 0); }
+ public static void AddFooEnum(FlatBufferBuilder builder, NamespaceA.NamespaceB.EnumInNestedNS fooEnum) { builder.AddSbyte(1, (sbyte)fooEnum, 0); }
+ public static void AddFooStruct(FlatBufferBuilder builder, Offset<NamespaceA.NamespaceB.StructInNestedNS> fooStructOffset) { builder.AddStruct(2, fooStructOffset.Value, 0); }
+ public static Offset<NamespaceA.TableInFirstNS> EndTableInFirstNS(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<NamespaceA.TableInFirstNS>(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.go b/tests/namespace_test/NamespaceA/TableInFirstNS.go
new file mode 100644
index 0000000..bbcbdc6
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.go
@@ -0,0 +1,83 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package NamespaceA
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+
+ NamespaceA__NamespaceB "NamespaceA/NamespaceB"
+)
+
+type TableInFirstNS struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsTableInFirstNS(buf []byte, offset flatbuffers.UOffsetT) *TableInFirstNS {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &TableInFirstNS{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *TableInFirstNS) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TableInFirstNS) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *TableInFirstNS) FooTable(obj *NamespaceA__NamespaceB.TableInNestedNS) *NamespaceA__NamespaceB.TableInNestedNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(NamespaceA__NamespaceB.TableInNestedNS)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *TableInFirstNS) FooEnum() NamespaceA__NamespaceB.EnumInNestedNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ return NamespaceA__NamespaceB.EnumInNestedNS(rcv._tab.GetInt8(o + rcv._tab.Pos))
+ }
+ return 0
+}
+
+func (rcv *TableInFirstNS) MutateFooEnum(n NamespaceA__NamespaceB.EnumInNestedNS) bool {
+ return rcv._tab.MutateInt8Slot(6, int8(n))
+}
+
+func (rcv *TableInFirstNS) FooStruct(obj *NamespaceA__NamespaceB.StructInNestedNS) *NamespaceA__NamespaceB.StructInNestedNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
+ if o != 0 {
+ x := o + rcv._tab.Pos
+ if obj == nil {
+ obj = new(NamespaceA__NamespaceB.StructInNestedNS)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func TableInFirstNSStart(builder *flatbuffers.Builder) {
+ builder.StartObject(3)
+}
+func TableInFirstNSAddFooTable(builder *flatbuffers.Builder, fooTable flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(fooTable), 0)
+}
+func TableInFirstNSAddFooEnum(builder *flatbuffers.Builder, fooEnum NamespaceA__NamespaceB.EnumInNestedNS) {
+ builder.PrependInt8Slot(1, int8(fooEnum), 0)
+}
+func TableInFirstNSAddFooStruct(builder *flatbuffers.Builder, fooStruct flatbuffers.UOffsetT) {
+ builder.PrependStructSlot(2, flatbuffers.UOffsetT(fooStruct), 0)
+}
+func TableInFirstNSEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.java b/tests/namespace_test/NamespaceA/TableInFirstNS.java
new file mode 100644
index 0000000..e097381
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.java
@@ -0,0 +1,34 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TableInFirstNS extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb) { return getRootAsTableInFirstNS(_bb, new TableInFirstNS()); }
+ public static TableInFirstNS getRootAsTableInFirstNS(ByteBuffer _bb, TableInFirstNS obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public TableInFirstNS __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public NamespaceA.NamespaceB.TableInNestedNS fooTable() { return fooTable(new NamespaceA.NamespaceB.TableInNestedNS()); }
+ public NamespaceA.NamespaceB.TableInNestedNS fooTable(NamespaceA.NamespaceB.TableInNestedNS obj) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+ public byte fooEnum() { int o = __offset(6); return o != 0 ? bb.get(o + bb_pos) : 0; }
+ public boolean mutateFooEnum(byte foo_enum) { int o = __offset(6); if (o != 0) { bb.put(o + bb_pos, foo_enum); return true; } else { return false; } }
+ public NamespaceA.NamespaceB.StructInNestedNS fooStruct() { return fooStruct(new NamespaceA.NamespaceB.StructInNestedNS()); }
+ public NamespaceA.NamespaceB.StructInNestedNS fooStruct(NamespaceA.NamespaceB.StructInNestedNS obj) { int o = __offset(8); return o != 0 ? obj.__assign(o + bb_pos, bb) : null; }
+
+ public static void startTableInFirstNS(FlatBufferBuilder builder) { builder.startTable(3); }
+ public static void addFooTable(FlatBufferBuilder builder, int fooTableOffset) { builder.addOffset(0, fooTableOffset, 0); }
+ public static void addFooEnum(FlatBufferBuilder builder, byte fooEnum) { builder.addByte(1, fooEnum, 0); }
+ public static void addFooStruct(FlatBufferBuilder builder, int fooStructOffset) { builder.addStruct(2, fooStructOffset, 0); }
+ public static int endTableInFirstNS(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.kt b/tests/namespace_test/NamespaceA/TableInFirstNS.kt
new file mode 100644
index 0000000..1ba0afc
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.kt
@@ -0,0 +1,68 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceA
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class TableInFirstNS : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : TableInFirstNS {
+ __init(_i, _bb)
+ return this
+ }
+ val fooTable : NamespaceA.NamespaceB.TableInNestedNS? get() = fooTable(NamespaceA.NamespaceB.TableInNestedNS())
+ fun fooTable(obj: NamespaceA.NamespaceB.TableInNestedNS) : NamespaceA.NamespaceB.TableInNestedNS? {
+ val o = __offset(4)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ val fooEnum : Byte
+ get() {
+ val o = __offset(6)
+ return if(o != 0) bb.get(o + bb_pos) else 0
+ }
+ fun mutateFooEnum(fooEnum: Byte) : Boolean {
+ val o = __offset(6)
+ return if (o != 0) {
+ bb.put(o + bb_pos, fooEnum)
+ true
+ } else {
+ false
+ }
+ }
+ val fooStruct : NamespaceA.NamespaceB.StructInNestedNS? get() = fooStruct(NamespaceA.NamespaceB.StructInNestedNS())
+ fun fooStruct(obj: NamespaceA.NamespaceB.StructInNestedNS) : NamespaceA.NamespaceB.StructInNestedNS? {
+ val o = __offset(8)
+ return if (o != 0) {
+ obj.__assign(o + bb_pos, bb)
+ } else {
+ null
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsTableInFirstNS(_bb: ByteBuffer): TableInFirstNS = getRootAsTableInFirstNS(_bb, TableInFirstNS())
+ fun getRootAsTableInFirstNS(_bb: ByteBuffer, obj: TableInFirstNS): TableInFirstNS {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun startTableInFirstNS(builder: FlatBufferBuilder) = builder.startTable(3)
+ fun addFooTable(builder: FlatBufferBuilder, fooTable: Int) = builder.addOffset(0, fooTable, 0)
+ fun addFooEnum(builder: FlatBufferBuilder, fooEnum: Byte) = builder.addByte(1, fooEnum, 0)
+ fun addFooStruct(builder: FlatBufferBuilder, fooStruct: Int) = builder.addStruct(2, fooStruct, 0)
+ fun endTableInFirstNS(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.lua b/tests/namespace_test/NamespaceA/TableInFirstNS.lua
new file mode 100644
index 0000000..f70f2c7
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.lua
@@ -0,0 +1,55 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: NamespaceA
+
+local flatbuffers = require('flatbuffers')
+
+local TableInFirstNS = {} -- the module
+local TableInFirstNS_mt = {} -- the class metatable
+
+function TableInFirstNS.New()
+ local o = {}
+ setmetatable(o, {__index = TableInFirstNS_mt})
+ return o
+end
+function TableInFirstNS.GetRootAsTableInFirstNS(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TableInFirstNS.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TableInFirstNS_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TableInFirstNS_mt:FooTable()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('NamespaceA.NamespaceB.TableInNestedNS').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function TableInFirstNS_mt:FooEnum()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 0
+end
+function TableInFirstNS_mt:FooStruct()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ local x = o + self.view.pos
+ local obj = require('NamespaceA.NamespaceB.StructInNestedNS').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function TableInFirstNS.Start(builder) builder:StartObject(3) end
+function TableInFirstNS.AddFooTable(builder, fooTable) builder:PrependUOffsetTRelativeSlot(0, fooTable, 0) end
+function TableInFirstNS.AddFooEnum(builder, fooEnum) builder:PrependInt8Slot(1, fooEnum, 0) end
+function TableInFirstNS.AddFooStruct(builder, fooStruct) builder:PrependStructSlot(2, fooStruct, 0) end
+function TableInFirstNS.End(builder) return builder:EndObject() end
+
+return TableInFirstNS -- return the module
\ No newline at end of file
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.php b/tests/namespace_test/NamespaceA/TableInFirstNS.php
new file mode 100644
index 0000000..9fb29c3
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.php
@@ -0,0 +1,120 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceA;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TableInFirstNS extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TableInFirstNS
+ */
+ public static function getRootAsTableInFirstNS(ByteBuffer $bb)
+ {
+ $obj = new TableInFirstNS();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TableInFirstNS
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getFooTable()
+ {
+ $obj = new TableInNestedNS();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @return sbyte
+ */
+ public function getFooEnum()
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->bb->getSbyte($o + $this->bb_pos) : \NamespaceA\NamespaceB\EnumInNestedNS::A;
+ }
+
+ public function getFooStruct()
+ {
+ $obj = new StructInNestedNS();
+ $o = $this->__offset(8);
+ return $o != 0 ? $obj->init($o + $this->bb_pos, $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTableInFirstNS(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(3);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TableInFirstNS
+ */
+ public static function createTableInFirstNS(FlatBufferBuilder $builder, $foo_table, $foo_enum, $foo_struct)
+ {
+ $builder->startObject(3);
+ self::addFooTable($builder, $foo_table);
+ self::addFooEnum($builder, $foo_enum);
+ self::addFooStruct($builder, $foo_struct);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addFooTable(FlatBufferBuilder $builder, $fooTable)
+ {
+ $builder->addOffsetX(0, $fooTable, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param sbyte
+ * @return void
+ */
+ public static function addFooEnum(FlatBufferBuilder $builder, $fooEnum)
+ {
+ $builder->addSbyteX(1, $fooEnum, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addFooStruct(FlatBufferBuilder $builder, $fooStruct)
+ {
+ $builder->addStructX(2, $fooStruct, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTableInFirstNS(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.py b/tests/namespace_test/NamespaceA/TableInFirstNS.py
new file mode 100644
index 0000000..40cbeba
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.py
@@ -0,0 +1,54 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceA
+
+import flatbuffers
+
+class TableInFirstNS(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsTableInFirstNS(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = TableInFirstNS()
+ x.Init(buf, n + offset)
+ return x
+
+ # TableInFirstNS
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TableInFirstNS
+ def FooTable(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInNestedNS import TableInNestedNS
+ obj = TableInNestedNS()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # TableInFirstNS
+ def FooEnum(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ return self._tab.Get(flatbuffers.number_types.Int8Flags, o + self._tab.Pos)
+ return 0
+
+ # TableInFirstNS
+ def FooStruct(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+ if o != 0:
+ x = o + self._tab.Pos
+ from .StructInNestedNS import StructInNestedNS
+ obj = StructInNestedNS()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def TableInFirstNSStart(builder): builder.StartObject(3)
+def TableInFirstNSAddFooTable(builder, fooTable): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(fooTable), 0)
+def TableInFirstNSAddFooEnum(builder, fooEnum): builder.PrependInt8Slot(1, fooEnum, 0)
+def TableInFirstNSAddFooStruct(builder, fooStruct): builder.PrependStructSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(fooStruct), 0)
+def TableInFirstNSEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceA/__init__.py b/tests/namespace_test/NamespaceA/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/namespace_test/NamespaceA/__init__.py
diff --git a/tests/namespace_test/NamespaceC/TableInC.cs b/tests/namespace_test/NamespaceC/TableInC.cs
new file mode 100644
index 0000000..74b85a4
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.cs
@@ -0,0 +1,43 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace NamespaceC
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct TableInC : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb) { return GetRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public TableInC __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public NamespaceA.TableInFirstNS? ReferToA1 { get { int o = __p.__offset(4); return o != 0 ? (NamespaceA.TableInFirstNS?)(new NamespaceA.TableInFirstNS()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+ public NamespaceA.SecondTableInA? ReferToA2 { get { int o = __p.__offset(6); return o != 0 ? (NamespaceA.SecondTableInA?)(new NamespaceA.SecondTableInA()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
+
+ public static Offset<NamespaceC.TableInC> CreateTableInC(FlatBufferBuilder builder,
+ Offset<NamespaceA.TableInFirstNS> refer_to_a1Offset = default(Offset<NamespaceA.TableInFirstNS>),
+ Offset<NamespaceA.SecondTableInA> refer_to_a2Offset = default(Offset<NamespaceA.SecondTableInA>)) {
+ builder.StartTable(2);
+ TableInC.AddReferToA2(builder, refer_to_a2Offset);
+ TableInC.AddReferToA1(builder, refer_to_a1Offset);
+ return TableInC.EndTableInC(builder);
+ }
+
+ public static void StartTableInC(FlatBufferBuilder builder) { builder.StartTable(2); }
+ public static void AddReferToA1(FlatBufferBuilder builder, Offset<NamespaceA.TableInFirstNS> referToA1Offset) { builder.AddOffset(0, referToA1Offset.Value, 0); }
+ public static void AddReferToA2(FlatBufferBuilder builder, Offset<NamespaceA.SecondTableInA> referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
+ public static Offset<NamespaceC.TableInC> EndTableInC(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<NamespaceC.TableInC>(o);
+ }
+};
+
+
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.go b/tests/namespace_test/NamespaceC/TableInC.go
new file mode 100644
index 0000000..59b3e48
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.go
@@ -0,0 +1,68 @@
+// Code generated by the FlatBuffers compiler. DO NOT EDIT.
+
+package NamespaceC
+
+import (
+ flatbuffers "github.com/google/flatbuffers/go"
+
+ NamespaceA "NamespaceA"
+)
+
+type TableInC struct {
+ _tab flatbuffers.Table
+}
+
+func GetRootAsTableInC(buf []byte, offset flatbuffers.UOffsetT) *TableInC {
+ n := flatbuffers.GetUOffsetT(buf[offset:])
+ x := &TableInC{}
+ x.Init(buf, n+offset)
+ return x
+}
+
+func (rcv *TableInC) Init(buf []byte, i flatbuffers.UOffsetT) {
+ rcv._tab.Bytes = buf
+ rcv._tab.Pos = i
+}
+
+func (rcv *TableInC) Table() flatbuffers.Table {
+ return rcv._tab
+}
+
+func (rcv *TableInC) ReferToA1(obj *NamespaceA.TableInFirstNS) *NamespaceA.TableInFirstNS {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(NamespaceA.TableInFirstNS)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func (rcv *TableInC) ReferToA2(obj *NamespaceA.SecondTableInA) *NamespaceA.SecondTableInA {
+ o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+ if o != 0 {
+ x := rcv._tab.Indirect(o + rcv._tab.Pos)
+ if obj == nil {
+ obj = new(NamespaceA.SecondTableInA)
+ }
+ obj.Init(rcv._tab.Bytes, x)
+ return obj
+ }
+ return nil
+}
+
+func TableInCStart(builder *flatbuffers.Builder) {
+ builder.StartObject(2)
+}
+func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0)
+}
+func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) {
+ builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0)
+}
+func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+ return builder.EndObject()
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.java b/tests/namespace_test/NamespaceC/TableInC.java
new file mode 100644
index 0000000..2d9e4bf
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.java
@@ -0,0 +1,40 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceC;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TableInC extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static TableInC getRootAsTableInC(ByteBuffer _bb) { return getRootAsTableInC(_bb, new TableInC()); }
+ public static TableInC getRootAsTableInC(ByteBuffer _bb, TableInC obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public TableInC __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public NamespaceA.TableInFirstNS referToA1() { return referToA1(new NamespaceA.TableInFirstNS()); }
+ public NamespaceA.TableInFirstNS referToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+ public NamespaceA.SecondTableInA referToA2() { return referToA2(new NamespaceA.SecondTableInA()); }
+ public NamespaceA.SecondTableInA referToA2(NamespaceA.SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
+
+ public static int createTableInC(FlatBufferBuilder builder,
+ int refer_to_a1Offset,
+ int refer_to_a2Offset) {
+ builder.startTable(2);
+ TableInC.addReferToA2(builder, refer_to_a2Offset);
+ TableInC.addReferToA1(builder, refer_to_a1Offset);
+ return TableInC.endTableInC(builder);
+ }
+
+ public static void startTableInC(FlatBufferBuilder builder) { builder.startTable(2); }
+ public static void addReferToA1(FlatBufferBuilder builder, int referToA1Offset) { builder.addOffset(0, referToA1Offset, 0); }
+ public static void addReferToA2(FlatBufferBuilder builder, int referToA2Offset) { builder.addOffset(1, referToA2Offset, 0); }
+ public static int endTableInC(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/namespace_test/NamespaceC/TableInC.kt b/tests/namespace_test/NamespaceC/TableInC.kt
new file mode 100644
index 0000000..e468642
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.kt
@@ -0,0 +1,59 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package NamespaceC
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class TableInC : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : TableInC {
+ __init(_i, _bb)
+ return this
+ }
+ val referToA1 : NamespaceA.TableInFirstNS? get() = referToA1(NamespaceA.TableInFirstNS())
+ fun referToA1(obj: NamespaceA.TableInFirstNS) : NamespaceA.TableInFirstNS? {
+ val o = __offset(4)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ val referToA2 : NamespaceA.SecondTableInA? get() = referToA2(NamespaceA.SecondTableInA())
+ fun referToA2(obj: NamespaceA.SecondTableInA) : NamespaceA.SecondTableInA? {
+ val o = __offset(6)
+ return if (o != 0) {
+ obj.__assign(__indirect(o + bb_pos), bb)
+ } else {
+ null
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsTableInC(_bb: ByteBuffer): TableInC = getRootAsTableInC(_bb, TableInC())
+ fun getRootAsTableInC(_bb: ByteBuffer, obj: TableInC): TableInC {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createTableInC(builder: FlatBufferBuilder, referToA1Offset: Int, referToA2Offset: Int) : Int {
+ builder.startTable(2)
+ addReferToA2(builder, referToA2Offset)
+ addReferToA1(builder, referToA1Offset)
+ return endTableInC(builder)
+ }
+ fun startTableInC(builder: FlatBufferBuilder) = builder.startTable(2)
+ fun addReferToA1(builder: FlatBufferBuilder, referToA1: Int) = builder.addOffset(0, referToA1, 0)
+ fun addReferToA2(builder: FlatBufferBuilder, referToA2: Int) = builder.addOffset(1, referToA2, 0)
+ fun endTableInC(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.lua b/tests/namespace_test/NamespaceC/TableInC.lua
new file mode 100644
index 0000000..bb4fef0
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.lua
@@ -0,0 +1,47 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: NamespaceC
+
+local flatbuffers = require('flatbuffers')
+
+local TableInC = {} -- the module
+local TableInC_mt = {} -- the class metatable
+
+function TableInC.New()
+ local o = {}
+ setmetatable(o, {__index = TableInC_mt})
+ return o
+end
+function TableInC.GetRootAsTableInC(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TableInC.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TableInC_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TableInC_mt:ReferToA1()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('NamespaceA.TableInFirstNS').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function TableInC_mt:ReferToA2()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('NamespaceA.SecondTableInA').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function TableInC.Start(builder) builder:StartObject(2) end
+function TableInC.AddReferToA1(builder, referToA1) builder:PrependUOffsetTRelativeSlot(0, referToA1, 0) end
+function TableInC.AddReferToA2(builder, referToA2) builder:PrependUOffsetTRelativeSlot(1, referToA2, 0) end
+function TableInC.End(builder) return builder:EndObject() end
+
+return TableInC -- return the module
\ No newline at end of file
diff --git a/tests/namespace_test/NamespaceC/TableInC.php b/tests/namespace_test/NamespaceC/TableInC.php
new file mode 100644
index 0000000..116aea1
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.php
@@ -0,0 +1,100 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace NamespaceC;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TableInC extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return TableInC
+ */
+ public static function getRootAsTableInC(ByteBuffer $bb)
+ {
+ $obj = new TableInC();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return TableInC
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ public function getReferToA1()
+ {
+ $obj = new TableInFirstNS();
+ $o = $this->__offset(4);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ public function getReferToA2()
+ {
+ $obj = new SecondTableInA();
+ $o = $this->__offset(6);
+ return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startTableInC(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(2);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return TableInC
+ */
+ public static function createTableInC(FlatBufferBuilder $builder, $refer_to_a1, $refer_to_a2)
+ {
+ $builder->startObject(2);
+ self::addReferToA1($builder, $refer_to_a1);
+ self::addReferToA2($builder, $refer_to_a2);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA1(FlatBufferBuilder $builder, $referToA1)
+ {
+ $builder->addOffsetX(0, $referToA1, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addReferToA2(FlatBufferBuilder $builder, $referToA2)
+ {
+ $builder->addOffsetX(1, $referToA2, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endTableInC(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/namespace_test/NamespaceC/TableInC.py b/tests/namespace_test/NamespaceC/TableInC.py
new file mode 100644
index 0000000..90b8736
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/TableInC.py
@@ -0,0 +1,46 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: NamespaceC
+
+import flatbuffers
+
+class TableInC(object):
+ __slots__ = ['_tab']
+
+ @classmethod
+ def GetRootAsTableInC(cls, buf, offset):
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+ x = TableInC()
+ x.Init(buf, n + offset)
+ return x
+
+ # TableInC
+ def Init(self, buf, pos):
+ self._tab = flatbuffers.table.Table(buf, pos)
+
+ # TableInC
+ def ReferToA1(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .TableInFirstNS import TableInFirstNS
+ obj = TableInFirstNS()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+ # TableInC
+ def ReferToA2(self):
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+ if o != 0:
+ x = self._tab.Indirect(o + self._tab.Pos)
+ from .SecondTableInA import SecondTableInA
+ obj = SecondTableInA()
+ obj.Init(self._tab.Bytes, x)
+ return obj
+ return None
+
+def TableInCStart(builder): builder.StartObject(2)
+def TableInCAddReferToA1(builder, referToA1): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToA1), 0)
+def TableInCAddReferToA2(builder, referToA2): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(referToA2), 0)
+def TableInCEnd(builder): return builder.EndObject()
diff --git a/tests/namespace_test/NamespaceC/__init__.py b/tests/namespace_test/NamespaceC/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/__init__.py
diff --git a/tests/namespace_test/namespace_test1.fbs b/tests/namespace_test/namespace_test1.fbs
new file mode 100644
index 0000000..49449bf
--- /dev/null
+++ b/tests/namespace_test/namespace_test1.fbs
@@ -0,0 +1,17 @@
+namespace NamespaceA.NamespaceB;
+
+table TableInNestedNS
+{
+ foo:int;
+}
+
+enum EnumInNestedNS:byte
+{
+ A, B, C
+}
+
+struct StructInNestedNS
+{
+ a:int;
+ b:int;
+}
\ No newline at end of file
diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h
new file mode 100644
index 0000000..daaf7ae
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.h
@@ -0,0 +1,182 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_
+#define FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+namespace NamespaceA {
+namespace NamespaceB {
+
+struct TableInNestedNS;
+
+struct StructInNestedNS;
+
+inline const flatbuffers::TypeTable *TableInNestedNSTypeTable();
+
+inline const flatbuffers::TypeTable *StructInNestedNSTypeTable();
+
+enum EnumInNestedNS {
+ EnumInNestedNS_A = 0,
+ EnumInNestedNS_B = 1,
+ EnumInNestedNS_C = 2,
+ EnumInNestedNS_MIN = EnumInNestedNS_A,
+ EnumInNestedNS_MAX = EnumInNestedNS_C
+};
+
+inline const EnumInNestedNS (&EnumValuesEnumInNestedNS())[3] {
+ static const EnumInNestedNS values[] = {
+ EnumInNestedNS_A,
+ EnumInNestedNS_B,
+ EnumInNestedNS_C
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesEnumInNestedNS() {
+ static const char * const names[4] = {
+ "A",
+ "B",
+ "C",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameEnumInNestedNS(EnumInNestedNS e) {
+ if (e < EnumInNestedNS_A || e > EnumInNestedNS_C) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesEnumInNestedNS()[index];
+}
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS {
+ private:
+ int32_t a_;
+ int32_t b_;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return StructInNestedNSTypeTable();
+ }
+ StructInNestedNS() {
+ memset(static_cast<void *>(this), 0, sizeof(StructInNestedNS));
+ }
+ StructInNestedNS(int32_t _a, int32_t _b)
+ : a_(flatbuffers::EndianScalar(_a)),
+ b_(flatbuffers::EndianScalar(_b)) {
+ }
+ int32_t a() const {
+ return flatbuffers::EndianScalar(a_);
+ }
+ void mutate_a(int32_t _a) {
+ flatbuffers::WriteScalar(&a_, _a);
+ }
+ int32_t b() const {
+ return flatbuffers::EndianScalar(b_);
+ }
+ void mutate_b(int32_t _b) {
+ flatbuffers::WriteScalar(&b_, _b);
+ }
+};
+FLATBUFFERS_STRUCT_END(StructInNestedNS, 8);
+
+struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return TableInNestedNSTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_FOO = 4
+ };
+ int32_t foo() const {
+ return GetField<int32_t>(VT_FOO, 0);
+ }
+ bool mutate_foo(int32_t _foo) {
+ return SetField<int32_t>(VT_FOO, _foo, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int32_t>(verifier, VT_FOO) &&
+ verifier.EndTable();
+ }
+};
+
+struct TableInNestedNSBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_foo(int32_t foo) {
+ fbb_.AddElement<int32_t>(TableInNestedNS::VT_FOO, foo, 0);
+ }
+ explicit TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ TableInNestedNSBuilder &operator=(const TableInNestedNSBuilder &);
+ flatbuffers::Offset<TableInNestedNS> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TableInNestedNS>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TableInNestedNS> CreateTableInNestedNS(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t foo = 0) {
+ TableInNestedNSBuilder builder_(_fbb);
+ builder_.add_foo(foo);
+ return builder_.Finish();
+}
+
+inline const flatbuffers::TypeTable *EnumInNestedNSTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ NamespaceA::NamespaceB::EnumInNestedNSTypeTable
+ };
+ static const char * const names[] = {
+ "A",
+ "B",
+ "C"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *TableInNestedNSTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_INT, 0, -1 }
+ };
+ static const char * const names[] = {
+ "foo"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *StructInNestedNSTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_INT, 0, -1 },
+ { flatbuffers::ET_INT, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 4, 8 };
+ static const char * const names[] = {
+ "a",
+ "b"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+} // namespace NamespaceB
+} // namespace NamespaceA
+
+#endif // FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_
diff --git a/tests/namespace_test/namespace_test1_generated.js b/tests/namespace_test/namespace_test1_generated.js
new file mode 100644
index 0000000..bd018d6
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.js
@@ -0,0 +1,219 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @const
+ * @namespace
+ */
+var NamespaceA = NamespaceA || {};
+
+/**
+ * @const
+ * @namespace
+ */
+NamespaceA.NamespaceB = NamespaceA.NamespaceB || {};
+
+/**
+ * @enum {number}
+ */
+NamespaceA.NamespaceB.EnumInNestedNS = {
+ A: 0,
+ B: 1,
+ C: 2
+};
+
+/**
+ * @enum {string}
+ */
+NamespaceA.NamespaceB.EnumInNestedNSName = {
+ 0: 'A',
+ 1: 'B',
+ 2: 'C'
+};
+
+/**
+ * @constructor
+ */
+NamespaceA.NamespaceB.TableInNestedNS = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.getRootAsTableInNestedNS = function(bb, obj) {
+ return (obj || new NamespaceA.NamespaceB.TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.getSizePrefixedRootAsTableInNestedNS = function(bb, obj) {
+ return (obj || new NamespaceA.NamespaceB.TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.prototype.foo = function() {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.prototype.mutate_foo = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+NamespaceA.NamespaceB.TableInNestedNS.startTableInNestedNS = function(builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} foo
+ */
+NamespaceA.NamespaceB.TableInNestedNS.addFoo = function(builder, foo) {
+ builder.addFieldInt32(0, foo, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.endTableInNestedNS = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} foo
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.NamespaceB.TableInNestedNS.createTableInNestedNS = function(builder, foo) {
+ NamespaceA.NamespaceB.TableInNestedNS.startTableInNestedNS(builder);
+ NamespaceA.NamespaceB.TableInNestedNS.addFoo(builder, foo);
+ return NamespaceA.NamespaceB.TableInNestedNS.endTableInNestedNS(builder);
+}
+
+/**
+ * @constructor
+ */
+NamespaceA.NamespaceB.StructInNestedNS = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceA.NamespaceB.StructInNestedNS}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns {number}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.prototype.a = function() {
+ return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.prototype.mutate_a = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns {number}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.prototype.b = function() {
+ return this.bb.readInt32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.prototype.mutate_b = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} a
+ * @param {number} b
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.NamespaceB.StructInNestedNS.createStructInNestedNS = function(builder, a, b) {
+ builder.prep(4, 8);
+ builder.writeInt32(b);
+ builder.writeInt32(a);
+ return builder.offset();
+};
+
+// Exports for Node.js and RequireJS
+this.NamespaceA = NamespaceA;
diff --git a/tests/namespace_test/namespace_test1_generated.lobster b/tests/namespace_test/namespace_test1_generated.lobster
new file mode 100644
index 0000000..6503005
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.lobster
@@ -0,0 +1,43 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+import flatbuffers
+
+namespace NamespaceA_NamespaceB
+
+enum EnumInNestedNS:
+ EnumInNestedNS_A = 0
+ EnumInNestedNS_B = 1
+ EnumInNestedNS_C = 2
+
+class TableInNestedNS
+
+class StructInNestedNS
+
+class TableInNestedNS : flatbuffers_handle
+ def foo():
+ return buf_.flatbuffers_field_int32(pos_, 4, 0)
+
+def GetRootAsTableInNestedNS(buf:string): return TableInNestedNS { buf, buf.flatbuffers_indirect(0) }
+
+struct TableInNestedNSBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(1)
+ return this
+ def add_foo(foo:int):
+ b_.PrependInt32Slot(0, foo, 0)
+ return this
+ def end():
+ return b_.EndObject()
+
+class StructInNestedNS : flatbuffers_handle
+ def a():
+ return buf_.read_int32_le(pos_ + 0)
+ def b():
+ return buf_.read_int32_le(pos_ + 4)
+
+def CreateStructInNestedNS(b_:flatbuffers_builder, a:int, b:int):
+ b_.Prep(4, 8)
+ b_.PrependInt32(b)
+ b_.PrependInt32(a)
+ return b_.Offset()
+
diff --git a/tests/namespace_test/namespace_test1_generated.rs b/tests/namespace_test/namespace_test1_generated.rs
new file mode 100644
index 0000000..ab30299
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.rs
@@ -0,0 +1,230 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+
+use std::mem;
+use std::cmp::Ordering;
+
+extern crate flatbuffers;
+use self::flatbuffers::EndianScalar;
+
+#[allow(unused_imports, dead_code)]
+pub mod namespace_a {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+#[allow(unused_imports, dead_code)]
+pub mod namespace_b {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ 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 EnumInNestedNS {
+ A = 0,
+ B = 1,
+ C = 2,
+
+}
+
+const ENUM_MIN_ENUM_IN_NESTED_NS: i8 = 0;
+const ENUM_MAX_ENUM_IN_NESTED_NS: i8 = 2;
+
+impl<'a> flatbuffers::Follow<'a> for EnumInNestedNS {
+ type Inner = Self;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::read_scalar_at::<Self>(buf, loc)
+ }
+}
+
+impl flatbuffers::EndianScalar for EnumInNestedNS {
+ #[inline]
+ fn to_little_endian(self) -> Self {
+ let n = i8::to_le(self as i8);
+ let p = &n as *const i8 as *const EnumInNestedNS;
+ 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 EnumInNestedNS;
+ unsafe { *p }
+ }
+}
+
+impl flatbuffers::Push for EnumInNestedNS {
+ type Output = EnumInNestedNS;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ flatbuffers::emplace_scalar::<EnumInNestedNS>(dst, *self);
+ }
+}
+
+#[allow(non_camel_case_types)]
+const ENUM_VALUES_ENUM_IN_NESTED_NS:[EnumInNestedNS; 3] = [
+ EnumInNestedNS::A,
+ EnumInNestedNS::B,
+ EnumInNestedNS::C
+];
+
+#[allow(non_camel_case_types)]
+const ENUM_NAMES_ENUM_IN_NESTED_NS:[&'static str; 3] = [
+ "A",
+ "B",
+ "C"
+];
+
+pub fn enum_name_enum_in_nested_ns(e: EnumInNestedNS) -> &'static str {
+ let index = e as i8;
+ ENUM_NAMES_ENUM_IN_NESTED_NS[index as usize]
+}
+
+// struct StructInNestedNS, aligned to 4
+#[repr(C, align(4))]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct StructInNestedNS {
+ a_: i32,
+ b_: i32,
+} // pub struct StructInNestedNS
+impl flatbuffers::SafeSliceAccess for StructInNestedNS {}
+impl<'a> flatbuffers::Follow<'a> for StructInNestedNS {
+ type Inner = &'a StructInNestedNS;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ <&'a StructInNestedNS>::follow(buf, loc)
+ }
+}
+impl<'a> flatbuffers::Follow<'a> for &'a StructInNestedNS {
+ type Inner = &'a StructInNestedNS;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::follow_cast_ref::<StructInNestedNS>(buf, loc)
+ }
+}
+impl<'b> flatbuffers::Push for StructInNestedNS {
+ type Output = StructInNestedNS;
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(self as *const StructInNestedNS as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+impl<'b> flatbuffers::Push for &'b StructInNestedNS {
+ type Output = StructInNestedNS;
+
+ #[inline]
+ fn push(&self, dst: &mut [u8], _rest: &[u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(*self as *const StructInNestedNS as *const u8, Self::size())
+ };
+ dst.copy_from_slice(src);
+ }
+}
+
+
+impl StructInNestedNS {
+ pub fn new<'a>(_a: i32, _b: i32) -> Self {
+ StructInNestedNS {
+ a_: _a.to_little_endian(),
+ b_: _b.to_little_endian(),
+
+ }
+ }
+ pub fn a<'a>(&'a self) -> i32 {
+ self.a_.from_little_endian()
+ }
+ pub fn b<'a>(&'a self) -> i32 {
+ self.b_.from_little_endian()
+ }
+}
+
+pub enum TableInNestedNSOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct TableInNestedNS<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for TableInNestedNS<'a> {
+ type Inner = TableInNestedNS<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> TableInNestedNS<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ TableInNestedNS {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args TableInNestedNSArgs) -> flatbuffers::WIPOffset<TableInNestedNS<'bldr>> {
+ let mut builder = TableInNestedNSBuilder::new(_fbb);
+ builder.add_foo(args.foo);
+ builder.finish()
+ }
+
+ pub const VT_FOO: flatbuffers::VOffsetT = 4;
+
+ #[inline]
+ pub fn foo(&self) -> i32 {
+ self._tab.get::<i32>(TableInNestedNS::VT_FOO, Some(0)).unwrap()
+ }
+}
+
+pub struct TableInNestedNSArgs {
+ pub foo: i32,
+}
+impl<'a> Default for TableInNestedNSArgs {
+ #[inline]
+ fn default() -> Self {
+ TableInNestedNSArgs {
+ foo: 0,
+ }
+ }
+}
+pub struct TableInNestedNSBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> TableInNestedNSBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_foo(&mut self, foo: i32) {
+ self.fbb_.push_slot::<i32>(TableInNestedNS::VT_FOO, foo, 0);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TableInNestedNSBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ TableInNestedNSBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<TableInNestedNS<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+} // pub mod NamespaceB
+} // pub mod NamespaceA
+
diff --git a/tests/namespace_test/namespace_test1_generated.ts b/tests/namespace_test/namespace_test1_generated.ts
new file mode 100644
index 0000000..615c7ce
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.ts
@@ -0,0 +1,181 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum {number}
+ */
+export namespace NamespaceA.NamespaceB{
+export enum EnumInNestedNS{
+ A= 0,
+ B= 1,
+ C= 2
+}};
+
+/**
+ * @constructor
+ */
+export namespace NamespaceA.NamespaceB{
+export class TableInNestedNS {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns TableInNestedNS
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInNestedNS {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TableInNestedNS= obj
+ * @returns TableInNestedNS
+ */
+static getRootAsTableInNestedNS(bb:flatbuffers.ByteBuffer, obj?:TableInNestedNS):TableInNestedNS {
+ return (obj || new TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TableInNestedNS= obj
+ * @returns TableInNestedNS
+ */
+static getSizePrefixedRootAsTableInNestedNS(bb:flatbuffers.ByteBuffer, obj?:TableInNestedNS):TableInNestedNS {
+ return (obj || new TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns number
+ */
+foo():number {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_foo(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startTableInNestedNS(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number foo
+ */
+static addFoo(builder:flatbuffers.Builder, foo:number) {
+ builder.addFieldInt32(0, foo, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endTableInNestedNS(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createTableInNestedNS(builder:flatbuffers.Builder, foo:number):flatbuffers.Offset {
+ TableInNestedNS.startTableInNestedNS(builder);
+ TableInNestedNS.addFoo(builder, foo);
+ return TableInNestedNS.endTableInNestedNS(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceA.NamespaceB{
+export class StructInNestedNS {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns StructInNestedNS
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):StructInNestedNS {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns number
+ */
+a():number {
+ return this.bb!.readInt32(this.bb_pos);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_a(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @returns number
+ */
+b():number {
+ return this.bb!.readInt32(this.bb_pos + 4);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_b(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number a
+ * @param number b
+ * @returns flatbuffers.Offset
+ */
+static createStructInNestedNS(builder:flatbuffers.Builder, a: number, b: number):flatbuffers.Offset {
+ builder.prep(4, 8);
+ builder.writeInt32(b);
+ builder.writeInt32(a);
+ return builder.offset();
+};
+
+}
+}
diff --git a/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart b/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart
new file mode 100644
index 0000000..f999e44
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_namespace_a.namespace_b_generated.dart
@@ -0,0 +1,198 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library namespace_a.namespace_b;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+
+class EnumInNestedNS {
+ final int value;
+ const EnumInNestedNS._(this.value);
+
+ factory EnumInNestedNS.fromValue(int value) {
+ if (value == null) value = 0;
+ if (!values.containsKey(value)) {
+ throw new StateError('Invalid value $value for bit flag enum EnumInNestedNS');
+ }
+ return values[value];
+ }
+
+ static const int minValue = 0;
+ static const int maxValue = 2;
+ static bool containsValue(int value) => values.containsKey(value);
+
+ static const EnumInNestedNS A = const EnumInNestedNS._(0);
+ static const EnumInNestedNS B = const EnumInNestedNS._(1);
+ static const EnumInNestedNS C = const EnumInNestedNS._(2);
+ static get values => {0: A,1: B,2: C,};
+
+ static const fb.Reader<EnumInNestedNS> reader = const _EnumInNestedNSReader();
+
+ @override
+ String toString() {
+ return 'EnumInNestedNS{value: $value}';
+ }
+}
+
+class _EnumInNestedNSReader extends fb.Reader<EnumInNestedNS> {
+ const _EnumInNestedNSReader();
+
+ @override
+ int get size => 1;
+
+ @override
+ EnumInNestedNS read(fb.BufferContext bc, int offset) =>
+ new EnumInNestedNS.fromValue(const fb.Int8Reader().read(bc, offset));
+}
+
+class TableInNestedNS {
+ TableInNestedNS._(this._bc, this._bcOffset);
+ factory TableInNestedNS(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TableInNestedNS> reader = const _TableInNestedNSReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get foo => const fb.Int32Reader().vTableGet(_bc, _bcOffset, 4, 0);
+
+ @override
+ String toString() {
+ return 'TableInNestedNS{foo: $foo}';
+ }
+}
+
+class _TableInNestedNSReader extends fb.TableReader<TableInNestedNS> {
+ const _TableInNestedNSReader();
+
+ @override
+ TableInNestedNS createObject(fb.BufferContext bc, int offset) =>
+ new TableInNestedNS._(bc, offset);
+}
+
+class TableInNestedNSBuilder {
+ TableInNestedNSBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addFoo(int foo) {
+ fbBuilder.addInt32(0, foo);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TableInNestedNSObjectBuilder extends fb.ObjectBuilder {
+ final int _foo;
+
+ TableInNestedNSObjectBuilder({
+ int foo,
+ })
+ : _foo = foo;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.startTable();
+ fbBuilder.addInt32(0, _foo);
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class StructInNestedNS {
+ StructInNestedNS._(this._bc, this._bcOffset);
+
+ static const fb.Reader<StructInNestedNS> reader = const _StructInNestedNSReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ int get a => const fb.Int32Reader().read(_bc, _bcOffset + 0);
+ int get b => const fb.Int32Reader().read(_bc, _bcOffset + 4);
+
+ @override
+ String toString() {
+ return 'StructInNestedNS{a: $a, b: $b}';
+ }
+}
+
+class _StructInNestedNSReader extends fb.StructReader<StructInNestedNS> {
+ const _StructInNestedNSReader();
+
+ @override
+ int get size => 8;
+
+ @override
+ StructInNestedNS createObject(fb.BufferContext bc, int offset) =>
+ new StructInNestedNS._(bc, offset);
+}
+
+class StructInNestedNSBuilder {
+ StructInNestedNSBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ int finish(int a, int b) {
+ fbBuilder.putInt32(b);
+ fbBuilder.putInt32(a);
+ return fbBuilder.offset;
+ }
+
+}
+
+class StructInNestedNSObjectBuilder extends fb.ObjectBuilder {
+ final int _a;
+ final int _b;
+
+ StructInNestedNSObjectBuilder({
+ int a,
+ int b,
+ })
+ : _a = a,
+ _b = b;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+
+ fbBuilder.putInt32(_b);
+ fbBuilder.putInt32(_a);
+ return fbBuilder.offset;
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/tests/namespace_test/namespace_test2.fbs b/tests/namespace_test/namespace_test2.fbs
new file mode 100644
index 0000000..11d7dea
--- /dev/null
+++ b/tests/namespace_test/namespace_test2.fbs
@@ -0,0 +1,24 @@
+include "namespace_test1.fbs";
+
+namespace NamespaceA;
+
+table TableInFirstNS
+{
+ foo_table:NamespaceB.TableInNestedNS;
+ foo_enum:NamespaceB.EnumInNestedNS;
+ foo_struct:NamespaceB.StructInNestedNS;
+}
+
+// Test switching namespaces inside a file.
+namespace NamespaceC;
+
+table TableInC {
+ refer_to_a1:NamespaceA.TableInFirstNS;
+ refer_to_a2:NamespaceA.SecondTableInA;
+}
+
+namespace NamespaceA;
+
+table SecondTableInA {
+ refer_to_c:NamespaceC.TableInC;
+}
diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h
new file mode 100644
index 0000000..135100a
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.h
@@ -0,0 +1,305 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
+#define FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+#include "namespace_test1_generated.h"
+
+namespace NamespaceA {
+
+struct TableInFirstNS;
+
+} // namespace NamespaceA
+
+namespace NamespaceC {
+
+struct TableInC;
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+struct SecondTableInA;
+
+inline const flatbuffers::TypeTable *TableInFirstNSTypeTable();
+
+} // namespace NamespaceA
+
+namespace NamespaceC {
+
+inline const flatbuffers::TypeTable *TableInCTypeTable();
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+inline const flatbuffers::TypeTable *SecondTableInATypeTable();
+
+struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return TableInFirstNSTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_FOO_TABLE = 4,
+ VT_FOO_ENUM = 6,
+ VT_FOO_STRUCT = 8
+ };
+ const NamespaceA::NamespaceB::TableInNestedNS *foo_table() const {
+ return GetPointer<const NamespaceA::NamespaceB::TableInNestedNS *>(VT_FOO_TABLE);
+ }
+ NamespaceA::NamespaceB::TableInNestedNS *mutable_foo_table() {
+ return GetPointer<NamespaceA::NamespaceB::TableInNestedNS *>(VT_FOO_TABLE);
+ }
+ NamespaceA::NamespaceB::EnumInNestedNS foo_enum() const {
+ return static_cast<NamespaceA::NamespaceB::EnumInNestedNS>(GetField<int8_t>(VT_FOO_ENUM, 0));
+ }
+ bool mutate_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS _foo_enum) {
+ return SetField<int8_t>(VT_FOO_ENUM, static_cast<int8_t>(_foo_enum), 0);
+ }
+ const NamespaceA::NamespaceB::StructInNestedNS *foo_struct() const {
+ return GetStruct<const NamespaceA::NamespaceB::StructInNestedNS *>(VT_FOO_STRUCT);
+ }
+ NamespaceA::NamespaceB::StructInNestedNS *mutable_foo_struct() {
+ return GetStruct<NamespaceA::NamespaceB::StructInNestedNS *>(VT_FOO_STRUCT);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_FOO_TABLE) &&
+ verifier.VerifyTable(foo_table()) &&
+ VerifyField<int8_t>(verifier, VT_FOO_ENUM) &&
+ VerifyField<NamespaceA::NamespaceB::StructInNestedNS>(verifier, VT_FOO_STRUCT) &&
+ verifier.EndTable();
+ }
+};
+
+struct TableInFirstNSBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_foo_table(flatbuffers::Offset<NamespaceA::NamespaceB::TableInNestedNS> foo_table) {
+ fbb_.AddOffset(TableInFirstNS::VT_FOO_TABLE, foo_table);
+ }
+ void add_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS foo_enum) {
+ fbb_.AddElement<int8_t>(TableInFirstNS::VT_FOO_ENUM, static_cast<int8_t>(foo_enum), 0);
+ }
+ void add_foo_struct(const NamespaceA::NamespaceB::StructInNestedNS *foo_struct) {
+ fbb_.AddStruct(TableInFirstNS::VT_FOO_STRUCT, foo_struct);
+ }
+ explicit TableInFirstNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ TableInFirstNSBuilder &operator=(const TableInFirstNSBuilder &);
+ flatbuffers::Offset<TableInFirstNS> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TableInFirstNS>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TableInFirstNS> CreateTableInFirstNS(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<NamespaceA::NamespaceB::TableInNestedNS> foo_table = 0,
+ NamespaceA::NamespaceB::EnumInNestedNS foo_enum = NamespaceA::NamespaceB::EnumInNestedNS_A,
+ const NamespaceA::NamespaceB::StructInNestedNS *foo_struct = 0) {
+ TableInFirstNSBuilder builder_(_fbb);
+ builder_.add_foo_struct(foo_struct);
+ builder_.add_foo_table(foo_table);
+ builder_.add_foo_enum(foo_enum);
+ return builder_.Finish();
+}
+
+} // namespace NamespaceA
+
+namespace NamespaceC {
+
+struct TableInC FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return TableInCTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_REFER_TO_A1 = 4,
+ VT_REFER_TO_A2 = 6
+ };
+ const NamespaceA::TableInFirstNS *refer_to_a1() const {
+ return GetPointer<const NamespaceA::TableInFirstNS *>(VT_REFER_TO_A1);
+ }
+ NamespaceA::TableInFirstNS *mutable_refer_to_a1() {
+ return GetPointer<NamespaceA::TableInFirstNS *>(VT_REFER_TO_A1);
+ }
+ const NamespaceA::SecondTableInA *refer_to_a2() const {
+ return GetPointer<const NamespaceA::SecondTableInA *>(VT_REFER_TO_A2);
+ }
+ NamespaceA::SecondTableInA *mutable_refer_to_a2() {
+ return GetPointer<NamespaceA::SecondTableInA *>(VT_REFER_TO_A2);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_REFER_TO_A1) &&
+ verifier.VerifyTable(refer_to_a1()) &&
+ VerifyOffset(verifier, VT_REFER_TO_A2) &&
+ verifier.VerifyTable(refer_to_a2()) &&
+ verifier.EndTable();
+ }
+};
+
+struct TableInCBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_refer_to_a1(flatbuffers::Offset<NamespaceA::TableInFirstNS> refer_to_a1) {
+ fbb_.AddOffset(TableInC::VT_REFER_TO_A1, refer_to_a1);
+ }
+ void add_refer_to_a2(flatbuffers::Offset<NamespaceA::SecondTableInA> refer_to_a2) {
+ fbb_.AddOffset(TableInC::VT_REFER_TO_A2, refer_to_a2);
+ }
+ explicit TableInCBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ TableInCBuilder &operator=(const TableInCBuilder &);
+ flatbuffers::Offset<TableInC> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<TableInC>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<TableInC> CreateTableInC(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<NamespaceA::TableInFirstNS> refer_to_a1 = 0,
+ flatbuffers::Offset<NamespaceA::SecondTableInA> refer_to_a2 = 0) {
+ TableInCBuilder builder_(_fbb);
+ builder_.add_refer_to_a2(refer_to_a2);
+ builder_.add_refer_to_a1(refer_to_a1);
+ return builder_.Finish();
+}
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+struct SecondTableInA FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return SecondTableInATypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_REFER_TO_C = 4
+ };
+ const NamespaceC::TableInC *refer_to_c() const {
+ return GetPointer<const NamespaceC::TableInC *>(VT_REFER_TO_C);
+ }
+ NamespaceC::TableInC *mutable_refer_to_c() {
+ return GetPointer<NamespaceC::TableInC *>(VT_REFER_TO_C);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_REFER_TO_C) &&
+ verifier.VerifyTable(refer_to_c()) &&
+ verifier.EndTable();
+ }
+};
+
+struct SecondTableInABuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_refer_to_c(flatbuffers::Offset<NamespaceC::TableInC> refer_to_c) {
+ fbb_.AddOffset(SecondTableInA::VT_REFER_TO_C, refer_to_c);
+ }
+ explicit SecondTableInABuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ SecondTableInABuilder &operator=(const SecondTableInABuilder &);
+ flatbuffers::Offset<SecondTableInA> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<SecondTableInA>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<SecondTableInA> CreateSecondTableInA(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<NamespaceC::TableInC> refer_to_c = 0) {
+ SecondTableInABuilder builder_(_fbb);
+ builder_.add_refer_to_c(refer_to_c);
+ return builder_.Finish();
+}
+
+} // namespace NamespaceA
+
+namespace NamespaceC {
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+inline const flatbuffers::TypeTable *TableInFirstNSTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_CHAR, 0, 1 },
+ { flatbuffers::ET_SEQUENCE, 0, 2 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ NamespaceA::NamespaceB::TableInNestedNSTypeTable,
+ NamespaceA::NamespaceB::EnumInNestedNSTypeTable,
+ NamespaceA::NamespaceB::StructInNestedNSTypeTable
+ };
+ static const char * const names[] = {
+ "foo_table",
+ "foo_enum",
+ "foo_struct"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 3, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+} // namespace NamespaceA
+
+namespace NamespaceC {
+
+inline const flatbuffers::TypeTable *TableInCTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 1 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ NamespaceA::TableInFirstNSTypeTable,
+ NamespaceA::SecondTableInATypeTable
+ };
+ static const char * const names[] = {
+ "refer_to_a1",
+ "refer_to_a2"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+} // namespace NamespaceC
+
+namespace NamespaceA {
+
+inline const flatbuffers::TypeTable *SecondTableInATypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ NamespaceC::TableInCTypeTable
+ };
+ static const char * const names[] = {
+ "refer_to_c"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+} // namespace NamespaceA
+
+#endif // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js
new file mode 100644
index 0000000..f54cda7
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.js
@@ -0,0 +1,358 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @const
+ * @namespace
+ */
+var NamespaceA = NamespaceA || {};
+
+/**
+ * @const
+ * @namespace
+ */
+NamespaceA.NamespaceB = NamespaceA.NamespaceB || {};
+
+/**
+ * @const
+ * @namespace
+ */
+var NamespaceC = NamespaceC || {};
+
+/**
+ * @constructor
+ */
+NamespaceA.TableInFirstNS = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceA.TableInFirstNS}
+ */
+NamespaceA.TableInFirstNS.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.TableInFirstNS=} obj
+ * @returns {NamespaceA.TableInFirstNS}
+ */
+NamespaceA.TableInFirstNS.getRootAsTableInFirstNS = function(bb, obj) {
+ return (obj || new NamespaceA.TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.TableInFirstNS=} obj
+ * @returns {NamespaceA.TableInFirstNS}
+ */
+NamespaceA.TableInFirstNS.getSizePrefixedRootAsTableInFirstNS = function(bb, obj) {
+ return (obj || new NamespaceA.TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS|null}
+ */
+NamespaceA.TableInFirstNS.prototype.fooTable = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @returns {NamespaceA.NamespaceB.EnumInNestedNS}
+ */
+NamespaceA.TableInFirstNS.prototype.fooEnum = function() {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb.readInt8(this.bb_pos + offset)) : NamespaceA.NamespaceB.EnumInNestedNS.A;
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.EnumInNestedNS} value
+ * @returns {boolean}
+ */
+NamespaceA.TableInFirstNS.prototype.mutate_foo_enum = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.StructInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.StructInNestedNS|null}
+ */
+NamespaceA.TableInFirstNS.prototype.fooStruct = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? (obj || new NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+NamespaceA.TableInFirstNS.startTableInFirstNS = function(builder) {
+ builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooTableOffset
+ */
+NamespaceA.TableInFirstNS.addFooTable = function(builder, fooTableOffset) {
+ builder.addFieldOffset(0, fooTableOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {NamespaceA.NamespaceB.EnumInNestedNS} fooEnum
+ */
+NamespaceA.TableInFirstNS.addFooEnum = function(builder, fooEnum) {
+ builder.addFieldInt8(1, fooEnum, NamespaceA.NamespaceB.EnumInNestedNS.A);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooStructOffset
+ */
+NamespaceA.TableInFirstNS.addFooStruct = function(builder, fooStructOffset) {
+ builder.addFieldStruct(2, fooStructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.TableInFirstNS.endTableInFirstNS = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooTableOffset
+ * @param {NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS} fooEnum
+ * @param {flatbuffers.Offset} fooStructOffset
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.TableInFirstNS.createTableInFirstNS = function(builder, fooTableOffset, fooEnum, fooStructOffset) {
+ NamespaceA.TableInFirstNS.startTableInFirstNS(builder);
+ NamespaceA.TableInFirstNS.addFooTable(builder, fooTableOffset);
+ NamespaceA.TableInFirstNS.addFooEnum(builder, fooEnum);
+ NamespaceA.TableInFirstNS.addFooStruct(builder, fooStructOffset);
+ return NamespaceA.TableInFirstNS.endTableInFirstNS(builder);
+}
+
+/**
+ * @constructor
+ */
+NamespaceC.TableInC = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceC.TableInC}
+ */
+NamespaceC.TableInC.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC}
+ */
+NamespaceC.TableInC.getRootAsTableInC = function(bb, obj) {
+ return (obj || new NamespaceC.TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC}
+ */
+NamespaceC.TableInC.getSizePrefixedRootAsTableInC = function(bb, obj) {
+ return (obj || new NamespaceC.TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.TableInFirstNS=} obj
+ * @returns {NamespaceA.TableInFirstNS|null}
+ */
+NamespaceC.TableInC.prototype.referToA1 = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceA.TableInFirstNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA|null}
+ */
+NamespaceC.TableInC.prototype.referToA2 = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? (obj || new NamespaceA.SecondTableInA).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+NamespaceC.TableInC.startTableInC = function(builder) {
+ builder.startObject(2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA1Offset
+ */
+NamespaceC.TableInC.addReferToA1 = function(builder, referToA1Offset) {
+ builder.addFieldOffset(0, referToA1Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA2Offset
+ */
+NamespaceC.TableInC.addReferToA2 = function(builder, referToA2Offset) {
+ builder.addFieldOffset(1, referToA2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceC.TableInC.endTableInC = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA1Offset
+ * @param {flatbuffers.Offset} referToA2Offset
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceC.TableInC.createTableInC = function(builder, referToA1Offset, referToA2Offset) {
+ NamespaceC.TableInC.startTableInC(builder);
+ NamespaceC.TableInC.addReferToA1(builder, referToA1Offset);
+ NamespaceC.TableInC.addReferToA2(builder, referToA2Offset);
+ return NamespaceC.TableInC.endTableInC(builder);
+}
+
+/**
+ * @constructor
+ */
+NamespaceA.SecondTableInA = function() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {NamespaceA.SecondTableInA}
+ */
+NamespaceA.SecondTableInA.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA}
+ */
+NamespaceA.SecondTableInA.getRootAsSecondTableInA = function(bb, obj) {
+ return (obj || new NamespaceA.SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA}
+ */
+NamespaceA.SecondTableInA.getSizePrefixedRootAsSecondTableInA = function(bb, obj) {
+ return (obj || new NamespaceA.SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC|null}
+ */
+NamespaceA.SecondTableInA.prototype.referToC = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceC.TableInC).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+NamespaceA.SecondTableInA.startSecondTableInA = function(builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToCOffset
+ */
+NamespaceA.SecondTableInA.addReferToC = function(builder, referToCOffset) {
+ builder.addFieldOffset(0, referToCOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.SecondTableInA.endSecondTableInA = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToCOffset
+ * @returns {flatbuffers.Offset}
+ */
+NamespaceA.SecondTableInA.createSecondTableInA = function(builder, referToCOffset) {
+ NamespaceA.SecondTableInA.startSecondTableInA(builder);
+ NamespaceA.SecondTableInA.addReferToC(builder, referToCOffset);
+ return NamespaceA.SecondTableInA.endSecondTableInA(builder);
+}
+
+// Exports for Node.js and RequireJS
+this.NamespaceA = NamespaceA;
+this.NamespaceC = NamespaceC;
diff --git a/tests/namespace_test/namespace_test2_generated.lobster b/tests/namespace_test/namespace_test2_generated.lobster
new file mode 100644
index 0000000..4383e68
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.lobster
@@ -0,0 +1,90 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+import flatbuffers
+
+namespace NamespaceA
+
+class TableInFirstNS
+
+namespace NamespaceC
+
+class TableInC
+
+namespace NamespaceA
+
+class SecondTableInA
+
+class TableInFirstNS : flatbuffers_handle
+ def foo_table():
+ let o = buf_.flatbuffers_field_table(pos_, 4)
+ return if o: NamespaceA_NamespaceB_TableInNestedNS { buf_, o } else: nil
+ def foo_enum():
+ return EnumInNestedNS(buf_.flatbuffers_field_int8(pos_, 6, 0))
+ def foo_struct():
+ let o = buf_.flatbuffers_field_struct(pos_, 8)
+ return if o: NamespaceA_NamespaceB_StructInNestedNS { buf_, o } else: nil
+
+def GetRootAsTableInFirstNS(buf:string): return TableInFirstNS { buf, buf.flatbuffers_indirect(0) }
+
+struct TableInFirstNSBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(3)
+ return this
+ def add_foo_table(foo_table:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(0, foo_table)
+ return this
+ def add_foo_enum(foo_enum:EnumInNestedNS):
+ b_.PrependInt8Slot(1, foo_enum, 0)
+ return this
+ def add_foo_struct(foo_struct:flatbuffers_offset):
+ b_.PrependStructSlot(2, foo_struct)
+ return this
+ def end():
+ return b_.EndObject()
+
+namespace NamespaceC
+
+class TableInC : flatbuffers_handle
+ def refer_to_a1():
+ let o = buf_.flatbuffers_field_table(pos_, 4)
+ return if o: NamespaceA_TableInFirstNS { buf_, o } else: nil
+ def refer_to_a2():
+ let o = buf_.flatbuffers_field_table(pos_, 6)
+ return if o: NamespaceA_SecondTableInA { buf_, o } else: nil
+
+def GetRootAsTableInC(buf:string): return TableInC { buf, buf.flatbuffers_indirect(0) }
+
+struct TableInCBuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(2)
+ return this
+ def add_refer_to_a1(refer_to_a1:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(0, refer_to_a1)
+ return this
+ def add_refer_to_a2(refer_to_a2:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(1, refer_to_a2)
+ return this
+ def end():
+ return b_.EndObject()
+
+namespace NamespaceA
+
+class SecondTableInA : flatbuffers_handle
+ def refer_to_c():
+ let o = buf_.flatbuffers_field_table(pos_, 4)
+ return if o: NamespaceC_TableInC { buf_, o } else: nil
+
+def GetRootAsSecondTableInA(buf:string): return SecondTableInA { buf, buf.flatbuffers_indirect(0) }
+
+struct SecondTableInABuilder:
+ b_:flatbuffers_builder
+ def start():
+ b_.StartObject(1)
+ return this
+ def add_refer_to_c(refer_to_c:flatbuffers_offset):
+ b_.PrependUOffsetTRelativeSlot(0, refer_to_c)
+ return this
+ def end():
+ return b_.EndObject()
+
diff --git a/tests/namespace_test/namespace_test2_generated.rs b/tests/namespace_test/namespace_test2_generated.rs
new file mode 100644
index 0000000..3c04c0f
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.rs
@@ -0,0 +1,296 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+
+use std::mem;
+use std::cmp::Ordering;
+
+extern crate flatbuffers;
+use self::flatbuffers::EndianScalar;
+
+#[allow(unused_imports, dead_code)]
+pub mod namespace_a {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+
+pub enum TableInFirstNSOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct TableInFirstNS<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for TableInFirstNS<'a> {
+ type Inner = TableInFirstNS<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> TableInFirstNS<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ TableInFirstNS {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args TableInFirstNSArgs<'args>) -> flatbuffers::WIPOffset<TableInFirstNS<'bldr>> {
+ let mut builder = TableInFirstNSBuilder::new(_fbb);
+ if let Some(x) = args.foo_struct { builder.add_foo_struct(x); }
+ if let Some(x) = args.foo_table { builder.add_foo_table(x); }
+ builder.add_foo_enum(args.foo_enum);
+ builder.finish()
+ }
+
+ pub const VT_FOO_TABLE: flatbuffers::VOffsetT = 4;
+ pub const VT_FOO_ENUM: flatbuffers::VOffsetT = 6;
+ pub const VT_FOO_STRUCT: flatbuffers::VOffsetT = 8;
+
+ #[inline]
+ pub fn foo_table(&self) -> Option<namespace_b::TableInNestedNS<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<namespace_b::TableInNestedNS<'a>>>(TableInFirstNS::VT_FOO_TABLE, None)
+ }
+ #[inline]
+ pub fn foo_enum(&self) -> namespace_b::EnumInNestedNS {
+ self._tab.get::<namespace_b::EnumInNestedNS>(TableInFirstNS::VT_FOO_ENUM, Some(namespace_b::EnumInNestedNS::A)).unwrap()
+ }
+ #[inline]
+ pub fn foo_struct(&self) -> Option<&'a namespace_b::StructInNestedNS> {
+ self._tab.get::<namespace_b::StructInNestedNS>(TableInFirstNS::VT_FOO_STRUCT, None)
+ }
+}
+
+pub struct TableInFirstNSArgs<'a> {
+ pub foo_table: Option<flatbuffers::WIPOffset<namespace_b::TableInNestedNS<'a >>>,
+ pub foo_enum: namespace_b::EnumInNestedNS,
+ pub foo_struct: Option<&'a namespace_b::StructInNestedNS>,
+}
+impl<'a> Default for TableInFirstNSArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ TableInFirstNSArgs {
+ foo_table: None,
+ foo_enum: namespace_b::EnumInNestedNS::A,
+ foo_struct: None,
+ }
+ }
+}
+pub struct TableInFirstNSBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> TableInFirstNSBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_foo_table(&mut self, foo_table: flatbuffers::WIPOffset<namespace_b::TableInNestedNS<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<namespace_b::TableInNestedNS>>(TableInFirstNS::VT_FOO_TABLE, foo_table);
+ }
+ #[inline]
+ pub fn add_foo_enum(&mut self, foo_enum: namespace_b::EnumInNestedNS) {
+ self.fbb_.push_slot::<namespace_b::EnumInNestedNS>(TableInFirstNS::VT_FOO_ENUM, foo_enum, namespace_b::EnumInNestedNS::A);
+ }
+ #[inline]
+ pub fn add_foo_struct(&mut self, foo_struct: &'b namespace_b::StructInNestedNS) {
+ self.fbb_.push_slot_always::<&namespace_b::StructInNestedNS>(TableInFirstNS::VT_FOO_STRUCT, foo_struct);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TableInFirstNSBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ TableInFirstNSBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<TableInFirstNS<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+pub enum SecondTableInAOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct SecondTableInA<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for SecondTableInA<'a> {
+ type Inner = SecondTableInA<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> SecondTableInA<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ SecondTableInA {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args SecondTableInAArgs<'args>) -> flatbuffers::WIPOffset<SecondTableInA<'bldr>> {
+ let mut builder = SecondTableInABuilder::new(_fbb);
+ if let Some(x) = args.refer_to_c { builder.add_refer_to_c(x); }
+ builder.finish()
+ }
+
+ pub const VT_REFER_TO_C: flatbuffers::VOffsetT = 4;
+
+ #[inline]
+ pub fn refer_to_c(&self) -> Option<super::namespace_c::TableInC<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_c::TableInC<'a>>>(SecondTableInA::VT_REFER_TO_C, None)
+ }
+}
+
+pub struct SecondTableInAArgs<'a> {
+ pub refer_to_c: Option<flatbuffers::WIPOffset<super::namespace_c::TableInC<'a >>>,
+}
+impl<'a> Default for SecondTableInAArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ SecondTableInAArgs {
+ refer_to_c: None,
+ }
+ }
+}
+pub struct SecondTableInABuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> SecondTableInABuilder<'a, 'b> {
+ #[inline]
+ pub fn add_refer_to_c(&mut self, refer_to_c: flatbuffers::WIPOffset<super::namespace_c::TableInC<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<super::namespace_c::TableInC>>(SecondTableInA::VT_REFER_TO_C, refer_to_c);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> SecondTableInABuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ SecondTableInABuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<SecondTableInA<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+} // pub mod NamespaceA
+
+#[allow(unused_imports, dead_code)]
+pub mod namespace_c {
+
+ use std::mem;
+ use std::cmp::Ordering;
+
+ extern crate flatbuffers;
+ use self::flatbuffers::EndianScalar;
+
+pub enum TableInCOffset {}
+#[derive(Copy, Clone, Debug, PartialEq)]
+
+pub struct TableInC<'a> {
+ pub _tab: flatbuffers::Table<'a>,
+}
+
+impl<'a> flatbuffers::Follow<'a> for TableInC<'a> {
+ type Inner = TableInC<'a>;
+ #[inline]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ Self {
+ _tab: flatbuffers::Table { buf: buf, loc: loc },
+ }
+ }
+}
+
+impl<'a> TableInC<'a> {
+ #[inline]
+ pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
+ TableInC {
+ _tab: table,
+ }
+ }
+ #[allow(unused_mut)]
+ pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
+ _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
+ args: &'args TableInCArgs<'args>) -> flatbuffers::WIPOffset<TableInC<'bldr>> {
+ let mut builder = TableInCBuilder::new(_fbb);
+ if let Some(x) = args.refer_to_a2 { builder.add_refer_to_a2(x); }
+ if let Some(x) = args.refer_to_a1 { builder.add_refer_to_a1(x); }
+ builder.finish()
+ }
+
+ pub const VT_REFER_TO_A1: flatbuffers::VOffsetT = 4;
+ pub const VT_REFER_TO_A2: flatbuffers::VOffsetT = 6;
+
+ #[inline]
+ pub fn refer_to_a1(&self) -> Option<super::namespace_a::TableInFirstNS<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_a::TableInFirstNS<'a>>>(TableInC::VT_REFER_TO_A1, None)
+ }
+ #[inline]
+ pub fn refer_to_a2(&self) -> Option<super::namespace_a::SecondTableInA<'a>> {
+ self._tab.get::<flatbuffers::ForwardsUOffset<super::namespace_a::SecondTableInA<'a>>>(TableInC::VT_REFER_TO_A2, None)
+ }
+}
+
+pub struct TableInCArgs<'a> {
+ pub refer_to_a1: Option<flatbuffers::WIPOffset<super::namespace_a::TableInFirstNS<'a >>>,
+ pub refer_to_a2: Option<flatbuffers::WIPOffset<super::namespace_a::SecondTableInA<'a >>>,
+}
+impl<'a> Default for TableInCArgs<'a> {
+ #[inline]
+ fn default() -> Self {
+ TableInCArgs {
+ refer_to_a1: None,
+ refer_to_a2: None,
+ }
+ }
+}
+pub struct TableInCBuilder<'a: 'b, 'b> {
+ fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
+ start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
+}
+impl<'a: 'b, 'b> TableInCBuilder<'a, 'b> {
+ #[inline]
+ pub fn add_refer_to_a1(&mut self, refer_to_a1: flatbuffers::WIPOffset<super::namespace_a::TableInFirstNS<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<super::namespace_a::TableInFirstNS>>(TableInC::VT_REFER_TO_A1, refer_to_a1);
+ }
+ #[inline]
+ pub fn add_refer_to_a2(&mut self, refer_to_a2: flatbuffers::WIPOffset<super::namespace_a::SecondTableInA<'b >>) {
+ self.fbb_.push_slot_always::<flatbuffers::WIPOffset<super::namespace_a::SecondTableInA>>(TableInC::VT_REFER_TO_A2, refer_to_a2);
+ }
+ #[inline]
+ pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> TableInCBuilder<'a, 'b> {
+ let start = _fbb.start_table();
+ TableInCBuilder {
+ fbb_: _fbb,
+ start_: start,
+ }
+ }
+ #[inline]
+ pub fn finish(self) -> flatbuffers::WIPOffset<TableInC<'a>> {
+ let o = self.fbb_.end_table(self.start_);
+ flatbuffers::WIPOffset::new(o.value())
+ }
+}
+
+} // pub mod NamespaceC
+
diff --git a/tests/namespace_test/namespace_test2_generated.ts b/tests/namespace_test/namespace_test2_generated.ts
new file mode 100644
index 0000000..7bd0543
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.ts
@@ -0,0 +1,302 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import * as NS8755221360535654258 from "./namespace_test1_generated";
+/**
+ * @constructor
+ */
+export namespace NamespaceA{
+export class TableInFirstNS {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns TableInFirstNS
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInFirstNS {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TableInFirstNS= obj
+ * @returns TableInFirstNS
+ */
+static getRootAsTableInFirstNS(bb:flatbuffers.ByteBuffer, obj?:TableInFirstNS):TableInFirstNS {
+ return (obj || new TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TableInFirstNS= obj
+ * @returns TableInFirstNS
+ */
+static getSizePrefixedRootAsTableInFirstNS(bb:flatbuffers.ByteBuffer, obj?:TableInFirstNS):TableInFirstNS {
+ return (obj || new TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param NamespaceA.NamespaceB.TableInNestedNS= obj
+ * @returns NamespaceA.NamespaceB.TableInNestedNS|null
+ */
+fooTable(obj?:NS8755221360535654258.NamespaceA.NamespaceB.TableInNestedNS):NS8755221360535654258.NamespaceA.NamespaceB.TableInNestedNS|null {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NS8755221360535654258.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @returns NamespaceA.NamespaceB.EnumInNestedNS
+ */
+fooEnum():NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? /** */ (this.bb!.readInt8(this.bb_pos + offset)) : NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS.A;
+};
+
+/**
+ * @param NamespaceA.NamespaceB.EnumInNestedNS value
+ * @returns boolean
+ */
+mutate_foo_enum(value:NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param NamespaceA.NamespaceB.StructInNestedNS= obj
+ * @returns NamespaceA.NamespaceB.StructInNestedNS|null
+ */
+fooStruct(obj?:NS8755221360535654258.NamespaceA.NamespaceB.StructInNestedNS):NS8755221360535654258.NamespaceA.NamespaceB.StructInNestedNS|null {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? (obj || new NS8755221360535654258.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb!) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startTableInFirstNS(builder:flatbuffers.Builder) {
+ builder.startObject(3);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset fooTableOffset
+ */
+static addFooTable(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(0, fooTableOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param NamespaceA.NamespaceB.EnumInNestedNS fooEnum
+ */
+static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS) {
+ builder.addFieldInt8(1, fooEnum, NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS.A);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset fooStructOffset
+ */
+static addFooStruct(builder:flatbuffers.Builder, fooStructOffset:flatbuffers.Offset) {
+ builder.addFieldStruct(2, fooStructOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endTableInFirstNS(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createTableInFirstNS(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offset, fooEnum:NS8755221360535654258.NamespaceA.NamespaceB.EnumInNestedNS, fooStructOffset:flatbuffers.Offset):flatbuffers.Offset {
+ TableInFirstNS.startTableInFirstNS(builder);
+ TableInFirstNS.addFooTable(builder, fooTableOffset);
+ TableInFirstNS.addFooEnum(builder, fooEnum);
+ TableInFirstNS.addFooStruct(builder, fooStructOffset);
+ return TableInFirstNS.endTableInFirstNS(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceC{
+export class TableInC {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns TableInC
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInC {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TableInC= obj
+ * @returns TableInC
+ */
+static getRootAsTableInC(bb:flatbuffers.ByteBuffer, obj?:TableInC):TableInC {
+ return (obj || new TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param TableInC= obj
+ * @returns TableInC
+ */
+static getSizePrefixedRootAsTableInC(bb:flatbuffers.ByteBuffer, obj?:TableInC):TableInC {
+ return (obj || new TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param NamespaceA.TableInFirstNS= obj
+ * @returns NamespaceA.TableInFirstNS|null
+ */
+referToA1(obj?:NamespaceA.TableInFirstNS):NamespaceA.TableInFirstNS|null {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceA.TableInFirstNS).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @param NamespaceA.SecondTableInA= obj
+ * @returns NamespaceA.SecondTableInA|null
+ */
+referToA2(obj?:NamespaceA.SecondTableInA):NamespaceA.SecondTableInA|null {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? (obj || new NamespaceA.SecondTableInA).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startTableInC(builder:flatbuffers.Builder) {
+ builder.startObject(2);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset referToA1Offset
+ */
+static addReferToA1(builder:flatbuffers.Builder, referToA1Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(0, referToA1Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset referToA2Offset
+ */
+static addReferToA2(builder:flatbuffers.Builder, referToA2Offset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, referToA2Offset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endTableInC(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createTableInC(builder:flatbuffers.Builder, referToA1Offset:flatbuffers.Offset, referToA2Offset:flatbuffers.Offset):flatbuffers.Offset {
+ TableInC.startTableInC(builder);
+ TableInC.addReferToA1(builder, referToA1Offset);
+ TableInC.addReferToA2(builder, referToA2Offset);
+ return TableInC.endTableInC(builder);
+}
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceA{
+export class SecondTableInA {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns SecondTableInA
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):SecondTableInA {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param SecondTableInA= obj
+ * @returns SecondTableInA
+ */
+static getRootAsSecondTableInA(bb:flatbuffers.ByteBuffer, obj?:SecondTableInA):SecondTableInA {
+ return (obj || new SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param SecondTableInA= obj
+ * @returns SecondTableInA
+ */
+static getSizePrefixedRootAsSecondTableInA(bb:flatbuffers.ByteBuffer, obj?:SecondTableInA):SecondTableInA {
+ return (obj || new SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param NamespaceC.TableInC= obj
+ * @returns NamespaceC.TableInC|null
+ */
+referToC(obj?:NamespaceC.TableInC):NamespaceC.TableInC|null {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? (obj || new NamespaceC.TableInC).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startSecondTableInA(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset referToCOffset
+ */
+static addReferToC(builder:flatbuffers.Builder, referToCOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(0, referToCOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endSecondTableInA(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createSecondTableInA(builder:flatbuffers.Builder, referToCOffset:flatbuffers.Offset):flatbuffers.Offset {
+ SecondTableInA.startSecondTableInA(builder);
+ SecondTableInA.addReferToC(builder, referToCOffset);
+ return SecondTableInA.endSecondTableInA(builder);
+}
+}
+}
diff --git a/tests/namespace_test/namespace_test2_namespace_a_generated.dart b/tests/namespace_test/namespace_test2_namespace_a_generated.dart
new file mode 100644
index 0000000..d5108eb
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_namespace_a_generated.dart
@@ -0,0 +1,189 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library namespace_a;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import 'namespace_test1_namespace_a_generated.dart';
+import './namespace_test2_namespace_c_generated.dart' as namespace_c;
+
+class TableInFirstNS {
+ TableInFirstNS._(this._bc, this._bcOffset);
+ factory TableInFirstNS(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TableInFirstNS> reader = const _TableInFirstNSReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ namespace_a_namespace_b.TableInNestedNS get fooTable => namespace_a_namespace_b.TableInNestedNS.reader.vTableGet(_bc, _bcOffset, 4, null);
+ EnumInNestedNS get fooEnum => new EnumInNestedNS.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 6, 0));
+ namespace_a_namespace_b.StructInNestedNS get fooStruct => namespace_a_namespace_b.StructInNestedNS.reader.vTableGet(_bc, _bcOffset, 8, null);
+
+ @override
+ String toString() {
+ return 'TableInFirstNS{fooTable: $fooTable, fooEnum: $fooEnum, fooStruct: $fooStruct}';
+ }
+}
+
+class _TableInFirstNSReader extends fb.TableReader<TableInFirstNS> {
+ const _TableInFirstNSReader();
+
+ @override
+ TableInFirstNS createObject(fb.BufferContext bc, int offset) =>
+ new TableInFirstNS._(bc, offset);
+}
+
+class TableInFirstNSBuilder {
+ TableInFirstNSBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addFooTableOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addFooEnum(EnumInNestedNS fooEnum) {
+ fbBuilder.addInt8(1, fooEnum?.value);
+ return fbBuilder.offset;
+ }
+ int addFooStruct(int offset) {
+ fbBuilder.addStruct(2, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TableInFirstNSObjectBuilder extends fb.ObjectBuilder {
+ final namespace_a_namespace_b.TableInNestedNSObjectBuilder _fooTable;
+ final EnumInNestedNS _fooEnum;
+ final namespace_a_namespace_b.StructInNestedNSObjectBuilder _fooStruct;
+
+ TableInFirstNSObjectBuilder({
+ namespace_a_namespace_b.TableInNestedNSObjectBuilder fooTable,
+ EnumInNestedNS fooEnum,
+ namespace_a_namespace_b.StructInNestedNSObjectBuilder fooStruct,
+ })
+ : _fooTable = fooTable,
+ _fooEnum = fooEnum,
+ _fooStruct = fooStruct;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int fooTableOffset = _fooTable?.getOrCreateOffset(fbBuilder);
+
+ fbBuilder.startTable();
+ if (fooTableOffset != null) {
+ fbBuilder.addOffset(0, fooTableOffset);
+ }
+ fbBuilder.addInt8(1, _fooEnum?.value);
+ if (_fooStruct != null) {
+ fbBuilder.addStruct(2, _fooStruct.finish(fbBuilder));
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
+class SecondTableInA {
+ SecondTableInA._(this._bc, this._bcOffset);
+ factory SecondTableInA(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<SecondTableInA> reader = const _SecondTableInAReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ namespace_c.TableInC get referToC => namespace_c.TableInC.reader.vTableGet(_bc, _bcOffset, 4, null);
+
+ @override
+ String toString() {
+ return 'SecondTableInA{referToC: $referToC}';
+ }
+}
+
+class _SecondTableInAReader extends fb.TableReader<SecondTableInA> {
+ const _SecondTableInAReader();
+
+ @override
+ SecondTableInA createObject(fb.BufferContext bc, int offset) =>
+ new SecondTableInA._(bc, offset);
+}
+
+class SecondTableInABuilder {
+ SecondTableInABuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addReferToCOffset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class SecondTableInAObjectBuilder extends fb.ObjectBuilder {
+ final namespace_c.TableInCObjectBuilder _referToC;
+
+ SecondTableInAObjectBuilder({
+ namespace_c.TableInCObjectBuilder referToC,
+ })
+ : _referToC = referToC;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int referToCOffset = _referToC?.getOrCreateOffset(fbBuilder);
+
+ fbBuilder.startTable();
+ if (referToCOffset != null) {
+ fbBuilder.addOffset(0, referToCOffset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/tests/namespace_test/namespace_test2_namespace_c_generated.dart b/tests/namespace_test/namespace_test2_namespace_c_generated.dart
new file mode 100644
index 0000000..7214feb
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_namespace_c_generated.dart
@@ -0,0 +1,102 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+// ignore_for_file: unused_import, unused_field, unused_local_variable
+
+library namespace_c;
+
+import 'dart:typed_data' show Uint8List;
+import 'package:flat_buffers/flat_buffers.dart' as fb;
+
+import 'namespace_test1_namespace_c_generated.dart';
+import './namespace_test2_namespace_a_generated.dart' as namespace_a;
+
+class TableInC {
+ TableInC._(this._bc, this._bcOffset);
+ factory TableInC(List<int> bytes) {
+ fb.BufferContext rootRef = new fb.BufferContext.fromBytes(bytes);
+ return reader.read(rootRef, 0);
+ }
+
+ static const fb.Reader<TableInC> reader = const _TableInCReader();
+
+ final fb.BufferContext _bc;
+ final int _bcOffset;
+
+ namespace_a.TableInFirstNS get referToA1 => namespace_a.TableInFirstNS.reader.vTableGet(_bc, _bcOffset, 4, null);
+ namespace_a.SecondTableInA get referToA2 => namespace_a.SecondTableInA.reader.vTableGet(_bc, _bcOffset, 6, null);
+
+ @override
+ String toString() {
+ return 'TableInC{referToA1: $referToA1, referToA2: $referToA2}';
+ }
+}
+
+class _TableInCReader extends fb.TableReader<TableInC> {
+ const _TableInCReader();
+
+ @override
+ TableInC createObject(fb.BufferContext bc, int offset) =>
+ new TableInC._(bc, offset);
+}
+
+class TableInCBuilder {
+ TableInCBuilder(this.fbBuilder) {
+ assert(fbBuilder != null);
+ }
+
+ final fb.Builder fbBuilder;
+
+ void begin() {
+ fbBuilder.startTable();
+ }
+
+ int addReferToA1Offset(int offset) {
+ fbBuilder.addOffset(0, offset);
+ return fbBuilder.offset;
+ }
+ int addReferToA2Offset(int offset) {
+ fbBuilder.addOffset(1, offset);
+ return fbBuilder.offset;
+ }
+
+ int finish() {
+ return fbBuilder.endTable();
+ }
+}
+
+class TableInCObjectBuilder extends fb.ObjectBuilder {
+ final namespace_a.TableInFirstNSObjectBuilder _referToA1;
+ final namespace_a.SecondTableInAObjectBuilder _referToA2;
+
+ TableInCObjectBuilder({
+ namespace_a.TableInFirstNSObjectBuilder referToA1,
+ namespace_a.SecondTableInAObjectBuilder referToA2,
+ })
+ : _referToA1 = referToA1,
+ _referToA2 = referToA2;
+
+ /// Finish building, and store into the [fbBuilder].
+ @override
+ int finish(
+ fb.Builder fbBuilder) {
+ assert(fbBuilder != null);
+ final int referToA1Offset = _referToA1?.getOrCreateOffset(fbBuilder);
+ final int referToA2Offset = _referToA2?.getOrCreateOffset(fbBuilder);
+
+ fbBuilder.startTable();
+ if (referToA1Offset != null) {
+ fbBuilder.addOffset(0, referToA1Offset);
+ }
+ if (referToA2Offset != null) {
+ fbBuilder.addOffset(1, referToA2Offset);
+ }
+ return fbBuilder.endTable();
+ }
+
+ /// Convenience method to serialize to byte list.
+ @override
+ Uint8List toBytes([String fileIdentifier]) {
+ fb.Builder fbBuilder = new fb.Builder();
+ int offset = finish(fbBuilder);
+ return fbBuilder.finish(offset, fileIdentifier);
+ }
+}
diff --git a/tests/native_type_test.fbs b/tests/native_type_test.fbs
new file mode 100644
index 0000000..de80bdf
--- /dev/null
+++ b/tests/native_type_test.fbs
@@ -0,0 +1,15 @@
+native_include "native_type_test_impl.h";
+
+namespace Geometry;
+
+struct Vector3D (native_type:"Native::Vector3D") {
+ x:float;
+ y:float;
+ z:float;
+}
+
+table ApplicationData {
+ vectors:[Vector3D];
+}
+
+root_type ApplicationData;
diff --git a/tests/native_type_test_generated.h b/tests/native_type_test_generated.h
new file mode 100644
index 0000000..9ba7c61
--- /dev/null
+++ b/tests/native_type_test_generated.h
@@ -0,0 +1,238 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_NATIVETYPETEST_GEOMETRY_H_
+#define FLATBUFFERS_GENERATED_NATIVETYPETEST_GEOMETRY_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+#include "native_type_test_impl.h"
+
+namespace Geometry {
+
+struct Vector3D;
+
+struct ApplicationData;
+struct ApplicationDataT;
+
+inline const flatbuffers::TypeTable *Vector3DTypeTable();
+
+inline const flatbuffers::TypeTable *ApplicationDataTypeTable();
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Vector3D FLATBUFFERS_FINAL_CLASS {
+ private:
+ float x_;
+ float y_;
+ float z_;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return Vector3DTypeTable();
+ }
+ Vector3D() {
+ memset(static_cast<void *>(this), 0, sizeof(Vector3D));
+ }
+ Vector3D(float _x, float _y, float _z)
+ : x_(flatbuffers::EndianScalar(_x)),
+ y_(flatbuffers::EndianScalar(_y)),
+ z_(flatbuffers::EndianScalar(_z)) {
+ }
+ float x() const {
+ return flatbuffers::EndianScalar(x_);
+ }
+ void mutate_x(float _x) {
+ flatbuffers::WriteScalar(&x_, _x);
+ }
+ float y() const {
+ return flatbuffers::EndianScalar(y_);
+ }
+ void mutate_y(float _y) {
+ flatbuffers::WriteScalar(&y_, _y);
+ }
+ float z() const {
+ return flatbuffers::EndianScalar(z_);
+ }
+ void mutate_z(float _z) {
+ flatbuffers::WriteScalar(&z_, _z);
+ }
+};
+FLATBUFFERS_STRUCT_END(Vector3D, 12);
+
+struct ApplicationDataT : public flatbuffers::NativeTable {
+ typedef ApplicationData TableType;
+ std::vector<Native::Vector3D> vectors;
+ ApplicationDataT() {
+ }
+};
+
+struct ApplicationData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef ApplicationDataT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return ApplicationDataTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_VECTORS = 4
+ };
+ const flatbuffers::Vector<const Geometry::Vector3D *> *vectors() const {
+ return GetPointer<const flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
+ }
+ flatbuffers::Vector<const Geometry::Vector3D *> *mutable_vectors() {
+ return GetPointer<flatbuffers::Vector<const Geometry::Vector3D *> *>(VT_VECTORS);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_VECTORS) &&
+ verifier.VerifyVector(vectors()) &&
+ verifier.EndTable();
+ }
+ ApplicationDataT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(ApplicationDataT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<ApplicationData> Pack(flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct ApplicationDataBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_vectors(flatbuffers::Offset<flatbuffers::Vector<const Geometry::Vector3D *>> vectors) {
+ fbb_.AddOffset(ApplicationData::VT_VECTORS, vectors);
+ }
+ explicit ApplicationDataBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ ApplicationDataBuilder &operator=(const ApplicationDataBuilder &);
+ flatbuffers::Offset<ApplicationData> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<ApplicationData>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<ApplicationData> CreateApplicationData(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<flatbuffers::Vector<const Geometry::Vector3D *>> vectors = 0) {
+ ApplicationDataBuilder builder_(_fbb);
+ builder_.add_vectors(vectors);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<ApplicationData> CreateApplicationDataDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ const std::vector<Geometry::Vector3D> *vectors = nullptr) {
+ auto vectors__ = vectors ? _fbb.CreateVectorOfStructs<Geometry::Vector3D>(*vectors) : 0;
+ return Geometry::CreateApplicationData(
+ _fbb,
+ vectors__);
+}
+
+flatbuffers::Offset<ApplicationData> CreateApplicationData(flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline ApplicationDataT *ApplicationData::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new ApplicationDataT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void ApplicationData::UnPackTo(ApplicationDataT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = vectors(); if (_e) { _o->vectors.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vectors[_i] = flatbuffers::UnPack(*_e->Get(_i)); } } };
+}
+
+inline flatbuffers::Offset<ApplicationData> ApplicationData::Pack(flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateApplicationData(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<ApplicationData> CreateApplicationData(flatbuffers::FlatBufferBuilder &_fbb, const ApplicationDataT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const ApplicationDataT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _vectors = _o->vectors.size() ? _fbb.CreateVectorOfNativeStructs<Geometry::Vector3D>(_o->vectors) : 0;
+ return Geometry::CreateApplicationData(
+ _fbb,
+ _vectors);
+}
+
+inline const flatbuffers::TypeTable *Vector3DTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 },
+ { flatbuffers::ET_FLOAT, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 4, 8, 12 };
+ static const char * const names[] = {
+ "x",
+ "y",
+ "z"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 3, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *ApplicationDataTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 1, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ Geometry::Vector3DTypeTable
+ };
+ static const char * const names[] = {
+ "vectors"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const Geometry::ApplicationData *GetApplicationData(const void *buf) {
+ return flatbuffers::GetRoot<Geometry::ApplicationData>(buf);
+}
+
+inline const Geometry::ApplicationData *GetSizePrefixedApplicationData(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<Geometry::ApplicationData>(buf);
+}
+
+inline ApplicationData *GetMutableApplicationData(void *buf) {
+ return flatbuffers::GetMutableRoot<ApplicationData>(buf);
+}
+
+inline bool VerifyApplicationDataBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<Geometry::ApplicationData>(nullptr);
+}
+
+inline bool VerifySizePrefixedApplicationDataBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<Geometry::ApplicationData>(nullptr);
+}
+
+inline void FinishApplicationDataBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<Geometry::ApplicationData> root) {
+ fbb.Finish(root);
+}
+
+inline void FinishSizePrefixedApplicationDataBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<Geometry::ApplicationData> root) {
+ fbb.FinishSizePrefixed(root);
+}
+
+inline flatbuffers::unique_ptr<Geometry::ApplicationDataT> UnPackApplicationData(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<Geometry::ApplicationDataT>(GetApplicationData(buf)->UnPack(res));
+}
+
+inline flatbuffers::unique_ptr<Geometry::ApplicationDataT> UnPackSizePrefixedApplicationData(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<Geometry::ApplicationDataT>(GetSizePrefixedApplicationData(buf)->UnPack(res));
+}
+
+} // namespace Geometry
+
+#endif // FLATBUFFERS_GENERATED_NATIVETYPETEST_GEOMETRY_H_
diff --git a/tests/native_type_test_impl.cpp b/tests/native_type_test_impl.cpp
new file mode 100644
index 0000000..04ddb96
--- /dev/null
+++ b/tests/native_type_test_impl.cpp
@@ -0,0 +1,13 @@
+#include "native_type_test_impl.h"
+#include "native_type_test_generated.h"
+
+namespace flatbuffers {
+ Geometry::Vector3D Pack(const Native::Vector3D &obj) {
+ return Geometry::Vector3D(obj.x, obj.y, obj.z);
+ }
+
+ const Native::Vector3D UnPack(const Geometry::Vector3D &obj) {
+ return Native::Vector3D(obj.x(), obj.y(), obj.z());
+ }
+}
+
diff --git a/tests/native_type_test_impl.h b/tests/native_type_test_impl.h
new file mode 100644
index 0000000..2473ad3
--- /dev/null
+++ b/tests/native_type_test_impl.h
@@ -0,0 +1,24 @@
+#ifndef NATIVE_TYPE_TEST_IMPL_H
+#define NATIVE_TYPE_TEST_IMPL_H
+
+namespace Native {
+ struct Vector3D {
+ float x;
+ float y;
+ float z;
+
+ Vector3D() { x = 0; y = 0; z = 0; };
+ Vector3D(float _x, float _y, float _z) { this->x = _x; this->y = _y; this->z = _z; }
+ };
+}
+
+namespace Geometry {
+ struct Vector3D;
+}
+
+namespace flatbuffers {
+ Geometry::Vector3D Pack(const Native::Vector3D &obj);
+ const Native::Vector3D UnPack(const Geometry::Vector3D &obj);
+}
+
+#endif // VECTOR3D_PACK_H
diff --git a/tests/phpTest.php b/tests/phpTest.php
new file mode 100644
index 0000000..c1447c2
--- /dev/null
+++ b/tests/phpTest.php
@@ -0,0 +1,632 @@
+<?php
+// manual load for testing. please use PSR style autoloader when you use flatbuffers.
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Constants.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "ByteBuffer.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "FlatbufferBuilder.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Table.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Struct.php"));
+foreach (glob(join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "MyGame", "Example", "*.php"))) as $file) {
+ require $file;
+}
+
+function main()
+{
+ /// Begin Test
+ $assert = new Assert();
+
+ // First, let's test reading a FlatBuffer generated by C++ code:
+ // This file was generated from monsterdata_test.json
+
+ // Now test it:
+ $data = file_get_contents('monsterdata_test.mon');
+ $bb = Google\FlatBuffers\ByteBuffer::wrap($data);
+ test_buffer($assert, $bb);
+
+ // Second, let's create a FlatBuffer from scratch in JavaScript, and test it also.
+ // We use an initial size of 1 to exercise the reallocation algorithm,
+ // normally a size larger than the typical FlatBuffer you generate would be
+ // better for performance.
+ $fbb = new Google\FlatBuffers\FlatBufferBuilder(1);
+
+ // We set up the same values as monsterdata.json:
+ $str = $fbb->createString("MyMonster");
+ $name = $fbb->createString('Fred');
+ \MyGame\Example\Monster::startMonster($fbb);
+ \MyGame\Example\Monster::addName($fbb, $name);
+ $enemy = \MyGame\Example\Monster::endMonster($fbb);
+
+ $inv = \MyGame\Example\Monster::CreateInventoryVector($fbb, array(0, 1, 2, 3, 4));
+
+ $fred = $fbb->createString('Fred');
+ \MyGame\Example\Monster::StartMonster($fbb);
+ \MyGame\Example\Monster::AddName($fbb, $fred);
+ $mon2 = \MyGame\Example\Monster::EndMonster($fbb);
+
+ \MyGame\Example\Monster::StartTest4Vector($fbb, 2);
+ \MyGame\Example\Test::CreateTest($fbb, 10, 20);
+ \MyGame\Example\Test::CreateTest($fbb, 30, 40);
+ $test4 = $fbb->endVector();
+
+ $testArrayOfString = \MyGame\Example\Monster::CreateTestarrayofstringVector($fbb, array(
+ $fbb->createString('test1'),
+ $fbb->createString('test2')
+ ));
+
+ \MyGame\Example\Monster::StartMonster($fbb);
+ \MyGame\Example\Monster::AddPos($fbb, \MyGame\Example\Vec3::CreateVec3($fbb,
+ 1.0, 2.0, 3.0, //float
+ 3.0, // double
+ \MyGame\Example\Color::Green,
+ 5, //short
+ 6));
+ \MyGame\Example\Monster::AddHp($fbb, 80);
+ \MyGame\Example\Monster::AddName($fbb, $str);
+ \MyGame\Example\Monster::AddInventory($fbb, $inv);
+ \MyGame\Example\Monster::AddTestType($fbb, \MyGame\Example\Any::Monster);
+ \MyGame\Example\Monster::AddTest($fbb, $mon2);
+ \MyGame\Example\Monster::AddTest4($fbb, $test4);
+ \MyGame\Example\Monster::AddTestarrayofstring($fbb, $testArrayOfString);
+ \MyGame\Example\Monster::AddEnemy($fbb, $enemy);
+ \MyGame\Example\Monster::AddTestbool($fbb, true);
+ $mon = \MyGame\Example\Monster::EndMonster($fbb);
+
+ \MyGame\Example\Monster::FinishMonsterBuffer($fbb, $mon);
+
+ // Test it:
+ test_buffer($assert, $fbb->dataBuffer());
+
+ testByteBuffer($assert);
+ fuzzTest1($assert);
+// testUnicode($assert);
+
+ echo 'FlatBuffers php test: completed successfully' . PHP_EOL;
+}
+
+try {
+ main();
+ exit(0);
+} catch(Exception $e) {
+ printf("Fatal error: Uncaught exception '%s' with message '%s. in %s:%d\n", get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
+ printf("Stack trace:\n");
+ echo $e->getTraceAsString() . PHP_EOL;
+ printf(" thrown in in %s:%d\n", $e->getFile(), $e->getLine());
+
+ die(-1);
+}
+
+function test_buffer(Assert $assert, Google\FlatBuffers\ByteBuffer $bb) {
+
+ $assert->ok(MyGame\Example\Monster::MonsterBufferHasIdentifier($bb));
+ $monster = \MyGame\Example\Monster::GetRootAsMonster($bb);
+
+ $assert->strictEqual($monster->GetHp(), 80);
+ $assert->strictEqual($monster->GetMana(), 150); // default
+
+ $assert->strictEqual($monster->GetName(), 'MyMonster');
+
+ $pos = $monster->GetPos();
+ $assert->strictEqual($pos->GetX(), 1.0);
+ $assert->strictEqual($pos->GetY(), 2.0);
+ $assert->strictEqual($pos->GetZ(), 3.0);
+
+ $assert->Equal($pos->GetTest1(), 3.0);
+ $assert->strictEqual($pos->GetTest2(), \MyGame\Example\Color::Green);
+
+ $t = $pos->GetTest3();
+ $assert->strictEqual($t->GetA(), 5);
+ $assert->strictEqual($t->GetB(), 6);
+ $assert->strictEqual($monster->GetTestType(), \MyGame\Example\Any::Monster);
+
+ $monster2 = new \MyGame\Example\Monster();
+ $assert->strictEqual($monster->GetTest($monster2) != null, true);
+ $assert->strictEqual($monster2->GetName(), 'Fred');
+
+ $assert->strictEqual($monster->GetInventoryLength(), 5);
+ $invsum = 0;
+ for ($i = 0; $i < $monster->GetInventoryLength(); $i++) {
+ $invsum += $monster->GetInventory($i);
+ }
+ $assert->strictEqual($invsum, 10);
+
+ $assert->strictEqual(bin2hex($monster->GetInventoryBytes()), "0001020304");
+
+ $test_0 = $monster->GetTest4(0);
+ $test_1 = $monster->GetTest4(1);
+ $assert->strictEqual($monster->GetTest4Length(), 2);
+ $assert->strictEqual($test_0->GetA() + $test_0->GetB() + $test_1->GetA() + $test_1->GetB(), 100);
+
+ $assert->strictEqual($monster->GetTestarrayofstringLength(), 2);
+ $assert->strictEqual($monster->GetTestarrayofstring(0), 'test1');
+ $assert->strictEqual($monster->GetTestarrayofstring(1), 'test2');
+
+ $fred = $monster->getEnemy();
+ $assert->Equal('Fred', $fred->getName());
+
+ $assert->strictEqual($monster->GetTestbool(), true);
+}
+
+//function testUnicode(Assert $assert) {
+// // missing unicode_test.mon, implemented later
+// $correct = file_get_contents('unicode_test.mon');
+// $json = json_decode(file_get_contents('unicode_test.json'));
+//
+// // Test reading
+// $bb = flatbuffers\ByteBuffer::Wrap($correct);
+// $monster = \MyGame\Example\Monster::GetRootAsMonster($bb);
+// $assert->strictEqual($monster->GetName(), $json["name"]);
+//
+// //$assert->deepEqual(new Buffer(monster.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(json.name));
+// //assert.strictEqual(monster.testarrayoftablesLength(), json.testarrayoftables.length);
+// foreach ($json["testarrayoftables"]as $i => $table) {
+// $value = $monster->GetTestArrayOfTables($i);
+// $assert->strictEqual($value->GetName(), $table["name"]);
+// //assert.deepEqual(new Buffer(value.name(flatbuffers.Encoding.UTF8_BYTES)), new Buffer(table.name));
+// }
+// $assert->strictEqual($monster->GetTestarrayofstringLength(), $json["testarrayofstring"]["length"]);
+// foreach ($json["testarrayofstring"] as $i => $string) {
+// $assert->strictEqual($monster->GetTestarrayofstring($i), $string);
+// //assert.deepEqual(new Buffer(monster.testarrayofstring(i, flatbuffers.Encoding.UTF8_BYTES)), new Buffer(string));
+// }
+//
+// // Test writing
+// $fbb = new FlatBuffers\FlatBufferBuilder(1);
+// $name = $fbb->CreateString($json["name"]);
+// $testarrayoftablesOffsets = array_map(function($table) use($fbb) {
+// $name = $fbb->CreateString($table["name"]);
+// \MyGame\Example\Monster::StartMonster($fbb);
+// \MyGame\Example\Monster::AddName($fbb, $name);
+// return \MyGame\Example\Monster::EndMonster($fbb);
+// }, $json["testarrayoftables"]);
+// $testarrayoftablesOffset = \MyGame\Example\Monster::CreateTestarrayoftablesVector($fbb,
+// $testarrayoftablesOffsets);
+//// $testarrayofstringOffset = \MyGame\Example\Monster::CreateTestarrayofstringVector($fbb,
+//// $json["testarrayofstring"].map(function(string) { return fbb.createString(string); }));
+//
+// \MyGame\Example\Monster::startMonster($fbb);
+// \MyGame\Example\Monster::addTestarrayofstring($fbb, $testarrayoftablesOffset);
+// \MyGame\Example\Monster::addTestarrayoftables($fbb, $testarrayoftablesOffset);
+// \MyGame\Example\Monster::addName($fbb, $name);
+// \MyGame\Example\Monster::finishMonsterBuffer($fbb, \MyGame\Example\Monster::endMonster($fbb));
+// //;assert.deepEqual(new Buffer(fbb.asUint8Array()), correct);
+//}
+
+// Low level stress/fuzz test: serialize/deserialize a variety of
+// different kinds of data in different combinations
+function fuzzTest1(Assert $assert)
+{
+
+ // Values we're testing against: chosen to ensure no bits get chopped
+ // off anywhere, and also be different from eachother.
+ $bool_val = true;
+ $char_val = -127; // 0x81
+ $uchar_val = 0xFF;
+ $short_val = -32222; // 0x8222;
+ $ushort_val = 0xFEEE;
+ $int_val = 0x7fffffff | 0;
+ // for now
+ $uint_val = 1;
+ $long_val = 2;
+ $ulong_val = 3;
+
+// var uint_val = 0xFDDDDDDD;
+// var long_val = new flatbuffers.Long(0x44444444, 0x84444444);
+// var ulong_val = new flatbuffers.Long(0xCCCCCCCC, 0xFCCCCCCC);
+
+ $float_val = 3.14159;
+ $double_val = 3.14159265359;
+
+ $test_values_max = 11;
+ $fields_per_object = 4;
+ // current implementation is not good at encoding.
+ $num_fuzz_objects = 1000;
+ $builder = new Google\FlatBuffers\FlatBufferBuilder(1);
+
+ // can't use same implementation due to PHP_INTMAX overflow issue.
+ // we use mt_rand function to reproduce fuzzy test.
+ mt_srand(48271);
+ $objects = array();
+ // Generate num_fuzz_objects random objects each consisting of
+ // fields_per_object fields, each of a random type.
+ for ($i = 0; $i < $num_fuzz_objects; $i++) {
+ $builder->startObject($fields_per_object);
+ for ($f = 0; $f < $fields_per_object; $f++) {
+ $choice = mt_rand() % $test_values_max;
+ switch ($choice) {
+ case 0:
+ $builder->addBoolX($f, $bool_val, 0);
+ break;
+ case 1:
+ $builder->addByteX($f, $char_val, 0);
+ break;
+ case 2:
+ $builder->addSbyteX($f, $uchar_val, 0);
+ break;
+ case 3:
+ $builder->addShortX($f, $short_val, 0);
+ break;
+ case 4:
+ $builder->addUshortX($f, $ushort_val, 0);
+ break;
+ case 5:
+ $builder->addIntX($f, $int_val, 0);
+ break;
+ case 6:
+ $builder->addUintX($f, $uint_val, 0);
+ break;
+ case 7:
+ $builder->addLongX($f, $long_val, 0);
+ break;
+ case 8:
+ $builder->addUlongX($f, $ulong_val, 0);
+ break;
+ case 9:
+ $builder->addFloatX($f, $float_val, 0);
+ break;
+ case 10:
+ $builder->addDoubleX($f, $double_val, 0);
+ break;
+ }
+ }
+ $objects[] = $builder->endObject();
+ }
+ $builder->prep(8, 0); // Align whole buffer.
+
+ mt_srand(48271); // Reset
+ $builder->finish($objects[count($objects) - 1]);
+
+ $view = Google\FlatBuffers\ByteBuffer::wrap($builder->sizedByteArray());
+ for ($i = 0; $i < $num_fuzz_objects; $i++) {
+ $offset = $view->capacity() - $objects[$i];
+ for ($f = 0; $f < $fields_per_object; $f++) {
+ $choice = mt_rand() % $test_values_max;
+ $vtable_offset = fieldIndexToOffset($f);
+ $vtable = $offset - $view->getInt($offset);
+ $assert->ok($vtable_offset < $view->getShort($vtable));
+ $field_offset = $offset + $view->getShort($vtable + $vtable_offset);
+ switch ($choice) {
+ case 0:
+ $assert->strictEqual(!!$view->getBool($field_offset), $bool_val);
+ break;
+ case 1:
+ $assert->strictEqual($view->getSbyte($field_offset), $char_val);
+ break;
+ case 2:
+ $assert->strictEqual($view->getByte($field_offset), $uchar_val);
+ break;
+ case 3:
+ $assert->strictEqual($view->getShort($field_offset), $short_val);
+ break;
+ case 4:
+ $assert->strictEqual($view->getUShort($field_offset), $ushort_val);
+ break;
+ case 5:
+ $assert->strictEqual($view->getInt($field_offset), $int_val);
+ break;
+ case 6:
+ $assert->strictEqual($view->getUint($field_offset), $uint_val);
+ break;
+ case 7:
+ if (PHP_INT_SIZE <= 4) break;
+ $assert->strictEqual($view->getLong($field_offset), $long_val);
+ break;
+ case 8:
+ if (PHP_INT_SIZE <= 4) break;
+ $assert->strictEqual($view->getUlong($field_offset), $ulong_val);
+ break;
+ case 9:
+ $assert->strictEqual(floor($view->getFloat($field_offset)), floor($float_val));
+ break;
+ case 10:
+ $assert->strictEqual($view->getDouble($field_offset), $double_val);
+ break;
+ }
+ }
+ }
+}
+
+function fieldIndexToOffset($field_id) {
+ // Should correspond to what EndTable() below builds up.
+ $fixed_fields = 2; // Vtable size and Object Size.
+ return ($field_id + $fixed_fields) * 2;
+}
+
+function testByteBuffer(Assert $assert) {
+
+ //Test: ByteBuffer_Length_MatchesBufferLength
+ $buffer = str_repeat("\0", 100);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal($uut->capacity(), strlen($buffer));
+
+ //Test: ByteBuffer_PutBytePopulatesBufferAtZeroOffset
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putByte(0, "\x63"); // 99
+ $assert->Equal("\x63", $uut->_buffer[0]); // don't share buffer as php user might confuse reference.
+
+ //Test: ByteBuffer_PutByteCannotPutAtOffsetPastLength
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putByte(1, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutShortPopulatesBufferCorrectly
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putShort(0, 1);
+
+ // Ensure Endiannes was written correctly
+ $assert->Equal(chr(0x01), $uut->_buffer[0]);
+ $assert->Equal(chr(0x00), $uut->_buffer[1]);
+
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putShort(0, -32768);
+
+ // Ensure Endiannes was written correctly
+ $assert->Equal(chr(0x00), $uut->_buffer[0]);
+ $assert->Equal(chr(0x80), $uut->_buffer[1]);
+
+ //Test: ByteBuffer_PutShortCannotPutAtOffsetPastLength
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putShort(2, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutShortChecksLength
+ $buffer = "\0";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putShort(0, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutShortChecksLengthAndOffset
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putShort(1, "\x63"); // 99
+ });
+
+ //Test: ByteBuffer_PutIntPopulatesBufferCorrectly
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putInt(0, 0x0A0B0C0D);
+ $assert->Equal(chr(0x0D), $uut->_buffer[0]);
+ $assert->Equal(chr(0x0C), $uut->_buffer[1]);
+ $assert->Equal(chr(0x0B), $uut->_buffer[2]);
+ $assert->Equal(chr(0x0A), $uut->_buffer[3]);
+
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putInt(0, -2147483648);
+ $assert->Equal(chr(0x00), $uut->_buffer[0]);
+ $assert->Equal(chr(0x00), $uut->_buffer[1]);
+ $assert->Equal(chr(0x00), $uut->_buffer[2]);
+ $assert->Equal(chr(0x80), $uut->_buffer[3]);
+
+ //Test: ByteBuffer_PutIntCannotPutAtOffsetPastLength
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putInt(2, 0x0A0B0C0D);
+ });
+
+ //Test: ByteBuffer_PutIntChecksLength
+ $buffer = str_repeat("\0", 1);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putInt(0, 0x0A0B0C0D);
+ });
+
+ //Test: ByteBuffer_PutIntChecksLengthAndOffset
+ $buffer = str_repeat("\0", 4);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putInt(2, 0x0A0B0C0D);
+ });
+
+ if (PHP_INT_SIZE > 4) {
+ //Test: ByteBuffer_PutLongPopulatesBufferCorrectly
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $uut->putLong(0, 0x010203040A0B0C0D);
+ $assert->Equal(chr(0x0D), $uut->_buffer[0]);
+ $assert->Equal(chr(0x0C), $uut->_buffer[1]);
+ $assert->Equal(chr(0x0B), $uut->_buffer[2]);
+ $assert->Equal(chr(0x0A), $uut->_buffer[3]);
+ $assert->Equal(chr(0x04), $uut->_buffer[4]);
+ $assert->Equal(chr(0x03), $uut->_buffer[5]);
+ $assert->Equal(chr(0x02), $uut->_buffer[6]);
+ $assert->Equal(chr(0x01), $uut->_buffer[7]);
+
+ //Test: ByteBuffer_PutLongCannotPutAtOffsetPastLength
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putLong(2, 0x010203040A0B0C0D);
+ });
+
+ //Test: ByteBuffer_PutLongCannotPutAtOffsetPastLength
+ $buffer = str_repeat("\0", 1);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putLong(0, 0x010203040A0B0C0D);
+ });
+
+
+ //Test: ByteBuffer_PutLongChecksLengthAndOffset
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->putLong(2, 0x010203040A0B0C0D);
+ });
+ }
+
+ //Test: ByteBuffer_GetByteReturnsCorrectData
+ $buffer = str_repeat("\0", 1);
+ $buffer[0] = "\x63";
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal("\x63", $uut->get(0));
+
+ //Test: ByteBuffer_GetByteChecksOffset
+ $buffer = str_repeat("\0", 1);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->get(1);
+ });
+
+ //Test: ByteBuffer_GetShortReturnsCorrectData
+ $buffer = str_repeat("\0", 2);
+ $buffer[0] = chr(0x01);
+ $buffer[1] = chr(0x00);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(1, $uut->getShort(0));
+
+ //Test: ByteBuffer_GetShortReturnsCorrectData (signed value)
+ $buffer = str_repeat("\0", 2);
+ $buffer[0] = chr(0x00);
+ $buffer[1] = chr(0x80);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(-32768, $uut->getShort(0));
+
+ //Test: ByteBuffer_GetShortChecksOffset
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getShort(2);
+ });
+
+ //Test: ByteBuffer_GetShortChecksLength
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getShort(1);
+ });
+
+ //Test: ByteBuffer_GetIntReturnsCorrectData
+ $buffer = str_repeat("\0", 4);
+ $buffer[0] = chr(0x0D);
+ $buffer[1] = chr(0x0C);
+ $buffer[2] = chr(0x0B);
+ $buffer[3] = chr(0x0A);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(0x0A0B0C0D, $uut->getInt(0));
+
+ $buffer = str_repeat("\0", 4);
+ $buffer[0] = chr(0x00);
+ $buffer[1] = chr(0x00);
+ $buffer[2] = chr(0x00);
+ $buffer[3] = chr(0x80);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(-2147483648, $uut->getInt(0));
+
+ //Test: ByteBuffer_GetIntChecksOffset
+ $buffer = str_repeat("\0", 4);
+
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getInt(4);
+ });
+
+ //Test: ByteBuffer_GetIntChecksLength
+ $buffer = str_repeat("\0", 2);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getInt(0);
+ });
+
+ if (PHP_INT_SIZE > 4) {
+ //Test: ByteBuffer_GetLongReturnsCorrectData
+ $buffer = str_repeat("\0", 8);
+ $buffer[0] = chr(0x0D);
+ $buffer[1] = chr(0x0C);
+ $buffer[2] = chr(0x0B);
+ $buffer[3] = chr(0x0A);
+ $buffer[4] = chr(0x04);
+ $buffer[5] = chr(0x03);
+ $buffer[6] = chr(0x02);
+ $buffer[7] = chr(0x01);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(0x010203040A0B0C0D, $uut->getLong(0));
+
+ //Test: Signed Long
+ $buffer = str_repeat("\0", 8);
+ $buffer[0] = chr(0x00);
+ $buffer[1] = chr(0x00);
+ $buffer[2] = chr(0x00);
+ $buffer[3] = chr(0x00);
+ $buffer[4] = chr(0x00);
+ $buffer[5] = chr(0x00);
+ $buffer[6] = chr(0x00);
+ $buffer[7] = chr(0x80);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(-1 << 63, $uut->getLong(0));
+ }
+
+ //Test: ByteBuffer_GetLongChecksOffset
+ $buffer = str_repeat("\0", 8);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getLong(8);
+ });
+
+ //Test: ByteBuffer_GetLongChecksLength
+ $buffer = str_repeat("\0", 7);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Throws(new OutOfRangeException(), function() use ($uut) {
+ $uut->getLong(0);
+ });
+
+ //Test: big endian
+ $buffer = str_repeat("\0", 2);
+ // 0xFF 0x00
+ // Little Endian: 255
+ // Big Endian: 65280
+ $buffer[0] = chr(0xff);
+ $buffer[1] = chr(0x00);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(65280, $uut->readLittleEndian(0, 2, true));
+
+ $buffer = str_repeat("\0", 4);
+ $buffer[0] = chr(0x0D);
+ $buffer[1] = chr(0x0C);
+ $buffer[2] = chr(0x0B);
+ $buffer[3] = chr(0x0A);
+ $uut = Google\FlatBuffers\ByteBuffer::wrap($buffer);
+ $assert->Equal(0x0D0C0B0A, $uut->readLittleEndian(0, 4, true));
+
+}
+
+class Assert {
+ public function ok($result, $message = "") {
+ if (!$result){
+ throw new Exception(!empty($message) ? $message : "{$result} is not true.");
+ }
+ }
+
+ public function Equal($result, $expected, $message = "") {
+ if ($result != $expected) {
+ throw new Exception(!empty($message) ? $message : "given the result {$result} is not equals as {$expected}");
+ }
+ }
+
+
+ public function strictEqual($result, $expected, $message = "") {
+ if ($result !== $expected) {
+ throw new Exception(!empty($message) ? $message : "given the result {$result} is not strict equals as {$expected}");
+ }
+ }
+
+ public function Throws($class, Callable $callback) {
+ try {
+ $callback();
+
+ throw new \Exception("passed statement don't throw an exception.");
+ } catch (\Exception $e) {
+ if (get_class($e) != get_class($class)) {
+ throw new Exception("passed statement doesn't throw " . get_class($class) . ". throwws " . get_class($e));
+ }
+ }
+ }
+}
diff --git a/tests/phpUnionVectorTest.php b/tests/phpUnionVectorTest.php
new file mode 100644
index 0000000..4b5e258
--- /dev/null
+++ b/tests/phpUnionVectorTest.php
@@ -0,0 +1,109 @@
+<?php
+
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Constants.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "ByteBuffer.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "FlatbufferBuilder.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Table.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Struct.php"));
+
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'Attacker.php'));
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'BookReader.php'));
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'Character.php'));
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'Movie.php'));
+
+class Assert {
+ public function ok($result, $message = "") {
+ if (!$result){
+ throw new Exception(!empty($message) ? $message : "{$result} is not true.");
+ }
+ }
+
+ public function Equal($result, $expected, $message = "") {
+ if ($result != $expected) {
+ throw new Exception(!empty($message) ? $message : "given the result {$result} is not equals as {$expected}");
+ }
+ }
+
+
+ public function strictEqual($result, $expected, $message = "") {
+ if ($result !== $expected) {
+ throw new Exception(!empty($message) ? $message : "given the result {$result} is not strict equals as {$expected}");
+ }
+ }
+
+ public function Throws($class, Callable $callback) {
+ try {
+ $callback();
+
+ throw new \Exception("passed statement don't throw an exception.");
+ } catch (\Exception $e) {
+ if (get_class($e) != get_class($class)) {
+ throw new Exception("passed statement doesn't throw " . get_class($class) . ". throwws " . get_class($e));
+ }
+ }
+ }
+}
+
+function main()
+{
+ $assert = new Assert();
+
+ $fbb = new Google\FlatBuffers\FlatBufferBuilder(1);
+
+ $charTypes = [
+ Character::Belle,
+ Character::MuLan,
+ Character::BookFan,
+ ];
+
+ Attacker::startAttacker($fbb);
+ Attacker::addSwordAttackDamage($fbb, 5);
+ $attackerOffset = Attacker::endAttacker($fbb);
+
+ $charTypesOffset = Movie::createCharactersTypeVector($fbb, $charTypes);
+ $charsOffset = Movie::createCharactersVector(
+ $fbb,
+ [
+ BookReader::createBookReader($fbb, 7),
+ $attackerOffset,
+ BookReader::createBookReader($fbb, 2),
+ ]
+ );
+
+ Movie::startMovie($fbb);
+ Movie::addCharactersType($fbb, $charTypesOffset);
+ Movie::addCharacters($fbb, $charsOffset);
+ Movie::finishMovieBuffer($fbb, Movie::endMovie($fbb));
+
+ $buf = Google\FlatBuffers\ByteBuffer::wrap($fbb->dataBuffer()->data());
+
+ $movie = Movie::getRootAsMovie($buf);
+
+ $assert->strictEqual($movie->getCharactersTypeLength(), count($charTypes));
+ $assert->strictEqual($movie->getCharactersLength(), $movie->getCharactersTypeLength());
+
+ for ($i = 0; $i < count($charTypes); ++$i) {
+ $assert->strictEqual($movie->getCharactersType($i), $charTypes[$i]);
+ }
+
+ $bookReader7 = $movie->getCharacters(0, new BookReader());
+ $assert->strictEqual($bookReader7->getBooksRead(), 7);
+
+ $attacker = $movie->getCharacters(1, new Attacker());
+ $assert->strictEqual($attacker->getSwordAttackDamage(), 5);
+
+ $bookReader2 = $movie->getCharacters(2, new BookReader());
+ $assert->strictEqual($bookReader2->getBooksRead(), 2);
+}
+
+try {
+ main();
+ exit(0);
+} catch(Exception $e) {
+ printf("Fatal error: Uncaught exception '%s' with message '%s. in %s:%d\n", get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
+ printf("Stack trace:\n");
+ echo $e->getTraceAsString() . PHP_EOL;
+ printf(" thrown in in %s:%d\n", $e->getFile(), $e->getLine());
+
+ die(-1);
+}
diff --git a/tests/phpUnionVectorTest.sh b/tests/phpUnionVectorTest.sh
new file mode 100755
index 0000000..a6c3f26
--- /dev/null
+++ b/tests/phpUnionVectorTest.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+../flatc --php -o php union_vector/union_vector.fbs
+php phpUnionVectorTest.php
+
+echo 'PHP union vector test passed'
diff --git a/tests/prototest/imported.proto b/tests/prototest/imported.proto
new file mode 100644
index 0000000..5b43e4b
--- /dev/null
+++ b/tests/prototest/imported.proto
@@ -0,0 +1,5 @@
+package proto.test;
+
+message ImportedMessage {
+ optional int32 a = 26;
+}
diff --git a/tests/prototest/test.golden b/tests/prototest/test.golden
new file mode 100644
index 0000000..cf861b9
--- /dev/null
+++ b/tests/prototest/test.golden
@@ -0,0 +1,59 @@
+// Generated from test.proto
+
+namespace proto.test;
+
+/// Enum doc comment.
+enum ProtoEnum : int {
+ NUL = 0,
+ FOO = 1,
+ /// Enum 2nd value doc comment misaligned.
+ BAR = 5,
+}
+
+table ImportedMessage {
+ a:int;
+}
+
+/// 2nd table doc comment with
+/// many lines.
+table ProtoMessage {
+ c:int = 16;
+ d:long;
+ p:uint;
+ e:ulong;
+ /// doc comment for f.
+ f:int = -1;
+ g:long;
+ h:uint;
+ q:ulong;
+ i:int;
+ j:long;
+ /// doc comment for k.
+ k:bool;
+ /// doc comment for l on 2
+ /// lines
+ l:string (required);
+ m:[ubyte];
+ n:proto.test.ProtoMessage_.OtherMessage;
+ o:[string];
+ z:proto.test.ImportedMessage;
+ /// doc comment for r.
+ r:proto.test.ProtoMessage_.Anonymous0;
+}
+
+namespace proto.test.ProtoMessage_;
+
+table OtherMessage {
+ a:double;
+ /// doc comment for b.
+ b:float = 3.14149;
+}
+
+table Anonymous0 {
+ /// doc comment for s.
+ s:proto.test.ImportedMessage;
+ /// doc comment for t on 2
+ /// lines.
+ t:proto.test.ProtoMessage_.OtherMessage;
+}
+
diff --git a/tests/prototest/test.proto b/tests/prototest/test.proto
new file mode 100644
index 0000000..45ce6c0
--- /dev/null
+++ b/tests/prototest/test.proto
@@ -0,0 +1,59 @@
+// Sample .proto file that we can translate to the corresponding .fbs.
+
+option some_option = is_ignored;
+import "imported.proto";
+
+package proto.test;
+
+/// Enum doc comment.
+enum ProtoEnum {
+ option allow_alias = true;
+ NUL = 0;
+ FOO = 1;
+ /// Enum 2nd value doc comment misaligned.
+ BAR = 5;
+ // Aliases
+ FOO_A1 = 1;
+ BAR_A1 = 5;
+ FOO_A2 = 1;
+}
+
+/// 2nd table doc comment with
+/// many lines.
+message ProtoMessage {
+ // Ignored non-doc comment.
+ // A nested message declaration, will be moved to top level in .fbs
+ message OtherMessage {
+ optional double a = 26;
+ /// doc comment for b.
+ optional float b = 32 [default = 3.14149];
+ }
+ optional int32 c = 12 [default = 16];
+ optional int64 d = 1 [default = 0];
+ optional uint32 p = 1;
+ optional uint64 e = 2;
+ /// doc comment for f.
+ optional sint32 f = 3 [default = -1];
+ optional sint64 g = 4;
+ optional fixed32 h = 5;
+ optional fixed64 q = 6;
+ optional sfixed32 i = 7;
+ optional sfixed64 j = 8;
+ /// doc comment for k.
+ optional bool k = 9;
+ /// doc comment for l on 2
+ /// lines
+ required string l = 10;
+ optional bytes m = 11;
+ optional OtherMessage n = 12;
+ repeated string o = 14;
+ optional ImportedMessage z = 16;
+ /// doc comment for r.
+ oneof r {
+ /// doc comment for s.
+ ImportedMessage s = 17;
+ /// doc comment for t on 2
+ /// lines.
+ OtherMessage t = 18;
+ }
+}
diff --git a/tests/prototest/test_union.golden b/tests/prototest/test_union.golden
new file mode 100644
index 0000000..18270eb
--- /dev/null
+++ b/tests/prototest/test_union.golden
@@ -0,0 +1,63 @@
+// Generated from test.proto
+
+namespace proto.test;
+
+/// Enum doc comment.
+enum ProtoEnum : int {
+ NUL = 0,
+ FOO = 1,
+ /// Enum 2nd value doc comment misaligned.
+ BAR = 5,
+}
+
+namespace proto.test.ProtoMessage_;
+
+union RUnion {
+ /// doc comment for s.
+ proto.test.ImportedMessage,
+ /// doc comment for t on 2
+ /// lines.
+ proto.test.ProtoMessage_.OtherMessage,
+}
+
+namespace proto.test;
+
+table ImportedMessage {
+ a:int;
+}
+
+/// 2nd table doc comment with
+/// many lines.
+table ProtoMessage {
+ c:int = 16;
+ d:long;
+ p:uint;
+ e:ulong;
+ /// doc comment for f.
+ f:int = -1;
+ g:long;
+ h:uint;
+ q:ulong;
+ i:int;
+ j:long;
+ /// doc comment for k.
+ k:bool;
+ /// doc comment for l on 2
+ /// lines
+ l:string (required);
+ m:[ubyte];
+ n:proto.test.ProtoMessage_.OtherMessage;
+ o:[string];
+ z:proto.test.ImportedMessage;
+ /// doc comment for r.
+ r:proto.test.ProtoMessage_.RUnion;
+}
+
+namespace proto.test.ProtoMessage_;
+
+table OtherMessage {
+ a:double;
+ /// doc comment for b.
+ b:float = 3.14149;
+}
+
diff --git a/tests/py_test.py b/tests/py_test.py
new file mode 100644
index 0000000..b152270
--- /dev/null
+++ b/tests/py_test.py
@@ -0,0 +1,1817 @@
+# coding=utf-8
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os.path
+import sys
+import imp
+PY_VERSION = sys.version_info[:2]
+
+import ctypes
+from collections import defaultdict
+import math
+import random
+import timeit
+import unittest
+
+from flatbuffers import compat
+from flatbuffers import util
+from flatbuffers.compat import range_func as compat_range
+from flatbuffers.compat import NumpyRequiredForThisFeature
+
+import flatbuffers
+from flatbuffers import number_types as N
+
+import MyGame # refers to generated code
+import MyGame.Example # refers to generated code
+import MyGame.Example.Any # refers to generated code
+import MyGame.Example.Color # refers to generated code
+import MyGame.Example.Monster # refers to generated code
+import MyGame.Example.Test # refers to generated code
+import MyGame.Example.Stat # refers to generated code
+import MyGame.Example.Vec3 # refers to generated code
+import MyGame.MonsterExtra # refers to generated code
+import MyGame.Example.ArrayTable # refers to generated code
+import MyGame.Example.ArrayStruct # refers to generated code
+import MyGame.Example.NestedStruct # refers to generated code
+import MyGame.Example.TestEnum # refers to generated code
+
+def assertRaises(test_case, fn, exception_class):
+ ''' Backwards-compatible assertion for exceptions raised. '''
+
+ exc = None
+ try:
+ fn()
+ except Exception as e:
+ exc = e
+ test_case.assertTrue(exc is not None)
+ test_case.assertTrue(isinstance(exc, exception_class))
+
+
+class TestWireFormat(unittest.TestCase):
+ def test_wire_format(self):
+ # Verify that using the generated Python code builds a buffer without
+ # returning errors, and is interpreted correctly, for size prefixed
+ # representation and regular:
+ for sizePrefix in [True, False]:
+ for file_identifier in [None, b"MONS"]:
+ gen_buf, gen_off = make_monster_from_generated_code(sizePrefix=sizePrefix, file_identifier=file_identifier)
+ CheckReadBuffer(gen_buf, gen_off, sizePrefix=sizePrefix, file_identifier=file_identifier)
+
+ # Verify that the canonical flatbuffer file is readable by the
+ # generated Python code. Note that context managers are not part of
+ # Python 2.5, so we use the simpler open/close methods here:
+ f = open('monsterdata_test.mon', 'rb')
+ canonicalWireData = f.read()
+ f.close()
+ CheckReadBuffer(bytearray(canonicalWireData), 0, file_identifier=b'MONS')
+
+ # Write the generated buffer out to a file:
+ f = open('monsterdata_python_wire.mon', 'wb')
+ f.write(gen_buf[gen_off:])
+ f.close()
+
+
+def CheckReadBuffer(buf, offset, sizePrefix=False, file_identifier=None):
+ ''' CheckReadBuffer checks that the given buffer is evaluated correctly
+ as the example Monster. '''
+
+ def asserter(stmt):
+ ''' An assertion helper that is separated from TestCase classes. '''
+ if not stmt:
+ raise AssertionError('CheckReadBuffer case failed')
+ if file_identifier:
+ # test prior to removal of size_prefix
+ asserter(util.GetBufferIdentifier(buf, offset, size_prefixed=sizePrefix) == file_identifier)
+ asserter(util.BufferHasIdentifier(buf, offset, file_identifier=file_identifier, size_prefixed=sizePrefix))
+ if sizePrefix:
+ size = util.GetSizePrefix(buf, offset)
+ asserter(size == len(buf[offset:])-4)
+ buf, offset = util.RemoveSizePrefix(buf, offset)
+ if file_identifier:
+ asserter(MyGame.Example.Monster.Monster.MonsterBufferHasIdentifier(buf, offset))
+ else:
+ asserter(not MyGame.Example.Monster.Monster.MonsterBufferHasIdentifier(buf, offset))
+ monster = MyGame.Example.Monster.Monster.GetRootAsMonster(buf, offset)
+
+ asserter(monster.Hp() == 80)
+ asserter(monster.Mana() == 150)
+ asserter(monster.Name() == b'MyMonster')
+
+ # initialize a Vec3 from Pos()
+ vec = monster.Pos()
+ asserter(vec is not None)
+
+ # verify the properties of the Vec3
+ asserter(vec.X() == 1.0)
+ asserter(vec.Y() == 2.0)
+ asserter(vec.Z() == 3.0)
+ asserter(vec.Test1() == 3.0)
+ asserter(vec.Test2() == 2)
+
+ # initialize a Test from Test3(...)
+ t = MyGame.Example.Test.Test()
+ t = vec.Test3(t)
+ asserter(t is not None)
+
+ # verify the properties of the Test
+ asserter(t.A() == 5)
+ asserter(t.B() == 6)
+
+ # verify that the enum code matches the enum declaration:
+ union_type = MyGame.Example.Any.Any
+ asserter(monster.TestType() == union_type.Monster)
+
+ # initialize a Table from a union field Test(...)
+ table2 = monster.Test()
+ asserter(type(table2) is flatbuffers.table.Table)
+
+ # initialize a Monster from the Table from the union
+ monster2 = MyGame.Example.Monster.Monster()
+ monster2.Init(table2.Bytes, table2.Pos)
+
+ asserter(monster2.Name() == b"Fred")
+
+ # iterate through the first monster's inventory:
+ asserter(monster.InventoryLength() == 5)
+
+ invsum = 0
+ for i in compat_range(monster.InventoryLength()):
+ v = monster.Inventory(i)
+ invsum += int(v)
+ asserter(invsum == 10)
+
+ for i in range(5):
+ asserter(monster.VectorOfLongs(i) == 10 ** (i * 2))
+
+ asserter(([-1.7976931348623157e+308, 0, 1.7976931348623157e+308]
+ == [monster.VectorOfDoubles(i)
+ for i in range(monster.VectorOfDoublesLength())]))
+
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ asserter(monster.InventoryAsNumpy().sum() == 10)
+ asserter(monster.InventoryAsNumpy().dtype == np.dtype('uint8'))
+
+ VectorOfLongs = monster.VectorOfLongsAsNumpy()
+ asserter(VectorOfLongs.dtype == np.dtype('int64'))
+ for i in range(5):
+ asserter(VectorOfLongs[i] == 10 ** (i * 2))
+
+ VectorOfDoubles = monster.VectorOfDoublesAsNumpy()
+ asserter(VectorOfDoubles.dtype == np.dtype('float64'))
+ asserter(VectorOfDoubles[0] == np.finfo('float64').min)
+ asserter(VectorOfDoubles[1] == 0.0)
+ asserter(VectorOfDoubles[2] == np.finfo('float64').max)
+
+ except ImportError:
+ # If numpy does not exist, trying to get vector as numpy
+ # array should raise NumpyRequiredForThisFeature. The way
+ # assertRaises has been implemented prevents us from
+ # asserting this error is raised outside of a test case.
+ pass
+
+ asserter(monster.Test4Length() == 2)
+
+ # create a 'Test' object and populate it:
+ test0 = monster.Test4(0)
+ asserter(type(test0) is MyGame.Example.Test.Test)
+
+ test1 = monster.Test4(1)
+ asserter(type(test1) is MyGame.Example.Test.Test)
+
+ # the position of test0 and test1 are swapped in monsterdata_java_wire
+ # and monsterdata_test_wire, so ignore ordering
+ v0 = test0.A()
+ v1 = test0.B()
+ v2 = test1.A()
+ v3 = test1.B()
+ sumtest12 = int(v0) + int(v1) + int(v2) + int(v3)
+
+ asserter(sumtest12 == 100)
+
+ asserter(monster.TestarrayofstringLength() == 2)
+ asserter(monster.Testarrayofstring(0) == b"test1")
+ asserter(monster.Testarrayofstring(1) == b"test2")
+
+ asserter(monster.TestarrayoftablesLength() == 0)
+ asserter(monster.TestnestedflatbufferLength() == 0)
+ asserter(monster.Testempty() is None)
+
+
+class TestFuzz(unittest.TestCase):
+ ''' Low level stress/fuzz test: serialize/deserialize a variety of
+ different kinds of data in different combinations '''
+
+ binary_type = compat.binary_types[0] # this will always exist
+ ofInt32Bytes = binary_type([0x83, 0x33, 0x33, 0x33])
+ ofInt64Bytes = binary_type([0x84, 0x44, 0x44, 0x44,
+ 0x44, 0x44, 0x44, 0x44])
+ overflowingInt32Val = flatbuffers.encode.Get(flatbuffers.packer.int32,
+ ofInt32Bytes, 0)
+ overflowingInt64Val = flatbuffers.encode.Get(flatbuffers.packer.int64,
+ ofInt64Bytes, 0)
+
+ # Values we're testing against: chosen to ensure no bits get chopped
+ # off anywhere, and also be different from eachother.
+ boolVal = True
+ int8Val = N.Int8Flags.py_type(-127) # 0x81
+ uint8Val = N.Uint8Flags.py_type(0xFF)
+ int16Val = N.Int16Flags.py_type(-32222) # 0x8222
+ uint16Val = N.Uint16Flags.py_type(0xFEEE)
+ int32Val = N.Int32Flags.py_type(overflowingInt32Val)
+ uint32Val = N.Uint32Flags.py_type(0xFDDDDDDD)
+ int64Val = N.Int64Flags.py_type(overflowingInt64Val)
+ uint64Val = N.Uint64Flags.py_type(0xFCCCCCCCCCCCCCCC)
+ # Python uses doubles, so force it here
+ float32Val = N.Float32Flags.py_type(ctypes.c_float(3.14159).value)
+ float64Val = N.Float64Flags.py_type(3.14159265359)
+
+ def test_fuzz(self):
+ return self.check_once(11, 100)
+
+ def check_once(self, fuzzFields, fuzzObjects):
+ testValuesMax = 11 # hardcoded to the number of scalar types
+
+ builder = flatbuffers.Builder(0)
+ l = LCG()
+
+ objects = [0 for _ in compat_range(fuzzObjects)]
+
+ # Generate fuzzObjects random objects each consisting of
+ # fuzzFields fields, each of a random type.
+ for i in compat_range(fuzzObjects):
+ builder.StartObject(fuzzFields)
+
+ for j in compat_range(fuzzFields):
+ choice = int(l.Next()) % testValuesMax
+ if choice == 0:
+ builder.PrependBoolSlot(int(j), self.boolVal, False)
+ elif choice == 1:
+ builder.PrependInt8Slot(int(j), self.int8Val, 0)
+ elif choice == 2:
+ builder.PrependUint8Slot(int(j), self.uint8Val, 0)
+ elif choice == 3:
+ builder.PrependInt16Slot(int(j), self.int16Val, 0)
+ elif choice == 4:
+ builder.PrependUint16Slot(int(j), self.uint16Val, 0)
+ elif choice == 5:
+ builder.PrependInt32Slot(int(j), self.int32Val, 0)
+ elif choice == 6:
+ builder.PrependUint32Slot(int(j), self.uint32Val, 0)
+ elif choice == 7:
+ builder.PrependInt64Slot(int(j), self.int64Val, 0)
+ elif choice == 8:
+ builder.PrependUint64Slot(int(j), self.uint64Val, 0)
+ elif choice == 9:
+ builder.PrependFloat32Slot(int(j), self.float32Val, 0)
+ elif choice == 10:
+ builder.PrependFloat64Slot(int(j), self.float64Val, 0)
+ else:
+ raise RuntimeError('unreachable')
+
+ off = builder.EndObject()
+
+ # store the offset from the end of the builder buffer,
+ # since it will keep growing:
+ objects[i] = off
+
+ # Do some bookkeeping to generate stats on fuzzes:
+ stats = defaultdict(int)
+ def check(table, desc, want, got):
+ stats[desc] += 1
+ self.assertEqual(want, got, "%s != %s, %s" % (want, got, desc))
+
+ l = LCG() # Reset.
+
+ # Test that all objects we generated are readable and return the
+ # expected values. We generate random objects in the same order
+ # so this is deterministic.
+ for i in compat_range(fuzzObjects):
+
+ table = flatbuffers.table.Table(builder.Bytes,
+ len(builder.Bytes) - objects[i])
+
+ for j in compat_range(fuzzFields):
+ field_count = flatbuffers.builder.VtableMetadataFields + j
+ f = N.VOffsetTFlags.py_type(field_count *
+ N.VOffsetTFlags.bytewidth)
+ choice = int(l.Next()) % testValuesMax
+
+ if choice == 0:
+ check(table, "bool", self.boolVal,
+ table.GetSlot(f, False, N.BoolFlags))
+ elif choice == 1:
+ check(table, "int8", self.int8Val,
+ table.GetSlot(f, 0, N.Int8Flags))
+ elif choice == 2:
+ check(table, "uint8", self.uint8Val,
+ table.GetSlot(f, 0, N.Uint8Flags))
+ elif choice == 3:
+ check(table, "int16", self.int16Val,
+ table.GetSlot(f, 0, N.Int16Flags))
+ elif choice == 4:
+ check(table, "uint16", self.uint16Val,
+ table.GetSlot(f, 0, N.Uint16Flags))
+ elif choice == 5:
+ check(table, "int32", self.int32Val,
+ table.GetSlot(f, 0, N.Int32Flags))
+ elif choice == 6:
+ check(table, "uint32", self.uint32Val,
+ table.GetSlot(f, 0, N.Uint32Flags))
+ elif choice == 7:
+ check(table, "int64", self.int64Val,
+ table.GetSlot(f, 0, N.Int64Flags))
+ elif choice == 8:
+ check(table, "uint64", self.uint64Val,
+ table.GetSlot(f, 0, N.Uint64Flags))
+ elif choice == 9:
+ check(table, "float32", self.float32Val,
+ table.GetSlot(f, 0, N.Float32Flags))
+ elif choice == 10:
+ check(table, "float64", self.float64Val,
+ table.GetSlot(f, 0, N.Float64Flags))
+ else:
+ raise RuntimeError('unreachable')
+
+ # If enough checks were made, verify that all scalar types were used:
+ self.assertEqual(testValuesMax, len(stats),
+ "fuzzing failed to test all scalar types: %s" % stats)
+
+
+class TestByteLayout(unittest.TestCase):
+ ''' TestByteLayout checks the bytes of a Builder in various scenarios. '''
+
+ def assertBuilderEquals(self, builder, want_chars_or_ints):
+ def integerize(x):
+ if isinstance(x, compat.string_types):
+ return ord(x)
+ return x
+
+ want_ints = list(map(integerize, want_chars_or_ints))
+ want = bytearray(want_ints)
+ got = builder.Bytes[builder.Head():] # use the buffer directly
+ self.assertEqual(want, got)
+
+ def test_numbers(self):
+ b = flatbuffers.Builder(0)
+ self.assertBuilderEquals(b, [])
+ b.PrependBool(True)
+ self.assertBuilderEquals(b, [1])
+ b.PrependInt8(-127)
+ self.assertBuilderEquals(b, [129, 1])
+ b.PrependUint8(255)
+ self.assertBuilderEquals(b, [255, 129, 1])
+ b.PrependInt16(-32222)
+ self.assertBuilderEquals(b, [0x22, 0x82, 0, 255, 129, 1]) # first pad
+ b.PrependUint16(0xFEEE)
+ # no pad this time:
+ self.assertBuilderEquals(b, [0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1])
+ b.PrependInt32(-53687092)
+ self.assertBuilderEquals(b, [204, 204, 204, 252, 0xEE, 0xFE,
+ 0x22, 0x82, 0, 255, 129, 1])
+ b.PrependUint32(0x98765432)
+ self.assertBuilderEquals(b, [0x32, 0x54, 0x76, 0x98,
+ 204, 204, 204, 252,
+ 0xEE, 0xFE, 0x22, 0x82,
+ 0, 255, 129, 1])
+
+ def test_numbers64(self):
+ b = flatbuffers.Builder(0)
+ b.PrependUint64(0x1122334455667788)
+ self.assertBuilderEquals(b, [0x88, 0x77, 0x66, 0x55,
+ 0x44, 0x33, 0x22, 0x11])
+
+ b = flatbuffers.Builder(0)
+ b.PrependInt64(0x1122334455667788)
+ self.assertBuilderEquals(b, [0x88, 0x77, 0x66, 0x55,
+ 0x44, 0x33, 0x22, 0x11])
+
+ def test_1xbyte_vector(self):
+ b = flatbuffers.Builder(0)
+ self.assertBuilderEquals(b, [])
+ b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 1, 1)
+ self.assertBuilderEquals(b, [0, 0, 0]) # align to 4bytes
+ b.PrependByte(1)
+ self.assertBuilderEquals(b, [1, 0, 0, 0])
+ b.EndVector(1)
+ self.assertBuilderEquals(b, [1, 0, 0, 0, 1, 0, 0, 0]) # padding
+
+ def test_2xbyte_vector(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 2, 1)
+ self.assertBuilderEquals(b, [0, 0]) # align to 4bytes
+ b.PrependByte(1)
+ self.assertBuilderEquals(b, [1, 0, 0])
+ b.PrependByte(2)
+ self.assertBuilderEquals(b, [2, 1, 0, 0])
+ b.EndVector(2)
+ self.assertBuilderEquals(b, [2, 0, 0, 0, 2, 1, 0, 0]) # padding
+
+ def test_1xuint16_vector(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Uint16Flags.bytewidth, 1, 1)
+ self.assertBuilderEquals(b, [0, 0]) # align to 4bytes
+ b.PrependUint16(1)
+ self.assertBuilderEquals(b, [1, 0, 0, 0])
+ b.EndVector(1)
+ self.assertBuilderEquals(b, [1, 0, 0, 0, 1, 0, 0, 0]) # padding
+
+ def test_2xuint16_vector(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Uint16Flags.bytewidth, 2, 1)
+ self.assertBuilderEquals(b, []) # align to 4bytes
+ b.PrependUint16(0xABCD)
+ self.assertBuilderEquals(b, [0xCD, 0xAB])
+ b.PrependUint16(0xDCBA)
+ self.assertBuilderEquals(b, [0xBA, 0xDC, 0xCD, 0xAB])
+ b.EndVector(2)
+ self.assertBuilderEquals(b, [2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB])
+
+ def test_create_ascii_string(self):
+ b = flatbuffers.Builder(0)
+ b.CreateString(u"foo", encoding='ascii')
+
+ # 0-terminated, no pad:
+ self.assertBuilderEquals(b, [3, 0, 0, 0, 'f', 'o', 'o', 0])
+ b.CreateString(u"moop", encoding='ascii')
+ # 0-terminated, 3-byte pad:
+ self.assertBuilderEquals(b, [4, 0, 0, 0, 'm', 'o', 'o', 'p',
+ 0, 0, 0, 0,
+ 3, 0, 0, 0, 'f', 'o', 'o', 0])
+
+ def test_create_utf8_string(self):
+ b = flatbuffers.Builder(0)
+ b.CreateString(u"Цлїςσδε")
+ self.assertBuilderEquals(b, "\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \
+ "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00")
+
+ b.CreateString(u"フムアムカモケモ")
+ self.assertBuilderEquals(b, "\x18\x00\x00\x00\xef\xbe\x8c\xef\xbe\x91" \
+ "\xef\xbd\xb1\xef\xbe\x91\xef\xbd\xb6\xef\xbe\x93\xef\xbd\xb9\xef" \
+ "\xbe\x93\x00\x00\x00\x00\x0e\x00\x00\x00\xd0\xa6\xd0\xbb\xd1\x97" \
+ "\xcf\x82\xcf\x83\xce\xb4\xce\xb5\x00\x00")
+
+ def test_create_arbitrary_string(self):
+ b = flatbuffers.Builder(0)
+ s = "\x01\x02\x03"
+ b.CreateString(s) # Default encoding is utf-8.
+ # 0-terminated, no pad:
+ self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0])
+ s2 = "\x04\x05\x06\x07"
+ b.CreateString(s2) # Default encoding is utf-8.
+ # 0-terminated, 3-byte pad:
+ self.assertBuilderEquals(b, [4, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0,
+ 3, 0, 0, 0, 1, 2, 3, 0])
+
+ def test_create_byte_vector(self):
+ b = flatbuffers.Builder(0)
+ b.CreateByteVector(b"")
+ # 0-byte pad:
+ self.assertBuilderEquals(b, [0, 0, 0, 0])
+
+ b = flatbuffers.Builder(0)
+ b.CreateByteVector(b"\x01\x02\x03")
+ # 1-byte pad:
+ self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0])
+
+ def test_create_numpy_vector_int8(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Systems endian:
+ b = flatbuffers.Builder(0)
+ x = np.array([1, 2, -3], dtype=np.int8)
+ b.CreateNumpyVector(x)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 2, 256 - 3, 0 # vector value + padding
+ ])
+
+ # Reverse endian:
+ b = flatbuffers.Builder(0)
+ x_other_endian = x.byteswap().newbyteorder()
+ b.CreateNumpyVector(x_other_endian)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 2, 256 - 3, 0 # vector value + padding
+ ])
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_uint16(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Systems endian:
+ b = flatbuffers.Builder(0)
+ x = np.array([1, 2, 312], dtype=np.uint16)
+ b.CreateNumpyVector(x)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 0, # 1
+ 2, 0, # 2
+ 312 - 256, 1, # 312
+ 0, 0 # padding
+ ])
+
+ # Reverse endian:
+ b = flatbuffers.Builder(0)
+ x_other_endian = x.byteswap().newbyteorder()
+ b.CreateNumpyVector(x_other_endian)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 0, # 1
+ 2, 0, # 2
+ 312 - 256, 1, # 312
+ 0, 0 # padding
+ ])
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_int64(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Systems endian:
+ b = flatbuffers.Builder(0)
+ x = np.array([1, 2, -12], dtype=np.int64)
+ b.CreateNumpyVector(x)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 0, 0, 0, 0, 0, 0, 0, # 1
+ 2, 0, 0, 0, 0, 0, 0, 0, # 2
+ 256 - 12, 255, 255, 255, 255, 255, 255, 255 # -12
+ ])
+
+ # Reverse endian:
+ b = flatbuffers.Builder(0)
+ x_other_endian = x.byteswap().newbyteorder()
+ b.CreateNumpyVector(x_other_endian)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 0, 0, 0, 0, 0, 0, 0, # 1
+ 2, 0, 0, 0, 0, 0, 0, 0, # 2
+ 256 - 12, 255, 255, 255, 255, 255, 255, 255 # -12
+ ])
+
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_float32(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Systems endian:
+ b = flatbuffers.Builder(0)
+ x = np.array([1, 2, -12], dtype=np.float32)
+ b.CreateNumpyVector(x)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 0, 0, 128, 63, # 1
+ 0, 0, 0, 64, # 2
+ 0, 0, 64, 193 # -12
+ ])
+
+ # Reverse endian:
+ b = flatbuffers.Builder(0)
+ x_other_endian = x.byteswap().newbyteorder()
+ b.CreateNumpyVector(x_other_endian)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 0, 0, 128, 63, # 1
+ 0, 0, 0, 64, # 2
+ 0, 0, 64, 193 # -12
+ ])
+
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_float64(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Systems endian:
+ b = flatbuffers.Builder(0)
+ x = np.array([1, 2, -12], dtype=np.float64)
+ b.CreateNumpyVector(x)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 0, 0, 0, 0, 0, 0, 240, 63, # 1
+ 0, 0, 0, 0, 0, 0, 0, 64, # 2
+ 0, 0, 0, 0, 0, 0, 40, 192 # -12
+ ])
+
+ # Reverse endian:
+ b = flatbuffers.Builder(0)
+ x_other_endian = x.byteswap().newbyteorder()
+ b.CreateNumpyVector(x_other_endian)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 0, 0, 0, 0, 0, 0, 240, 63, # 1
+ 0, 0, 0, 0, 0, 0, 0, 64, # 2
+ 0, 0, 0, 0, 0, 0, 40, 192 # -12
+ ])
+
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_bool(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Systems endian:
+ b = flatbuffers.Builder(0)
+ x = np.array([True, False, True], dtype=np.bool)
+ b.CreateNumpyVector(x)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 0, 1, 0 # vector values + padding
+ ])
+
+ # Reverse endian:
+ b = flatbuffers.Builder(0)
+ x_other_endian = x.byteswap().newbyteorder()
+ b.CreateNumpyVector(x_other_endian)
+ self.assertBuilderEquals(b, [
+ 3, 0, 0, 0, # vector length
+ 1, 0, 1, 0 # vector values + padding
+ ])
+
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_reject_strings(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Create String array
+ b = flatbuffers.Builder(0)
+ x = np.array(["hello", "fb", "testing"])
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ TypeError)
+
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_create_numpy_vector_reject_object(self):
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ import numpy as np
+
+ # Create String array
+ b = flatbuffers.Builder(0)
+ x = np.array([{"m": 0}, {"as": -2.1, 'c': 'c'}])
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ TypeError)
+
+ except ImportError:
+ b = flatbuffers.Builder(0)
+ x = 0
+ assertRaises(
+ self,
+ lambda: b.CreateNumpyVector(x),
+ NumpyRequiredForThisFeature)
+
+ def test_empty_vtable(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(0)
+ self.assertBuilderEquals(b, [])
+ b.EndObject()
+ self.assertBuilderEquals(b, [4, 0, 4, 0, 4, 0, 0, 0])
+
+ def test_vtable_with_one_true_bool(self):
+ b = flatbuffers.Builder(0)
+ self.assertBuilderEquals(b, [])
+ b.StartObject(1)
+ self.assertBuilderEquals(b, [])
+ b.PrependBoolSlot(0, True, False)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 6, 0, # vtable bytes
+ 8, 0, # length of object including vtable offset
+ 7, 0, # start of bool value
+ 6, 0, 0, 0, # offset for start of vtable (int32)
+ 0, 0, 0, # padded to 4 bytes
+ 1, # bool value
+ ])
+
+ def test_vtable_with_one_default_bool(self):
+ b = flatbuffers.Builder(0)
+ self.assertBuilderEquals(b, [])
+ b.StartObject(1)
+ self.assertBuilderEquals(b, [])
+ b.PrependBoolSlot(0, False, False)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 4, 0, # vtable bytes
+ 4, 0, # end of object from here
+ # entry 1 is zero and not stored
+ 4, 0, 0, 0, # offset for start of vtable (int32)
+ ])
+
+ def test_vtable_with_one_int16(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(1)
+ b.PrependInt16Slot(0, 0x789A, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 6, 0, # vtable bytes
+ 8, 0, # end of object from here
+ 6, 0, # offset to value
+ 6, 0, 0, 0, # offset for start of vtable (int32)
+ 0, 0, # padding to 4 bytes
+ 0x9A, 0x78,
+ ])
+
+ def test_vtable_with_two_int16(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(2)
+ b.PrependInt16Slot(0, 0x3456, 0)
+ b.PrependInt16Slot(1, 0x789A, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 8, 0, # vtable bytes
+ 8, 0, # end of object from here
+ 6, 0, # offset to value 0
+ 4, 0, # offset to value 1
+ 8, 0, 0, 0, # offset for start of vtable (int32)
+ 0x9A, 0x78, # value 1
+ 0x56, 0x34, # value 0
+ ])
+
+ def test_vtable_with_int16_and_bool(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(2)
+ b.PrependInt16Slot(0, 0x3456, 0)
+ b.PrependBoolSlot(1, True, False)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 8, 0, # vtable bytes
+ 8, 0, # end of object from here
+ 6, 0, # offset to value 0
+ 5, 0, # offset to value 1
+ 8, 0, 0, 0, # offset for start of vtable (int32)
+ 0, # padding
+ 1, # value 1
+ 0x56, 0x34, # value 0
+ ])
+
+ def test_vtable_with_empty_vector(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 0, 1)
+ vecend = b.EndVector(0)
+ b.StartObject(1)
+ b.PrependUOffsetTRelativeSlot(0, vecend, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 6, 0, # vtable bytes
+ 8, 0,
+ 4, 0, # offset to vector offset
+ 6, 0, 0, 0, # offset for start of vtable (int32)
+ 4, 0, 0, 0,
+ 0, 0, 0, 0, # length of vector (not in struct)
+ ])
+
+ def test_vtable_with_empty_vector_of_byte_and_some_scalars(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Uint8Flags.bytewidth, 0, 1)
+ vecend = b.EndVector(0)
+ b.StartObject(2)
+ b.PrependInt16Slot(0, 55, 0)
+ b.PrependUOffsetTRelativeSlot(1, vecend, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 8, 0, # vtable bytes
+ 12, 0,
+ 10, 0, # offset to value 0
+ 4, 0, # offset to vector offset
+ 8, 0, 0, 0, # vtable loc
+ 8, 0, 0, 0, # value 1
+ 0, 0, 55, 0, # value 0
+
+ 0, 0, 0, 0, # length of vector (not in struct)
+ ])
+
+ def test_vtable_with_1_int16_and_2vector_of_int16(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Int16Flags.bytewidth, 2, 1)
+ b.PrependInt16(0x1234)
+ b.PrependInt16(0x5678)
+ vecend = b.EndVector(2)
+ b.StartObject(2)
+ b.PrependUOffsetTRelativeSlot(1, vecend, 0)
+ b.PrependInt16Slot(0, 55, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 8, 0, # vtable bytes
+ 12, 0, # length of object
+ 6, 0, # start of value 0 from end of vtable
+ 8, 0, # start of value 1 from end of buffer
+ 8, 0, 0, 0, # offset for start of vtable (int32)
+ 0, 0, # padding
+ 55, 0, # value 0
+ 4, 0, 0, 0, # vector position from here
+ 2, 0, 0, 0, # length of vector (uint32)
+ 0x78, 0x56, # vector value 1
+ 0x34, 0x12, # vector value 0
+ ])
+
+ def test_vtable_with_1_struct_of_1_int8__1_int16__1_int32(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(1)
+ b.Prep(4+4+4, 0)
+ b.PrependInt8(55)
+ b.Pad(3)
+ b.PrependInt16(0x1234)
+ b.Pad(2)
+ b.PrependInt32(0x12345678)
+ structStart = b.Offset()
+ b.PrependStructSlot(0, structStart, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 6, 0, # vtable bytes
+ 16, 0, # end of object from here
+ 4, 0, # start of struct from here
+ 6, 0, 0, 0, # offset for start of vtable (int32)
+ 0x78, 0x56, 0x34, 0x12, # value 2
+ 0, 0, # padding
+ 0x34, 0x12, # value 1
+ 0, 0, 0, # padding
+ 55, # value 0
+ ])
+
+ def test_vtable_with_1_vector_of_2_struct_of_2_int8(self):
+ b = flatbuffers.Builder(0)
+ b.StartVector(flatbuffers.number_types.Int8Flags.bytewidth*2, 2, 1)
+ b.PrependInt8(33)
+ b.PrependInt8(44)
+ b.PrependInt8(55)
+ b.PrependInt8(66)
+ vecend = b.EndVector(2)
+ b.StartObject(1)
+ b.PrependUOffsetTRelativeSlot(0, vecend, 0)
+ b.EndObject()
+ self.assertBuilderEquals(b, [
+ 6, 0, # vtable bytes
+ 8, 0,
+ 4, 0, # offset of vector offset
+ 6, 0, 0, 0, # offset for start of vtable (int32)
+ 4, 0, 0, 0, # vector start offset
+
+ 2, 0, 0, 0, # vector length
+ 66, # vector value 1,1
+ 55, # vector value 1,0
+ 44, # vector value 0,1
+ 33, # vector value 0,0
+ ])
+
+ def test_table_with_some_elements(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(2)
+ b.PrependInt8Slot(0, 33, 0)
+ b.PrependInt16Slot(1, 66, 0)
+ off = b.EndObject()
+ b.Finish(off)
+
+ self.assertBuilderEquals(b, [
+ 12, 0, 0, 0, # root of table: points to vtable offset
+
+ 8, 0, # vtable bytes
+ 8, 0, # end of object from here
+ 7, 0, # start of value 0
+ 4, 0, # start of value 1
+
+ 8, 0, 0, 0, # offset for start of vtable (int32)
+
+ 66, 0, # value 1
+ 0, # padding
+ 33, # value 0
+ ])
+
+ def test__one_unfinished_table_and_one_finished_table(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(2)
+ b.PrependInt8Slot(0, 33, 0)
+ b.PrependInt8Slot(1, 44, 0)
+ off = b.EndObject()
+ b.Finish(off)
+
+ b.StartObject(3)
+ b.PrependInt8Slot(0, 55, 0)
+ b.PrependInt8Slot(1, 66, 0)
+ b.PrependInt8Slot(2, 77, 0)
+ off = b.EndObject()
+ b.Finish(off)
+
+ self.assertBuilderEquals(b, [
+ 16, 0, 0, 0, # root of table: points to object
+ 0, 0, # padding
+
+ 10, 0, # vtable bytes
+ 8, 0, # size of object
+ 7, 0, # start of value 0
+ 6, 0, # start of value 1
+ 5, 0, # start of value 2
+ 10, 0, 0, 0, # offset for start of vtable (int32)
+ 0, # padding
+ 77, # value 2
+ 66, # value 1
+ 55, # value 0
+
+ 12, 0, 0, 0, # root of table: points to object
+
+ 8, 0, # vtable bytes
+ 8, 0, # size of object
+ 7, 0, # start of value 0
+ 6, 0, # start of value 1
+ 8, 0, 0, 0, # offset for start of vtable (int32)
+ 0, 0, # padding
+ 44, # value 1
+ 33, # value 0
+ ])
+
+ def test_a_bunch_of_bools(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(8)
+ b.PrependBoolSlot(0, True, False)
+ b.PrependBoolSlot(1, True, False)
+ b.PrependBoolSlot(2, True, False)
+ b.PrependBoolSlot(3, True, False)
+ b.PrependBoolSlot(4, True, False)
+ b.PrependBoolSlot(5, True, False)
+ b.PrependBoolSlot(6, True, False)
+ b.PrependBoolSlot(7, True, False)
+ off = b.EndObject()
+ b.Finish(off)
+
+ self.assertBuilderEquals(b, [
+ 24, 0, 0, 0, # root of table: points to vtable offset
+
+ 20, 0, # vtable bytes
+ 12, 0, # size of object
+ 11, 0, # start of value 0
+ 10, 0, # start of value 1
+ 9, 0, # start of value 2
+ 8, 0, # start of value 3
+ 7, 0, # start of value 4
+ 6, 0, # start of value 5
+ 5, 0, # start of value 6
+ 4, 0, # start of value 7
+ 20, 0, 0, 0, # vtable offset
+
+ 1, # value 7
+ 1, # value 6
+ 1, # value 5
+ 1, # value 4
+ 1, # value 3
+ 1, # value 2
+ 1, # value 1
+ 1, # value 0
+ ])
+
+ def test_three_bools(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(3)
+ b.PrependBoolSlot(0, True, False)
+ b.PrependBoolSlot(1, True, False)
+ b.PrependBoolSlot(2, True, False)
+ off = b.EndObject()
+ b.Finish(off)
+
+ self.assertBuilderEquals(b, [
+ 16, 0, 0, 0, # root of table: points to vtable offset
+
+ 0, 0, # padding
+
+ 10, 0, # vtable bytes
+ 8, 0, # size of object
+ 7, 0, # start of value 0
+ 6, 0, # start of value 1
+ 5, 0, # start of value 2
+ 10, 0, 0, 0, # vtable offset from here
+
+ 0, # padding
+ 1, # value 2
+ 1, # value 1
+ 1, # value 0
+ ])
+
+ def test_some_floats(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(1)
+ b.PrependFloat32Slot(0, 1.0, 0.0)
+ off = b.EndObject()
+
+ self.assertBuilderEquals(b, [
+ 6, 0, # vtable bytes
+ 8, 0, # size of object
+ 4, 0, # start of value 0
+ 6, 0, 0, 0, # vtable offset
+
+ 0, 0, 128, 63, # value 0
+ ])
+
+
+def make_monster_from_generated_code(sizePrefix = False, file_identifier=None):
+ ''' Use generated code to build the example Monster. '''
+
+ b = flatbuffers.Builder(0)
+ string = b.CreateString("MyMonster")
+ test1 = b.CreateString("test1")
+ test2 = b.CreateString("test2")
+ fred = b.CreateString("Fred")
+
+ MyGame.Example.Monster.MonsterStartInventoryVector(b, 5)
+ b.PrependByte(4)
+ b.PrependByte(3)
+ b.PrependByte(2)
+ b.PrependByte(1)
+ b.PrependByte(0)
+ inv = b.EndVector(5)
+
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddName(b, fred)
+ mon2 = MyGame.Example.Monster.MonsterEnd(b)
+
+ MyGame.Example.Monster.MonsterStartTest4Vector(b, 2)
+ MyGame.Example.Test.CreateTest(b, 10, 20)
+ MyGame.Example.Test.CreateTest(b, 30, 40)
+ test4 = b.EndVector(2)
+
+ MyGame.Example.Monster.MonsterStartTestarrayofstringVector(b, 2)
+ b.PrependUOffsetTRelative(test2)
+ b.PrependUOffsetTRelative(test1)
+ testArrayOfString = b.EndVector(2)
+
+ MyGame.Example.Monster.MonsterStartVectorOfLongsVector(b, 5)
+ b.PrependInt64(100000000)
+ b.PrependInt64(1000000)
+ b.PrependInt64(10000)
+ b.PrependInt64(100)
+ b.PrependInt64(1)
+ VectorOfLongs = b.EndVector(5)
+
+ MyGame.Example.Monster.MonsterStartVectorOfDoublesVector(b, 3)
+ b.PrependFloat64(1.7976931348623157e+308)
+ b.PrependFloat64(0)
+ b.PrependFloat64(-1.7976931348623157e+308)
+ VectorOfDoubles = b.EndVector(3)
+
+ MyGame.Example.Monster.MonsterStart(b)
+
+ pos = MyGame.Example.Vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
+ MyGame.Example.Monster.MonsterAddPos(b, pos)
+
+ MyGame.Example.Monster.MonsterAddHp(b, 80)
+ MyGame.Example.Monster.MonsterAddName(b, string)
+ MyGame.Example.Monster.MonsterAddInventory(b, inv)
+ MyGame.Example.Monster.MonsterAddTestType(b, 1)
+ MyGame.Example.Monster.MonsterAddTest(b, mon2)
+ MyGame.Example.Monster.MonsterAddTest4(b, test4)
+ MyGame.Example.Monster.MonsterAddTestarrayofstring(b, testArrayOfString)
+ MyGame.Example.Monster.MonsterAddVectorOfLongs(b, VectorOfLongs)
+ MyGame.Example.Monster.MonsterAddVectorOfDoubles(b, VectorOfDoubles)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+
+ if sizePrefix:
+ b.FinishSizePrefixed(mon, file_identifier)
+ else:
+ b.Finish(mon, file_identifier)
+
+ return b.Bytes, b.Head()
+
+
+class TestAllCodePathsOfExampleSchema(unittest.TestCase):
+ def setUp(self, *args, **kwargs):
+ super(TestAllCodePathsOfExampleSchema, self).setUp(*args, **kwargs)
+
+ b = flatbuffers.Builder(0)
+ MyGame.Example.Monster.MonsterStart(b)
+ gen_mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(gen_mon)
+
+ self.mon = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+
+ def test_default_monster_pos(self):
+ self.assertTrue(self.mon.Pos() is None)
+
+ def test_nondefault_monster_mana(self):
+ b = flatbuffers.Builder(0)
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddMana(b, 50)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ got_mon = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertEqual(50, got_mon.Mana())
+
+ def test_default_monster_hp(self):
+ self.assertEqual(100, self.mon.Hp())
+
+ def test_default_monster_name(self):
+ self.assertEqual(None, self.mon.Name())
+
+ def test_default_monster_inventory_item(self):
+ self.assertEqual(0, self.mon.Inventory(0))
+
+ def test_default_monster_inventory_length(self):
+ self.assertEqual(0, self.mon.InventoryLength())
+
+ def test_default_monster_color(self):
+ self.assertEqual(MyGame.Example.Color.Color.Blue, self.mon.Color())
+
+ def test_nondefault_monster_color(self):
+ b = flatbuffers.Builder(0)
+ color = MyGame.Example.Color.Color.Red
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddColor(b, color)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertEqual(MyGame.Example.Color.Color.Red, mon2.Color())
+
+ def test_default_monster_testtype(self):
+ self.assertEqual(0, self.mon.TestType())
+
+ def test_default_monster_test_field(self):
+ self.assertEqual(None, self.mon.Test())
+
+ def test_default_monster_test4_item(self):
+ self.assertEqual(None, self.mon.Test4(0))
+
+ def test_default_monster_test4_length(self):
+ self.assertEqual(0, self.mon.Test4Length())
+
+ def test_default_monster_testarrayofstring(self):
+ self.assertEqual("", self.mon.Testarrayofstring(0))
+
+ def test_default_monster_testarrayofstring_length(self):
+ self.assertEqual(0, self.mon.TestarrayofstringLength())
+
+ def test_default_monster_testarrayoftables(self):
+ self.assertEqual(None, self.mon.Testarrayoftables(0))
+
+ def test_nondefault_monster_testarrayoftables(self):
+ b = flatbuffers.Builder(0)
+
+ # make a child Monster within a vector of Monsters:
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddHp(b, 99)
+ sub_monster = MyGame.Example.Monster.MonsterEnd(b)
+
+ # build the vector:
+ MyGame.Example.Monster.MonsterStartTestarrayoftablesVector(b, 1)
+ b.PrependUOffsetTRelative(sub_monster)
+ vec = b.EndVector(1)
+
+ # make the parent monster and include the vector of Monster:
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddTestarrayoftables(b, vec)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ # inspect the resulting data:
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Output(), 0)
+ self.assertEqual(99, mon2.Testarrayoftables(0).Hp())
+ self.assertEqual(1, mon2.TestarrayoftablesLength())
+
+ def test_default_monster_testarrayoftables_length(self):
+ self.assertEqual(0, self.mon.TestarrayoftablesLength())
+
+ def test_nondefault_monster_enemy(self):
+ b = flatbuffers.Builder(0)
+
+ # make an Enemy object:
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddHp(b, 88)
+ enemy = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(enemy)
+
+ # make the parent monster and include the vector of Monster:
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddEnemy(b, enemy)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ # inspect the resulting data:
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertEqual(88, mon2.Enemy().Hp())
+
+ def test_default_monster_testnestedflatbuffer(self):
+ self.assertEqual(0, self.mon.Testnestedflatbuffer(0))
+
+ def test_default_monster_testnestedflatbuffer_length(self):
+ self.assertEqual(0, self.mon.TestnestedflatbufferLength())
+
+ def test_nondefault_monster_testnestedflatbuffer(self):
+ b = flatbuffers.Builder(0)
+
+ MyGame.Example.Monster.MonsterStartTestnestedflatbufferVector(b, 3)
+ b.PrependByte(4)
+ b.PrependByte(2)
+ b.PrependByte(0)
+ sub_buf = b.EndVector(3)
+
+ # make the parent monster and include the vector of Monster:
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddTestnestedflatbuffer(b, sub_buf)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ # inspect the resulting data:
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertEqual(3, mon2.TestnestedflatbufferLength())
+ self.assertEqual(0, mon2.Testnestedflatbuffer(0))
+ self.assertEqual(2, mon2.Testnestedflatbuffer(1))
+ self.assertEqual(4, mon2.Testnestedflatbuffer(2))
+ try:
+ imp.find_module('numpy')
+ # if numpy exists, then we should be able to get the
+ # vector as a numpy array
+ self.assertEqual([0, 2, 4], mon2.TestnestedflatbufferAsNumpy().tolist())
+ except ImportError:
+ assertRaises(self,
+ lambda: mon2.TestnestedflatbufferAsNumpy(),
+ NumpyRequiredForThisFeature)
+
+ def test_nondefault_monster_testempty(self):
+ b = flatbuffers.Builder(0)
+
+ # make a Stat object:
+ MyGame.Example.Stat.StatStart(b)
+ MyGame.Example.Stat.StatAddVal(b, 123)
+ my_stat = MyGame.Example.Stat.StatEnd(b)
+ b.Finish(my_stat)
+
+ # include the stat object in a monster:
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddTestempty(b, my_stat)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ # inspect the resulting data:
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertEqual(123, mon2.Testempty().Val())
+
+ def test_default_monster_testbool(self):
+ self.assertFalse(self.mon.Testbool())
+
+ def test_nondefault_monster_testbool(self):
+ b = flatbuffers.Builder(0)
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddTestbool(b, True)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ # inspect the resulting data:
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertTrue(mon2.Testbool())
+
+ def test_default_monster_testhashes(self):
+ self.assertEqual(0, self.mon.Testhashs32Fnv1())
+ self.assertEqual(0, self.mon.Testhashu32Fnv1())
+ self.assertEqual(0, self.mon.Testhashs64Fnv1())
+ self.assertEqual(0, self.mon.Testhashu64Fnv1())
+ self.assertEqual(0, self.mon.Testhashs32Fnv1a())
+ self.assertEqual(0, self.mon.Testhashu32Fnv1a())
+ self.assertEqual(0, self.mon.Testhashs64Fnv1a())
+ self.assertEqual(0, self.mon.Testhashu64Fnv1a())
+
+ def test_nondefault_monster_testhashes(self):
+ b = flatbuffers.Builder(0)
+ MyGame.Example.Monster.MonsterStart(b)
+ MyGame.Example.Monster.MonsterAddTesthashs32Fnv1(b, 1)
+ MyGame.Example.Monster.MonsterAddTesthashu32Fnv1(b, 2)
+ MyGame.Example.Monster.MonsterAddTesthashs64Fnv1(b, 3)
+ MyGame.Example.Monster.MonsterAddTesthashu64Fnv1(b, 4)
+ MyGame.Example.Monster.MonsterAddTesthashs32Fnv1a(b, 5)
+ MyGame.Example.Monster.MonsterAddTesthashu32Fnv1a(b, 6)
+ MyGame.Example.Monster.MonsterAddTesthashs64Fnv1a(b, 7)
+ MyGame.Example.Monster.MonsterAddTesthashu64Fnv1a(b, 8)
+ mon = MyGame.Example.Monster.MonsterEnd(b)
+ b.Finish(mon)
+
+ # inspect the resulting data:
+ mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
+ b.Head())
+ self.assertEqual(1, mon2.Testhashs32Fnv1())
+ self.assertEqual(2, mon2.Testhashu32Fnv1())
+ self.assertEqual(3, mon2.Testhashs64Fnv1())
+ self.assertEqual(4, mon2.Testhashu64Fnv1())
+ self.assertEqual(5, mon2.Testhashs32Fnv1a())
+ self.assertEqual(6, mon2.Testhashu32Fnv1a())
+ self.assertEqual(7, mon2.Testhashs64Fnv1a())
+ self.assertEqual(8, mon2.Testhashu64Fnv1a())
+
+ def test_getrootas_for_nonroot_table(self):
+ b = flatbuffers.Builder(0)
+ string = b.CreateString("MyStat")
+
+ MyGame.Example.Stat.StatStart(b)
+ MyGame.Example.Stat.StatAddId(b, string)
+ MyGame.Example.Stat.StatAddVal(b, 12345678)
+ MyGame.Example.Stat.StatAddCount(b, 12345)
+ stat = MyGame.Example.Stat.StatEnd(b)
+ b.Finish(stat)
+
+ stat2 = MyGame.Example.Stat.Stat.GetRootAsStat(b.Bytes, b.Head())
+
+ self.assertEqual(b"MyStat", stat2.Id())
+ self.assertEqual(12345678, stat2.Val())
+ self.assertEqual(12345, stat2.Count())
+
+
+class TestAllCodePathsOfMonsterExtraSchema(unittest.TestCase):
+ def setUp(self, *args, **kwargs):
+ super(TestAllCodePathsOfMonsterExtraSchema, self).setUp(*args, **kwargs)
+
+ b = flatbuffers.Builder(0)
+ MyGame.MonsterExtra.MonsterExtraStart(b)
+ gen_mon = MyGame.MonsterExtra.MonsterExtraEnd(b)
+ b.Finish(gen_mon)
+
+ self.mon = MyGame.MonsterExtra.MonsterExtra.GetRootAsMonsterExtra(b.Bytes, b.Head())
+
+ def test_default_nan_inf(self):
+ self.assertTrue(math.isnan(self.mon.F1()))
+ self.assertEqual(self.mon.F2(), float("inf"))
+ self.assertEqual(self.mon.F3(), float("-inf"))
+
+ self.assertTrue(math.isnan(self.mon.D1()))
+ self.assertEqual(self.mon.D2(), float("inf"))
+ self.assertEqual(self.mon.D3(), float("-inf"))
+
+
+class TestVtableDeduplication(unittest.TestCase):
+ ''' TestVtableDeduplication verifies that vtables are deduplicated. '''
+
+ def test_vtable_deduplication(self):
+ b = flatbuffers.Builder(0)
+
+ b.StartObject(4)
+ b.PrependByteSlot(0, 0, 0)
+ b.PrependByteSlot(1, 11, 0)
+ b.PrependByteSlot(2, 22, 0)
+ b.PrependInt16Slot(3, 33, 0)
+ obj0 = b.EndObject()
+
+ b.StartObject(4)
+ b.PrependByteSlot(0, 0, 0)
+ b.PrependByteSlot(1, 44, 0)
+ b.PrependByteSlot(2, 55, 0)
+ b.PrependInt16Slot(3, 66, 0)
+ obj1 = b.EndObject()
+
+ b.StartObject(4)
+ b.PrependByteSlot(0, 0, 0)
+ b.PrependByteSlot(1, 77, 0)
+ b.PrependByteSlot(2, 88, 0)
+ b.PrependInt16Slot(3, 99, 0)
+ obj2 = b.EndObject()
+
+ got = b.Bytes[b.Head():]
+
+ want = bytearray([
+ 240, 255, 255, 255, # == -12. offset to dedupped vtable.
+ 99, 0,
+ 88,
+ 77,
+ 248, 255, 255, 255, # == -8. offset to dedupped vtable.
+ 66, 0,
+ 55,
+ 44,
+ 12, 0,
+ 8, 0,
+ 0, 0,
+ 7, 0,
+ 6, 0,
+ 4, 0,
+ 12, 0, 0, 0,
+ 33, 0,
+ 22,
+ 11,
+ ])
+
+ self.assertEqual((len(want), want), (len(got), got))
+
+ table0 = flatbuffers.table.Table(b.Bytes, len(b.Bytes) - obj0)
+ table1 = flatbuffers.table.Table(b.Bytes, len(b.Bytes) - obj1)
+ table2 = flatbuffers.table.Table(b.Bytes, len(b.Bytes) - obj2)
+
+ def _checkTable(tab, voffsett_value, b, c, d):
+ # vtable size
+ got = tab.GetVOffsetTSlot(0, 0)
+ self.assertEqual(12, got, 'case 0, 0')
+
+ # object size
+ got = tab.GetVOffsetTSlot(2, 0)
+ self.assertEqual(8, got, 'case 2, 0')
+
+ # default value
+ got = tab.GetVOffsetTSlot(4, 0)
+ self.assertEqual(voffsett_value, got, 'case 4, 0')
+
+ got = tab.GetSlot(6, 0, N.Uint8Flags)
+ self.assertEqual(b, got, 'case 6, 0')
+
+ val = tab.GetSlot(8, 0, N.Uint8Flags)
+ self.assertEqual(c, val, 'failed 8, 0')
+
+ got = tab.GetSlot(10, 0, N.Uint8Flags)
+ self.assertEqual(d, got, 'failed 10, 0')
+
+ _checkTable(table0, 0, 11, 22, 33)
+ _checkTable(table1, 0, 44, 55, 66)
+ _checkTable(table2, 0, 77, 88, 99)
+
+
+class TestExceptions(unittest.TestCase):
+ def test_object_is_nested_error(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(0)
+ assertRaises(self, lambda: b.StartObject(0),
+ flatbuffers.builder.IsNestedError)
+
+ def test_object_is_not_nested_error(self):
+ b = flatbuffers.Builder(0)
+ assertRaises(self, lambda: b.EndObject(),
+ flatbuffers.builder.IsNotNestedError)
+
+ def test_struct_is_not_inline_error(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(0)
+ assertRaises(self, lambda: b.PrependStructSlot(0, 1, 0),
+ flatbuffers.builder.StructIsNotInlineError)
+
+ def test_unreachable_error(self):
+ b = flatbuffers.Builder(0)
+ assertRaises(self, lambda: b.PrependUOffsetTRelative(1),
+ flatbuffers.builder.OffsetArithmeticError)
+
+ def test_create_string_is_nested_error(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(0)
+ s = 'test1'
+ assertRaises(self, lambda: b.CreateString(s),
+ flatbuffers.builder.IsNestedError)
+
+ def test_create_byte_vector_is_nested_error(self):
+ b = flatbuffers.Builder(0)
+ b.StartObject(0)
+ s = b'test1'
+ assertRaises(self, lambda: b.CreateByteVector(s),
+ flatbuffers.builder.IsNestedError)
+
+ def test_finished_bytes_error(self):
+ b = flatbuffers.Builder(0)
+ assertRaises(self, lambda: b.Output(),
+ flatbuffers.builder.BuilderNotFinishedError)
+
+
+class TestFixedLengthArrays(unittest.TestCase):
+ def test_fixed_length_array(self):
+ builder = flatbuffers.Builder(0)
+
+ a = 0.5
+ b = range(0, 15)
+ c = 1
+ d_a = [[1, 2], [3, 4]]
+ d_b = [MyGame.Example.TestEnum.TestEnum.B, \
+ MyGame.Example.TestEnum.TestEnum.C]
+ d_c = [[MyGame.Example.TestEnum.TestEnum.A, \
+ MyGame.Example.TestEnum.TestEnum.B], \
+ [MyGame.Example.TestEnum.TestEnum.C, \
+ MyGame.Example.TestEnum.TestEnum.B]]
+
+ arrayOffset = MyGame.Example.ArrayStruct.CreateArrayStruct(builder, \
+ a, b, c, d_a, d_b, d_c)
+
+ # Create a table with the ArrayStruct.
+ MyGame.Example.ArrayTable.ArrayTableStart(builder)
+ MyGame.Example.ArrayTable.ArrayTableAddA(builder, arrayOffset)
+ tableOffset = MyGame.Example.ArrayTable.ArrayTableEnd(builder)
+
+ builder.Finish(tableOffset)
+
+ buf = builder.Output()
+
+ table = MyGame.Example.ArrayTable.ArrayTable.GetRootAsArrayTable(buf, 0)
+
+ # Verify structure.
+ nested = MyGame.Example.NestedStruct.NestedStruct()
+ self.assertEqual(table.A().A(), 0.5)
+ self.assertEqual(table.A().B(), \
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
+ self.assertEqual(table.A().C(), 1)
+ self.assertEqual(table.A().D(nested, 0).A(), [1, 2])
+ self.assertEqual(table.A().D(nested, 1).A(), [3, 4])
+ self.assertEqual(table.A().D(nested, 0).B(), \
+ MyGame.Example.TestEnum.TestEnum.B)
+ self.assertEqual(table.A().D(nested, 1).B(), \
+ MyGame.Example.TestEnum.TestEnum.C)
+ self.assertEqual(table.A().D(nested, 0).C(), \
+ [MyGame.Example.TestEnum.TestEnum.A, \
+ MyGame.Example.TestEnum.TestEnum.B])
+ self.assertEqual(table.A().D(nested, 1).C(), \
+ [MyGame.Example.TestEnum.TestEnum.C, \
+ MyGame.Example.TestEnum.TestEnum.B])
+
+
+def CheckAgainstGoldDataGo():
+ try:
+ gen_buf, gen_off = make_monster_from_generated_code()
+ fn = 'monsterdata_go_wire.mon'
+ if not os.path.exists(fn):
+ print('Go-generated data does not exist, failed.')
+ return False
+
+ # would like to use a context manager here, but it's less
+ # backwards-compatible:
+ f = open(fn, 'rb')
+ go_wire_data = f.read()
+ f.close()
+
+ CheckReadBuffer(bytearray(go_wire_data), 0)
+ if not bytearray(gen_buf[gen_off:]) == bytearray(go_wire_data):
+ raise AssertionError('CheckAgainstGoldDataGo failed')
+ except:
+ print('Failed to test against Go-generated test data.')
+ return False
+
+ print('Can read Go-generated test data, and Python generates bytewise identical data.')
+ return True
+
+
+def CheckAgainstGoldDataJava():
+ try:
+ gen_buf, gen_off = make_monster_from_generated_code()
+ fn = 'monsterdata_java_wire.mon'
+ if not os.path.exists(fn):
+ print('Java-generated data does not exist, failed.')
+ return False
+ f = open(fn, 'rb')
+ java_wire_data = f.read()
+ f.close()
+
+ CheckReadBuffer(bytearray(java_wire_data), 0)
+ except:
+ print('Failed to read Java-generated test data.')
+ return False
+
+ print('Can read Java-generated test data.')
+ return True
+
+
+class LCG(object):
+ ''' Include simple random number generator to ensure results will be the
+ same cross platform.
+ http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator '''
+
+ __slots__ = ['n']
+
+ InitialLCGSeed = 48271
+
+ def __init__(self):
+ self.n = self.InitialLCGSeed
+
+ def Reset(self):
+ self.n = self.InitialLCGSeed
+
+ def Next(self):
+ self.n = ((self.n * 279470273) % 4294967291) & 0xFFFFFFFF
+ return self.n
+
+
+def BenchmarkVtableDeduplication(count):
+ '''
+ BenchmarkVtableDeduplication measures the speed of vtable deduplication
+ by creating `prePop` vtables, then populating `count` objects with a
+ different single vtable.
+
+ When count is large (as in long benchmarks), memory usage may be high.
+ '''
+
+ for prePop in (1, 10, 100, 1000):
+ builder = flatbuffers.Builder(0)
+ n = 1 + int(math.log(prePop, 1.5))
+
+ # generate some layouts:
+ layouts = set()
+ r = list(compat_range(n))
+ while len(layouts) < prePop:
+ layouts.add(tuple(sorted(random.sample(r, int(max(1, n / 2))))))
+
+ layouts = list(layouts)
+
+ # pre-populate vtables:
+ for layout in layouts:
+ builder.StartObject(n)
+ for j in layout:
+ builder.PrependInt16Slot(j, j, 0)
+ builder.EndObject()
+
+ # benchmark deduplication of a new vtable:
+ def f():
+ layout = random.choice(layouts)
+ builder.StartObject(n)
+ for j in layout:
+ builder.PrependInt16Slot(j, j, 0)
+ builder.EndObject()
+
+ duration = timeit.timeit(stmt=f, number=count)
+ rate = float(count) / duration
+ print(('vtable deduplication rate (n=%d, vtables=%d): %.2f sec' % (
+ prePop,
+ len(builder.vtables),
+ rate))
+ )
+
+
+def BenchmarkCheckReadBuffer(count, buf, off):
+ '''
+ BenchmarkCheckReadBuffer measures the speed of flatbuffer reading
+ by re-using the CheckReadBuffer function with the gold data.
+ '''
+
+ def f():
+ CheckReadBuffer(buf, off)
+
+ duration = timeit.timeit(stmt=f, number=count)
+ rate = float(count) / duration
+ data = float(len(buf) * count) / float(1024 * 1024)
+ data_rate = data / float(duration)
+
+ print(('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/sec, %.2fMB/sec')
+ % (count, len(buf), duration, rate, data_rate))
+
+
+def BenchmarkMakeMonsterFromGeneratedCode(count, length):
+ '''
+ BenchmarkMakeMonsterFromGeneratedCode measures the speed of flatbuffer
+ creation by re-using the make_monster_from_generated_code function for
+ generating gold data examples.
+ '''
+
+ duration = timeit.timeit(stmt=make_monster_from_generated_code,
+ number=count)
+ rate = float(count) / duration
+ data = float(length * count) / float(1024 * 1024)
+ data_rate = data / float(duration)
+
+ print(('built %d %d-byte flatbuffers in %.2fsec: %.2f/sec, %.2fMB/sec' % \
+ (count, length, duration, rate, data_rate)))
+
+
+def backward_compatible_run_tests(**kwargs):
+ if PY_VERSION < (2, 6):
+ sys.stderr.write("Python version less than 2.6 are not supported")
+ sys.stderr.flush()
+ return False
+
+ # python2.6 has a reduced-functionality unittest.main function:
+ if PY_VERSION == (2, 6):
+ try:
+ unittest.main(**kwargs)
+ except SystemExit as e:
+ if not e.code == 0:
+ return False
+ return True
+
+ # python2.7 and above let us not exit once unittest.main is run:
+ kwargs['exit'] = False
+ kwargs['verbosity'] = 0
+ ret = unittest.main(**kwargs)
+ if ret.result.errors or ret.result.failures:
+ return False
+
+ return True
+
+def main():
+ import os
+ import sys
+ if not len(sys.argv) == 4:
+ sys.stderr.write('Usage: %s <benchmark vtable count>'
+ '<benchmark read count> <benchmark build count>\n'
+ % sys.argv[0])
+ sys.stderr.write(' Provide COMPARE_GENERATED_TO_GO=1 to check'
+ 'for bytewise comparison to Go data.\n')
+ sys.stderr.write(' Provide COMPARE_GENERATED_TO_JAVA=1 to check'
+ 'for bytewise comparison to Java data.\n')
+ sys.stderr.flush()
+ sys.exit(1)
+
+ kwargs = dict(argv=sys.argv[:-3])
+
+ # run tests, and run some language comparison checks if needed:
+ success = backward_compatible_run_tests(**kwargs)
+ if success and os.environ.get('COMPARE_GENERATED_TO_GO', 0) == "1":
+ success = success and CheckAgainstGoldDataGo()
+ if success and os.environ.get('COMPARE_GENERATED_TO_JAVA', 0) == "1":
+ success = success and CheckAgainstGoldDataJava()
+
+ if not success:
+ sys.stderr.write('Tests failed, skipping benchmarks.\n')
+ sys.stderr.flush()
+ sys.exit(1)
+
+ # run benchmarks (if 0, they will be a noop):
+ bench_vtable = int(sys.argv[1])
+ bench_traverse = int(sys.argv[2])
+ bench_build = int(sys.argv[3])
+ if bench_vtable:
+ BenchmarkVtableDeduplication(bench_vtable)
+ if bench_traverse:
+ buf, off = make_monster_from_generated_code()
+ BenchmarkCheckReadBuffer(bench_traverse, buf, off)
+ if bench_build:
+ buf, off = make_monster_from_generated_code()
+ BenchmarkMakeMonsterFromGeneratedCode(bench_build, len(buf))
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/rust_usage_test/Cargo.toml b/tests/rust_usage_test/Cargo.toml
new file mode 100644
index 0000000..490d6d2
--- /dev/null
+++ b/tests/rust_usage_test/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "rust_usage_test"
+version = "0.1.0"
+authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
+
+[dependencies]
+flatbuffers = { path = "../../rust/flatbuffers" }
+
+[[bin]]
+name = "monster_example"
+path = "bin/monster_example.rs"
+
+[[bin]]
+name = "alloc_check"
+path = "bin/alloc_check.rs"
+
+
+[dev-dependencies]
+quickcheck = "0.6"
+# TODO(rw): look into moving to criterion.rs
+bencher = "0.1.5"
+
+[[bench]]
+# setup for bencher
+name = "flatbuffers_benchmarks"
+harness = false
diff --git a/tests/rust_usage_test/benches/flatbuffers_benchmarks.rs b/tests/rust_usage_test/benches/flatbuffers_benchmarks.rs
new file mode 100644
index 0000000..2c6be1f
--- /dev/null
+++ b/tests/rust_usage_test/benches/flatbuffers_benchmarks.rs
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#[macro_use]
+extern crate bencher;
+use bencher::Bencher;
+
+extern crate flatbuffers;
+
+#[allow(dead_code, unused_imports)]
+#[path = "../../monster_test_generated.rs"]
+mod monster_test_generated;
+pub use monster_test_generated::my_game;
+
+fn traverse_canonical_buffer(bench: &mut Bencher) {
+ let owned_data = {
+ let mut builder = &mut flatbuffers::FlatBufferBuilder::new();
+ create_serialized_example_with_generated_code(&mut builder, true);
+ builder.finished_data().to_vec()
+ };
+ let data = &owned_data[..];
+ let n = data.len() as u64;
+ bench.iter(|| {
+ traverse_serialized_example_with_generated_code(data);
+ });
+ bench.bytes = n;
+}
+
+fn create_canonical_buffer_then_reset(bench: &mut Bencher) {
+ let mut builder = &mut flatbuffers::FlatBufferBuilder::new();
+ // warmup
+ create_serialized_example_with_generated_code(&mut builder, true);
+ let n = builder.finished_data().len() as u64;
+ builder.reset();
+
+ bench.iter(|| {
+ let _ = create_serialized_example_with_generated_code(&mut builder, true);
+ builder.reset();
+ });
+
+ bench.bytes = n;
+}
+
+#[inline(always)]
+fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder, finish: bool) -> usize{
+ let s0 = builder.create_string("test1");
+ let s1 = builder.create_string("test2");
+ let t0_name = builder.create_string("Barney");
+ let t1_name = builder.create_string("Fred");
+ let t2_name = builder.create_string("Wilma");
+ let t0 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
+ hp: 1000,
+ name: Some(t0_name),
+ ..Default::default()
+ });
+ let t1 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
+ name: Some(t1_name),
+ ..Default::default()
+ });
+ let t2 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
+ name: Some(t2_name),
+ ..Default::default()
+ });
+ let mon = {
+ let name = builder.create_string("MyMonster");
+ let fred_name = builder.create_string("Fred");
+ let inventory = builder.create_vector_direct(&[0u8, 1, 2, 3, 4]);
+ let test4 = builder.create_vector_direct(&[my_game::example::Test::new(10, 20),
+ my_game::example::Test::new(30, 40)]);
+ let pos = my_game::example::Vec3::new(1.0, 2.0, 3.0, 3.0, my_game::example::Color::Green, &my_game::example::Test::new(5i16, 6i8));
+ let args = my_game::example::MonsterArgs{
+ hp: 80,
+ mana: 150,
+ name: Some(name),
+ pos: Some(&pos),
+ test_type: my_game::example::Any::Monster,
+ test: Some(my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
+ name: Some(fred_name),
+ ..Default::default()
+ }).as_union_value()),
+ inventory: Some(inventory),
+ test4: Some(test4),
+ testarrayofstring: Some(builder.create_vector(&[s0, s1])),
+ testarrayoftables: Some(builder.create_vector(&[t0, t1, t2])),
+ ..Default::default()
+ };
+ my_game::example::Monster::create(builder, &args)
+ };
+ if finish {
+ my_game::example::finish_monster_buffer(builder, mon);
+ }
+
+ builder.finished_data().len()
+
+ // make it do some work
+ // if builder.finished_data().len() == 0 { panic!("bad benchmark"); }
+}
+
+#[inline(always)]
+fn blackbox<T>(t: T) -> T {
+ // encapsulate this in case we need to turn it into a noop
+ bencher::black_box(t)
+}
+
+#[inline(always)]
+fn traverse_serialized_example_with_generated_code(bytes: &[u8]) {
+ let m = my_game::example::get_root_as_monster(bytes);
+ blackbox(m.hp());
+ blackbox(m.mana());
+ blackbox(m.name());
+ let pos = m.pos().unwrap();
+ blackbox(pos.x());
+ blackbox(pos.y());
+ blackbox(pos.z());
+ blackbox(pos.test1());
+ blackbox(pos.test2());
+ let pos_test3 = pos.test3();
+ blackbox(pos_test3.a());
+ blackbox(pos_test3.b());
+ blackbox(m.test_type());
+ let table2 = m.test().unwrap();
+ let monster2 = my_game::example::Monster::init_from_table(table2);
+ blackbox(monster2.name());
+ blackbox(m.inventory());
+ blackbox(m.test4());
+ let testarrayoftables = m.testarrayoftables().unwrap();
+ blackbox(testarrayoftables.get(0).hp());
+ blackbox(testarrayoftables.get(0).name());
+ blackbox(testarrayoftables.get(1).name());
+ blackbox(testarrayoftables.get(2).name());
+ let testarrayofstring = m.testarrayofstring().unwrap();
+ blackbox(testarrayofstring.get(0));
+ blackbox(testarrayofstring.get(1));
+}
+
+fn create_string_10(bench: &mut Bencher) {
+ let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
+ let mut i = 0;
+ bench.iter(|| {
+ builder.create_string("foobarbaz"); // zero-terminated -> 10 bytes
+ i += 1;
+ if i == 10000 {
+ builder.reset();
+ i = 0;
+ }
+ });
+
+ bench.bytes = 10;
+}
+
+fn create_string_100(bench: &mut Bencher) {
+ let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
+ let s_owned = (0..99).map(|_| "x").collect::<String>();
+ let s: &str = &s_owned;
+
+ let mut i = 0;
+ bench.iter(|| {
+ builder.create_string(s); // zero-terminated -> 100 bytes
+ i += 1;
+ if i == 1000 {
+ builder.reset();
+ i = 0;
+ }
+ });
+
+ bench.bytes = s.len() as u64;
+}
+
+fn create_byte_vector_100_naive(bench: &mut Bencher) {
+ let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
+ let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>();
+ let v: &[u8] = &v_owned;
+
+ let mut i = 0;
+ bench.iter(|| {
+ builder.create_vector(v); // zero-terminated -> 100 bytes
+ i += 1;
+ if i == 10000 {
+ builder.reset();
+ i = 0;
+ }
+ });
+
+ bench.bytes = v.len() as u64;
+}
+
+fn create_byte_vector_100_optimal(bench: &mut Bencher) {
+ let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20);
+ let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>();
+ let v: &[u8] = &v_owned;
+
+ let mut i = 0;
+ bench.iter(|| {
+ builder.create_vector_direct(v);
+ i += 1;
+ if i == 10000 {
+ builder.reset();
+ i = 0;
+ }
+ });
+
+ bench.bytes = v.len() as u64;
+}
+
+benchmark_group!(benches, create_byte_vector_100_naive, create_byte_vector_100_optimal, traverse_canonical_buffer, create_canonical_buffer_then_reset, create_string_10, create_string_100);
+benchmark_main!(benches);
diff --git a/tests/rust_usage_test/bin/alloc_check.rs b/tests/rust_usage_test/bin/alloc_check.rs
new file mode 100644
index 0000000..ae1039c
--- /dev/null
+++ b/tests/rust_usage_test/bin/alloc_check.rs
@@ -0,0 +1,143 @@
+// define a passthrough allocator that tracks alloc calls.
+// (note that we can't drop this in to the usual test suite, because it's a big
+// global variable).
+use std::alloc::{GlobalAlloc, Layout, System};
+
+static mut N_ALLOCS: usize = 0;
+
+struct TrackingAllocator;
+
+impl TrackingAllocator {
+ fn n_allocs(&self) -> usize {
+ unsafe { N_ALLOCS }
+ }
+}
+unsafe impl GlobalAlloc for TrackingAllocator {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ N_ALLOCS += 1;
+ System.alloc(layout)
+ }
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ System.dealloc(ptr, layout)
+ }
+}
+
+// use the tracking allocator:
+#[global_allocator]
+static A: TrackingAllocator = TrackingAllocator;
+
+// import the flatbuffers generated code:
+extern crate flatbuffers;
+#[allow(dead_code, unused_imports)]
+#[path = "../../monster_test_generated.rs"]
+mod monster_test_generated;
+pub use monster_test_generated::my_game;
+
+// verbatim from the test suite:
+fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder) {
+ let mon = {
+ let _ = builder.create_vector_of_strings(&["these", "unused", "strings", "check", "the", "create_vector_of_strings", "function"]);
+
+ let s0 = builder.create_string("test1");
+ let s1 = builder.create_string("test2");
+ let fred_name = builder.create_string("Fred");
+
+ // can't inline creation of this Vec3 because we refer to it by reference, so it must live
+ // long enough to be used by MonsterArgs.
+ let pos = my_game::example::Vec3::new(1.0, 2.0, 3.0, 3.0, my_game::example::Color::Green, &my_game::example::Test::new(5i16, 6i8));
+
+ let args = my_game::example::MonsterArgs{
+ hp: 80,
+ mana: 150,
+ name: Some(builder.create_string("MyMonster")),
+ pos: Some(&pos),
+ test_type: my_game::example::Any::Monster,
+ test: Some(my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
+ name: Some(fred_name),
+ ..Default::default()
+ }).as_union_value()),
+ inventory: Some(builder.create_vector_direct(&[0u8, 1, 2, 3, 4][..])),
+ test4: Some(builder.create_vector_direct(&[my_game::example::Test::new(10, 20),
+ my_game::example::Test::new(30, 40)])),
+ testarrayofstring: Some(builder.create_vector(&[s0, s1])),
+ ..Default::default()
+ };
+ my_game::example::Monster::create(builder, &args)
+ };
+ my_game::example::finish_monster_buffer(builder, mon);
+}
+
+fn main() {
+ // test the allocation tracking:
+ {
+ let before = A.n_allocs();
+ let _x: Vec<u8> = vec![0u8; 1];
+ let after = A.n_allocs();
+ assert_eq!(before + 1, after);
+ }
+
+ let builder = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ // warm up the builder (it can make small allocs internally, such as for storing vtables):
+ create_serialized_example_with_generated_code(builder);
+ }
+
+ // reset the builder, clearing its heap-allocated memory:
+ builder.reset();
+
+ {
+ let before = A.n_allocs();
+ create_serialized_example_with_generated_code(builder);
+ let after = A.n_allocs();
+ assert_eq!(before, after, "KO: Heap allocs occurred in Rust write path");
+ }
+
+ let buf = builder.finished_data();
+
+ // use the allocation tracking on the read path:
+ {
+ let before = A.n_allocs();
+
+ // do many reads, forcing them to execute by using assert_eq:
+ {
+ let m = my_game::example::get_root_as_monster(buf);
+ assert_eq!(80, m.hp());
+ assert_eq!(150, m.mana());
+ assert_eq!("MyMonster", m.name());
+
+ let pos = m.pos().unwrap();
+ assert_eq!(pos.x(), 1.0f32);
+ assert_eq!(pos.y(), 2.0f32);
+ assert_eq!(pos.z(), 3.0f32);
+ assert_eq!(pos.test1(), 3.0f64);
+ assert_eq!(pos.test2(), my_game::example::Color::Green);
+ let pos_test3 = pos.test3();
+ assert_eq!(pos_test3.a(), 5i16);
+ assert_eq!(pos_test3.b(), 6i8);
+ assert_eq!(m.test_type(), my_game::example::Any::Monster);
+ let table2 = m.test().unwrap();
+ let m2 = my_game::example::Monster::init_from_table(table2);
+
+ assert_eq!(m2.name(), "Fred");
+
+ let inv = m.inventory().unwrap();
+ assert_eq!(inv.len(), 5);
+ assert_eq!(inv.iter().sum::<u8>(), 10u8);
+
+ let test4 = m.test4().unwrap();
+ assert_eq!(test4.len(), 2);
+ assert_eq!(test4[0].a() as i32 + test4[0].b() as i32 +
+ test4[1].a() as i32 + test4[1].b() as i32, 100);
+
+ let testarrayofstring = m.testarrayofstring().unwrap();
+ assert_eq!(testarrayofstring.len(), 2);
+ assert_eq!(testarrayofstring.get(0), "test1");
+ assert_eq!(testarrayofstring.get(1), "test2");
+ }
+
+ // assert that no allocs occurred:
+ let after = A.n_allocs();
+ assert_eq!(before, after, "KO: Heap allocs occurred in Rust read path");
+ }
+ println!("Rust: Heap alloc checks completed successfully");
+}
diff --git a/tests/rust_usage_test/bin/monster_example.rs b/tests/rust_usage_test/bin/monster_example.rs
new file mode 100644
index 0000000..3c9a0a0
--- /dev/null
+++ b/tests/rust_usage_test/bin/monster_example.rs
@@ -0,0 +1,19 @@
+extern crate flatbuffers;
+
+#[allow(dead_code, unused_imports)]
+#[path = "../../monster_test_generated.rs"]
+mod monster_test_generated;
+pub use monster_test_generated::my_game;
+
+use std::io::Read;
+
+fn main() {
+ let mut f = std::fs::File::open("../monsterdata_test.mon").unwrap();
+ let mut buf = Vec::new();
+ f.read_to_end(&mut buf).expect("file reading failed");
+
+ let monster = my_game::example::get_root_as_monster(&buf[..]);
+ println!("{}", monster.hp()); // `80`
+ println!("{}", monster.mana()); // default value of `150`
+ println!("{:?}", monster.name()); // Some("MyMonster")
+}
diff --git a/tests/rust_usage_test/tests/integration_test.rs b/tests/rust_usage_test/tests/integration_test.rs
new file mode 100644
index 0000000..0dace96
--- /dev/null
+++ b/tests/rust_usage_test/tests/integration_test.rs
@@ -0,0 +1,2716 @@
+/*
+ *
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern crate quickcheck;
+
+extern crate flatbuffers;
+
+#[allow(dead_code, unused_imports)]
+#[path = "../../monster_test_generated.rs"]
+mod monster_test_generated;
+pub use monster_test_generated::my_game;
+
+// Include simple random number generator to ensure results will be the
+// same across platforms.
+// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
+struct LCG(u64);
+impl LCG {
+ fn new() -> Self {
+ LCG { 0: 48271 }
+ }
+ fn next(&mut self) -> u64 {
+ let old = self.0;
+ self.0 = (self.0 * 279470273u64) % 4294967291u64;
+ old
+ }
+ fn reset(&mut self) {
+ self.0 = 48271
+ }
+}
+
+// test helper macro to return an error if two expressions are not equal
+macro_rules! check_eq {
+ ($field_call:expr, $want:expr) => (
+ if $field_call == $want {
+ Ok(())
+ } else {
+ Err(stringify!($field_call))
+ }
+ )
+}
+
+#[test]
+fn macro_check_eq() {
+ assert!(check_eq!(1, 1).is_ok());
+ assert!(check_eq!(1, 2).is_err());
+}
+
+// test helper macro to return an error if two expressions are equal
+macro_rules! check_is_some {
+ ($field_call:expr) => (
+ if $field_call.is_some() {
+ Ok(())
+ } else {
+ Err(stringify!($field_call))
+ }
+ )
+}
+
+#[test]
+fn macro_check_is_some() {
+ let some: Option<usize> = Some(0);
+ let none: Option<usize> = None;
+ assert!(check_is_some!(some).is_ok());
+ assert!(check_is_some!(none).is_err());
+}
+
+
+fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder) {
+ let mon = {
+ let s0 = builder.create_string("test1");
+ let s1 = builder.create_string("test2");
+ let fred_name = builder.create_string("Fred");
+
+ // can't inline creation of this Vec3 because we refer to it by reference, so it must live
+ // long enough to be used by MonsterArgs.
+ let pos = my_game::example::Vec3::new(1.0, 2.0, 3.0, 3.0, my_game::example::Color::Green, &my_game::example::Test::new(5i16, 6i8));
+
+ let args = my_game::example::MonsterArgs{
+ hp: 80,
+ mana: 150,
+ name: Some(builder.create_string("MyMonster")),
+ pos: Some(&pos),
+ test_type: my_game::example::Any::Monster,
+ test: Some(my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{
+ name: Some(fred_name),
+ ..Default::default()
+ }).as_union_value()),
+ inventory: Some(builder.create_vector_direct(&[0u8, 1, 2, 3, 4][..])),
+ test4: Some(builder.create_vector_direct(&[my_game::example::Test::new(10, 20),
+ my_game::example::Test::new(30, 40)])),
+ testarrayofstring: Some(builder.create_vector(&[s0, s1])),
+ ..Default::default()
+ };
+ my_game::example::Monster::create(builder, &args)
+ };
+ my_game::example::finish_monster_buffer(builder, mon);
+}
+
+fn create_serialized_example_with_library_code(builder: &mut flatbuffers::FlatBufferBuilder) {
+ let nested_union_mon = {
+ let name = builder.create_string("Fred");
+ let table_start = builder.start_table();
+ builder.push_slot_always(my_game::example::Monster::VT_NAME, name);
+ builder.end_table(table_start)
+ };
+ let pos = my_game::example::Vec3::new(1.0, 2.0, 3.0, 3.0, my_game::example::Color::Green, &my_game::example::Test::new(5i16, 6i8));
+ let inv = builder.create_vector(&[0u8, 1, 2, 3, 4]);
+
+ let test4 = builder.create_vector(&[my_game::example::Test::new(10, 20),
+ my_game::example::Test::new(30, 40)][..]);
+
+ let name = builder.create_string("MyMonster");
+ let testarrayofstring = builder.create_vector_of_strings(&["test1", "test2"][..]);
+
+ // begin building
+
+ let table_start = builder.start_table();
+ builder.push_slot(my_game::example::Monster::VT_HP, 80i16, 100);
+ builder.push_slot_always(my_game::example::Monster::VT_NAME, name);
+ builder.push_slot_always(my_game::example::Monster::VT_POS, &pos);
+ builder.push_slot(my_game::example::Monster::VT_TEST_TYPE, my_game::example::Any::Monster, my_game::example::Any::NONE);
+ builder.push_slot_always(my_game::example::Monster::VT_TEST, nested_union_mon);
+ builder.push_slot_always(my_game::example::Monster::VT_INVENTORY, inv);
+ builder.push_slot_always(my_game::example::Monster::VT_TEST4, test4);
+ builder.push_slot_always(my_game::example::Monster::VT_TESTARRAYOFSTRING, testarrayofstring);
+ let root = builder.end_table(table_start);
+ builder.finish(root, Some(my_game::example::MONSTER_IDENTIFIER));
+}
+
+fn serialized_example_is_accessible_and_correct(bytes: &[u8], identifier_required: bool, size_prefixed: bool) -> Result<(), &'static str> {
+
+ if identifier_required {
+ let correct = if size_prefixed {
+ my_game::example::monster_size_prefixed_buffer_has_identifier(bytes)
+ } else {
+ my_game::example::monster_buffer_has_identifier(bytes)
+ };
+ check_eq!(correct, true)?;
+ }
+
+ let m = if size_prefixed {
+ my_game::example::get_size_prefixed_root_as_monster(bytes)
+ } else {
+ my_game::example::get_root_as_monster(bytes)
+ };
+
+ check_eq!(m.hp(), 80)?;
+ check_eq!(m.mana(), 150)?;
+ check_eq!(m.name(), "MyMonster")?;
+
+ let pos = m.pos().unwrap();
+ check_eq!(pos.x(), 1.0f32)?;
+ check_eq!(pos.y(), 2.0f32)?;
+ check_eq!(pos.z(), 3.0f32)?;
+ check_eq!(pos.test1(), 3.0f64)?;
+ check_eq!(pos.test2(), my_game::example::Color::Green)?;
+
+ let pos_test3 = pos.test3();
+ check_eq!(pos_test3.a(), 5i16)?;
+ check_eq!(pos_test3.b(), 6i8)?;
+
+ check_eq!(m.test_type(), my_game::example::Any::Monster)?;
+ check_is_some!(m.test())?;
+ let table2 = m.test().unwrap();
+ let monster2 = my_game::example::Monster::init_from_table(table2);
+
+ check_eq!(monster2.name(), "Fred")?;
+
+ check_is_some!(m.inventory())?;
+ let inv = m.inventory().unwrap();
+ check_eq!(inv.len(), 5)?;
+ check_eq!(inv.iter().sum::<u8>(), 10u8)?;
+
+ check_is_some!(m.test4())?;
+ let test4 = m.test4().unwrap();
+ check_eq!(test4.len(), 2)?;
+ check_eq!(test4[0].a() as i32 + test4[0].b() as i32 +
+ test4[1].a() as i32 + test4[1].b() as i32, 100)?;
+
+ check_is_some!(m.testarrayofstring())?;
+ let testarrayofstring = m.testarrayofstring().unwrap();
+ check_eq!(testarrayofstring.len(), 2)?;
+ check_eq!(testarrayofstring.get(0), "test1")?;
+ check_eq!(testarrayofstring.get(1), "test2")?;
+
+ Ok(())
+}
+
+// Disabled due to Windows CI limitations.
+// #[test]
+// fn builder_initializes_with_maximum_buffer_size() {
+// flatbuffers::FlatBufferBuilder::new_with_capacity(flatbuffers::FLATBUFFERS_MAX_BUFFER_SIZE);
+// }
+
+#[should_panic]
+#[test]
+fn builder_abort_with_greater_than_maximum_buffer_size() {
+ flatbuffers::FlatBufferBuilder::new_with_capacity(flatbuffers::FLATBUFFERS_MAX_BUFFER_SIZE+1);
+}
+
+#[test]
+fn builder_collapses_into_vec() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ create_serialized_example_with_generated_code(&mut b);
+ let (backing_buf, head) = b.collapse();
+ serialized_example_is_accessible_and_correct(&backing_buf[head..], true, false).unwrap();
+}
+
+#[cfg(test)]
+mod generated_constants {
+ extern crate flatbuffers;
+ use super::my_game;
+
+ #[test]
+ fn monster_identifier() {
+ assert_eq!("MONS", my_game::example::MONSTER_IDENTIFIER);
+ }
+
+ #[test]
+ fn monster_file_extension() {
+ assert_eq!("mon", my_game::example::MONSTER_EXTENSION);
+ }
+}
+
+#[cfg(test)]
+mod lifetime_correctness {
+ extern crate flatbuffers;
+
+ use std::mem;
+
+ use super::my_game;
+ use super::load_file;
+
+ #[test]
+ fn table_get_field_from_static_buffer_1() {
+ let buf = load_file("../monsterdata_test.mon").expect("missing monsterdata_test.mon");
+ // create 'static slice
+ let slice: &[u8] = &buf;
+ let slice: &'static [u8] = unsafe { mem::transmute(slice) };
+ // make sure values retrieved from the 'static buffer are themselves 'static
+ let monster: my_game::example::Monster<'static> = my_game::example::get_root_as_monster(slice);
+ // this line should compile:
+ let name: Option<&'static str> = monster._tab.get::<flatbuffers::ForwardsUOffset<&str>>(my_game::example::Monster::VT_NAME, None);
+ assert_eq!(name, Some("MyMonster"));
+ }
+
+ #[test]
+ fn table_get_field_from_static_buffer_2() {
+ static DATA: [u8; 4] = [0, 0, 0, 0]; // some binary data
+ let table: flatbuffers::Table<'static> = flatbuffers::Table::new(&DATA, 0);
+ // this line should compile:
+ table.get::<&'static str>(0, None);
+ }
+
+ #[test]
+ fn table_object_self_lifetime_in_closure() {
+ // This test is designed to ensure that lifetimes for temporary intermediate tables aren't inflated beyond where the need to be.
+ let buf = load_file("../monsterdata_test.mon").expect("missing monsterdata_test.mon");
+ let monster = my_game::example::get_root_as_monster(&buf);
+ let enemy: Option<my_game::example::Monster> = monster.enemy();
+ // This line won't compile if "self" is required to live for the lifetime of buf above as the borrow disappears at the end of the closure.
+ let enemy_of_my_enemy = enemy.map(|e| {
+ // enemy (the Option) is consumed, and the enum's value is taken as a temporary (e) at the start of the closure
+ let name = e.name();
+ // ... the temporary dies here, so for this to compile name's lifetime must not be tied to the temporary
+ name
+ // If this test fails the error would be "`e` dropped here while still borrowed"
+ });
+ assert_eq!(enemy_of_my_enemy, Some("Fred"));
+ }
+}
+
+#[cfg(test)]
+mod roundtrip_generated_code {
+ extern crate flatbuffers;
+
+ use super::my_game;
+
+ fn build_mon<'a, 'b>(builder: &'a mut flatbuffers::FlatBufferBuilder, args: &'b my_game::example::MonsterArgs) -> my_game::example::Monster<'a> {
+ let mon = my_game::example::Monster::create(builder, &args);
+ my_game::example::finish_monster_buffer(builder, mon);
+ my_game::example::get_root_as_monster(builder.finished_data())
+ }
+
+ #[test]
+ fn scalar_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{hp: 123, name: Some(name), ..Default::default()});
+ assert_eq!(m.hp(), 123);
+ }
+ #[test]
+ fn scalar_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.hp(), 100);
+ }
+ #[test]
+ fn string_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foobar");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.name(), "foobar");
+ }
+ #[test]
+ fn struct_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ pos: Some(&my_game::example::Vec3::new(1.0, 2.0, 3.0, 4.0,
+ my_game::example::Color::Green,
+ &my_game::example::Test::new(98, 99))),
+ ..Default::default()
+ });
+ assert_eq!(m.pos(), Some(&my_game::example::Vec3::new(1.0, 2.0, 3.0, 4.0,
+ my_game::example::Color::Green,
+ &my_game::example::Test::new(98, 99))));
+ }
+ #[test]
+ fn struct_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.pos(), None);
+ }
+ #[test]
+ fn enum_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), color: my_game::example::Color::Red, ..Default::default()});
+ assert_eq!(m.color(), my_game::example::Color::Red);
+ }
+ #[test]
+ fn enum_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.color(), my_game::example::Color::Blue);
+ }
+ #[test]
+ fn union_store() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ let name_inner = b.create_string("foo");
+ let name_outer = b.create_string("bar");
+
+ let inner = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name_inner),
+ ..Default::default()
+ });
+ let outer = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name_outer),
+ test_type: my_game::example::Any::Monster,
+ test: Some(inner.as_union_value()),
+ ..Default::default()
+ });
+ my_game::example::finish_monster_buffer(b, outer);
+ }
+
+ let mon = my_game::example::get_root_as_monster(b.finished_data());
+ assert_eq!(mon.name(), "bar");
+ assert_eq!(mon.test_type(), my_game::example::Any::Monster);
+ assert_eq!(my_game::example::Monster::init_from_table(mon.test().unwrap()).name(),
+ "foo");
+ assert_eq!(mon.test_as_monster().unwrap().name(), "foo");
+ assert_eq!(mon.test_as_test_simple_table_with_enum(), None);
+ assert_eq!(mon.test_as_my_game_example_2_monster(), None);
+ }
+ #[test]
+ fn union_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.test_type(), my_game::example::Any::NONE);
+ assert_eq!(m.test(), None);
+ }
+ #[test]
+ fn table_full_namespace_store() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ let name_inner = b.create_string("foo");
+ let name_outer = b.create_string("bar");
+
+ let inner = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name_inner),
+ ..Default::default()
+ });
+ let outer = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name_outer),
+ enemy: Some(inner),
+ ..Default::default()
+ });
+ my_game::example::finish_monster_buffer(b, outer);
+ }
+
+ let mon = my_game::example::get_root_as_monster(b.finished_data());
+ assert_eq!(mon.name(), "bar");
+ assert_eq!(mon.enemy().unwrap().name(), "foo");
+ }
+ #[test]
+ fn table_full_namespace_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.enemy(), None);
+ }
+ #[test]
+ fn table_store() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ let id_inner = b.create_string("foo");
+ let name_outer = b.create_string("bar");
+
+ let inner = my_game::example::Stat::create(b, &my_game::example::StatArgs{
+ id: Some(id_inner),
+ ..Default::default()
+ });
+ let outer = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name_outer),
+ testempty: Some(inner),
+ ..Default::default()
+ });
+ my_game::example::finish_monster_buffer(b, outer);
+ }
+
+ let mon = my_game::example::get_root_as_monster(b.finished_data());
+ assert_eq!(mon.name(), "bar");
+ assert_eq!(mon.testempty().unwrap().id(), Some("foo"));
+ }
+ #[test]
+ fn table_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert_eq!(m.testempty(), None);
+ }
+ #[test]
+ fn nested_flatbuffer_store() {
+ let b0 = {
+ let mut b0 = flatbuffers::FlatBufferBuilder::new();
+ let args = my_game::example::MonsterArgs{
+ hp: 123,
+ name: Some(b0.create_string("foobar")),
+ ..Default::default()
+ };
+ let mon = my_game::example::Monster::create(&mut b0, &args);
+ my_game::example::finish_monster_buffer(&mut b0, mon);
+ b0
+ };
+
+ let b1 = {
+ let mut b1 = flatbuffers::FlatBufferBuilder::new();
+ let args = my_game::example::MonsterArgs{
+ testnestedflatbuffer: Some(b1.create_vector(b0.finished_data())),
+ name: Some(b1.create_string("foo")),
+ ..Default::default()
+ };
+ let mon = my_game::example::Monster::create(&mut b1, &args);
+ my_game::example::finish_monster_buffer(&mut b1, mon);
+ b1
+ };
+
+ let m = my_game::example::get_root_as_monster(b1.finished_data());
+
+ assert!(m.testnestedflatbuffer().is_some());
+ assert_eq!(m.testnestedflatbuffer().unwrap(), b0.finished_data());
+
+ let m2_a = my_game::example::get_root_as_monster(m.testnestedflatbuffer().unwrap());
+ assert_eq!(m2_a.hp(), 123);
+ assert_eq!(m2_a.name(), "foobar");
+
+ assert!(m.testnestedflatbuffer_nested_flatbuffer().is_some());
+ let m2_b = m.testnestedflatbuffer_nested_flatbuffer().unwrap();
+
+ assert_eq!(m2_b.hp(), 123);
+ assert_eq!(m2_b.name(), "foobar");
+ }
+ #[test]
+ fn nested_flatbuffer_default() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{name: Some(name), ..Default::default()});
+ assert!(m.testnestedflatbuffer().is_none());
+ }
+ #[test]
+ fn vector_of_string_store_helper_build() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let v = b.create_vector_of_strings(&["foobar", "baz"]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ testarrayofstring: Some(v), ..Default::default()});
+ assert_eq!(m.testarrayofstring().unwrap().len(), 2);
+ assert_eq!(m.testarrayofstring().unwrap().get(0), "foobar");
+ assert_eq!(m.testarrayofstring().unwrap().get(1), "baz");
+ }
+ #[test]
+ fn vector_of_string_store_manual_build() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let s0 = b.create_string("foobar");
+ let s1 = b.create_string("baz");
+ let v = b.create_vector(&[s0, s1]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ testarrayofstring: Some(v), ..Default::default()});
+ assert_eq!(m.testarrayofstring().unwrap().len(), 2);
+ assert_eq!(m.testarrayofstring().unwrap().get(0), "foobar");
+ assert_eq!(m.testarrayofstring().unwrap().get(1), "baz");
+ }
+ #[test]
+ fn vector_of_ubyte_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let v = b.create_vector(&[123u8, 234u8][..]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ inventory: Some(v), ..Default::default()});
+ assert_eq!(m.inventory().unwrap(), &[123, 234][..]);
+ }
+ #[test]
+ fn vector_of_bool_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let v = b.create_vector(&[false, true, false, true][..]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ testarrayofbools: Some(v), ..Default::default()});
+ assert_eq!(m.testarrayofbools().unwrap(), &[false, true, false, true][..]);
+ }
+ #[test]
+ fn vector_of_f64_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let v = b.create_vector(&[3.14159265359f64][..]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ vector_of_doubles: Some(v), ..Default::default()});
+ assert_eq!(m.vector_of_doubles().unwrap().len(), 1);
+ assert_eq!(m.vector_of_doubles().unwrap().get(0), 3.14159265359f64);
+ }
+ #[test]
+ fn vector_of_struct_store() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let v = b.create_vector(&[my_game::example::Test::new(127, -128), my_game::example::Test::new(3, 123)][..]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ test4: Some(v), ..Default::default()});
+ assert_eq!(m.test4().unwrap(), &[my_game::example::Test::new(127, -128), my_game::example::Test::new(3, 123)][..]);
+ }
+ #[test]
+ fn vector_of_struct_store_with_type_inference() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let v = b.create_vector(&[my_game::example::Test::new(127, -128),
+ my_game::example::Test::new(3, 123),
+ my_game::example::Test::new(100, 101)]);
+ let name = b.create_string("foo");
+ let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ test4: Some(v), ..Default::default()});
+ assert_eq!(m.test4().unwrap(), &[my_game::example::Test::new(127, -128), my_game::example::Test::new(3, 123), my_game::example::Test::new(100, 101)][..]);
+ }
+ // TODO(rw) this passes, but I don't want to change the monster test schema right now
+ // #[test]
+ // fn vector_of_enum_store() {
+ // let mut b = flatbuffers::FlatBufferBuilder::new();
+ // let v = b.create_vector::<my_game::example::Color>(&[my_game::example::Color::Red, my_game::example::Color::Green][..]);
+ // let name = b.create_string("foo");
+ // let m = build_mon(&mut b, &my_game::example::MonsterArgs{
+ // name: Some(name),
+ // vector_of_enum: Some(v), ..Default::default()});
+ // assert_eq!(m.vector_of_enum().unwrap().len(), 2);
+ // assert_eq!(m.vector_of_enum().unwrap().get(0), my_game::example::Color::Red);
+ // assert_eq!(m.vector_of_enum().unwrap().get(1), my_game::example::Color::Green);
+ // }
+ #[test]
+ fn vector_of_table_store() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ let t0 = {
+ let name = b.create_string("foo");
+ let args = my_game::example::MonsterArgs{hp: 55, name: Some(name), ..Default::default()};
+ my_game::example::Monster::create(b, &args)
+ };
+ let t1 = {
+ let name = b.create_string("bar");
+ let args = my_game::example::MonsterArgs{name: Some(name), ..Default::default()};
+ my_game::example::Monster::create(b, &args)
+ };
+ let v = b.create_vector(&[t0, t1][..]);
+ let name = b.create_string("foo");
+ let m = build_mon(b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ testarrayoftables: Some(v), ..Default::default()});
+ assert_eq!(m.testarrayoftables().unwrap().len(), 2);
+ assert_eq!(m.testarrayoftables().unwrap().get(0).hp(), 55);
+ assert_eq!(m.testarrayoftables().unwrap().get(0).name(), "foo");
+ assert_eq!(m.testarrayoftables().unwrap().get(1).hp(), 100);
+ assert_eq!(m.testarrayoftables().unwrap().get(1).name(), "bar");
+ }
+}
+
+#[cfg(test)]
+mod generated_code_alignment_and_padding {
+ extern crate flatbuffers;
+ use super::my_game;
+
+ #[test]
+ fn enum_color_is_1_byte() {
+ assert_eq!(1, ::std::mem::size_of::<my_game::example::Color>());
+ }
+
+ #[test]
+ fn enum_color_is_aligned_to_1() {
+ assert_eq!(1, ::std::mem::align_of::<my_game::example::Color>());
+ }
+
+ #[test]
+ fn union_any_is_1_byte() {
+ assert_eq!(1, ::std::mem::size_of::<my_game::example::Any>());
+ }
+
+ #[test]
+ fn union_any_is_aligned_to_1() {
+ assert_eq!(1, ::std::mem::align_of::<my_game::example::Any>());
+ }
+
+ #[test]
+ fn struct_test_is_4_bytes() {
+ assert_eq!(4, ::std::mem::size_of::<my_game::example::Test>());
+ }
+
+ #[test]
+ fn struct_test_is_aligned_to_2() {
+ assert_eq!(2, ::std::mem::align_of::<my_game::example::Test>());
+ }
+
+ #[test]
+ fn struct_vec3_is_32_bytes() {
+ assert_eq!(32, ::std::mem::size_of::<my_game::example::Vec3>());
+ }
+
+ #[test]
+ fn struct_vec3_is_aligned_to_8() {
+ assert_eq!(8, ::std::mem::align_of::<my_game::example::Vec3>());
+ }
+
+ #[test]
+ fn struct_vec3_is_written_with_correct_alignment_in_table() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ let name = b.create_string("foo");
+ let mon = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ pos: Some(&my_game::example::Vec3::new(1.0, 2.0, 3.0, 4.0,
+ my_game::example::Color::Green,
+ &my_game::example::Test::new(98, 99))),
+ ..Default::default()});
+ my_game::example::finish_monster_buffer(b, mon);
+ }
+ let buf = b.finished_data();
+ let mon = my_game::example::get_root_as_monster(buf);
+ let vec3 = mon.pos().unwrap();
+
+ let start_ptr = buf.as_ptr() as usize;
+ let vec3_ptr = vec3 as *const my_game::example::Vec3 as usize;
+
+ assert!(vec3_ptr > start_ptr);
+ let aln = ::std::mem::align_of::<my_game::example::Vec3>();
+ assert_eq!((vec3_ptr - start_ptr) % aln, 0);
+ }
+
+ #[test]
+ fn struct_ability_is_8_bytes() {
+ assert_eq!(8, ::std::mem::size_of::<my_game::example::Ability>());
+ }
+
+ #[test]
+ fn struct_ability_is_aligned_to_4() {
+ assert_eq!(4, ::std::mem::align_of::<my_game::example::Ability>());
+ }
+
+ #[test]
+ fn struct_ability_is_written_with_correct_alignment_in_table_vector() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ {
+ let name = b.create_string("foo");
+ let v = b.create_vector(&[my_game::example::Ability::new(1, 2),
+ my_game::example::Ability::new(3, 4),
+ my_game::example::Ability::new(5, 6)]);
+ let mon = my_game::example::Monster::create(b, &my_game::example::MonsterArgs{
+ name: Some(name),
+ testarrayofsortedstruct: Some(v),
+ ..Default::default()});
+ my_game::example::finish_monster_buffer(b, mon);
+ }
+ let buf = b.finished_data();
+ let mon = my_game::example::get_root_as_monster(buf);
+ let abilities = mon.testarrayofsortedstruct().unwrap();
+
+ let start_ptr = buf.as_ptr() as usize;
+ for a in abilities.iter() {
+ let a_ptr = a as *const my_game::example::Ability as usize;
+ assert!(a_ptr > start_ptr);
+ let aln = ::std::mem::align_of::<my_game::example::Ability>();
+ assert_eq!((a_ptr - start_ptr) % aln, 0);
+ }
+ }
+}
+
+#[cfg(test)]
+mod roundtrip_byteswap {
+ extern crate quickcheck;
+ extern crate flatbuffers;
+
+ const N: u64 = 10000;
+
+ fn palindrome_32(x: f32) -> bool {
+ x == f32::from_bits(x.to_bits().swap_bytes())
+ }
+ fn palindrome_64(x: f64) -> bool {
+ x == f64::from_bits(x.to_bits().swap_bytes())
+ }
+
+ fn prop_f32(x: f32) {
+ use flatbuffers::byte_swap_f32;
+
+ let there = byte_swap_f32(x);
+
+ let back_again = byte_swap_f32(there);
+
+ if !palindrome_32(x) {
+ assert!(x != there);
+ }
+
+ assert_eq!(x, back_again);
+ }
+
+ fn prop_f64(x: f64) {
+ use flatbuffers::byte_swap_f64;
+
+ let there = byte_swap_f64(x);
+ let back_again = byte_swap_f64(there);
+
+ if !palindrome_64(x) {
+ assert!(x != there);
+ }
+
+ assert_eq!(x, back_again);
+ }
+
+ #[test]
+ fn fuzz_f32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_f32 as fn(f32)); }
+ #[test]
+ fn fuzz_f64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_f64 as fn(f64)); }
+}
+
+#[cfg(test)]
+mod roundtrip_vectors {
+
+ #[cfg(test)]
+ mod scalar {
+ extern crate quickcheck;
+ extern crate flatbuffers;
+
+ const N: u64 = 20;
+
+ fn prop<T>(xs: Vec<T>)
+ where
+ T: for<'a> flatbuffers::Follow<'a, Inner = T>
+ + flatbuffers::EndianScalar
+ + flatbuffers::Push
+ + ::std::fmt::Debug,
+ {
+ use flatbuffers::Follow;
+
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<T>(xs.len());
+ for i in (0..xs.len()).rev() {
+ b.push::<T>(xs[i]);
+ }
+ let vecend = b.end_vector::<T>(xs.len());
+ b.finish_minimal(vecend);
+
+ let buf = b.finished_data();
+
+ let got = <flatbuffers::ForwardsUOffset<flatbuffers::Vector<T>>>::follow(&buf[..], 0);
+ let mut result_vec: Vec<T> = Vec::with_capacity(got.len());
+ for i in 0..got.len() {
+ result_vec.push(got.get(i));
+ }
+ assert_eq!(result_vec, xs);
+ }
+
+ #[test]
+ fn easy_u8() {
+ prop::<u8>(vec![]);
+ prop::<u8>(vec![1u8]);
+ prop::<u8>(vec![1u8, 2u8]);
+ prop::<u8>(vec![1u8, 2u8, 3u8]);
+ prop::<u8>(vec![1u8, 2u8, 3u8, 4u8]);
+ }
+
+ #[test]
+ fn fuzz_bool() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<bool> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_u8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u8> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_i8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i8> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_u16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u16> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_i16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i16> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_u32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u32> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_i32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i32> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_u64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u64> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_i64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i64> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_f32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<f32> as fn(Vec<_>)); }
+ #[test]
+ fn fuzz_f64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<f64> as fn(Vec<_>)); }
+ }
+
+ #[cfg(test)]
+ mod create_vector_direct {
+ extern crate quickcheck;
+ extern crate flatbuffers;
+
+ const N: u64 = 20;
+
+ // This uses a macro because lifetimes for the trait-bounded function get too
+ // complicated.
+ macro_rules! impl_prop {
+ ($test_name:ident, $fn_name:ident, $ty:ident) => (
+ fn $fn_name(xs: Vec<$ty>) {
+ use flatbuffers::Follow;
+
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.create_vector_direct(&xs[..]);
+ let buf = b.unfinished_data();
+
+ let got = <flatbuffers::Vector<$ty>>::follow(&buf[..], 0).safe_slice();
+ assert_eq!(got, &xs[..]);
+ }
+ #[test]
+ fn $test_name() { quickcheck::QuickCheck::new().max_tests(N).quickcheck($fn_name as fn(Vec<_>)); }
+ )
+ }
+
+ impl_prop!(test_bool, prop_bool, bool);
+ impl_prop!(test_u8, prop_u8, u8);
+ impl_prop!(test_i8, prop_i8, i8);
+
+ #[cfg(test)]
+ #[cfg(target_endian = "little")]
+ mod host_is_le {
+ const N: u64 = 20;
+ use super::flatbuffers;
+ use super::quickcheck;
+ impl_prop!(test_u16, prop_u16, u16);
+ impl_prop!(test_u32, prop_u32, u32);
+ impl_prop!(test_u64, prop_u64, u64);
+ impl_prop!(test_i16, prop_i16, i16);
+ impl_prop!(test_i32, prop_i32, i32);
+ impl_prop!(test_i64, prop_i64, i64);
+ impl_prop!(test_f32, prop_f32, f32);
+ impl_prop!(test_f64, prop_f64, f64);
+ }
+ }
+
+ #[cfg(test)]
+ mod string_manual_build {
+ extern crate quickcheck;
+ extern crate flatbuffers;
+
+ fn prop(xs: Vec<String>) {
+ use flatbuffers::Follow;
+
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let mut offsets = Vec::new();
+ for s in xs.iter().rev() {
+ offsets.push(b.create_string(s.as_str()));
+ }
+
+ b.start_vector::<flatbuffers::WIPOffset<&str>>(xs.len());
+ for &i in offsets.iter() {
+ b.push(i);
+ }
+ let vecend = b.end_vector::<flatbuffers::WIPOffset<&str>>(xs.len());
+
+ b.finish_minimal(vecend);
+
+ let buf = b.finished_data();
+ let got = <flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&str>>>>::follow(buf, 0);
+
+ assert_eq!(got.len(), xs.len());
+ for i in 0..xs.len() {
+ assert_eq!(got.get(i), &xs[i][..]);
+ }
+ }
+
+ #[test]
+ fn fuzz() {
+ quickcheck::QuickCheck::new().max_tests(20).quickcheck(prop as fn(Vec<_>));
+ }
+ }
+
+ #[cfg(test)]
+ mod string_helper_build {
+ extern crate quickcheck;
+ extern crate flatbuffers;
+
+ fn prop(input: Vec<String>) {
+ let xs: Vec<&str> = input.iter().map(|s: &String| &s[..]).collect();
+
+ use flatbuffers::Follow;
+
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let vecend = b.create_vector_of_strings(&xs[..]);
+
+ b.finish_minimal(vecend);
+
+ let buf = b.finished_data();
+ let got = <flatbuffers::ForwardsUOffset<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&str>>>>::follow(buf, 0);
+
+ assert_eq!(got.len(), xs.len());
+ for i in 0..xs.len() {
+ assert_eq!(got.get(i), &xs[i][..]);
+ }
+ }
+
+ #[test]
+ fn fuzz() {
+ quickcheck::QuickCheck::new().max_tests(100).quickcheck(prop as fn(Vec<_>));
+ }
+ }
+
+ #[cfg(test)]
+ mod ubyte {
+ extern crate quickcheck;
+ extern crate flatbuffers;
+
+ #[test]
+ fn fuzz_manual_build() {
+ fn prop(vec: Vec<u8>) {
+ let xs = &vec[..];
+
+ let mut b1 = flatbuffers::FlatBufferBuilder::new();
+ b1.start_vector::<u8>(xs.len());
+
+ for i in (0..xs.len()).rev() {
+ b1.push(xs[i]);
+ }
+ b1.end_vector::<u8>(xs.len());
+
+ let mut b2 = flatbuffers::FlatBufferBuilder::new();
+ b2.create_vector(xs);
+ assert_eq!(b1.unfinished_data(), b2.unfinished_data());
+ }
+ quickcheck::QuickCheck::new().max_tests(100).quickcheck(prop as fn(Vec<_>));
+ }
+ }
+}
+
+#[cfg(test)]
+mod framing_format {
+ extern crate flatbuffers;
+
+ use super::my_game;
+
+ #[test]
+ fn test_size_prefixed_buffer() {
+ // Create size prefixed buffer.
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let args = &my_game::example::MonsterArgs{
+ mana: 200,
+ hp: 300,
+ name: Some(b.create_string("bob")),
+ ..Default::default()
+ };
+ let mon = my_game::example::Monster::create(&mut b, &args);
+ b.finish_size_prefixed(mon, None);
+
+ // Access it.
+ let buf = b.finished_data();
+ let m = flatbuffers::get_size_prefixed_root::<my_game::example::Monster>(buf);
+ assert_eq!(m.mana(), 200);
+ assert_eq!(m.hp(), 300);
+ assert_eq!(m.name(), "bob");
+ }
+}
+
+#[cfg(test)]
+mod roundtrip_table {
+ use std::collections::HashMap;
+
+ extern crate flatbuffers;
+ extern crate quickcheck;
+
+ use super::LCG;
+
+ #[test]
+ fn table_of_mixed_scalars_fuzz() {
+ // Values we're testing against: chosen to ensure no bits get chopped
+ // off anywhere, and also be different from eachother.
+ let bool_val: bool = true;
+ let char_val: i8 = -127; // 0x81
+ let uchar_val: u8 = 0xFF;
+ let short_val: i16 = -32222; // 0x8222;
+ let ushort_val: u16 = 0xFEEE;
+ let int_val: i32 = unsafe { ::std::mem::transmute(0x83333333u32) };
+ let uint_val: u32 = 0xFDDDDDDD;
+ let long_val: i64 = unsafe { ::std::mem::transmute(0x8444444444444444u64) }; // TODO: byte literal?
+ let ulong_val: u64 = 0xFCCCCCCCCCCCCCCCu64;
+ let float_val: f32 = 3.14159;
+ let double_val: f64 = 3.14159265359;
+
+ let test_value_types_max: isize = 11;
+ let max_fields_per_object: flatbuffers::VOffsetT = 100;
+ let num_fuzz_objects: isize = 1000; // The higher, the more thorough :)
+
+ let mut builder = flatbuffers::FlatBufferBuilder::new();
+ let mut lcg = LCG::new();
+
+ let mut objects: Vec<flatbuffers::UOffsetT> = vec![0; num_fuzz_objects as usize];
+
+ // Generate num_fuzz_objects random objects each consisting of
+ // fields_per_object fields, each of a random type.
+ for i in 0..(num_fuzz_objects as usize) {
+ let fields_per_object = (lcg.next() % (max_fields_per_object as u64)) as flatbuffers::VOffsetT;
+ let start = builder.start_table();
+
+ for j in 0..fields_per_object {
+ let choice = lcg.next() % (test_value_types_max as u64);
+
+ let f = flatbuffers::field_index_to_field_offset(j);
+
+ match choice {
+ 0 => {builder.push_slot::<bool>(f, bool_val, false);}
+ 1 => {builder.push_slot::<i8>(f, char_val, 0);}
+ 2 => {builder.push_slot::<u8>(f, uchar_val, 0);}
+ 3 => {builder.push_slot::<i16>(f, short_val, 0);}
+ 4 => {builder.push_slot::<u16>(f, ushort_val, 0);}
+ 5 => {builder.push_slot::<i32>(f, int_val, 0);}
+ 6 => {builder.push_slot::<u32>(f, uint_val, 0);}
+ 7 => {builder.push_slot::<i64>(f, long_val, 0);}
+ 8 => {builder.push_slot::<u64>(f, ulong_val, 0);}
+ 9 => {builder.push_slot::<f32>(f, float_val, 0.0);}
+ 10 => {builder.push_slot::<f64>(f, double_val, 0.0);}
+ _ => { panic!("unknown choice: {}", choice); }
+ }
+ }
+ objects[i] = builder.end_table(start).value();
+ }
+
+ // Do some bookkeeping to generate stats on fuzzes:
+ let mut stats: HashMap<u64, u64> = HashMap::new();
+ let mut values_generated: u64 = 0;
+
+ // Embrace PRNG determinism:
+ lcg.reset();
+
+ // Test that all objects we generated are readable and return the
+ // expected values. We generate random objects in the same order
+ // so this is deterministic:
+ for i in 0..(num_fuzz_objects as usize) {
+ let table = {
+ let buf = builder.unfinished_data();
+ let loc = buf.len() as flatbuffers::UOffsetT - objects[i];
+ flatbuffers::Table::new(buf, loc as usize)
+ };
+
+ let fields_per_object = (lcg.next() % (max_fields_per_object as u64)) as flatbuffers::VOffsetT;
+ for j in 0..fields_per_object {
+ let choice = lcg.next() % (test_value_types_max as u64);
+
+ *stats.entry(choice).or_insert(0) += 1;
+ values_generated += 1;
+
+ let f = flatbuffers::field_index_to_field_offset(j);
+
+ match choice {
+ 0 => { assert_eq!(bool_val, table.get::<bool>(f, Some(false)).unwrap()); }
+ 1 => { assert_eq!(char_val, table.get::<i8>(f, Some(0)).unwrap()); }
+ 2 => { assert_eq!(uchar_val, table.get::<u8>(f, Some(0)).unwrap()); }
+ 3 => { assert_eq!(short_val, table.get::<i16>(f, Some(0)).unwrap()); }
+ 4 => { assert_eq!(ushort_val, table.get::<u16>(f, Some(0)).unwrap()); }
+ 5 => { assert_eq!(int_val, table.get::<i32>(f, Some(0)).unwrap()); }
+ 6 => { assert_eq!(uint_val, table.get::<u32>(f, Some(0)).unwrap()); }
+ 7 => { assert_eq!(long_val, table.get::<i64>(f, Some(0)).unwrap()); }
+ 8 => { assert_eq!(ulong_val, table.get::<u64>(f, Some(0)).unwrap()); }
+ 9 => { assert_eq!(float_val, table.get::<f32>(f, Some(0.0)).unwrap()); }
+ 10 => { assert_eq!(double_val, table.get::<f64>(f, Some(0.0)).unwrap()); }
+ _ => { panic!("unknown choice: {}", choice); }
+ }
+ }
+ }
+
+ // Assert that we tested all the fuzz cases enough:
+ let min_tests_per_choice = 1000;
+ assert!(values_generated > 0);
+ assert!(min_tests_per_choice > 0);
+ for i in 0..test_value_types_max as u64 {
+ assert!(stats[&i] >= min_tests_per_choice,
+ format!("inadequately-tested fuzz case: {}", i));
+ }
+ }
+
+ #[test]
+ fn table_of_byte_strings_fuzz() {
+ fn prop(vec: Vec<Vec<u8>>) {
+ use flatbuffers::field_index_to_field_offset as fi2fo;
+ use flatbuffers::Follow;
+
+ let xs = &vec[..];
+
+ // build
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let str_offsets: Vec<flatbuffers::WIPOffset<_>> = xs.iter().map(|s| b.create_byte_string(&s[..])).collect();
+ let table_start = b.start_table();
+
+ for i in 0..xs.len() {
+ b.push_slot_always(fi2fo(i as flatbuffers::VOffsetT), str_offsets[i]);
+ }
+ let root = b.end_table(table_start);
+ b.finish_minimal(root);
+
+ // use
+ let buf = b.finished_data();
+ let tab = <flatbuffers::ForwardsUOffset<flatbuffers::Table>>::follow(buf, 0);
+
+ for i in 0..xs.len() {
+ let v = tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<u8>>>(fi2fo(i as flatbuffers::VOffsetT), None);
+ assert!(v.is_some());
+ let v2 = v.unwrap().safe_slice();
+ assert_eq!(v2, &xs[i][..]);
+ }
+ }
+ prop(vec![vec![1,2,3]]);
+
+ let n = 20;
+ quickcheck::QuickCheck::new().max_tests(n).quickcheck(prop as fn(Vec<_>));
+ }
+
+ #[test]
+ fn fuzz_table_of_strings() {
+ fn prop(vec: Vec<String>) {
+ use flatbuffers::field_index_to_field_offset as fi2fo;
+ use flatbuffers::Follow;
+
+ let xs = &vec[..];
+
+ // build
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let str_offsets: Vec<flatbuffers::WIPOffset<_>> = xs.iter().map(|s| b.create_string(&s[..])).collect();
+ let table_start = b.start_table();
+
+ for i in 0..xs.len() {
+ b.push_slot_always(fi2fo(i as flatbuffers::VOffsetT), str_offsets[i]);
+ }
+ let root = b.end_table(table_start);
+ b.finish_minimal(root);
+
+ // use
+ let buf = b.finished_data();
+ let tab = <flatbuffers::ForwardsUOffset<flatbuffers::Table>>::follow(buf, 0);
+
+ for i in 0..xs.len() {
+ let v = tab.get::<flatbuffers::ForwardsUOffset<&str>>(fi2fo(i as flatbuffers::VOffsetT), None);
+ assert_eq!(v, Some(&xs[i][..]));
+ }
+ }
+ let n = 20;
+ quickcheck::QuickCheck::new().max_tests(n).quickcheck(prop as fn(Vec<String>));
+ }
+
+ mod table_of_vectors_of_scalars {
+ extern crate flatbuffers;
+ extern crate quickcheck;
+
+ const N: u64 = 20;
+
+ fn prop<T>(vecs: Vec<Vec<T>>)
+ where
+ T: for<'a> flatbuffers::Follow<'a, Inner = T>
+ + flatbuffers::EndianScalar
+ + flatbuffers::Push
+ + ::std::fmt::Debug,
+ {
+ use flatbuffers::field_index_to_field_offset as fi2fo;
+ use flatbuffers::Follow;
+
+ // build
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let mut offs = vec![];
+ for vec in &vecs {
+ b.start_vector::<T>(vec.len());
+
+ let xs = &vec[..];
+ for i in (0..xs.len()).rev() {
+ b.push::<T>(xs[i]);
+ }
+ let vecend = b.end_vector::<T>(xs.len());
+ offs.push(vecend);
+ }
+
+ let table_start = b.start_table();
+
+ for i in 0..vecs.len() {
+ b.push_slot_always(fi2fo(i as flatbuffers::VOffsetT), offs[i]);
+ }
+ let root = b.end_table(table_start);
+ b.finish_minimal(root);
+
+ // use
+ let buf = b.finished_data();
+ let tab = <flatbuffers::ForwardsUOffset<flatbuffers::Table>>::follow(buf, 0);
+
+ for i in 0..vecs.len() {
+ let got = tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<T>>>(fi2fo(i as flatbuffers::VOffsetT), None);
+ assert!(got.is_some());
+ let got2 = got.unwrap();
+ let mut got3: Vec<T> = Vec::with_capacity(got2.len());
+ for i in 0..got2.len() {
+ got3.push(got2.get(i));
+ }
+ assert_eq!(vecs[i], got3);
+ }
+ }
+
+ #[test]
+ fn fuzz_bool() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<bool>>)); }
+
+ #[test]
+ fn fuzz_u8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u8>>)); }
+ #[test]
+ fn fuzz_u16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u16>>)); }
+ #[test]
+ fn fuzz_u32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u32>>)); }
+ #[test]
+ fn fuzz_u64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u64>>)); }
+
+ #[test]
+ fn fuzz_i8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u8>>)); }
+ #[test]
+ fn fuzz_i16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u16>>)); }
+ #[test]
+ fn fuzz_i32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u32>>)); }
+ #[test]
+ fn fuzz_i64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<u64>>)); }
+
+ #[test]
+ fn fuzz_f32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<f32>>)); }
+ #[test]
+ fn fuzz_f64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop as fn(Vec<Vec<f64>>)); }
+ }
+}
+
+#[cfg(test)]
+mod roundtrip_scalars {
+ extern crate flatbuffers;
+ extern crate quickcheck;
+
+ const N: u64 = 1000;
+
+ fn prop<T: PartialEq + ::std::fmt::Debug + Copy + flatbuffers::EndianScalar>(x: T) {
+ let mut buf = vec![0u8; ::std::mem::size_of::<T>()];
+ flatbuffers::emplace_scalar(&mut buf[..], x);
+ let y = flatbuffers::read_scalar(&buf[..]);
+ assert_eq!(x, y);
+ }
+
+ #[test]
+ fn fuzz_bool() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<bool> as fn(_)); }
+ #[test]
+ fn fuzz_u8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u8> as fn(_)); }
+ #[test]
+ fn fuzz_i8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i8> as fn(_)); }
+
+ #[test]
+ fn fuzz_u16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u16> as fn(_)); }
+ #[test]
+ fn fuzz_i16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i16> as fn(_)); }
+
+ #[test]
+ fn fuzz_u32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u32> as fn(_)); }
+ #[test]
+ fn fuzz_i32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i32> as fn(_)); }
+
+ #[test]
+ fn fuzz_u64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<u64> as fn(_)); }
+ #[test]
+ fn fuzz_i64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<i64> as fn(_)); }
+
+ #[test]
+ fn fuzz_f32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<f32> as fn(_)); }
+ #[test]
+ fn fuzz_f64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop::<f64> as fn(_)); }
+}
+
+#[cfg(test)]
+mod roundtrip_push_follow_scalars {
+ extern crate flatbuffers;
+ extern crate quickcheck;
+
+ use flatbuffers::Push;
+
+ const N: u64 = 1000;
+
+ // This uses a macro because lifetimes for a trait-bounded function get too
+ // complicated.
+ macro_rules! impl_prop {
+ ($fn_name:ident, $ty:ident) => (
+ fn $fn_name(x: $ty) {
+ let mut buf = vec![0u8; ::std::mem::size_of::<$ty>()];
+ x.push(&mut buf[..], &[][..]);
+ let fs: flatbuffers::FollowStart<$ty> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&buf[..], 0), x);
+ }
+ )
+ }
+
+ impl_prop!(prop_bool, bool);
+ impl_prop!(prop_u8, u8);
+ impl_prop!(prop_i8, i8);
+ impl_prop!(prop_u16, u16);
+ impl_prop!(prop_i16, i16);
+ impl_prop!(prop_u32, u32);
+ impl_prop!(prop_i32, i32);
+ impl_prop!(prop_u64, u64);
+ impl_prop!(prop_i64, i64);
+ impl_prop!(prop_f32, f32);
+ impl_prop!(prop_f64, f64);
+
+ #[test]
+ fn fuzz_bool() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_bool as fn(bool)); }
+ #[test]
+ fn fuzz_u8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_u8 as fn(u8)); }
+ #[test]
+ fn fuzz_i8() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_i8 as fn(i8)); }
+ #[test]
+ fn fuzz_u16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_u16 as fn(u16)); }
+ #[test]
+ fn fuzz_i16() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_i16 as fn(i16)); }
+ #[test]
+ fn fuzz_u32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_u32 as fn(u32)); }
+ #[test]
+ fn fuzz_i32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_i32 as fn(i32)); }
+ #[test]
+ fn fuzz_u64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_u64 as fn(u64)); }
+ #[test]
+ fn fuzz_i64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_i64 as fn(i64)); }
+ #[test]
+ fn fuzz_f32() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_f32 as fn(f32)); }
+ #[test]
+ fn fuzz_f64() { quickcheck::QuickCheck::new().max_tests(N).quickcheck(prop_f64 as fn(f64)); }
+}
+
+
+#[cfg(test)]
+mod write_and_read_examples {
+ extern crate flatbuffers;
+
+ use super::create_serialized_example_with_library_code;
+ use super::create_serialized_example_with_generated_code;
+ use super::serialized_example_is_accessible_and_correct;
+
+ #[test]
+ fn generated_code_creates_correct_example() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ create_serialized_example_with_generated_code(b);
+ let buf = b.finished_data();
+ serialized_example_is_accessible_and_correct(&buf[..], true, false).unwrap();
+ }
+
+ #[test]
+ fn generated_code_creates_correct_example_repeatedly_with_reset() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ for _ in 0..100 {
+ create_serialized_example_with_generated_code(b);
+ {
+ let buf = b.finished_data();
+ serialized_example_is_accessible_and_correct(&buf[..], true, false).unwrap();
+ }
+ b.reset();
+ }
+ }
+
+ #[test]
+ fn library_code_creates_correct_example() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ create_serialized_example_with_library_code(b);
+ let buf = b.finished_data();
+ serialized_example_is_accessible_and_correct(&buf[..], true, false).unwrap();
+ }
+
+ #[test]
+ fn library_code_creates_correct_example_repeatedly_with_reset() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ for _ in 0..100 {
+ create_serialized_example_with_library_code(b);
+ {
+ let buf = b.finished_data();
+ serialized_example_is_accessible_and_correct(&buf[..], true, false).unwrap();
+ }
+ b.reset();
+ }
+ }
+}
+
+#[cfg(test)]
+mod read_examples_from_other_language_ports {
+ extern crate flatbuffers;
+
+ use super::load_file;
+ use super::serialized_example_is_accessible_and_correct;
+
+ #[test]
+ fn gold_cpp_example_data_is_accessible_and_correct() {
+ let buf = load_file("../monsterdata_test.mon").expect("missing monsterdata_test.mon");
+ serialized_example_is_accessible_and_correct(&buf[..], true, false).unwrap();
+ }
+ #[test]
+ fn java_wire_example_data_is_accessible_and_correct() {
+ let buf = load_file("../monsterdata_java_wire.mon");
+ if buf.is_err() {
+ println!("skipping java wire test because it is not present");
+ return;
+ }
+ let buf = buf.unwrap();
+ serialized_example_is_accessible_and_correct(&buf[..], true, false).unwrap();
+ }
+ #[test]
+ fn java_wire_size_prefixed_example_data_is_accessible_and_correct() {
+ let buf = load_file("../monsterdata_java_wire_sp.mon");
+ if buf.is_err() {
+ println!("skipping java wire test because it is not present");
+ return;
+ }
+ let buf = buf.unwrap();
+ serialized_example_is_accessible_and_correct(&buf[..], true, true).unwrap();
+ }
+}
+
+#[cfg(test)]
+mod generated_code_asserts {
+ extern crate flatbuffers;
+
+ use super::my_game;
+
+ #[test]
+ #[should_panic]
+ fn monster_builder_fails_when_name_is_missing() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ my_game::example::Monster::create(b, &my_game::example::MonsterArgs{..Default::default()});
+ }
+}
+
+#[cfg(test)]
+mod generated_key_comparisons {
+ extern crate flatbuffers;
+
+ use super::my_game;
+
+ #[test]
+ fn struct_ability_key_compare_less_than() {
+ let a = my_game::example::Ability::new(1, 2);
+ let b = my_game::example::Ability::new(2, 1);
+ let c = my_game::example::Ability::new(3, 3);
+
+ assert_eq!(a.key_compare_less_than(&a), false);
+ assert_eq!(b.key_compare_less_than(&b), false);
+ assert_eq!(c.key_compare_less_than(&c), false);
+
+ assert_eq!(a.key_compare_less_than(&b), true);
+ assert_eq!(a.key_compare_less_than(&c), true);
+
+ assert_eq!(b.key_compare_less_than(&a), false);
+ assert_eq!(b.key_compare_less_than(&c), true);
+
+ assert_eq!(c.key_compare_less_than(&a), false);
+ assert_eq!(c.key_compare_less_than(&b), false);
+ }
+
+ #[test]
+ fn struct_key_compare_with_value() {
+ let a = my_game::example::Ability::new(1, 2);
+
+ assert_eq!(a.key_compare_with_value(0), ::std::cmp::Ordering::Greater);
+ assert_eq!(a.key_compare_with_value(1), ::std::cmp::Ordering::Equal);
+ assert_eq!(a.key_compare_with_value(2), ::std::cmp::Ordering::Less);
+ }
+
+ #[test]
+ fn struct_key_compare_less_than() {
+ let a = my_game::example::Ability::new(1, 2);
+ let b = my_game::example::Ability::new(2, 1);
+ let c = my_game::example::Ability::new(3, 3);
+
+ assert_eq!(a.key_compare_less_than(&a), false);
+ assert_eq!(b.key_compare_less_than(&b), false);
+ assert_eq!(c.key_compare_less_than(&c), false);
+
+ assert_eq!(a.key_compare_less_than(&b), true);
+ assert_eq!(a.key_compare_less_than(&c), true);
+
+ assert_eq!(b.key_compare_less_than(&a), false);
+ assert_eq!(b.key_compare_less_than(&c), true);
+
+ assert_eq!(c.key_compare_less_than(&a), false);
+ assert_eq!(c.key_compare_less_than(&b), false);
+ }
+
+ #[test]
+ fn table_key_compare_with_value() {
+ // setup
+ let builder = &mut flatbuffers::FlatBufferBuilder::new();
+ super::create_serialized_example_with_library_code(builder);
+ let buf = builder.finished_data();
+ let a = my_game::example::get_root_as_monster(buf);
+
+ // preconditions
+ assert_eq!(a.name(), "MyMonster");
+
+ assert_eq!(a.key_compare_with_value("AAA"), ::std::cmp::Ordering::Greater);
+ assert_eq!(a.key_compare_with_value("MyMonster"), ::std::cmp::Ordering::Equal);
+ assert_eq!(a.key_compare_with_value("ZZZ"), ::std::cmp::Ordering::Less);
+ }
+
+ #[test]
+ fn table_key_compare_less_than() {
+ // setup
+ let builder = &mut flatbuffers::FlatBufferBuilder::new();
+ super::create_serialized_example_with_library_code(builder);
+ let buf = builder.finished_data();
+ let a = my_game::example::get_root_as_monster(buf);
+ let b = a.test_as_monster().unwrap();
+
+ // preconditions
+ assert_eq!(a.name(), "MyMonster");
+ assert_eq!(b.name(), "Fred");
+
+ assert_eq!(a.key_compare_less_than(&a), false);
+ assert_eq!(a.key_compare_less_than(&b), false);
+
+ assert_eq!(b.key_compare_less_than(&a), true);
+ assert_eq!(b.key_compare_less_than(&b), false);
+ }
+}
+
+#[cfg(test)]
+mod included_schema_generated_code {
+ extern crate flatbuffers;
+
+ //extern crate rust_usage_test;
+
+ // TODO(rw): make generated sub-namespace files importable
+ //#[test]
+ //fn namespace_test_mod_is_importable() {
+ // use rust_usage_test::namespace_test;
+ //}
+ //#[test]
+ //fn namespace_test1_mod_is_importable() {
+ // use rust_usage_test::namespace_test::namespace_test1_generated;
+ //}
+ //#[test]
+ //fn namespace_test2_mod_is_importable() {
+ // use rust_usage_test::namespace_test::namespace_test2_generated;
+ //}
+}
+
+#[cfg(test)]
+mod builder_asserts {
+ extern crate flatbuffers;
+
+ #[test]
+ #[should_panic]
+ fn end_table_should_panic_when_not_in_table() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.end_table(flatbuffers::WIPOffset::new(0));
+ }
+
+ #[test]
+ #[should_panic]
+ fn create_string_should_panic_when_in_table() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_table();
+ b.create_string("foo");
+ }
+
+ #[test]
+ #[should_panic]
+ fn create_byte_string_should_panic_when_in_table() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_table();
+ b.create_byte_string(b"foo");
+ }
+
+ #[test]
+ #[should_panic]
+ fn push_struct_slot_should_panic_when_not_in_table() {
+ #[derive(Copy, Clone, Debug, PartialEq)]
+ #[repr(C, packed)]
+ struct foo { }
+ impl<'b> flatbuffers::Push for &'b foo {
+ type Output = foo;
+ fn push<'a>(&'a self, _dst: &'a mut [u8], _rest: &'a [u8]) { }
+ }
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push_slot_always(0, &foo{});
+ }
+
+ #[test]
+ #[should_panic]
+ fn finished_bytes_should_panic_when_table_is_not_finished() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_table();
+ b.finished_data();
+ }
+
+ #[test]
+ #[should_panic]
+ fn required_panics_when_field_not_set() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let start = b.start_table();
+ let o = b.end_table(start);
+ b.required(o, 4 /* byte offset to first field */, "test field");
+ }
+}
+
+#[cfg(test)]
+mod follow_impls {
+ extern crate flatbuffers;
+ use flatbuffers::Follow;
+ use flatbuffers::field_index_to_field_offset as fi2fo;
+
+ // Define a test struct to use in a few tests. This replicates the work that the code generator
+ // would normally do when defining a FlatBuffer struct. For reference, compare the following
+ // `FooStruct` code with the code generated for the `Vec3` struct in
+ // `../../monster_test_generated.rs`.
+ use flatbuffers::EndianScalar;
+ #[derive(Copy, Clone, Debug, PartialEq)]
+ #[repr(C, packed)]
+ struct FooStruct {
+ a: i8,
+ b: u8,
+ c: i16,
+ }
+ impl FooStruct {
+ fn new(_a: i8, _b: u8, _c: i16) -> Self {
+ FooStruct {
+ a: _a.to_little_endian(),
+ b: _b.to_little_endian(),
+ c: _c.to_little_endian(),
+ }
+ }
+ }
+ impl flatbuffers::SafeSliceAccess for FooStruct {}
+ impl<'a> flatbuffers::Follow<'a> for FooStruct {
+ type Inner = &'a FooStruct;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ <&'a FooStruct>::follow(buf, loc)
+ }
+ }
+ impl<'a> flatbuffers::Follow<'a> for &'a FooStruct {
+ type Inner = &'a FooStruct;
+ #[inline(always)]
+ fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
+ flatbuffers::follow_cast_ref::<FooStruct>(buf, loc)
+ }
+ }
+
+ #[test]
+ fn to_u8() {
+ let vec: Vec<u8> = vec![255, 3];
+ let fs: flatbuffers::FollowStart<u8> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&vec[..], 1), 3);
+ }
+
+ #[test]
+ fn to_u16() {
+ let vec: Vec<u8> = vec![255, 255, 3, 4];
+ let fs: flatbuffers::FollowStart<u16> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&vec[..], 2), 1027);
+ }
+
+ #[test]
+ fn to_f32() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, /* start of value */ 208, 15, 73, 64];
+ let fs: flatbuffers::FollowStart<f32> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&vec[..], 4), 3.14159);
+ }
+
+ #[test]
+ fn to_string() {
+ let vec: Vec<u8> = vec![255,255,255,255, 3, 0, 0, 0, 'f' as u8, 'o' as u8, 'o' as u8, 0];
+ let off: flatbuffers::FollowStart<&str> = flatbuffers::FollowStart::new();
+ assert_eq!(off.self_follow(&vec[..], 4), "foo");
+ }
+
+ #[test]
+ fn to_byte_slice() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, 4, 0, 0, 0, 1, 2, 3, 4];
+ let off: flatbuffers::FollowStart<flatbuffers::Vector<u8>> = flatbuffers::FollowStart::new();
+ assert_eq!(off.self_follow(&vec[..], 4).safe_slice(), &[1, 2, 3, 4][..]);
+ }
+
+ #[test]
+ fn to_byte_vector() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, 4, 0, 0, 0, 1, 2, 3, 4];
+ let off: flatbuffers::FollowStart<flatbuffers::Vector<u8>> = flatbuffers::FollowStart::new();
+ assert_eq!(off.self_follow(&vec[..], 4).safe_slice(), &[1, 2, 3, 4][..]);
+ }
+
+ #[test]
+ fn to_byte_string_zero_teriminated() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, 3, 0, 0, 0, 1, 2, 3, 0];
+ let off: flatbuffers::FollowStart<flatbuffers::Vector<u8>> = flatbuffers::FollowStart::new();
+ assert_eq!(off.self_follow(&vec[..], 4).safe_slice(), &[1, 2, 3][..]);
+ }
+
+ #[cfg(target_endian = "little")]
+ #[test]
+ fn to_slice_of_u16() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, 2, 0, 0, 0, 1, 2, 3, 4];
+ let off: flatbuffers::FollowStart<&[u16]> = flatbuffers::FollowStart::new();
+ assert_eq!(off.self_follow(&vec[..], 4), &vec![513, 1027][..]);
+ }
+
+ #[test]
+ fn to_vector_of_u16() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, 2, 0, 0, 0, 1, 2, 3, 4];
+ let off: flatbuffers::FollowStart<flatbuffers::Vector<u16>> = flatbuffers::FollowStart::new();
+ assert_eq!(off.self_follow(&vec[..], 4).len(), 2);
+ assert_eq!(off.self_follow(&vec[..], 4).get(0), 513);
+ assert_eq!(off.self_follow(&vec[..], 4).get(1), 1027);
+ }
+
+ #[test]
+ fn to_struct() {
+ let vec: Vec<u8> = vec![255, 255, 255, 255, 1, 2, 3, 4];
+ let off: flatbuffers::FollowStart<&FooStruct> = flatbuffers::FollowStart::new();
+ assert_eq!(*off.self_follow(&vec[..], 4), FooStruct::new(1, 2, 1027));
+ }
+
+ #[test]
+ fn to_vector_of_offset_to_string_elements() {
+ let buf: Vec<u8> = vec![/* vec len */ 1, 0, 0, 0, /* offset to string */ 4, 0, 0, 0, /* str length */ 3, 0, 0, 0, 'f' as u8, 'o' as u8, 'o' as u8, 0];
+ let s: flatbuffers::FollowStart<flatbuffers::Vector<flatbuffers::ForwardsUOffset<&str>>> = flatbuffers::FollowStart::new();
+ assert_eq!(s.self_follow(&buf[..], 0).len(), 1);
+ assert_eq!(s.self_follow(&buf[..], 0).get(0), "foo");
+ }
+
+ #[test]
+ fn to_slice_of_struct_elements() {
+ let buf: Vec<u8> = vec![1, 0, 0, 0, /* struct data */ 1, 2, 3, 4];
+ let fs: flatbuffers::FollowStart<flatbuffers::Vector<FooStruct>> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&buf[..], 0).safe_slice(), &vec![FooStruct::new(1, 2, 1027)][..]);
+ }
+
+ #[test]
+ fn to_vector_of_struct_elements() {
+ let buf: Vec<u8> = vec![1, 0, 0, 0, /* struct data */ 1, 2, 3, 4];
+ let fs: flatbuffers::FollowStart<flatbuffers::Vector<FooStruct>> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&buf[..], 0).len(), 1);
+ assert_eq!(fs.self_follow(&buf[..], 0).get(0), &FooStruct::new(1, 2, 1027));
+ }
+
+ #[test]
+ fn to_root_to_empty_table() {
+ let buf: Vec<u8> = vec![
+ 12, 0, 0, 0, // offset to root table
+ // enter vtable
+ 4, 0, // vtable len
+ 0, 0, // inline size
+ 255, 255, 255, 255, // canary
+ // enter table
+ 8, 0, 0, 0, // vtable location
+ ];
+ let fs: flatbuffers::FollowStart<flatbuffers::ForwardsUOffset<flatbuffers::Table>> = flatbuffers::FollowStart::new();
+ assert_eq!(fs.self_follow(&buf[..], 0), flatbuffers::Table::new(&buf[..], 12));
+ }
+
+ #[test]
+ fn to_root_table_get_slot_scalar_u8() {
+ let buf: Vec<u8> = vec![
+ 14, 0, 0, 0, // offset to root table
+ // enter vtable
+ 6, 0, // vtable len
+ 2, 0, // inline size
+ 5, 0, // value loc
+ 255, 255, 255, 255, // canary
+ // enter table
+ 10, 0, 0, 0, // vtable location
+ 0, 99 // value (with padding)
+ ];
+ let fs: flatbuffers::FollowStart<flatbuffers::ForwardsUOffset<flatbuffers::Table>> = flatbuffers::FollowStart::new();
+ let tab = fs.self_follow(&buf[..], 0);
+ assert_eq!(tab.get::<u8>(fi2fo(0), Some(123)), Some(99));
+ }
+
+ #[test]
+ fn to_root_to_table_get_slot_scalar_u8_default_via_vtable_len() {
+ let buf: Vec<u8> = vec![
+ 12, 0, 0, 0, // offset to root table
+ // enter vtable
+ 4, 0, // vtable len
+ 2, 0, // inline size
+ 255, 255, 255, 255, // canary
+ // enter table
+ 8, 0, 0, 0, // vtable location
+ ];
+ let fs: flatbuffers::FollowStart<flatbuffers::ForwardsUOffset<flatbuffers::Table>> = flatbuffers::FollowStart::new();
+ let tab = fs.self_follow(&buf[..], 0);
+ assert_eq!(tab.get::<u8>(fi2fo(0), Some(123)), Some(123));
+ }
+
+ #[test]
+ fn to_root_to_table_get_slot_scalar_u8_default_via_vtable_zero() {
+ let buf: Vec<u8> = vec![
+ 14, 0, 0, 0, // offset to root table
+ // enter vtable
+ 6, 0, // vtable len
+ 2, 0, // inline size
+ 0, 0, // zero means use the default value
+ 255, 255, 255, 255, // canary
+ // enter table
+ 10, 0, 0, 0, // vtable location
+ ];
+ let fs: flatbuffers::FollowStart<flatbuffers::ForwardsUOffset<flatbuffers::Table>> = flatbuffers::FollowStart::new();
+ let tab = fs.self_follow(&buf[..], 0);
+ assert_eq!(tab.get::<u8>(fi2fo(0), Some(123)), Some(123));
+ }
+
+ #[test]
+ fn to_root_to_table_get_slot_string_multiple_types() {
+ let buf: Vec<u8> = vec![
+ 14, 0, 0, 0, // offset to root table
+ // enter vtable
+ 6, 0, // vtable len
+ 2, 0, // inline size
+ 4, 0, // value loc
+ 255, 255, 255, 255, // canary
+ // enter table
+ 10, 0, 0, 0, // vtable location
+ 8, 0, 0, 0, // offset to string
+ // leave table
+ 255, 255, 255, 255, // canary
+ // enter string
+ 3, 0, 0, 0, 109, 111, 111, 0 // string length and contents
+ ];
+ let tab = <flatbuffers::ForwardsUOffset<flatbuffers::Table>>::follow(&buf[..], 0);
+ assert_eq!(tab.get::<flatbuffers::ForwardsUOffset<&str>>(fi2fo(0), None), Some("moo"));
+ let byte_vec = tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<u8>>>(fi2fo(0), None).unwrap().safe_slice();
+ assert_eq!(byte_vec, &vec![109, 111, 111][..]);
+ let v = tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<u8>>>(fi2fo(0), None).unwrap();
+ assert_eq!(v.len(), 3);
+ assert_eq!(v.get(0), 109);
+ assert_eq!(v.get(1), 111);
+ assert_eq!(v.get(2), 111);
+ }
+
+ #[test]
+ fn to_root_to_table_get_slot_string_multiple_types_default_via_vtable_len() {
+ let buf: Vec<u8> = vec![
+ 12, 0, 0, 0, // offset to root table
+ // enter vtable
+ 4, 0, // vtable len
+ 4, 0, // table inline len
+ 255, 255, 255, 255, // canary
+ // enter table
+ 8, 0, 0, 0, // vtable location
+ ];
+ let tab = <flatbuffers::ForwardsUOffset<flatbuffers::Table>>::follow(&buf[..], 0);
+ assert_eq!(tab.get::<flatbuffers::ForwardsUOffset<&str>>(fi2fo(0), Some("abc")), Some("abc"));
+ #[cfg(target_endian = "little")]
+ {
+ assert_eq!(tab.get::<flatbuffers::ForwardsUOffset<&[u8]>>(fi2fo(0), Some(&vec![70, 71, 72][..])), Some(&vec![70, 71, 72][..]));
+ }
+
+ let default_vec_buf: Vec<u8> = vec![3, 0, 0, 0, 70, 71, 72, 0];
+ let default_vec = flatbuffers::Vector::new(&default_vec_buf[..], 0);
+ let v = tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<u8>>>(fi2fo(0), Some(default_vec)).unwrap();
+ assert_eq!(v.len(), 3);
+ assert_eq!(v.get(0), 70);
+ assert_eq!(v.get(1), 71);
+ assert_eq!(v.get(2), 72);
+ }
+
+ #[test]
+ fn to_root_to_table_get_slot_string_multiple_types_default_via_vtable_zero() {
+ let buf: Vec<u8> = vec![
+ 14, 0, 0, 0, // offset to root table
+ // enter vtable
+ 6, 0, // vtable len
+ 2, 0, // inline size
+ 0, 0, // value loc
+ 255, 255, 255, 255, // canary
+ // enter table
+ 10, 0, 0, 0, // vtable location
+ ];
+ let tab = <flatbuffers::ForwardsUOffset<flatbuffers::Table>>::follow(&buf[..], 0);
+ assert_eq!(tab.get::<flatbuffers::ForwardsUOffset<&str>>(fi2fo(0), Some("abc")), Some("abc"));
+ #[cfg(target_endian = "little")]
+ {
+ assert_eq!(tab.get::<flatbuffers::ForwardsUOffset<&[u8]>>(fi2fo(0), Some(&vec![70, 71, 72][..])), Some(&vec![70, 71, 72][..]));
+ }
+
+ let default_vec_buf: Vec<u8> = vec![3, 0, 0, 0, 70, 71, 72, 0];
+ let default_vec = flatbuffers::Vector::new(&default_vec_buf[..], 0);
+ let v = tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<u8>>>(fi2fo(0), Some(default_vec)).unwrap();
+ assert_eq!(v.len(), 3);
+ assert_eq!(v.get(0), 70);
+ assert_eq!(v.get(1), 71);
+ assert_eq!(v.get(2), 72);
+ }
+}
+
+#[cfg(test)]
+mod push_impls {
+ extern crate flatbuffers;
+
+ use super::my_game;
+
+ fn check<'a>(b: &'a flatbuffers::FlatBufferBuilder, want: &'a [u8]) {
+ let got = b.unfinished_data();
+ assert_eq!(want, got);
+ }
+
+ #[test]
+ fn push_u8() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(123u8);
+ check(&b, &[123]);
+ }
+
+ #[test]
+ fn push_u64() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(0x12345678);
+ check(&b, &[0x78, 0x56, 0x34, 0x12]);
+ }
+
+ #[test]
+ fn push_f64() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(3.14159265359f64);
+ check(&b, &[234, 46, 68, 84, 251, 33, 9, 64]);
+ }
+
+ #[test]
+ fn push_generated_struct() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(my_game::example::Test::new(10, 20));
+ check(&b, &[10, 0, 20, 0]);
+ }
+
+ #[test]
+ fn push_u8_vector_with_offset_with_alignment() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.create_vector(&[1u8, 2, 3, 4, 5, 6, 7, 8, 9][..]);
+ b.push(off);
+ check(&b, &[/* loc */ 4, 0, 0, 0, /* len */ 9, 0, 0, 0, /* val */ 1, 2, 3, 4, 5, 6, 7, 8, 9, /* padding */ 0, 0, 0]);
+ }
+
+ #[test]
+ fn push_u8_u16_alignment() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(1u8);
+ b.push(2u16);
+ check(&b, &[2, 0, 0, 1]);
+ }
+
+ #[test]
+ fn push_u8_u32_alignment() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(1u8);
+ b.push(2u32);
+ check(&b, &[2, 0, 0, 0, 0, 0, 0, 1]);
+ }
+
+ #[test]
+ fn push_u8_u64_alignment() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(1u8);
+ b.push(2u64);
+ check(&b, &[2, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 1]);
+ }
+}
+
+#[cfg(test)]
+mod vtable_deduplication {
+ extern crate flatbuffers;
+ use flatbuffers::field_index_to_field_offset as fi2fo;
+
+ fn check<'a>(b: &'a flatbuffers::FlatBufferBuilder, want: &'a [u8]) {
+ let got = b.unfinished_data();
+ assert_eq!(want, got);
+ }
+
+ #[test]
+ fn one_empty_table() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let start0 = b.start_table();
+ b.end_table(start0);
+ check(&b, &[
+ 4, 0, // vtable size in bytes
+ 4, 0, // object inline data in bytes
+
+ 4, 0, 0, 0, // backwards offset to vtable
+ ]);
+ }
+
+ #[test]
+ fn two_empty_tables_are_deduplicated() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let start0 = b.start_table();
+ b.end_table(start0);
+ let start1 = b.start_table();
+ b.end_table(start1);
+ check(&b, &[
+ 252, 255, 255, 255, // forwards offset to vtable
+
+ 4, 0, // vtable size in bytes
+ 4, 0, // object inline data in bytes
+
+ 4, 0, 0, 0, // backwards offset to vtable
+ ]);
+ }
+
+ #[test]
+ fn two_tables_with_two_conveniently_sized_inline_elements_are_deduplicated() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let start0 = b.start_table();
+ b.push_slot::<u64>(fi2fo(0), 100, 0);
+ b.push_slot::<u32>(fi2fo(1), 101, 0);
+ b.end_table(start0);
+ let start1 = b.start_table();
+ b.push_slot::<u64>(fi2fo(0), 200, 0);
+ b.push_slot::<u32>(fi2fo(1), 201, 0);
+ b.end_table(start1);
+ check(&b, &[
+ 240, 255, 255, 255, // forwards offset to vtable
+
+ 201, 0, 0, 0, // value #1
+ 200, 0, 0, 0, 0, 0, 0, 0, // value #0
+
+ 8, 0, // vtable size in bytes
+ 16, 0, // object inline data in bytes
+ 8, 0, // offset in object for value #0
+ 4, 0, // offset in object for value #1
+
+ 8, 0, 0, 0, // backwards offset to vtable
+ 101, 0, 0, 0, // value #1
+ 100, 0, 0, 0, 0, 0, 0, 0 // value #0
+ ]);
+ }
+
+ #[test]
+ fn many_identical_tables_use_few_vtables() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ for _ in 0..1000 {
+ let start = b.start_table();
+ b.push_slot::<u8>(fi2fo(0), 100, 0);
+ b.push_slot::<u32>(fi2fo(1), 101, 0);
+ b.end_table(start);
+ }
+ assert!(b.num_written_vtables() <= 10);
+ }
+}
+
+#[cfg(test)]
+mod byte_layouts {
+ extern crate flatbuffers;
+ use flatbuffers::field_index_to_field_offset as fi2fo;
+
+ fn check<'a>(b: &'a flatbuffers::FlatBufferBuilder, want: &'a [u8]) {
+ let got = b.unfinished_data();
+ assert_eq!(want, got);
+ }
+
+ #[test]
+ fn layout_01_basic_numbers() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(true);
+ check(&b, &[1]);
+ b.push(-127i8);
+ check(&b, &[129, 1]);
+ b.push(255u8);
+ check(&b, &[255, 129, 1]);
+ b.push(-32222i16);
+ check(&b, &[0x22, 0x82, 0, 255, 129, 1]); // first pad
+ b.push(0xFEEEu16);
+ check(&b, &[0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1]); // no pad this time
+ b.push(-53687092i32);
+ check(&b, &[204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1]);
+ b.push(0x98765432u32);
+ check(&b, &[0x32, 0x54, 0x76, 0x98, 204, 204, 204, 252, 0xEE, 0xFE, 0x22, 0x82, 0, 255, 129, 1]);
+ }
+
+ #[test]
+ fn layout_01b_bigger_numbers() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.push(0x1122334455667788u64);
+ check(&b, &[0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11]);
+ }
+
+ #[test]
+ fn layout_02_1xbyte_vector() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ check(&b, &[]);
+ b.start_vector::<u8>(1);
+ check(&b, &[0, 0, 0]); // align to 4bytes
+ b.push(1u8);
+ check(&b, &[1, 0, 0, 0]);
+ b.end_vector::<u8>(1);
+ check(&b, &[1, 0, 0, 0, 1, 0, 0, 0]); // padding
+ }
+
+ #[test]
+ fn layout_03_2xbyte_vector() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<u8>(2);
+ check(&b, &[0, 0]); // align to 4bytes
+ b.push(1u8);
+ check(&b, &[1, 0, 0]);
+ b.push(2u8);
+ check(&b, &[2, 1, 0, 0]);
+ b.end_vector::<u8>(2);
+ check(&b, &[2, 0, 0, 0, 2, 1, 0, 0]); // padding
+ }
+
+ #[test]
+ fn layout_03b_11xbyte_vector_matches_builder_size() {
+ let mut b = flatbuffers::FlatBufferBuilder::new_with_capacity(12);
+ b.start_vector::<u8>(8);
+
+ let mut gold = vec![0u8; 0];
+ check(&b, &gold[..]);
+
+ for i in 1u8..=8 {
+ b.push(i);
+ gold.insert(0, i);
+ check(&b, &gold[..]);
+ }
+ b.end_vector::<u8>(8);
+ let want = vec![8u8, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1];
+ check(&b, &want[..]);
+ }
+ #[test]
+ fn layout_04_1xuint16_vector() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<u16>(1);
+ check(&b, &[0, 0]); // align to 4bytes
+ b.push(1u16);
+ check(&b, &[1, 0, 0, 0]);
+ b.end_vector::<u16>(1);
+ check(&b, &[1, 0, 0, 0, 1, 0, 0, 0]); // padding
+ }
+
+ #[test]
+ fn layout_05_2xuint16_vector() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let _off = b.start_vector::<u16>(2);
+ check(&b, &[]); // align to 4bytes
+ b.push(0xABCDu16);
+ check(&b, &[0xCD, 0xAB]);
+ b.push(0xDCBAu16);
+ check(&b, &[0xBA, 0xDC, 0xCD, 0xAB]);
+ b.end_vector::<u16>(2);
+ check(&b, &[2, 0, 0, 0, 0xBA, 0xDC, 0xCD, 0xAB]);
+ }
+
+ #[test]
+ fn layout_06_create_string() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off0 = b.create_string("foo");
+ assert_eq!(8, off0.value());
+ check(&b, b"\x03\x00\x00\x00foo\x00"); // 0-terminated, no pad
+ let off1 = b.create_string("moop");
+ assert_eq!(20, off1.value());
+ check(&b, b"\x04\x00\x00\x00moop\x00\x00\x00\x00\
+ \x03\x00\x00\x00foo\x00"); // 0-terminated, 3-byte pad
+ }
+
+ #[test]
+ fn layout_06b_create_string_unicode() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ // These characters are chinese from blog.golang.org/strings
+ // We use escape codes here so that editors without unicode support
+ // aren't bothered:
+ let uni_str = "\u{65e5}\u{672c}\u{8a9e}";
+ let off0 = b.create_string(uni_str);
+ assert_eq!(16, off0.value());
+ check(&b, &[9, 0, 0, 0, 230, 151, 165, 230, 156, 172, 232, 170, 158, 0, // null-terminated, 2-byte pad
+ 0, 0]);
+ }
+
+ #[test]
+ fn layout_06c_create_byte_string() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off0 = b.create_byte_string(b"foo");
+ assert_eq!(8, off0.value());
+ check(&b, b"\x03\x00\x00\x00foo\x00"); // 0-terminated, no pad
+ let off1 = b.create_byte_string(b"moop");
+ assert_eq!(20, off1.value());
+ check(&b, b"\x04\x00\x00\x00moop\x00\x00\x00\x00\
+ \x03\x00\x00\x00foo\x00"); // 0-terminated, 3-byte pad
+ }
+
+ #[test]
+ fn layout_07_empty_vtable() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off0 = b.start_table();
+ check(&b, &[]);
+ b.end_table(off0);
+ check(&b, &[4, 0, // vtable length
+ 4, 0, // length of table including vtable offset
+ 4, 0, 0, 0]); // offset for start of vtable
+ }
+
+ #[test]
+ fn layout_08_vtable_with_one_true_bool() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ check(&b, &[]);
+ let off0 = b.start_table();
+ assert_eq!(0, off0.value());
+ check(&b, &[]);
+ b.push_slot(fi2fo(0), true, false);
+ check(&b, &[1]);
+ let off1 = b.end_table(off0);
+ assert_eq!(8, off1.value());
+ check(&b, &[
+ 6, 0, // vtable bytes
+ 8, 0, // length of object including vtable offset
+ 7, 0, // start of bool value
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, 0, // padded to 4 bytes
+ 1, // bool value
+ ]);
+ }
+
+ #[test]
+ fn layout_09_vtable_with_one_default_bool() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ check(&b, &[]);
+ let off = b.start_table();
+ check(&b, &[]);
+ b.push_slot(fi2fo(0), false, false);
+ b.end_table(off);
+ check(&b, &[
+ 4, 0, // vtable bytes
+ 4, 0, // end of object from here
+ // entry 1 is zero and not stored.
+ 4, 0, 0, 0, // offset for start of vtable (int32)
+ ]);
+ }
+
+ #[test]
+ fn layout_10_vtable_with_one_int16() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ check(&b, &[]);
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 0x789Ai16, 0);
+ b.end_table(off);
+ check(&b, &[
+ 6, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 6, 0, // offset to value
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, // padding to 4 bytes
+ 0x9A, 0x78,
+ ]);
+ }
+
+ #[test]
+ fn layout_11_vtable_with_two_int16() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 0x3456i16, 0);
+ b.push_slot(fi2fo(1), 0x789Ai16, 0);
+ b.end_table(off);
+ check(&b, &[
+ 8, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 6, 0, // offset to value 0
+ 4, 0, // offset to value 1
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0x9A, 0x78, // value 1
+ 0x56, 0x34, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_12_vtable_with_int16_and_bool() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 0x3456i16, 0);
+ b.push_slot(fi2fo(1), true, false);
+ b.end_table(off);
+ check(&b, &[
+ 8, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 6, 0, // offset to value 0
+ 5, 0, // offset to value 1
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0, // padding
+ 1, // value 1
+ 0x56, 0x34, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_12b_vtable_with_empty_vector() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<u8>(0);
+ let vecend = b.end_vector::<u8>(0);
+ let off = b.start_table();
+ b.push_slot_always(fi2fo(0), vecend);
+ b.end_table(off);
+ check(&b, &[
+ 6, 0, // vtable bytes
+ 8, 0,
+ 4, 0, // offset to vector offset
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 4, 0, 0, 0,
+ 0, 0, 0, 0, // length of vector (not in struct)
+ ]);
+ }
+
+ #[test]
+ fn layout_12c_vtable_with_empty_vector_of_byte_and_some_scalars() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<u8>(0);
+ let vecend = b.end_vector::<u8>(0);
+ let off = b.start_table();
+ b.push_slot::<i16>(fi2fo(0), 55i16, 0);
+ b.push_slot_always::<flatbuffers::WIPOffset<_>>(fi2fo(1), vecend);
+ b.end_table(off);
+ check(&b, &[
+ 8, 0, // vtable bytes
+ 12, 0,
+ 10, 0, // offset to value 0
+ 4, 0, // offset to vector offset
+ 8, 0, 0, 0, // vtable loc
+ 8, 0, 0, 0, // value 1
+ 0, 0, 55, 0, // value 0
+
+ 0, 0, 0, 0, // length of vector (not in struct)
+ ]);
+ }
+ #[test]
+ fn layout_13_vtable_with_1_int16_and_2_vector_of_i16() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<i16>(2);
+ b.push(0x1234i16);
+ b.push(0x5678i16);
+ let vecend = b.end_vector::<i16>(2);
+ let off = b.start_table();
+ b.push_slot_always(fi2fo(1), vecend);
+ b.push_slot(fi2fo(0), 55i16, 0);
+ b.end_table(off);
+ check(&b, &[
+ 8, 0, // vtable bytes
+ 12, 0, // length of object
+ 6, 0, // start of value 0 from end of vtable
+ 8, 0, // start of value 1 from end of buffer
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, // padding
+ 55, 0, // value 0
+ 4, 0, 0, 0, // vector position from here
+ 2, 0, 0, 0, // length of vector (uint32)
+ 0x78, 0x56, // vector value 1
+ 0x34, 0x12, // vector value 0
+ ]);
+ }
+ #[test]
+ fn layout_14_vtable_with_1_struct_of_int8_and_int16_and_int32() {
+ #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+ #[repr(C, packed)]
+ struct foo {
+ a: i32,
+ _pad0: [u8; 2],
+ b: i16,
+ _pad1: [u8; 3],
+ c: i8,
+ _pad2: [u8; 4],
+ }
+ assert_eq!(::std::mem::size_of::<foo>(), 16);
+ impl<'b> flatbuffers::Push for &'b foo {
+ type Output = foo;
+ fn push<'a>(&'a self, dst: &'a mut [u8], _rest: &'a [u8]) {
+ let src = unsafe {
+ ::std::slice::from_raw_parts(*self as *const foo as *const u8, ::std::mem::size_of::<foo>())
+ };
+ dst.copy_from_slice(src);
+ }
+ }
+
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ let x = foo{a: 0x12345678i32.to_le(), _pad0: [0,0], b: 0x1234i16.to_le(), _pad1: [0, 0, 0], c: 0x12i8.to_le(), _pad2: [0, 0, 0, 0]};
+ b.push_slot_always(fi2fo(0), &x);
+ b.end_table(off);
+ check(&b, &[
+ 6, 0, // vtable bytes
+ 20, 0, // end of object from here
+ 4, 0, // start of struct from here
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+
+ 0x78, 0x56, 0x34, 0x12, // value a
+ 0, 0, // padding
+ 0x34, 0x12, // value b
+ 0, 0, 0, // padding
+ 0x12, // value c
+ 0, 0, 0, 0, // padding
+ ]);
+ }
+ #[test]
+ fn layout_15_vtable_with_1_vector_of_4_int8() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ b.start_vector::<i8>(4);
+ b.push(33i8);
+ b.push(44i8);
+ b.push(55i8);
+ b.push(66i8);
+ let vecend = b.end_vector::<i8>(4);
+ let off = b.start_table();
+ b.push_slot_always(fi2fo(0), vecend);
+ b.end_table(off);
+ check(&b, &[
+ 6, 0, // vtable bytes
+ 8, 0,
+ 4, 0, // offset of vector offset
+ 6, 0, 0, 0, // offset for start of vtable (int32)
+ 4, 0, 0, 0, // vector start offset
+
+ 4, 0, 0, 0, // vector length
+ 66, // vector value 1,1
+ 55, // vector value 1,0
+ 44, // vector value 0,1
+ 33, // vector value 0,0
+ ]);
+ }
+
+ #[test]
+ fn layout_16_table_with_some_elements() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 33i8, 0);
+ b.push_slot(fi2fo(1), 66i16, 0);
+ let off2 = b.end_table(off);
+ b.finish_minimal(off2);
+
+ check(&b, &[
+ 12, 0, 0, 0, // root of table: points to vtable offset
+
+ 8, 0, // vtable bytes
+ 8, 0, // end of object from here
+ 7, 0, // start of value 0
+ 4, 0, // start of value 1
+
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+
+ 66, 0, // value 1
+ 0, // padding
+ 33, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_17_one_unfinished_table_and_one_finished_table() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ {
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 33i8, 0);
+ b.push_slot(fi2fo(1), 44i8, 0);
+ b.end_table(off);
+ }
+
+ {
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 55i8, 0);
+ b.push_slot(fi2fo(1), 66i8, 0);
+ b.push_slot(fi2fo(2), 77i8, 0);
+ let off2 = b.end_table(off);
+ b.finish_minimal(off2);
+ }
+
+ check(&b, &[
+ 16, 0, 0, 0, // root of table: points to object
+ 0, 0, // padding
+
+ 10, 0, // vtable bytes
+ 8, 0, // size of object
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 5, 0, // start of value 2
+ 10, 0, 0, 0, // offset for start of vtable (int32)
+ 0, // padding
+ 77, // value 2
+ 66, // value 1
+ 55, // value 0
+
+ //12, 0, 0, 0, // root of table: points to object
+
+ 8, 0, // vtable bytes
+ 8, 0, // size of object
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 8, 0, 0, 0, // offset for start of vtable (int32)
+ 0, 0, // padding
+ 44, // value 1
+ 33, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_18_a_bunch_of_bools() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), true, false);
+ b.push_slot(fi2fo(1), true, false);
+ b.push_slot(fi2fo(2), true, false);
+ b.push_slot(fi2fo(3), true, false);
+ b.push_slot(fi2fo(4), true, false);
+ b.push_slot(fi2fo(5), true, false);
+ b.push_slot(fi2fo(6), true, false);
+ b.push_slot(fi2fo(7), true, false);
+ let off2 = b.end_table(off);
+ b.finish_minimal(off2);
+
+ check(&b, &[
+ 24, 0, 0, 0, // root of table: points to vtable offset
+
+ 20, 0, // vtable bytes
+ 12, 0, // size of object
+ 11, 0, // start of value 0
+ 10, 0, // start of value 1
+ 9, 0, // start of value 2
+ 8, 0, // start of value 3
+ 7, 0, // start of value 4
+ 6, 0, // start of value 5
+ 5, 0, // start of value 6
+ 4, 0, // start of value 7
+ 20, 0, 0, 0, // vtable offset
+
+ 1, // value 7
+ 1, // value 6
+ 1, // value 5
+ 1, // value 4
+ 1, // value 3
+ 1, // value 2
+ 1, // value 1
+ 1, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_19_three_bools() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), true, false);
+ b.push_slot(fi2fo(1), true, false);
+ b.push_slot(fi2fo(2), true, false);
+ let off2 = b.end_table(off);
+ b.finish_minimal(off2);
+
+ check(&b, &[
+ 16, 0, 0, 0, // root of table: points to vtable offset
+
+ 0, 0, // padding
+
+ 10, 0, // vtable bytes
+ 8, 0, // size of object
+ 7, 0, // start of value 0
+ 6, 0, // start of value 1
+ 5, 0, // start of value 2
+ 10, 0, 0, 0, // vtable offset from here
+
+ 0, // padding
+ 1, // value 2
+ 1, // value 1
+ 1, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_20_some_floats() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot(fi2fo(0), 1.0f32, 0.0);
+ b.end_table(off);
+
+ check(&b, &[
+ 6, 0, // vtable bytes
+ 8, 0, // size of object
+ 4, 0, // start of value 0
+ 6, 0, 0, 0, // vtable offset
+
+ 0, 0, 128, 63, // value 0
+ ]);
+ }
+
+ #[test]
+ fn layout_21_vtable_defaults() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot::<i8>(fi2fo(0), 1, 1);
+ b.push_slot::<i8>(fi2fo(1), 3, 2);
+ b.push_slot::<i8>(fi2fo(2), 3, 3);
+ b.end_table(off);
+ check(&b, &[
+ 8, 0, // vtable size in bytes
+ 8, 0, // object inline data in bytes
+ 0, 0, // entry 1/3: 0 => default
+ 7, 0, // entry 2/3: 7 => table start + 7 bytes
+ // entry 3/3: not present => default
+ 8, 0, 0, 0,
+ 0, 0, 0,
+ 3,
+ ]);
+ }
+
+ #[test]
+ fn layout_22_root() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ // skipped: b.push_slot_scalar::<i16>(0, 1, 1);
+ b.push_slot::<i16>(fi2fo(1), 3, 2);
+ b.push_slot::<i16>(fi2fo(2), 3, 3);
+ let table_end = b.end_table(off);
+ b.finish_minimal(table_end);
+ check(&b, &[
+ 12, 0, 0, 0, // root
+
+ 8, 0, // vtable size in bytes
+ 8, 0, // object inline data in bytes
+ 0, 0, // entry 1/3: 0 => default
+ 6, 0, // entry 2/3: 6 => table start + 6 bytes
+ // entry 3/3: not present => default
+ 8, 0, 0, 0, // size of table data in bytes
+ 0, 0, // padding
+ 3, 0, // value 2/3
+ ]);
+ }
+ #[test]
+ fn layout_23_varied_slots_and_root() {
+ let mut b = flatbuffers::FlatBufferBuilder::new();
+ let off = b.start_table();
+ b.push_slot::<i16>(fi2fo(0), 1, 0);
+ b.push_slot::<u8>(fi2fo(1), 2, 0);
+ b.push_slot::<f32>(fi2fo(2), 3.0, 0.0);
+ let table_end = b.end_table(off);
+ b.finish_minimal(table_end);
+ check(&b, &[
+ 16, 0, 0, 0, // root
+ 0, 0, // padding
+ 10, 0, // vtable bytes
+ 12, 0, // object inline data size
+ 10, 0, // offset to value #1 (i16)
+ 9, 0, // offset to value #2 (u8)
+ 4, 0, // offset to value #3 (f32)
+ 10, 0, // offset to vtable
+ 0, 0, // padding
+ 0, 0, 64, 64, // value #3 => 3.0 (float32)
+ 0, 2, // value #1 => 2 (u8)
+ 1, 0, // value #0 => 1 (int16)
+ ]);
+ }
+}
+
+// this is not technically a test, but we want to always keep this generated
+// file up-to-date, and the simplest way to do that is to make sure that when
+// tests are run, the file is generated.
+#[test]
+fn write_example_wire_data_to_file() {
+ let b = &mut flatbuffers::FlatBufferBuilder::new();
+ create_serialized_example_with_generated_code(b);
+
+ use ::std::io::Write;
+ let mut f = std::fs::File::create("../monsterdata_rust_wire.mon").unwrap();
+ f.write_all(b.finished_data()).unwrap();
+}
+
+fn load_file(filename: &str) -> Result<Vec<u8>, std::io::Error> {
+ use std::io::Read;
+ let mut f = std::fs::File::open(filename)?;
+ let mut buf = Vec::new();
+ f.read_to_end(&mut buf)?;
+ Ok(buf)
+}
diff --git a/tests/test.cpp b/tests/test.cpp
new file mode 100644
index 0000000..461840c
--- /dev/null
+++ b/tests/test.cpp
@@ -0,0 +1,3068 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cmath>
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/minireflect.h"
+#include "flatbuffers/registry.h"
+#include "flatbuffers/util.h"
+
+// clang-format off
+#ifdef FLATBUFFERS_CPP98_STL
+ #include "flatbuffers/stl_emulation.h"
+ namespace std {
+ using flatbuffers::unique_ptr;
+ }
+#endif
+// clang-format on
+
+#include "monster_test_generated.h"
+#include "namespace_test/namespace_test1_generated.h"
+#include "namespace_test/namespace_test2_generated.h"
+#include "union_vector/union_vector_generated.h"
+#include "monster_extra_generated.h"
+#if !defined(_MSC_VER) || _MSC_VER >= 1700
+#include "arrays_test_generated.h"
+#endif
+
+#include "native_type_test_generated.h"
+#include "test_assert.h"
+
+#include "flatbuffers/flexbuffers.h"
+
+
+// clang-format off
+// Check that char* and uint8_t* are interoperable types.
+// The reinterpret_cast<> between the pointers are used to simplify data loading.
+static_assert(flatbuffers::is_same<uint8_t, char>::value ||
+ flatbuffers::is_same<uint8_t, unsigned char>::value,
+ "unexpected uint8_t type");
+
+#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+ // Ensure IEEE-754 support if tests of floats with NaN/Inf will run.
+ static_assert(std::numeric_limits<float>::is_iec559 &&
+ std::numeric_limits<double>::is_iec559,
+ "IEC-559 (IEEE-754) standard required");
+#endif
+// clang-format on
+
+// Shortcuts for the infinity.
+static const auto infinityf = std::numeric_limits<float>::infinity();
+static const auto infinityd = std::numeric_limits<double>::infinity();
+
+using namespace MyGame::Example;
+
+void FlatBufferBuilderTest();
+
+// Include simple random number generator to ensure results will be the
+// same cross platform.
+// http://en.wikipedia.org/wiki/Park%E2%80%93Miller_random_number_generator
+uint32_t lcg_seed = 48271;
+uint32_t lcg_rand() {
+ return lcg_seed = (static_cast<uint64_t>(lcg_seed) * 279470273UL) % 4294967291UL;
+}
+void lcg_reset() { lcg_seed = 48271; }
+
+std::string test_data_path =
+#ifdef BAZEL_TEST_DATA_PATH
+ "../com_github_google_flatbuffers/tests/";
+#else
+ "tests/";
+#endif
+
+// example of how to build up a serialized buffer algorithmically:
+flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
+ flatbuffers::FlatBufferBuilder builder;
+
+ auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
+
+ auto name = builder.CreateString("MyMonster");
+
+ unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ auto inventory = builder.CreateVector(inv_data, 10);
+
+ // Alternatively, create the vector first, and fill in data later:
+ // unsigned char *inv_buf = nullptr;
+ // auto inventory = builder.CreateUninitializedVector<unsigned char>(
+ // 10, &inv_buf);
+ // memcpy(inv_buf, inv_data, 10);
+
+ Test tests[] = { Test(10, 20), Test(30, 40) };
+ auto testv = builder.CreateVectorOfStructs(tests, 2);
+
+ // clang-format off
+ #ifndef FLATBUFFERS_CPP98_STL
+ // Create a vector of structures from a lambda.
+ auto testv2 = builder.CreateVectorOfStructs<Test>(
+ 2, [&](size_t i, Test* s) -> void {
+ *s = tests[i];
+ });
+ #else
+ // Create a vector of structures using a plain old C++ function.
+ auto testv2 = builder.CreateVectorOfStructs<Test>(
+ 2, [](size_t i, Test* s, void *state) -> void {
+ *s = (reinterpret_cast<Test*>(state))[i];
+ }, tests);
+ #endif // FLATBUFFERS_CPP98_STL
+ // clang-format on
+
+ // create monster with very few fields set:
+ // (same functionality as CreateMonster below, but sets fields manually)
+ flatbuffers::Offset<Monster> mlocs[3];
+ auto fred = builder.CreateString("Fred");
+ auto barney = builder.CreateString("Barney");
+ auto wilma = builder.CreateString("Wilma");
+ MonsterBuilder mb1(builder);
+ mb1.add_name(fred);
+ mlocs[0] = mb1.Finish();
+ MonsterBuilder mb2(builder);
+ mb2.add_name(barney);
+ mb2.add_hp(1000);
+ mlocs[1] = mb2.Finish();
+ MonsterBuilder mb3(builder);
+ mb3.add_name(wilma);
+ mlocs[2] = mb3.Finish();
+
+ // Create an array of strings. Also test string pooling, and lambdas.
+ auto vecofstrings =
+ builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(
+ 4,
+ [](size_t i, flatbuffers::FlatBufferBuilder *b)
+ -> flatbuffers::Offset<flatbuffers::String> {
+ static const char *names[] = { "bob", "fred", "bob", "fred" };
+ return b->CreateSharedString(names[i]);
+ },
+ &builder);
+
+ // Creating vectors of strings in one convenient call.
+ std::vector<std::string> names2;
+ names2.push_back("jane");
+ names2.push_back("mary");
+ auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
+
+ // Create an array of sorted tables, can be used with binary search when read:
+ auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
+
+ // Create an array of sorted structs,
+ // can be used with binary search when read:
+ std::vector<Ability> abilities;
+ abilities.push_back(Ability(4, 40));
+ abilities.push_back(Ability(3, 30));
+ abilities.push_back(Ability(2, 20));
+ abilities.push_back(Ability(1, 10));
+ auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
+
+ // Create a nested FlatBuffer.
+ // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
+ // since they can be memcpy'd around much easier than other FlatBuffer
+ // values. They have little overhead compared to storing the table directly.
+ // As a test, create a mostly empty Monster buffer:
+ flatbuffers::FlatBufferBuilder nested_builder;
+ auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
+ nested_builder.CreateString("NestedMonster"));
+ FinishMonsterBuffer(nested_builder, nmloc);
+ // Now we can store the buffer in the parent. Note that by default, vectors
+ // are only aligned to their elements or size field, so in this case if the
+ // buffer contains 64-bit elements, they may not be correctly aligned. We fix
+ // that with:
+ builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
+ nested_builder.GetBufferMinAlignment());
+ // If for whatever reason you don't have the nested_builder available, you
+ // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
+ // the largest force_align value in your schema if you're using it.
+ auto nested_flatbuffer_vector = builder.CreateVector(
+ nested_builder.GetBufferPointer(), nested_builder.GetSize());
+
+ // Test a nested FlexBuffer:
+ flexbuffers::Builder flexbuild;
+ flexbuild.Int(1234);
+ flexbuild.Finish();
+ auto flex = builder.CreateVector(flexbuild.GetBuffer());
+
+ // Test vector of enums.
+ Color colors[] = { Color_Blue, Color_Green };
+ // We use this special creation function because we have an array of
+ // pre-C++11 (enum class) enums whose size likely is int, yet its declared
+ // type in the schema is byte.
+ auto vecofcolors = builder.CreateVectorScalarCast<uint8_t, Color>(colors, 2);
+
+ // shortcut for creating monster with all fields set:
+ auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory, Color_Blue,
+ Any_Monster, mlocs[1].Union(), // Store a union.
+ testv, vecofstrings, vecoftables, 0,
+ nested_flatbuffer_vector, 0, false, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f, vecofstrings2,
+ vecofstructs, flex, testv2, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, AnyUniqueAliases_NONE, 0,
+ AnyAmbiguousAliases_NONE, 0, vecofcolors);
+
+ FinishMonsterBuffer(builder, mloc);
+
+ // clang-format off
+ #ifdef FLATBUFFERS_TEST_VERBOSE
+ // print byte data for debugging:
+ auto p = builder.GetBufferPointer();
+ for (flatbuffers::uoffset_t i = 0; i < builder.GetSize(); i++)
+ printf("%d ", p[i]);
+ #endif
+ // clang-format on
+
+ // return the buffer for the caller to use.
+ auto bufferpointer =
+ reinterpret_cast<const char *>(builder.GetBufferPointer());
+ buffer.assign(bufferpointer, bufferpointer + builder.GetSize());
+
+ return builder.Release();
+}
+
+// example of accessing a buffer loaded in memory:
+void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length,
+ bool pooled = true) {
+ // First, verify the buffers integrity (optional)
+ flatbuffers::Verifier verifier(flatbuf, length);
+ TEST_EQ(VerifyMonsterBuffer(verifier), true);
+
+ // clang-format off
+ #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
+ std::vector<uint8_t> test_buff;
+ test_buff.resize(length * 2);
+ std::memcpy(&test_buff[0], flatbuf, length);
+ std::memcpy(&test_buff[length], flatbuf, length);
+
+ flatbuffers::Verifier verifier1(&test_buff[0], length);
+ TEST_EQ(VerifyMonsterBuffer(verifier1), true);
+ TEST_EQ(verifier1.GetComputedSize(), length);
+
+ flatbuffers::Verifier verifier2(&test_buff[length], length);
+ TEST_EQ(VerifyMonsterBuffer(verifier2), true);
+ TEST_EQ(verifier2.GetComputedSize(), length);
+ #endif
+ // clang-format on
+
+ TEST_EQ(strcmp(MonsterIdentifier(), "MONS"), 0);
+ TEST_EQ(MonsterBufferHasIdentifier(flatbuf), true);
+ TEST_EQ(strcmp(MonsterExtension(), "mon"), 0);
+
+ // Access the buffer from the root.
+ auto monster = GetMonster(flatbuf);
+
+ TEST_EQ(monster->hp(), 80);
+ TEST_EQ(monster->mana(), 150); // default
+ TEST_EQ_STR(monster->name()->c_str(), "MyMonster");
+ // Can't access the following field, it is deprecated in the schema,
+ // which means accessors are not generated:
+ // monster.friendly()
+
+ auto pos = monster->pos();
+ TEST_NOTNULL(pos);
+ TEST_EQ(pos->z(), 3);
+ TEST_EQ(pos->test3().a(), 10);
+ TEST_EQ(pos->test3().b(), 20);
+
+ auto inventory = monster->inventory();
+ TEST_EQ(VectorLength(inventory), 10UL); // Works even if inventory is null.
+ TEST_NOTNULL(inventory);
+ unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ // Check compatibilty of iterators with STL.
+ std::vector<unsigned char> inv_vec(inventory->begin(), inventory->end());
+ int n = 0;
+ for (auto it = inventory->begin(); it != inventory->end(); ++it, ++n) {
+ auto indx = it - inventory->begin();
+ TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
+ TEST_EQ(*it, inv_data[indx]);
+ }
+ TEST_EQ(n, inv_vec.size());
+
+ n = 0;
+ for (auto it = inventory->cbegin(); it != inventory->cend(); ++it, ++n) {
+ auto indx = it - inventory->cbegin();
+ TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
+ TEST_EQ(*it, inv_data[indx]);
+ }
+ TEST_EQ(n, inv_vec.size());
+
+ n = 0;
+ for (auto it = inventory->rbegin(); it != inventory->rend(); ++it, ++n) {
+ auto indx = inventory->rend() - it - 1;
+ TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
+ TEST_EQ(*it, inv_data[indx]);
+ }
+ TEST_EQ(n, inv_vec.size());
+
+ n = 0;
+ for (auto it = inventory->crbegin(); it != inventory->crend(); ++it, ++n) {
+ auto indx = inventory->crend() - it - 1;
+ TEST_EQ(*it, inv_vec.at(indx)); // Use bounds-check.
+ TEST_EQ(*it, inv_data[indx]);
+ }
+ TEST_EQ(n, inv_vec.size());
+
+ TEST_EQ(monster->color(), Color_Blue);
+
+ // Example of accessing a union:
+ TEST_EQ(monster->test_type(), Any_Monster); // First make sure which it is.
+ auto monster2 = reinterpret_cast<const Monster *>(monster->test());
+ TEST_NOTNULL(monster2);
+ TEST_EQ_STR(monster2->name()->c_str(), "Fred");
+
+ // Example of accessing a vector of strings:
+ auto vecofstrings = monster->testarrayofstring();
+ TEST_EQ(vecofstrings->size(), 4U);
+ TEST_EQ_STR(vecofstrings->Get(0)->c_str(), "bob");
+ TEST_EQ_STR(vecofstrings->Get(1)->c_str(), "fred");
+ if (pooled) {
+ // These should have pointer equality because of string pooling.
+ TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
+ TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
+ }
+
+ auto vecofstrings2 = monster->testarrayofstring2();
+ if (vecofstrings2) {
+ TEST_EQ(vecofstrings2->size(), 2U);
+ TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
+ TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
+ }
+
+ // Example of accessing a vector of tables:
+ auto vecoftables = monster->testarrayoftables();
+ TEST_EQ(vecoftables->size(), 3U);
+ for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it)
+ TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
+ TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
+ TEST_EQ(vecoftables->Get(0)->hp(), 1000);
+ TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
+ TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
+ TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
+ TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
+ TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
+
+ // Test accessing a vector of sorted structs
+ auto vecofstructs = monster->testarrayofsortedstruct();
+ if (vecofstructs) { // not filled in monster_test.bfbs
+ for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size() - 1; i++) {
+ auto left = vecofstructs->Get(i);
+ auto right = vecofstructs->Get(i + 1);
+ TEST_EQ(true, (left->KeyCompareLessThan(right)));
+ }
+ TEST_NOTNULL(vecofstructs->LookupByKey(3));
+ TEST_EQ(static_cast<const Ability *>(nullptr),
+ vecofstructs->LookupByKey(5));
+ }
+
+ // Test nested FlatBuffers if available:
+ auto nested_buffer = monster->testnestedflatbuffer();
+ if (nested_buffer) {
+ // nested_buffer is a vector of bytes you can memcpy. However, if you
+ // actually want to access the nested data, this is a convenient
+ // accessor that directly gives you the root table:
+ auto nested_monster = monster->testnestedflatbuffer_nested_root();
+ TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
+ }
+
+ // Test flexbuffer if available:
+ auto flex = monster->flex();
+ // flex is a vector of bytes you can memcpy etc.
+ TEST_EQ(flex->size(), 4); // Encoded FlexBuffer bytes.
+ // However, if you actually want to access the nested data, this is a
+ // convenient accessor that directly gives you the root value:
+ TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
+
+ // Test vector of enums:
+ auto colors = monster->vector_of_enums();
+ if (colors) {
+ TEST_EQ(colors->size(), 2);
+ TEST_EQ(colors->Get(0), Color_Blue);
+ TEST_EQ(colors->Get(1), Color_Green);
+ }
+
+ // Since Flatbuffers uses explicit mechanisms to override the default
+ // compiler alignment, double check that the compiler indeed obeys them:
+ // (Test consists of a short and byte):
+ TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
+ TEST_EQ(sizeof(Test), 4UL);
+
+ const flatbuffers::Vector<const Test *> *tests_array[] = {
+ monster->test4(),
+ monster->test5(),
+ };
+ for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
+ auto tests = tests_array[i];
+ TEST_NOTNULL(tests);
+ auto test_0 = tests->Get(0);
+ auto test_1 = tests->Get(1);
+ TEST_EQ(test_0->a(), 10);
+ TEST_EQ(test_0->b(), 20);
+ TEST_EQ(test_1->a(), 30);
+ TEST_EQ(test_1->b(), 40);
+ for (auto it = tests->begin(); it != tests->end(); ++it) {
+ TEST_EQ(it->a() == 10 || it->a() == 30, true); // Just testing iterators.
+ }
+ }
+
+ // Checking for presence of fields:
+ TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_HP), true);
+ TEST_EQ(flatbuffers::IsFieldPresent(monster, Monster::VT_MANA), false);
+
+ // Obtaining a buffer from a root:
+ TEST_EQ(GetBufferStartFromRootPointer(monster), flatbuf);
+}
+
+// Change a FlatBuffer in-place, after it has been constructed.
+void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
+ // Get non-const pointer to root.
+ auto monster = GetMutableMonster(flatbuf);
+
+ // Each of these tests mutates, then tests, then set back to the original,
+ // so we can test that the buffer in the end still passes our original test.
+ auto hp_ok = monster->mutate_hp(10);
+ TEST_EQ(hp_ok, true); // Field was present.
+ TEST_EQ(monster->hp(), 10);
+ // Mutate to default value
+ auto hp_ok_default = monster->mutate_hp(100);
+ TEST_EQ(hp_ok_default, true); // Field was present.
+ TEST_EQ(monster->hp(), 100);
+ // Test that mutate to default above keeps field valid for further mutations
+ auto hp_ok_2 = monster->mutate_hp(20);
+ TEST_EQ(hp_ok_2, true);
+ TEST_EQ(monster->hp(), 20);
+ monster->mutate_hp(80);
+
+ // Monster originally at 150 mana (default value)
+ auto mana_default_ok = monster->mutate_mana(150); // Mutate to default value.
+ TEST_EQ(mana_default_ok,
+ true); // Mutation should succeed, because default value.
+ TEST_EQ(monster->mana(), 150);
+ auto mana_ok = monster->mutate_mana(10);
+ TEST_EQ(mana_ok, false); // Field was NOT present, because default value.
+ TEST_EQ(monster->mana(), 150);
+
+ // Mutate structs.
+ auto pos = monster->mutable_pos();
+ auto test3 = pos->mutable_test3(); // Struct inside a struct.
+ test3.mutate_a(50); // Struct fields never fail.
+ TEST_EQ(test3.a(), 50);
+ test3.mutate_a(10);
+
+ // Mutate vectors.
+ auto inventory = monster->mutable_inventory();
+ inventory->Mutate(9, 100);
+ TEST_EQ(inventory->Get(9), 100);
+ inventory->Mutate(9, 9);
+
+ auto tables = monster->mutable_testarrayoftables();
+ auto first = tables->GetMutableObject(0);
+ TEST_EQ(first->hp(), 1000);
+ first->mutate_hp(0);
+ TEST_EQ(first->hp(), 0);
+ first->mutate_hp(1000);
+
+ // Run the verifier and the regular test to make sure we didn't trample on
+ // anything.
+ AccessFlatBufferTest(flatbuf, length);
+}
+
+// Unpack a FlatBuffer into objects.
+void ObjectFlatBuffersTest(uint8_t *flatbuf) {
+ // Optional: we can specify resolver and rehasher functions to turn hashed
+ // strings into object pointers and back, to implement remote references
+ // and such.
+ auto resolver = flatbuffers::resolver_function_t(
+ [](void **pointer_adr, flatbuffers::hash_value_t hash) {
+ (void)pointer_adr;
+ (void)hash;
+ // Don't actually do anything, leave variable null.
+ });
+ auto rehasher = flatbuffers::rehasher_function_t(
+ [](void *pointer) -> flatbuffers::hash_value_t {
+ (void)pointer;
+ return 0;
+ });
+
+ // Turn a buffer into C++ objects.
+ auto monster1 = UnPackMonster(flatbuf, &resolver);
+
+ // Re-serialize the data.
+ flatbuffers::FlatBufferBuilder fbb1;
+ fbb1.Finish(CreateMonster(fbb1, monster1.get(), &rehasher),
+ MonsterIdentifier());
+
+ // Unpack again, and re-serialize again.
+ auto monster2 = UnPackMonster(fbb1.GetBufferPointer(), &resolver);
+ flatbuffers::FlatBufferBuilder fbb2;
+ fbb2.Finish(CreateMonster(fbb2, monster2.get(), &rehasher),
+ MonsterIdentifier());
+
+ // Now we've gone full round-trip, the two buffers should match.
+ auto len1 = fbb1.GetSize();
+ auto len2 = fbb2.GetSize();
+ TEST_EQ(len1, len2);
+ TEST_EQ(memcmp(fbb1.GetBufferPointer(), fbb2.GetBufferPointer(), len1), 0);
+
+ // Test it with the original buffer test to make sure all data survived.
+ AccessFlatBufferTest(fbb2.GetBufferPointer(), len2, false);
+
+ // Test accessing fields, similar to AccessFlatBufferTest above.
+ TEST_EQ(monster2->hp, 80);
+ TEST_EQ(monster2->mana, 150); // default
+ TEST_EQ_STR(monster2->name.c_str(), "MyMonster");
+
+ auto &pos = monster2->pos;
+ TEST_NOTNULL(pos);
+ TEST_EQ(pos->z(), 3);
+ TEST_EQ(pos->test3().a(), 10);
+ TEST_EQ(pos->test3().b(), 20);
+
+ auto &inventory = monster2->inventory;
+ TEST_EQ(inventory.size(), 10UL);
+ unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ for (auto it = inventory.begin(); it != inventory.end(); ++it)
+ TEST_EQ(*it, inv_data[it - inventory.begin()]);
+
+ TEST_EQ(monster2->color, Color_Blue);
+
+ auto monster3 = monster2->test.AsMonster();
+ TEST_NOTNULL(monster3);
+ TEST_EQ_STR(monster3->name.c_str(), "Fred");
+
+ auto &vecofstrings = monster2->testarrayofstring;
+ TEST_EQ(vecofstrings.size(), 4U);
+ TEST_EQ_STR(vecofstrings[0].c_str(), "bob");
+ TEST_EQ_STR(vecofstrings[1].c_str(), "fred");
+
+ auto &vecofstrings2 = monster2->testarrayofstring2;
+ TEST_EQ(vecofstrings2.size(), 2U);
+ TEST_EQ_STR(vecofstrings2[0].c_str(), "jane");
+ TEST_EQ_STR(vecofstrings2[1].c_str(), "mary");
+
+ auto &vecoftables = monster2->testarrayoftables;
+ TEST_EQ(vecoftables.size(), 3U);
+ TEST_EQ_STR(vecoftables[0]->name.c_str(), "Barney");
+ TEST_EQ(vecoftables[0]->hp, 1000);
+ TEST_EQ_STR(vecoftables[1]->name.c_str(), "Fred");
+ TEST_EQ_STR(vecoftables[2]->name.c_str(), "Wilma");
+
+ auto &tests = monster2->test4;
+ TEST_EQ(tests[0].a(), 10);
+ TEST_EQ(tests[0].b(), 20);
+ TEST_EQ(tests[1].a(), 30);
+ TEST_EQ(tests[1].b(), 40);
+}
+
+// Prefix a FlatBuffer with a size field.
+void SizePrefixedTest() {
+ // Create size prefixed buffer.
+ flatbuffers::FlatBufferBuilder fbb;
+ FinishSizePrefixedMonsterBuffer(
+ fbb,
+ CreateMonster(fbb, 0, 200, 300, fbb.CreateString("bob")));
+
+ // Verify it.
+ flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
+ TEST_EQ(VerifySizePrefixedMonsterBuffer(verifier), true);
+
+ // Access it.
+ auto m = GetSizePrefixedMonster(fbb.GetBufferPointer());
+ TEST_EQ(m->mana(), 200);
+ TEST_EQ(m->hp(), 300);
+ TEST_EQ_STR(m->name()->c_str(), "bob");
+}
+
+void TriviallyCopyableTest() {
+ // clang-format off
+ #if __GNUG__ && __GNUC__ < 5
+ TEST_EQ(__has_trivial_copy(Vec3), true);
+ #else
+ #if __cplusplus >= 201103L
+ TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
+ #endif
+ #endif
+ // clang-format on
+}
+
+// Check stringify of an default enum value to json
+void JsonDefaultTest() {
+ // load FlatBuffer schema (.fbs) from disk
+ std::string schemafile;
+ TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
+ false, &schemafile), true);
+ // parse schema first, so we can use it to parse the data after
+ flatbuffers::Parser parser;
+ auto include_test_path =
+ flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = { test_data_path.c_str(),
+ include_test_path.c_str(), nullptr };
+
+ TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
+ // create incomplete monster and store to json
+ parser.opts.output_default_scalars_in_json = true;
+ parser.opts.output_enum_identifiers = true;
+ flatbuffers::FlatBufferBuilder builder;
+ auto name = builder.CreateString("default_enum");
+ MonsterBuilder color_monster(builder);
+ color_monster.add_name(name);
+ FinishMonsterBuffer(builder, color_monster.Finish());
+ std::string jsongen;
+ auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+ // default value of the "color" field is Blue
+ TEST_EQ(std::string::npos != jsongen.find("color: \"Blue\""), true);
+ // default value of the "testf" field is 3.14159
+ TEST_EQ(std::string::npos != jsongen.find("testf: 3.14159"), true);
+}
+
+void JsonEnumsTest() {
+ // load FlatBuffer schema (.fbs) from disk
+ std::string schemafile;
+ TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
+ false, &schemafile),
+ true);
+ // parse schema first, so we can use it to parse the data after
+ flatbuffers::Parser parser;
+ auto include_test_path =
+ flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = { test_data_path.c_str(),
+ include_test_path.c_str(), nullptr };
+ parser.opts.output_enum_identifiers = true;
+ TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
+ flatbuffers::FlatBufferBuilder builder;
+ auto name = builder.CreateString("bitflag_enum");
+ MonsterBuilder color_monster(builder);
+ color_monster.add_name(name);
+ color_monster.add_color(Color(Color_Blue | Color_Red));
+ FinishMonsterBuffer(builder, color_monster.Finish());
+ std::string jsongen;
+ auto result = GenerateText(parser, builder.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ(std::string::npos != jsongen.find("color: \"Red Blue\""), true);
+}
+
+#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+// The IEEE-754 quiet_NaN is not simple binary constant.
+// All binary NaN bit strings have all the bits of the biased exponent field E
+// set to 1. A quiet NaN bit string should be encoded with the first bit d[1]
+// of the trailing significand field T being 1 (d[0] is implicit bit).
+// It is assumed that endianness of floating-point is same as integer.
+template<typename T, typename U, U qnan_base> bool is_quiet_nan_impl(T v) {
+ static_assert(sizeof(T) == sizeof(U), "unexpected");
+ U b = 0;
+ std::memcpy(&b, &v, sizeof(T));
+ return ((b & qnan_base) == qnan_base);
+}
+static bool is_quiet_nan(float v) {
+ return is_quiet_nan_impl<float, uint32_t, 0x7FC00000u>(v);
+}
+static bool is_quiet_nan(double v) {
+ return is_quiet_nan_impl<double, uint64_t, 0x7FF8000000000000ul>(v);
+}
+
+void TestMonsterExtraFloats() {
+ TEST_EQ(is_quiet_nan(1.0), false);
+ TEST_EQ(is_quiet_nan(infinityd), false);
+ TEST_EQ(is_quiet_nan(-infinityf), false);
+ TEST_EQ(is_quiet_nan(std::numeric_limits<float>::quiet_NaN()), true);
+ TEST_EQ(is_quiet_nan(std::numeric_limits<double>::quiet_NaN()), true);
+
+ using namespace flatbuffers;
+ using namespace MyGame;
+ // Load FlatBuffer schema (.fbs) from disk.
+ std::string schemafile;
+ TEST_EQ(LoadFile((test_data_path + "monster_extra.fbs").c_str(), false,
+ &schemafile),
+ true);
+ // Parse schema first, so we can use it to parse the data after.
+ Parser parser;
+ auto include_test_path = ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = { test_data_path.c_str(),
+ include_test_path.c_str(), nullptr };
+ TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
+ // Create empty extra and store to json.
+ parser.opts.output_default_scalars_in_json = true;
+ parser.opts.output_enum_identifiers = true;
+ FlatBufferBuilder builder;
+ const auto def_root = MonsterExtraBuilder(builder).Finish();
+ FinishMonsterExtraBuffer(builder, def_root);
+ const auto def_obj = builder.GetBufferPointer();
+ const auto def_extra = GetMonsterExtra(def_obj);
+ TEST_NOTNULL(def_extra);
+ TEST_EQ(is_quiet_nan(def_extra->f0()), true);
+ TEST_EQ(is_quiet_nan(def_extra->f1()), true);
+ TEST_EQ(def_extra->f2(), +infinityf);
+ TEST_EQ(def_extra->f3(), -infinityf);
+ TEST_EQ(is_quiet_nan(def_extra->d0()), true);
+ TEST_EQ(is_quiet_nan(def_extra->d1()), true);
+ TEST_EQ(def_extra->d2(), +infinityd);
+ TEST_EQ(def_extra->d3(), -infinityd);
+ std::string jsongen;
+ auto result = GenerateText(parser, def_obj, &jsongen);
+ TEST_EQ(result, true);
+ // Check expected default values.
+ TEST_EQ(std::string::npos != jsongen.find("f0: nan"), true);
+ TEST_EQ(std::string::npos != jsongen.find("f1: nan"), true);
+ TEST_EQ(std::string::npos != jsongen.find("f2: inf"), true);
+ TEST_EQ(std::string::npos != jsongen.find("f3: -inf"), true);
+ TEST_EQ(std::string::npos != jsongen.find("d0: nan"), true);
+ TEST_EQ(std::string::npos != jsongen.find("d1: nan"), true);
+ TEST_EQ(std::string::npos != jsongen.find("d2: inf"), true);
+ TEST_EQ(std::string::npos != jsongen.find("d3: -inf"), true);
+ // Parse 'mosterdata_extra.json'.
+ const auto extra_base = test_data_path + "monsterdata_extra";
+ jsongen = "";
+ TEST_EQ(LoadFile((extra_base + ".json").c_str(), false, &jsongen), true);
+ TEST_EQ(parser.Parse(jsongen.c_str()), true);
+ const auto test_file = parser.builder_.GetBufferPointer();
+ const auto test_size = parser.builder_.GetSize();
+ Verifier verifier(test_file, test_size);
+ TEST_ASSERT(VerifyMonsterExtraBuffer(verifier));
+ const auto extra = GetMonsterExtra(test_file);
+ TEST_NOTNULL(extra);
+ TEST_EQ(is_quiet_nan(extra->f0()), true);
+ TEST_EQ(is_quiet_nan(extra->f1()), true);
+ TEST_EQ(extra->f2(), +infinityf);
+ TEST_EQ(extra->f3(), -infinityf);
+ TEST_EQ(is_quiet_nan(extra->d0()), true);
+ TEST_EQ(extra->d1(), +infinityd);
+ TEST_EQ(extra->d2(), -infinityd);
+ TEST_EQ(is_quiet_nan(extra->d3()), true);
+ TEST_NOTNULL(extra->fvec());
+ TEST_EQ(extra->fvec()->size(), 4);
+ TEST_EQ(extra->fvec()->Get(0), 1.0f);
+ TEST_EQ(extra->fvec()->Get(1), -infinityf);
+ TEST_EQ(extra->fvec()->Get(2), +infinityf);
+ TEST_EQ(is_quiet_nan(extra->fvec()->Get(3)), true);
+ TEST_NOTNULL(extra->dvec());
+ TEST_EQ(extra->dvec()->size(), 4);
+ TEST_EQ(extra->dvec()->Get(0), 2.0);
+ TEST_EQ(extra->dvec()->Get(1), +infinityd);
+ TEST_EQ(extra->dvec()->Get(2), -infinityd);
+ TEST_EQ(is_quiet_nan(extra->dvec()->Get(3)), true);
+}
+#else
+void TestMonsterExtraFloats() {}
+#endif
+
+// example of parsing text straight into a buffer, and generating
+// text back from it:
+void ParseAndGenerateTextTest(bool binary) {
+ // load FlatBuffer schema (.fbs) and JSON from disk
+ std::string schemafile;
+ std::string jsonfile;
+ TEST_EQ(flatbuffers::LoadFile(
+ (test_data_path + "monster_test." + (binary ? "bfbs" : "fbs"))
+ .c_str(),
+ binary, &schemafile),
+ true);
+ TEST_EQ(flatbuffers::LoadFile(
+ (test_data_path + "monsterdata_test.golden").c_str(), false,
+ &jsonfile),
+ true);
+
+ auto include_test_path =
+ flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = { test_data_path.c_str(),
+ include_test_path.c_str(), nullptr };
+
+ // parse schema first, so we can use it to parse the data after
+ flatbuffers::Parser parser;
+ if (binary) {
+ flatbuffers::Verifier verifier(
+ reinterpret_cast<const uint8_t *>(schemafile.c_str()),
+ schemafile.size());
+ TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
+ //auto schema = reflection::GetSchema(schemafile.c_str());
+ TEST_EQ(parser.Deserialize((const uint8_t *)schemafile.c_str(), schemafile.size()), true);
+ } else {
+ TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
+ }
+ TEST_EQ(parser.Parse(jsonfile.c_str(), include_directories), true);
+
+ // here, parser.builder_ contains a binary buffer that is the parsed data.
+
+ // First, verify it, just in case:
+ flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
+ parser.builder_.GetSize());
+ TEST_EQ(VerifyMonsterBuffer(verifier), true);
+
+ AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
+ parser.builder_.GetSize(), false);
+
+ // to ensure it is correct, we now generate text back from the binary,
+ // and compare the two:
+ std::string jsongen;
+ auto result =
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
+
+ // We can also do the above using the convenient Registry that knows about
+ // a set of file_identifiers mapped to schemas.
+ flatbuffers::Registry registry;
+ // Make sure schemas can find their includes.
+ registry.AddIncludeDirectory(test_data_path.c_str());
+ registry.AddIncludeDirectory(include_test_path.c_str());
+ // Call this with many schemas if possible.
+ registry.Register(MonsterIdentifier(),
+ (test_data_path + "monster_test.fbs").c_str());
+ // Now we got this set up, we can parse by just specifying the identifier,
+ // the correct schema will be loaded on the fly:
+ auto buf = registry.TextToFlatBuffer(jsonfile.c_str(), MonsterIdentifier());
+ // If this fails, check registry.lasterror_.
+ TEST_NOTNULL(buf.data());
+ // Test the buffer, to be sure:
+ AccessFlatBufferTest(buf.data(), buf.size(), false);
+ // We can use the registry to turn this back into text, in this case it
+ // will get the file_identifier from the binary:
+ std::string text;
+ auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
+ // If this fails, check registry.lasterror_.
+ TEST_EQ(ok, true);
+ TEST_EQ_STR(text.c_str(), jsonfile.c_str());
+
+ // Generate text for UTF-8 strings without escapes.
+ std::string jsonfile_utf8;
+ TEST_EQ(flatbuffers::LoadFile((test_data_path + "unicode_test.json").c_str(),
+ false, &jsonfile_utf8),
+ true);
+ TEST_EQ(parser.Parse(jsonfile_utf8.c_str(), include_directories), true);
+ // To ensure it is correct, generate utf-8 text back from the binary.
+ std::string jsongen_utf8;
+ // request natural printing for utf-8 strings
+ parser.opts.natural_utf8 = true;
+ parser.opts.strict_json = true;
+ TEST_EQ(
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen_utf8),
+ true);
+ TEST_EQ_STR(jsongen_utf8.c_str(), jsonfile_utf8.c_str());
+}
+
+void ReflectionTest(uint8_t *flatbuf, size_t length) {
+ // Load a binary schema.
+ std::string bfbsfile;
+ TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.bfbs").c_str(),
+ true, &bfbsfile),
+ true);
+
+ // Verify it, just in case:
+ flatbuffers::Verifier verifier(
+ reinterpret_cast<const uint8_t *>(bfbsfile.c_str()), bfbsfile.length());
+ TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
+
+ // Make sure the schema is what we expect it to be.
+ auto &schema = *reflection::GetSchema(bfbsfile.c_str());
+ auto root_table = schema.root_table();
+ TEST_EQ_STR(root_table->name()->c_str(), "MyGame.Example.Monster");
+ auto fields = root_table->fields();
+ auto hp_field_ptr = fields->LookupByKey("hp");
+ TEST_NOTNULL(hp_field_ptr);
+ auto &hp_field = *hp_field_ptr;
+ TEST_EQ_STR(hp_field.name()->c_str(), "hp");
+ TEST_EQ(hp_field.id(), 2);
+ TEST_EQ(hp_field.type()->base_type(), reflection::Short);
+ auto friendly_field_ptr = fields->LookupByKey("friendly");
+ TEST_NOTNULL(friendly_field_ptr);
+ TEST_NOTNULL(friendly_field_ptr->attributes());
+ TEST_NOTNULL(friendly_field_ptr->attributes()->LookupByKey("priority"));
+
+ // Make sure the table index is what we expect it to be.
+ auto pos_field_ptr = fields->LookupByKey("pos");
+ TEST_NOTNULL(pos_field_ptr);
+ TEST_EQ(pos_field_ptr->type()->base_type(), reflection::Obj);
+ auto pos_table_ptr = schema.objects()->Get(pos_field_ptr->type()->index());
+ TEST_NOTNULL(pos_table_ptr);
+ TEST_EQ_STR(pos_table_ptr->name()->c_str(), "MyGame.Example.Vec3");
+
+ // Now use it to dynamically access a buffer.
+ auto &root = *flatbuffers::GetAnyRoot(flatbuf);
+
+ // Verify the buffer first using reflection based verification
+ TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
+ true);
+
+ auto hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
+ TEST_EQ(hp, 80);
+
+ // Rather than needing to know the type, we can also get the value of
+ // any field as an int64_t/double/string, regardless of what it actually is.
+ auto hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
+ TEST_EQ(hp_int64, 80);
+ auto hp_double = flatbuffers::GetAnyFieldF(root, hp_field);
+ TEST_EQ(hp_double, 80.0);
+ auto hp_string = flatbuffers::GetAnyFieldS(root, hp_field, &schema);
+ TEST_EQ_STR(hp_string.c_str(), "80");
+
+ // Get struct field through reflection
+ auto pos_struct = flatbuffers::GetFieldStruct(root, *pos_field_ptr);
+ TEST_NOTNULL(pos_struct);
+ TEST_EQ(flatbuffers::GetAnyFieldF(*pos_struct,
+ *pos_table_ptr->fields()->LookupByKey("z")),
+ 3.0f);
+
+ auto test3_field = pos_table_ptr->fields()->LookupByKey("test3");
+ auto test3_struct = flatbuffers::GetFieldStruct(*pos_struct, *test3_field);
+ TEST_NOTNULL(test3_struct);
+ auto test3_object = schema.objects()->Get(test3_field->type()->index());
+
+ TEST_EQ(flatbuffers::GetAnyFieldF(*test3_struct,
+ *test3_object->fields()->LookupByKey("a")),
+ 10);
+
+ // We can also modify it.
+ flatbuffers::SetField<uint16_t>(&root, hp_field, 200);
+ hp = flatbuffers::GetFieldI<uint16_t>(root, hp_field);
+ TEST_EQ(hp, 200);
+
+ // We can also set fields generically:
+ flatbuffers::SetAnyFieldI(&root, hp_field, 300);
+ hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
+ TEST_EQ(hp_int64, 300);
+ flatbuffers::SetAnyFieldF(&root, hp_field, 300.5);
+ hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
+ TEST_EQ(hp_int64, 300);
+ flatbuffers::SetAnyFieldS(&root, hp_field, "300");
+ hp_int64 = flatbuffers::GetAnyFieldI(root, hp_field);
+ TEST_EQ(hp_int64, 300);
+
+ // Test buffer is valid after the modifications
+ TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), flatbuf, length),
+ true);
+
+ // Reset it, for further tests.
+ flatbuffers::SetField<uint16_t>(&root, hp_field, 80);
+
+ // More advanced functionality: changing the size of items in-line!
+ // First we put the FlatBuffer inside an std::vector.
+ std::vector<uint8_t> resizingbuf(flatbuf, flatbuf + length);
+ // Find the field we want to modify.
+ auto &name_field = *fields->LookupByKey("name");
+ // Get the root.
+ // This time we wrap the result from GetAnyRoot in a smartpointer that
+ // will keep rroot valid as resizingbuf resizes.
+ auto rroot = flatbuffers::piv(
+ flatbuffers::GetAnyRoot(flatbuffers::vector_data(resizingbuf)),
+ resizingbuf);
+ SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
+ &resizingbuf);
+ // Here resizingbuf has changed, but rroot is still valid.
+ TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "totally new string");
+ // Now lets extend a vector by 100 elements (10 -> 110).
+ auto &inventory_field = *fields->LookupByKey("inventory");
+ auto rinventory = flatbuffers::piv(
+ flatbuffers::GetFieldV<uint8_t>(**rroot, inventory_field), resizingbuf);
+ flatbuffers::ResizeVector<uint8_t>(schema, 110, 50, *rinventory,
+ &resizingbuf);
+ // rinventory still valid, so lets read from it.
+ TEST_EQ(rinventory->Get(10), 50);
+
+ // For reflection uses not covered already, there is a more powerful way:
+ // we can simply generate whatever object we want to add/modify in a
+ // FlatBuffer of its own, then add that to an existing FlatBuffer:
+ // As an example, let's add a string to an array of strings.
+ // First, find our field:
+ auto &testarrayofstring_field = *fields->LookupByKey("testarrayofstring");
+ // Find the vector value:
+ auto rtestarrayofstring = flatbuffers::piv(
+ flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>(
+ **rroot, testarrayofstring_field),
+ resizingbuf);
+ // It's a vector of 2 strings, to which we add one more, initialized to
+ // offset 0.
+ flatbuffers::ResizeVector<flatbuffers::Offset<flatbuffers::String>>(
+ schema, 3, 0, *rtestarrayofstring, &resizingbuf);
+ // Here we just create a buffer that contans a single string, but this
+ // could also be any complex set of tables and other values.
+ flatbuffers::FlatBufferBuilder stringfbb;
+ stringfbb.Finish(stringfbb.CreateString("hank"));
+ // Add the contents of it to our existing FlatBuffer.
+ // We do this last, so the pointer doesn't get invalidated (since it is
+ // at the end of the buffer):
+ auto string_ptr = flatbuffers::AddFlatBuffer(
+ resizingbuf, stringfbb.GetBufferPointer(), stringfbb.GetSize());
+ // Finally, set the new value in the vector.
+ rtestarrayofstring->MutateOffset(2, string_ptr);
+ TEST_EQ_STR(rtestarrayofstring->Get(0)->c_str(), "bob");
+ TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
+ // Test integrity of all resize operations above.
+ flatbuffers::Verifier resize_verifier(
+ reinterpret_cast<const uint8_t *>(flatbuffers::vector_data(resizingbuf)),
+ resizingbuf.size());
+ TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
+
+ // Test buffer is valid using reflection as well
+ TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
+ flatbuffers::vector_data(resizingbuf),
+ resizingbuf.size()),
+ true);
+
+ // As an additional test, also set it on the name field.
+ // Note: unlike the name change above, this just overwrites the offset,
+ // rather than changing the string in-place.
+ SetFieldT(*rroot, name_field, string_ptr);
+ TEST_EQ_STR(GetFieldS(**rroot, name_field)->c_str(), "hank");
+
+ // Using reflection, rather than mutating binary FlatBuffers, we can also copy
+ // tables and other things out of other FlatBuffers into a FlatBufferBuilder,
+ // either part or whole.
+ flatbuffers::FlatBufferBuilder fbb;
+ auto root_offset = flatbuffers::CopyTable(
+ fbb, schema, *root_table, *flatbuffers::GetAnyRoot(flatbuf), true);
+ fbb.Finish(root_offset, MonsterIdentifier());
+ // Test that it was copied correctly:
+ AccessFlatBufferTest(fbb.GetBufferPointer(), fbb.GetSize());
+
+ // Test buffer is valid using reflection as well
+ TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
+ fbb.GetBufferPointer(), fbb.GetSize()),
+ true);
+}
+
+void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
+ auto s = flatbuffers::FlatBufferToString(flatbuf, Monster::MiniReflectTypeTable());
+ TEST_EQ_STR(
+ s.c_str(),
+ "{ "
+ "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
+ "{ a: 10, b: 20 } }, "
+ "hp: 80, "
+ "name: \"MyMonster\", "
+ "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
+ "test_type: Monster, "
+ "test: { name: \"Fred\" }, "
+ "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
+ "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
+ "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" "
+ "}, "
+ "{ name: \"Wilma\" } ], "
+ // TODO(wvo): should really print this nested buffer correctly.
+ "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, "
+ "0, "
+ "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
+ "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
+ "testarrayofstring2: [ \"jane\", \"mary\" ], "
+ "testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
+ "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
+ "{ id: 4, distance: 40 } ], "
+ "flex: [ 210, 4, 5, 2 ], "
+ "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
+ "vector_of_enums: [ Blue, Green ] "
+ "}");
+
+ Test test(16, 32);
+ Vec3 vec(1,2,3, 1.5, Color_Red, test);
+ flatbuffers::FlatBufferBuilder vec_builder;
+ vec_builder.Finish(vec_builder.CreateStruct(vec));
+ auto vec_buffer = vec_builder.Release();
+ auto vec_str = flatbuffers::FlatBufferToString(vec_buffer.data(),
+ Vec3::MiniReflectTypeTable());
+ TEST_EQ_STR(
+ vec_str.c_str(),
+ "{ x: 1.0, y: 2.0, z: 3.0, test1: 1.5, test2: Red, test3: { a: 16, b: 32 } }");
+}
+
+// Parse a .proto schema, output as .fbs
+void ParseProtoTest() {
+ // load the .proto and the golden file from disk
+ std::string protofile;
+ std::string goldenfile;
+ std::string goldenunionfile;
+ TEST_EQ(
+ flatbuffers::LoadFile((test_data_path + "prototest/test.proto").c_str(),
+ false, &protofile),
+ true);
+ TEST_EQ(
+ flatbuffers::LoadFile((test_data_path + "prototest/test.golden").c_str(),
+ false, &goldenfile),
+ true);
+ TEST_EQ(
+ flatbuffers::LoadFile((test_data_path +
+ "prototest/test_union.golden").c_str(),
+ false, &goldenunionfile),
+ true);
+
+ flatbuffers::IDLOptions opts;
+ opts.include_dependence_headers = false;
+ opts.proto_mode = true;
+
+ // Parse proto.
+ flatbuffers::Parser parser(opts);
+ auto protopath = test_data_path + "prototest/";
+ const char *include_directories[] = { protopath.c_str(), nullptr };
+ TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
+
+ // Generate fbs.
+ auto fbs = flatbuffers::GenerateFBS(parser, "test");
+
+ // Ensure generated file is parsable.
+ flatbuffers::Parser parser2;
+ TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
+ TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
+
+ // Parse proto with --oneof-union option.
+ opts.proto_oneof_union = true;
+ flatbuffers::Parser parser3(opts);
+ TEST_EQ(parser3.Parse(protofile.c_str(), include_directories), true);
+
+ // Generate fbs.
+ auto fbs_union = flatbuffers::GenerateFBS(parser3, "test");
+
+ // Ensure generated file is parsable.
+ flatbuffers::Parser parser4;
+ TEST_EQ(parser4.Parse(fbs_union.c_str(), nullptr), true);
+ TEST_EQ_STR(fbs_union.c_str(), goldenunionfile.c_str());
+}
+
+template<typename T>
+void CompareTableFieldValue(flatbuffers::Table *table,
+ flatbuffers::voffset_t voffset, T val) {
+ T read = table->GetField(voffset, static_cast<T>(0));
+ TEST_EQ(read, val);
+}
+
+// Low level stress/fuzz test: serialize/deserialize a variety of
+// different kinds of data in different combinations
+void FuzzTest1() {
+ // Values we're testing against: chosen to ensure no bits get chopped
+ // off anywhere, and also be different from eachother.
+ const uint8_t bool_val = true;
+ const int8_t char_val = -127; // 0x81
+ const uint8_t uchar_val = 0xFF;
+ const int16_t short_val = -32222; // 0x8222;
+ const uint16_t ushort_val = 0xFEEE;
+ const int32_t int_val = 0x83333333;
+ const uint32_t uint_val = 0xFDDDDDDD;
+ const int64_t long_val = 0x8444444444444444LL;
+ const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
+ const float float_val = 3.14159f;
+ const double double_val = 3.14159265359;
+
+ const int test_values_max = 11;
+ const flatbuffers::voffset_t fields_per_object = 4;
+ const int num_fuzz_objects = 10000; // The higher, the more thorough :)
+
+ flatbuffers::FlatBufferBuilder builder;
+
+ lcg_reset(); // Keep it deterministic.
+
+ flatbuffers::uoffset_t objects[num_fuzz_objects];
+
+ // Generate num_fuzz_objects random objects each consisting of
+ // fields_per_object fields, each of a random type.
+ for (int i = 0; i < num_fuzz_objects; i++) {
+ auto start = builder.StartTable();
+ for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
+ int choice = lcg_rand() % test_values_max;
+ auto off = flatbuffers::FieldIndexToOffset(f);
+ switch (choice) {
+ case 0: builder.AddElement<uint8_t>(off, bool_val, 0); break;
+ case 1: builder.AddElement<int8_t>(off, char_val, 0); break;
+ case 2: builder.AddElement<uint8_t>(off, uchar_val, 0); break;
+ case 3: builder.AddElement<int16_t>(off, short_val, 0); break;
+ case 4: builder.AddElement<uint16_t>(off, ushort_val, 0); break;
+ case 5: builder.AddElement<int32_t>(off, int_val, 0); break;
+ case 6: builder.AddElement<uint32_t>(off, uint_val, 0); break;
+ case 7: builder.AddElement<int64_t>(off, long_val, 0); break;
+ case 8: builder.AddElement<uint64_t>(off, ulong_val, 0); break;
+ case 9: builder.AddElement<float>(off, float_val, 0); break;
+ case 10: builder.AddElement<double>(off, double_val, 0); break;
+ }
+ }
+ objects[i] = builder.EndTable(start);
+ }
+ builder.PreAlign<flatbuffers::largest_scalar_t>(0); // Align whole buffer.
+
+ lcg_reset(); // Reset.
+
+ uint8_t *eob = builder.GetCurrentBufferPointer() + builder.GetSize();
+
+ // Test that all objects we generated are readable and return the
+ // expected values. We generate random objects in the same order
+ // so this is deterministic.
+ for (int i = 0; i < num_fuzz_objects; i++) {
+ auto table = reinterpret_cast<flatbuffers::Table *>(eob - objects[i]);
+ for (flatbuffers::voffset_t f = 0; f < fields_per_object; f++) {
+ int choice = lcg_rand() % test_values_max;
+ flatbuffers::voffset_t off = flatbuffers::FieldIndexToOffset(f);
+ switch (choice) {
+ case 0: CompareTableFieldValue(table, off, bool_val); break;
+ case 1: CompareTableFieldValue(table, off, char_val); break;
+ case 2: CompareTableFieldValue(table, off, uchar_val); break;
+ case 3: CompareTableFieldValue(table, off, short_val); break;
+ case 4: CompareTableFieldValue(table, off, ushort_val); break;
+ case 5: CompareTableFieldValue(table, off, int_val); break;
+ case 6: CompareTableFieldValue(table, off, uint_val); break;
+ case 7: CompareTableFieldValue(table, off, long_val); break;
+ case 8: CompareTableFieldValue(table, off, ulong_val); break;
+ case 9: CompareTableFieldValue(table, off, float_val); break;
+ case 10: CompareTableFieldValue(table, off, double_val); break;
+ }
+ }
+ }
+}
+
+// High level stress/fuzz test: generate a big schema and
+// matching json data in random combinations, then parse both,
+// generate json back from the binary, and compare with the original.
+void FuzzTest2() {
+ lcg_reset(); // Keep it deterministic.
+
+ const int num_definitions = 30;
+ const int num_struct_definitions = 5; // Subset of num_definitions.
+ const int fields_per_definition = 15;
+ const int instances_per_definition = 5;
+ const int deprecation_rate = 10; // 1 in deprecation_rate fields will
+ // be deprecated.
+
+ std::string schema = "namespace test;\n\n";
+
+ struct RndDef {
+ std::string instances[instances_per_definition];
+
+ // Since we're generating schema and corresponding data in tandem,
+ // this convenience function adds strings to both at once.
+ static void Add(RndDef (&definitions_l)[num_definitions],
+ std::string &schema_l, const int instances_per_definition_l,
+ const char *schema_add, const char *instance_add,
+ int definition) {
+ schema_l += schema_add;
+ for (int i = 0; i < instances_per_definition_l; i++)
+ definitions_l[definition].instances[i] += instance_add;
+ }
+ };
+
+ // clang-format off
+ #define AddToSchemaAndInstances(schema_add, instance_add) \
+ RndDef::Add(definitions, schema, instances_per_definition, \
+ schema_add, instance_add, definition)
+
+ #define Dummy() \
+ RndDef::Add(definitions, schema, instances_per_definition, \
+ "byte", "1", definition)
+ // clang-format on
+
+ RndDef definitions[num_definitions];
+
+ // We are going to generate num_definitions, the first
+ // num_struct_definitions will be structs, the rest tables. For each
+ // generate random fields, some of which may be struct/table types
+ // referring to previously generated structs/tables.
+ // Simultanenously, we generate instances_per_definition JSON data
+ // definitions, which will have identical structure to the schema
+ // being generated. We generate multiple instances such that when creating
+ // hierarchy, we get some variety by picking one randomly.
+ for (int definition = 0; definition < num_definitions; definition++) {
+ std::string definition_name = "D" + flatbuffers::NumToString(definition);
+
+ bool is_struct = definition < num_struct_definitions;
+
+ AddToSchemaAndInstances(
+ ((is_struct ? "struct " : "table ") + definition_name + " {\n").c_str(),
+ "{\n");
+
+ for (int field = 0; field < fields_per_definition; field++) {
+ const bool is_last_field = field == fields_per_definition - 1;
+
+ // Deprecate 1 in deprecation_rate fields. Only table fields can be
+ // deprecated.
+ // Don't deprecate the last field to avoid dangling commas in JSON.
+ const bool deprecated =
+ !is_struct && !is_last_field && (lcg_rand() % deprecation_rate == 0);
+
+ std::string field_name = "f" + flatbuffers::NumToString(field);
+ AddToSchemaAndInstances((" " + field_name + ":").c_str(),
+ deprecated ? "" : (field_name + ": ").c_str());
+ // Pick random type:
+ auto base_type = static_cast<flatbuffers::BaseType>(
+ lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
+ switch (base_type) {
+ case flatbuffers::BASE_TYPE_STRING:
+ if (is_struct) {
+ Dummy(); // No strings in structs.
+ } else {
+ AddToSchemaAndInstances("string", deprecated ? "" : "\"hi\"");
+ }
+ break;
+ case flatbuffers::BASE_TYPE_VECTOR:
+ if (is_struct) {
+ Dummy(); // No vectors in structs.
+ } else {
+ AddToSchemaAndInstances("[ubyte]",
+ deprecated ? "" : "[\n0,\n1,\n255\n]");
+ }
+ break;
+ case flatbuffers::BASE_TYPE_NONE:
+ case flatbuffers::BASE_TYPE_UTYPE:
+ case flatbuffers::BASE_TYPE_STRUCT:
+ case flatbuffers::BASE_TYPE_UNION:
+ if (definition) {
+ // Pick a random previous definition and random data instance of
+ // that definition.
+ int defref = lcg_rand() % definition;
+ int instance = lcg_rand() % instances_per_definition;
+ AddToSchemaAndInstances(
+ ("D" + flatbuffers::NumToString(defref)).c_str(),
+ deprecated ? ""
+ : definitions[defref].instances[instance].c_str());
+ } else {
+ // If this is the first definition, we have no definition we can
+ // refer to.
+ Dummy();
+ }
+ break;
+ case flatbuffers::BASE_TYPE_BOOL:
+ AddToSchemaAndInstances(
+ "bool", deprecated ? "" : (lcg_rand() % 2 ? "true" : "false"));
+ break;
+ case flatbuffers::BASE_TYPE_ARRAY:
+ if (!is_struct) {
+ AddToSchemaAndInstances(
+ "ubyte",
+ deprecated ? "" : "255"); // No fixed-length arrays in tables.
+ } else {
+ AddToSchemaAndInstances("[int:3]", deprecated ? "" : "[\n,\n,\n]");
+ }
+ break;
+ default:
+ // All the scalar types.
+ schema += flatbuffers::kTypeNames[base_type];
+
+ if (!deprecated) {
+ // We want each instance to use its own random value.
+ for (int inst = 0; inst < instances_per_definition; inst++)
+ definitions[definition].instances[inst] +=
+ flatbuffers::IsFloat(base_type)
+ ? flatbuffers::NumToString<double>(lcg_rand() % 128)
+ .c_str()
+ : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
+ }
+ }
+ AddToSchemaAndInstances(deprecated ? "(deprecated);\n" : ";\n",
+ deprecated ? "" : is_last_field ? "\n" : ",\n");
+ }
+ AddToSchemaAndInstances("}\n\n", "}");
+ }
+
+ schema += "root_type D" + flatbuffers::NumToString(num_definitions - 1);
+ schema += ";\n";
+
+ flatbuffers::Parser parser;
+
+ // Will not compare against the original if we don't write defaults
+ parser.builder_.ForceDefaults(true);
+
+ // Parse the schema, parse the generated data, then generate text back
+ // from the binary and compare against the original.
+ TEST_EQ(parser.Parse(schema.c_str()), true);
+
+ const std::string &json =
+ definitions[num_definitions - 1].instances[0] + "\n";
+
+ TEST_EQ(parser.Parse(json.c_str()), true);
+
+ std::string jsongen;
+ parser.opts.indent_step = 0;
+ auto result =
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+
+ if (jsongen != json) {
+ // These strings are larger than a megabyte, so we show the bytes around
+ // the first bytes that are different rather than the whole string.
+ size_t len = std::min(json.length(), jsongen.length());
+ for (size_t i = 0; i < len; i++) {
+ if (json[i] != jsongen[i]) {
+ i -= std::min(static_cast<size_t>(10), i); // show some context;
+ size_t end = std::min(len, i + 20);
+ for (; i < end; i++)
+ TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
+ static_cast<int>(i), jsongen[i], json[i]);
+ break;
+ }
+ }
+ TEST_NOTNULL(NULL);
+ }
+
+ // clang-format off
+ #ifdef FLATBUFFERS_TEST_VERBOSE
+ TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
+ static_cast<int>(schema.length() / 1024),
+ static_cast<int>(json.length() / 1024));
+ #endif
+ // clang-format on
+}
+
+// Test that parser errors are actually generated.
+void TestError_(const char *src, const char *error_substr, bool strict_json,
+ const char *file, int line, const char *func) {
+ flatbuffers::IDLOptions opts;
+ opts.strict_json = strict_json;
+ flatbuffers::Parser parser(opts);
+ if (parser.Parse(src)) {
+ TestFail("true", "false",
+ ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
+ func);
+ } else if (!strstr(parser.error_.c_str(), error_substr)) {
+ TestFail(parser.error_.c_str(), error_substr,
+ ("parser.Parse(\"" + std::string(src) + "\")").c_str(), file, line,
+ func);
+ }
+}
+
+void TestError_(const char *src, const char *error_substr, const char *file,
+ int line, const char *func) {
+ TestError_(src, error_substr, false, file, line, func);
+}
+
+#ifdef _WIN32
+# define TestError(src, ...) \
+ TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __FUNCTION__)
+#else
+# define TestError(src, ...) \
+ TestError_(src, __VA_ARGS__, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#endif
+
+// Test that parsing errors occur as we'd expect.
+// Also useful for coverage, making sure these paths are run.
+void ErrorTest() {
+ // In order they appear in idl_parser.cpp
+ TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
+ TestError("\"\0", "illegal");
+ TestError("\"\\q", "escape code");
+ TestError("table ///", "documentation");
+ TestError("@", "illegal");
+ TestError("table 1", "expecting");
+ TestError("table X { Y:[[int]]; }", "nested vector");
+ TestError("table X { Y:1; }", "illegal type");
+ TestError("table X { Y:int; Y:int; }", "field already");
+ TestError("table Y {} table X { Y:int; }", "same as table");
+ TestError("struct X { Y:string; }", "only scalar");
+ TestError("table X { Y:string = \"\"; }", "default values");
+ TestError("struct X { a:uint = 42; }", "default values");
+ TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
+ TestError("struct X { Y:int (deprecated); }", "deprecate");
+ TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
+ "missing type field");
+ TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
+ "type id");
+ TestError("table X { Y:int; } root_type X; { Z:", "unknown field");
+ TestError("table X { Y:int; } root_type X; { Y:", "string constant", true);
+ TestError("table X { Y:int; } root_type X; { \"Y\":1, }", "string constant",
+ true);
+ TestError(
+ "struct X { Y:int; Z:int; } table W { V:X; } root_type W; "
+ "{ V:{ Y:1 } }",
+ "wrong number");
+ TestError("enum E:byte { A } table X { Y:E; } root_type X; { Y:U }",
+ "unknown enum value");
+ TestError("table X { Y:byte; } root_type X; { Y:; }", "starting");
+ TestError("enum X:byte { Y } enum X {", "enum already");
+ TestError("enum X:float {}", "underlying");
+ TestError("enum X:byte { Y, Y }", "value already");
+ TestError("enum X:byte { Y=2, Z=1 }", "ascending");
+ TestError("table X { Y:int; } table X {", "datatype already");
+ TestError("struct X (force_align: 7) { Y:int; }", "force_align");
+ TestError("struct X {}", "size 0");
+ TestError("{}", "no root");
+ TestError("table X { Y:byte; } root_type X; { Y:1 } { Y:1 }", "end of file");
+ TestError("table X { Y:byte; } root_type X; { Y:1 } table Y{ Z:int }",
+ "end of file");
+ TestError("root_type X;", "unknown root");
+ TestError("struct X { Y:int; } root_type X;", "a table");
+ TestError("union X { Y }", "referenced");
+ TestError("union Z { X } struct X { Y:int; }", "only tables");
+ TestError("table X { Y:[int]; YLength:int; }", "clash");
+ TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
+ // float to integer conversion is forbidden
+ TestError("table X { Y:int; } root_type X; { Y:1.0 }", "float");
+ TestError("table X { Y:bool; } root_type X; { Y:1.0 }", "float");
+ TestError("enum X:bool { Y = true }", "must be integral");
+}
+
+template<typename T>
+T TestValue(const char *json, const char *type_name,
+ const char *decls = nullptr) {
+ flatbuffers::Parser parser;
+ parser.builder_.ForceDefaults(true); // return defaults
+ auto check_default = json ? false : true;
+ if (check_default) { parser.opts.output_default_scalars_in_json = true; }
+ // Simple schema.
+ std::string schema = std::string(decls ? decls : "") + "\n" +
+ "table X { Y:" + std::string(type_name) +
+ "; } root_type X;";
+ auto schema_done = parser.Parse(schema.c_str());
+ TEST_EQ_STR(parser.error_.c_str(), "");
+ TEST_EQ(schema_done, true);
+
+ auto done = parser.Parse(check_default ? "{}" : json);
+ TEST_EQ_STR(parser.error_.c_str(), "");
+ TEST_EQ(done, true);
+
+ // Check with print.
+ std::string print_back;
+ parser.opts.indent_step = -1;
+ TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), &print_back),
+ true);
+ // restore value from its default
+ if (check_default) { TEST_EQ(parser.Parse(print_back.c_str()), true); }
+
+ auto root = flatbuffers::GetRoot<flatbuffers::Table>(
+ parser.builder_.GetBufferPointer());
+ return root->GetField<T>(flatbuffers::FieldIndexToOffset(0), 0);
+}
+
+bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
+
+// Additional parser testing not covered elsewhere.
+void ValueTest() {
+ // Test scientific notation numbers.
+ TEST_EQ(FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"),
+ 3.14159f),
+ true);
+ // number in string
+ TEST_EQ(FloatCompare(TestValue<float>("{ Y:\"0.0314159e+2\" }", "float"),
+ 3.14159f),
+ true);
+
+ // Test conversion functions.
+ TEST_EQ(FloatCompare(TestValue<float>("{ Y:cos(rad(180)) }", "float"), -1),
+ true);
+
+ // int embedded to string
+ TEST_EQ(TestValue<int>("{ Y:\"-876\" }", "int=-123"), -876);
+ TEST_EQ(TestValue<int>("{ Y:\"876\" }", "int=-123"), 876);
+
+ // Test negative hex constant.
+ TEST_EQ(TestValue<int>("{ Y:-0x8ea0 }", "int=-0x8ea0"), -36512);
+ TEST_EQ(TestValue<int>(nullptr, "int=-0x8ea0"), -36512);
+
+ // positive hex constant
+ TEST_EQ(TestValue<int>("{ Y:0x1abcdef }", "int=0x1"), 0x1abcdef);
+ // with optional '+' sign
+ TEST_EQ(TestValue<int>("{ Y:+0x1abcdef }", "int=+0x1"), 0x1abcdef);
+ // hex in string
+ TEST_EQ(TestValue<int>("{ Y:\"0x1abcdef\" }", "int=+0x1"), 0x1abcdef);
+
+ // Make sure we do unsigned 64bit correctly.
+ TEST_EQ(TestValue<uint64_t>("{ Y:12335089644688340133 }", "ulong"),
+ 12335089644688340133ULL);
+
+ // bool in string
+ TEST_EQ(TestValue<bool>("{ Y:\"false\" }", "bool=true"), false);
+ TEST_EQ(TestValue<bool>("{ Y:\"true\" }", "bool=\"true\""), true);
+ TEST_EQ(TestValue<bool>("{ Y:'false' }", "bool=true"), false);
+ TEST_EQ(TestValue<bool>("{ Y:'true' }", "bool=\"true\""), true);
+
+ // check comments before and after json object
+ TEST_EQ(TestValue<int>("/*before*/ { Y:1 } /*after*/", "int"), 1);
+ TEST_EQ(TestValue<int>("//before \n { Y:1 } //after", "int"), 1);
+
+}
+
+void NestedListTest() {
+ flatbuffers::Parser parser1;
+ TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
+ "root_type T;"
+ "{ F:[ [10,20], [30,40]] }"),
+ true);
+}
+
+void EnumStringsTest() {
+ flatbuffers::Parser parser1;
+ TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
+ "root_type T;"
+ "{ F:[ A, B, \"C\", \"A B C\" ] }"),
+ true);
+ flatbuffers::Parser parser2;
+ TEST_EQ(parser2.Parse("enum E:byte { A, B, C } table T { F:[int]; }"
+ "root_type T;"
+ "{ F:[ \"E.C\", \"E.A E.B E.C\" ] }"),
+ true);
+ // unsigned bit_flags
+ flatbuffers::Parser parser3;
+ TEST_EQ(
+ parser3.Parse("enum E:uint16 (bit_flags) { F0, F07=7, F08, F14=14, F15 }"
+ " table T { F: E = \"F15 F08\"; }"
+ "root_type T;"),
+ true);
+}
+
+void EnumNamesTest() {
+ TEST_EQ_STR("Red", EnumNameColor(Color_Red));
+ TEST_EQ_STR("Green", EnumNameColor(Color_Green));
+ TEST_EQ_STR("Blue", EnumNameColor(Color_Blue));
+ // Check that Color to string don't crash while decode a mixture of Colors.
+ // 1) Example::Color enum is enum with unfixed underlying type.
+ // 2) Valid enum range: [0; 2^(ceil(log2(Color_ANY))) - 1].
+ // Consequence: A value is out of this range will lead to UB (since C++17).
+ // For details see C++17 standard or explanation on the SO:
+ // stackoverflow.com/questions/18195312/what-happens-if-you-static-cast-invalid-value-to-enum-class
+ TEST_EQ_STR("", EnumNameColor(static_cast<Color>(0)));
+ TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY-1)));
+ TEST_EQ_STR("", EnumNameColor(static_cast<Color>(Color_ANY+1)));
+}
+
+void EnumOutOfRangeTest() {
+ TestError("enum X:byte { Y = 128 }", "enum value does not fit");
+ TestError("enum X:byte { Y = -129 }", "enum value does not fit");
+ TestError("enum X:byte { Y = 126, Z0, Z1 }", "enum value does not fit");
+ TestError("enum X:ubyte { Y = -1 }", "enum value does not fit");
+ TestError("enum X:ubyte { Y = 256 }", "enum value does not fit");
+ TestError("enum X:ubyte { Y = 255, Z }", "enum value does not fit");
+ // Unions begin with an implicit "NONE = 0".
+ TestError("table Y{} union X { Y = -1 }",
+ "enum values must be specified in ascending order");
+ TestError("table Y{} union X { Y = 256 }", "enum value does not fit");
+ TestError("table Y{} union X { Y = 255, Z:Y }", "enum value does not fit");
+ TestError("enum X:int { Y = -2147483649 }", "enum value does not fit");
+ TestError("enum X:int { Y = 2147483648 }", "enum value does not fit");
+ TestError("enum X:uint { Y = -1 }", "enum value does not fit");
+ TestError("enum X:uint { Y = 4294967297 }", "enum value does not fit");
+ TestError("enum X:long { Y = 9223372036854775808 }", "does not fit");
+ TestError("enum X:long { Y = 9223372036854775807, Z }", "enum value does not fit");
+ TestError("enum X:ulong { Y = -1 }", "does not fit");
+ TestError("enum X:ubyte (bit_flags) { Y=8 }", "bit flag out");
+ TestError("enum X:byte (bit_flags) { Y=7 }", "must be unsigned"); // -128
+ // bit_flgs out of range
+ TestError("enum X:ubyte (bit_flags) { Y0,Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8 }", "out of range");
+}
+
+void EnumValueTest() {
+ // json: "{ Y:0 }", schema: table X { Y : "E"}
+ // 0 in enum (V=0) E then Y=0 is valid.
+ TEST_EQ(TestValue<int>("{ Y:0 }", "E", "enum E:int { V }"), 0);
+ TEST_EQ(TestValue<int>("{ Y:V }", "E", "enum E:int { V }"), 0);
+ // A default value of Y is 0.
+ TEST_EQ(TestValue<int>("{ }", "E", "enum E:int { V }"), 0);
+ TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { V=5 }"), 5);
+ // Generate json with defaults and check.
+ TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { V=5 }"), 5);
+ // 5 in enum
+ TEST_EQ(TestValue<int>("{ Y:5 }", "E", "enum E:int { Z, V=5 }"), 5);
+ TEST_EQ(TestValue<int>("{ Y:5 }", "E=V", "enum E:int { Z, V=5 }"), 5);
+ // Generate json with defaults and check.
+ TEST_EQ(TestValue<int>(nullptr, "E", "enum E:int { Z, V=5 }"), 0);
+ TEST_EQ(TestValue<int>(nullptr, "E=V", "enum E:int { Z, V=5 }"), 5);
+ // u84 test
+ TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
+ "enum E:ulong { V = 13835058055282163712 }"),
+ 13835058055282163712ULL);
+ TEST_EQ(TestValue<uint64_t>(nullptr, "E=V",
+ "enum E:ulong { V = 18446744073709551615 }"),
+ 18446744073709551615ULL);
+ // Assign non-enum value to enum field. Is it right?
+ TEST_EQ(TestValue<int>("{ Y:7 }", "E", "enum E:int { V = 0 }"), 7);
+}
+
+void IntegerOutOfRangeTest() {
+ TestError("table T { F:byte; } root_type T; { F:128 }",
+ "constant does not fit");
+ TestError("table T { F:byte; } root_type T; { F:-129 }",
+ "constant does not fit");
+ TestError("table T { F:ubyte; } root_type T; { F:256 }",
+ "constant does not fit");
+ TestError("table T { F:ubyte; } root_type T; { F:-1 }",
+ "constant does not fit");
+ TestError("table T { F:short; } root_type T; { F:32768 }",
+ "constant does not fit");
+ TestError("table T { F:short; } root_type T; { F:-32769 }",
+ "constant does not fit");
+ TestError("table T { F:ushort; } root_type T; { F:65536 }",
+ "constant does not fit");
+ TestError("table T { F:ushort; } root_type T; { F:-1 }",
+ "constant does not fit");
+ TestError("table T { F:int; } root_type T; { F:2147483648 }",
+ "constant does not fit");
+ TestError("table T { F:int; } root_type T; { F:-2147483649 }",
+ "constant does not fit");
+ TestError("table T { F:uint; } root_type T; { F:4294967296 }",
+ "constant does not fit");
+ TestError("table T { F:uint; } root_type T; { F:-1 }",
+ "constant does not fit");
+ // Check fixed width aliases
+ TestError("table X { Y:uint8; } root_type X; { Y: -1 }", "does not fit");
+ TestError("table X { Y:uint8; } root_type X; { Y: 256 }", "does not fit");
+ TestError("table X { Y:uint16; } root_type X; { Y: -1 }", "does not fit");
+ TestError("table X { Y:uint16; } root_type X; { Y: 65536 }", "does not fit");
+ TestError("table X { Y:uint32; } root_type X; { Y: -1 }", "");
+ TestError("table X { Y:uint32; } root_type X; { Y: 4294967296 }",
+ "does not fit");
+ TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
+ TestError("table X { Y:uint64; } root_type X; { Y: -9223372036854775809 }",
+ "does not fit");
+ TestError("table X { Y:uint64; } root_type X; { Y: 18446744073709551616 }",
+ "does not fit");
+
+ TestError("table X { Y:int8; } root_type X; { Y: -129 }", "does not fit");
+ TestError("table X { Y:int8; } root_type X; { Y: 128 }", "does not fit");
+ TestError("table X { Y:int16; } root_type X; { Y: -32769 }", "does not fit");
+ TestError("table X { Y:int16; } root_type X; { Y: 32768 }", "does not fit");
+ TestError("table X { Y:int32; } root_type X; { Y: -2147483649 }", "");
+ TestError("table X { Y:int32; } root_type X; { Y: 2147483648 }",
+ "does not fit");
+ TestError("table X { Y:int64; } root_type X; { Y: -9223372036854775809 }",
+ "does not fit");
+ TestError("table X { Y:int64; } root_type X; { Y: 9223372036854775808 }",
+ "does not fit");
+ // check out-of-int64 as int8
+ TestError("table X { Y:int8; } root_type X; { Y: -9223372036854775809 }",
+ "does not fit");
+ TestError("table X { Y:int8; } root_type X; { Y: 9223372036854775808 }",
+ "does not fit");
+
+ // Check default values
+ TestError("table X { Y:int64=-9223372036854775809; } root_type X; {}",
+ "does not fit");
+ TestError("table X { Y:int64= 9223372036854775808; } root_type X; {}",
+ "does not fit");
+ TestError("table X { Y:uint64; } root_type X; { Y: -1 }", "");
+ TestError("table X { Y:uint64=-9223372036854775809; } root_type X; {}",
+ "does not fit");
+ TestError("table X { Y:uint64= 18446744073709551616; } root_type X; {}",
+ "does not fit");
+}
+
+void IntegerBoundaryTest() {
+ // Check numerical compatibility with non-C++ languages.
+ // By the C++ standard, std::numerical_limits<int64_t>::min() == -9223372036854775807 (-2^63+1) or less*
+ // The Flatbuffers grammar and most of the languages (C#, Java, Rust) expect
+ // that minimum values are: -128, -32768,.., -9223372036854775808.
+ // Since C++20, static_cast<int64>(0x8000000000000000ULL) is well-defined two's complement cast.
+ // Therefore -9223372036854775808 should be valid negative value.
+ TEST_EQ(flatbuffers::numeric_limits<int8_t>::min(), -128);
+ TEST_EQ(flatbuffers::numeric_limits<int8_t>::max(), 127);
+ TEST_EQ(flatbuffers::numeric_limits<int16_t>::min(), -32768);
+ TEST_EQ(flatbuffers::numeric_limits<int16_t>::max(), 32767);
+ TEST_EQ(flatbuffers::numeric_limits<int32_t>::min() + 1, -2147483647);
+ TEST_EQ(flatbuffers::numeric_limits<int32_t>::max(), 2147483647ULL);
+ TEST_EQ(flatbuffers::numeric_limits<int64_t>::min() + 1LL,
+ -9223372036854775807LL);
+ TEST_EQ(flatbuffers::numeric_limits<int64_t>::max(), 9223372036854775807ULL);
+ TEST_EQ(flatbuffers::numeric_limits<uint8_t>::max(), 255);
+ TEST_EQ(flatbuffers::numeric_limits<uint16_t>::max(), 65535);
+ TEST_EQ(flatbuffers::numeric_limits<uint32_t>::max(), 4294967295ULL);
+ TEST_EQ(flatbuffers::numeric_limits<uint64_t>::max(),
+ 18446744073709551615ULL);
+
+ TEST_EQ(TestValue<int8_t>("{ Y:127 }", "byte"), 127);
+ TEST_EQ(TestValue<int8_t>("{ Y:-128 }", "byte"), -128);
+ TEST_EQ(TestValue<uint8_t>("{ Y:255 }", "ubyte"), 255);
+ TEST_EQ(TestValue<uint8_t>("{ Y:0 }", "ubyte"), 0);
+ TEST_EQ(TestValue<int16_t>("{ Y:32767 }", "short"), 32767);
+ TEST_EQ(TestValue<int16_t>("{ Y:-32768 }", "short"), -32768);
+ TEST_EQ(TestValue<uint16_t>("{ Y:65535 }", "ushort"), 65535);
+ TEST_EQ(TestValue<uint16_t>("{ Y:0 }", "ushort"), 0);
+ TEST_EQ(TestValue<int32_t>("{ Y:2147483647 }", "int"), 2147483647);
+ TEST_EQ(TestValue<int32_t>("{ Y:-2147483648 }", "int") + 1, -2147483647);
+ TEST_EQ(TestValue<uint32_t>("{ Y:4294967295 }", "uint"), 4294967295);
+ TEST_EQ(TestValue<uint32_t>("{ Y:0 }", "uint"), 0);
+ TEST_EQ(TestValue<int64_t>("{ Y:9223372036854775807 }", "long"),
+ 9223372036854775807LL);
+ TEST_EQ(TestValue<int64_t>("{ Y:-9223372036854775808 }", "long") + 1LL,
+ -9223372036854775807LL);
+ TEST_EQ(TestValue<uint64_t>("{ Y:18446744073709551615 }", "ulong"),
+ 18446744073709551615ULL);
+ TEST_EQ(TestValue<uint64_t>("{ Y:0 }", "ulong"), 0);
+ TEST_EQ(TestValue<uint64_t>("{ Y: 18446744073709551615 }", "uint64"),
+ 18446744073709551615ULL);
+ // check that the default works
+ TEST_EQ(TestValue<uint64_t>(nullptr, "uint64 = 18446744073709551615"),
+ 18446744073709551615ULL);
+}
+
+void ValidFloatTest() {
+ // check rounding to infinity
+ TEST_EQ(TestValue<float>("{ Y:+3.4029e+38 }", "float"), +infinityf);
+ TEST_EQ(TestValue<float>("{ Y:-3.4029e+38 }", "float"), -infinityf);
+ TEST_EQ(TestValue<double>("{ Y:+1.7977e+308 }", "double"), +infinityd);
+ TEST_EQ(TestValue<double>("{ Y:-1.7977e+308 }", "double"), -infinityd);
+
+ TEST_EQ(
+ FloatCompare(TestValue<float>("{ Y:0.0314159e+2 }", "float"), 3.14159f),
+ true);
+ // float in string
+ TEST_EQ(FloatCompare(TestValue<float>("{ Y:\" 0.0314159e+2 \" }", "float"),
+ 3.14159f),
+ true);
+
+ TEST_EQ(TestValue<float>("{ Y:1 }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:1.0 }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:1. }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:+1. }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:-1. }", "float"), -1.0f);
+ TEST_EQ(TestValue<float>("{ Y:1.e0 }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:1.e+0 }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:1.e-0 }", "float"), 1.0f);
+ TEST_EQ(TestValue<float>("{ Y:0.125 }", "float"), 0.125f);
+ TEST_EQ(TestValue<float>("{ Y:.125 }", "float"), 0.125f);
+ TEST_EQ(TestValue<float>("{ Y:-.125 }", "float"), -0.125f);
+ TEST_EQ(TestValue<float>("{ Y:+.125 }", "float"), +0.125f);
+ TEST_EQ(TestValue<float>("{ Y:5 }", "float"), 5.0f);
+ TEST_EQ(TestValue<float>("{ Y:\"5\" }", "float"), 5.0f);
+
+ #if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
+ // Old MSVC versions may have problem with this check.
+ // https://www.exploringbinary.com/visual-c-plus-plus-strtod-still-broken/
+ TEST_EQ(TestValue<double>("{ Y:6.9294956446009195e15 }", "double"),
+ 6929495644600920.0);
+ // check nan's
+ TEST_EQ(std::isnan(TestValue<double>("{ Y:nan }", "double")), true);
+ TEST_EQ(std::isnan(TestValue<float>("{ Y:nan }", "float")), true);
+ TEST_EQ(std::isnan(TestValue<float>("{ Y:\"nan\" }", "float")), true);
+ TEST_EQ(std::isnan(TestValue<float>("{ Y:+nan }", "float")), true);
+ TEST_EQ(std::isnan(TestValue<float>("{ Y:-nan }", "float")), true);
+ TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=nan")), true);
+ TEST_EQ(std::isnan(TestValue<float>(nullptr, "float=-nan")), true);
+ // check inf
+ TEST_EQ(TestValue<float>("{ Y:inf }", "float"), infinityf);
+ TEST_EQ(TestValue<float>("{ Y:\"inf\" }", "float"), infinityf);
+ TEST_EQ(TestValue<float>("{ Y:+inf }", "float"), infinityf);
+ TEST_EQ(TestValue<float>("{ Y:-inf }", "float"), -infinityf);
+ TEST_EQ(TestValue<float>(nullptr, "float=inf"), infinityf);
+ TEST_EQ(TestValue<float>(nullptr, "float=-inf"), -infinityf);
+ TestValue<double>(
+ "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
+ "3.0e2] }",
+ "[double]");
+ TestValue<float>(
+ "{ Y : [0.2, .2, 1.0, -1.0, -2., 2., 1e0, -1e0, 1.0e0, -1.0e0, -3.e2, "
+ "3.0e2] }",
+ "[float]");
+
+ // Test binary format of float point.
+ // https://en.cppreference.com/w/cpp/language/floating_literal
+ // 0x11.12p-1 = (1*16^1 + 2*16^0 + 3*16^-1 + 4*16^-2) * 2^-1 =
+ TEST_EQ(TestValue<double>("{ Y:0x12.34p-1 }", "double"), 9.1015625);
+ // hex fraction 1.2 (decimal 1.125) scaled by 2^3, that is 9.0
+ TEST_EQ(TestValue<float>("{ Y:-0x0.2p0 }", "float"), -0.125f);
+ TEST_EQ(TestValue<float>("{ Y:-0x.2p1 }", "float"), -0.25f);
+ TEST_EQ(TestValue<float>("{ Y:0x1.2p3 }", "float"), 9.0f);
+ TEST_EQ(TestValue<float>("{ Y:0x10.1p0 }", "float"), 16.0625f);
+ TEST_EQ(TestValue<double>("{ Y:0x1.2p3 }", "double"), 9.0);
+ TEST_EQ(TestValue<double>("{ Y:0x10.1p0 }", "double"), 16.0625);
+ TEST_EQ(TestValue<double>("{ Y:0xC.68p+2 }", "double"), 49.625);
+ TestValue<double>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[double]");
+ TestValue<float>("{ Y : [0x20.4ep1, +0x20.4ep1, -0x20.4ep1] }", "[float]");
+
+#else // FLATBUFFERS_HAS_NEW_STRTOD
+ TEST_OUTPUT_LINE("FLATBUFFERS_HAS_NEW_STRTOD tests skipped");
+#endif // !FLATBUFFERS_HAS_NEW_STRTOD
+}
+
+void InvalidFloatTest() {
+ auto invalid_msg = "invalid number";
+ auto comma_msg = "expecting: ,";
+ TestError("table T { F:float; } root_type T; { F:1,0 }", "");
+ TestError("table T { F:float; } root_type T; { F:. }", "");
+ TestError("table T { F:float; } root_type T; { F:- }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:+ }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:-. }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:+. }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:.e }", "");
+ TestError("table T { F:float; } root_type T; { F:-e }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:+e }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:-.e }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:+.e }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:-e1 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:+e1 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.0e+ }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.0e- }", invalid_msg);
+ // exponent pP is mandatory for hex-float
+ TestError("table T { F:float; } root_type T; { F:0x0 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:-0x. }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x. }", invalid_msg);
+ // eE not exponent in hex-float!
+ TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0p }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0p+ }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0p- }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0pa1 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0e+ }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0e- }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0e+0 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0e-0 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0ep+ }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:0x0.0ep- }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.2.3 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.2.e3 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.2e.3 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.2e0.3 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.2e3. }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.2e3.0 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:+-1.0 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.0e+-1 }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:\"1.0e+-1\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:1.e0e }", comma_msg);
+ TestError("table T { F:float; } root_type T; { F:0x1.p0e }", comma_msg);
+ TestError("table T { F:float; } root_type T; { F:\" 0x10 \" }", invalid_msg);
+ // floats in string
+ TestError("table T { F:float; } root_type T; { F:\"1,2.\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:\"1.2e3.\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:\"0x1.p0e\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:\"0x1.0\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:\" 0x1.0\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:\"+ 0\" }", invalid_msg);
+ // disable escapes for "number-in-string"
+ TestError("table T { F:float; } root_type T; { F:\"\\f1.2e3.\" }", "invalid");
+ TestError("table T { F:float; } root_type T; { F:\"\\t1.2e3.\" }", "invalid");
+ TestError("table T { F:float; } root_type T; { F:\"\\n1.2e3.\" }", "invalid");
+ TestError("table T { F:float; } root_type T; { F:\"\\r1.2e3.\" }", "invalid");
+ TestError("table T { F:float; } root_type T; { F:\"4\\x005\" }", "invalid");
+ TestError("table T { F:float; } root_type T; { F:\"\'12\'\" }", invalid_msg);
+ // null is not a number constant!
+ TestError("table T { F:float; } root_type T; { F:\"null\" }", invalid_msg);
+ TestError("table T { F:float; } root_type T; { F:null }", invalid_msg);
+}
+
+void GenerateTableTextTest() {
+ std::string schemafile;
+ std::string jsonfile;
+ bool ok =
+ flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
+ false, &schemafile) &&
+ flatbuffers::LoadFile((test_data_path + "monsterdata_test.json").c_str(),
+ false, &jsonfile);
+ TEST_EQ(ok, true);
+ auto include_test_path =
+ flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = {test_data_path.c_str(),
+ include_test_path.c_str(), nullptr};
+ flatbuffers::IDLOptions opt;
+ opt.indent_step = -1;
+ flatbuffers::Parser parser(opt);
+ ok = parser.Parse(schemafile.c_str(), include_directories) &&
+ parser.Parse(jsonfile.c_str(), include_directories);
+ TEST_EQ(ok, true);
+ // Test root table
+ const Monster *monster = GetMonster(parser.builder_.GetBufferPointer());
+ std::string jsongen;
+ auto result = GenerateTextFromTable(parser, monster, "MyGame.Example.Monster",
+ &jsongen);
+ TEST_EQ(result, true);
+ // Test sub table
+ const Vec3 *pos = monster->pos();
+ jsongen.clear();
+ result = GenerateTextFromTable(parser, pos, "MyGame.Example.Vec3", &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(
+ jsongen.c_str(),
+ "{x: 1.0,y: 2.0,z: 3.0,test1: 3.0,test2: \"Green\",test3: {a: 5,b: 6}}");
+ const Test &test3 = pos->test3();
+ jsongen.clear();
+ result =
+ GenerateTextFromTable(parser, &test3, "MyGame.Example.Test", &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(jsongen.c_str(), "{a: 5,b: 6}");
+ const Test *test4 = monster->test4()->Get(0);
+ jsongen.clear();
+ result =
+ GenerateTextFromTable(parser, test4, "MyGame.Example.Test", &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(jsongen.c_str(), "{a: 10,b: 20}");
+}
+
+template<typename T>
+void NumericUtilsTestInteger(const char *lower, const char *upper) {
+ T x;
+ TEST_EQ(flatbuffers::StringToNumber("1q", &x), false);
+ TEST_EQ(x, 0);
+ TEST_EQ(flatbuffers::StringToNumber(upper, &x), false);
+ TEST_EQ(x, flatbuffers::numeric_limits<T>::max());
+ TEST_EQ(flatbuffers::StringToNumber(lower, &x), false);
+ auto expval = flatbuffers::is_unsigned<T>::value
+ ? flatbuffers::numeric_limits<T>::max()
+ : flatbuffers::numeric_limits<T>::lowest();
+ TEST_EQ(x, expval);
+}
+
+template<typename T>
+void NumericUtilsTestFloat(const char *lower, const char *upper) {
+ T f;
+ TEST_EQ(flatbuffers::StringToNumber("", &f), false);
+ TEST_EQ(flatbuffers::StringToNumber("1q", &f), false);
+ TEST_EQ(f, 0);
+ TEST_EQ(flatbuffers::StringToNumber(upper, &f), true);
+ TEST_EQ(f, +flatbuffers::numeric_limits<T>::infinity());
+ TEST_EQ(flatbuffers::StringToNumber(lower, &f), true);
+ TEST_EQ(f, -flatbuffers::numeric_limits<T>::infinity());
+}
+
+void NumericUtilsTest() {
+ NumericUtilsTestInteger<uint64_t>("-1", "18446744073709551616");
+ NumericUtilsTestInteger<uint8_t>("-1", "256");
+ NumericUtilsTestInteger<int64_t>("-9223372036854775809",
+ "9223372036854775808");
+ NumericUtilsTestInteger<int8_t>("-129", "128");
+ NumericUtilsTestFloat<float>("-3.4029e+38", "+3.4029e+38");
+ NumericUtilsTestFloat<float>("-1.7977e+308", "+1.7977e+308");
+}
+
+void IsAsciiUtilsTest() {
+ char c = -128;
+ for (int cnt = 0; cnt < 256; cnt++) {
+ auto alpha = (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
+ auto dec = (('0' <= c) && (c <= '9'));
+ auto hex = (('a' <= c) && (c <= 'f')) || (('A' <= c) && (c <= 'F'));
+ TEST_EQ(flatbuffers::is_alpha(c), alpha);
+ TEST_EQ(flatbuffers::is_alnum(c), alpha || dec);
+ TEST_EQ(flatbuffers::is_digit(c), dec);
+ TEST_EQ(flatbuffers::is_xdigit(c), dec || hex);
+ c += 1;
+ }
+}
+
+void UnicodeTest() {
+ flatbuffers::Parser parser;
+ // Without setting allow_non_utf8 = true, we treat \x sequences as byte
+ // sequences which are then validated as UTF-8.
+ TEST_EQ(parser.Parse("table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
+ "\\u5225\\u30B5\\u30A4\\u30C8\\xE2\\x82\\xAC\\u0080\\uD8"
+ "3D\\uDE0E\" }"),
+ true);
+ std::string jsongen;
+ parser.opts.indent_step = -1;
+ auto result =
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(jsongen.c_str(),
+ "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
+ "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
+}
+
+void UnicodeTestAllowNonUTF8() {
+ flatbuffers::Parser parser;
+ parser.opts.allow_non_utf8 = true;
+ TEST_EQ(
+ parser.Parse(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
+ "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
+ true);
+ std::string jsongen;
+ parser.opts.indent_step = -1;
+ auto result =
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(
+ jsongen.c_str(),
+ "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
+ "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
+}
+
+void UnicodeTestGenerateTextFailsOnNonUTF8() {
+ flatbuffers::Parser parser;
+ // Allow non-UTF-8 initially to model what happens when we load a binary
+ // flatbuffer from disk which contains non-UTF-8 strings.
+ parser.opts.allow_non_utf8 = true;
+ TEST_EQ(
+ parser.Parse(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
+ "\\u5225\\u30B5\\u30A4\\u30C8\\x01\\x80\\u0080\\uD83D\\uDE0E\" }"),
+ true);
+ std::string jsongen;
+ parser.opts.indent_step = -1;
+ // Now, disallow non-UTF-8 (the default behavior) so GenerateText indicates
+ // failure.
+ parser.opts.allow_non_utf8 = false;
+ auto result =
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, false);
+}
+
+void UnicodeSurrogatesTest() {
+ flatbuffers::Parser parser;
+
+ TEST_EQ(parser.Parse("table T { F:string (id: 0); }"
+ "root_type T;"
+ "{ F:\"\\uD83D\\uDCA9\"}"),
+ true);
+ auto root = flatbuffers::GetRoot<flatbuffers::Table>(
+ parser.builder_.GetBufferPointer());
+ auto string = root->GetPointer<flatbuffers::String *>(
+ flatbuffers::FieldIndexToOffset(0));
+ TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
+}
+
+void UnicodeInvalidSurrogatesTest() {
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\uD800\"}",
+ "unpaired high surrogate");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\uD800abcd\"}",
+ "unpaired high surrogate");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\uD800\\n\"}",
+ "unpaired high surrogate");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\uD800\\uD800\"}",
+ "multiple high surrogates");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\\uDC00\"}",
+ "unpaired low surrogate");
+}
+
+void InvalidUTF8Test() {
+ // "1 byte" pattern, under min length of 2 bytes
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\x80\"}",
+ "illegal UTF-8 sequence");
+ // 2 byte pattern, string too short
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xDF\"}",
+ "illegal UTF-8 sequence");
+ // 3 byte pattern, string too short
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xEF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // 4 byte pattern, string too short
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xF7\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // "5 byte" pattern, string too short
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xFB\xBF\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // "6 byte" pattern, string too short
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xFD\xBF\xBF\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // "7 byte" pattern, string too short
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // "5 byte" pattern, over max length of 4 bytes
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xFB\xBF\xBF\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // "6 byte" pattern, over max length of 4 bytes
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xFD\xBF\xBF\xBF\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+ // "7 byte" pattern, over max length of 4 bytes
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xFE\xBF\xBF\xBF\xBF\xBF\xBF\"}",
+ "illegal UTF-8 sequence");
+
+ // Three invalid encodings for U+000A (\n, aka NEWLINE)
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xC0\x8A\"}",
+ "illegal UTF-8 sequence");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xE0\x80\x8A\"}",
+ "illegal UTF-8 sequence");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xF0\x80\x80\x8A\"}",
+ "illegal UTF-8 sequence");
+
+ // Two invalid encodings for U+00A9 (COPYRIGHT SYMBOL)
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xE0\x81\xA9\"}",
+ "illegal UTF-8 sequence");
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xF0\x80\x81\xA9\"}",
+ "illegal UTF-8 sequence");
+
+ // Invalid encoding for U+20AC (EURO SYMBOL)
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ "{ F:\"\xF0\x82\x82\xAC\"}",
+ "illegal UTF-8 sequence");
+
+ // UTF-16 surrogate values between U+D800 and U+DFFF cannot be encoded in
+ // UTF-8
+ TestError(
+ "table T { F:string; }"
+ "root_type T;"
+ // U+10400 "encoded" as U+D801 U+DC00
+ "{ F:\"\xED\xA0\x81\xED\xB0\x80\"}",
+ "illegal UTF-8 sequence");
+
+ // Check independence of identifier from locale.
+ std::string locale_ident;
+ locale_ident += "table T { F";
+ locale_ident += static_cast<char>(-32); // unsigned 0xE0
+ locale_ident += " :string; }";
+ locale_ident += "root_type T;";
+ locale_ident += "{}";
+ TestError(locale_ident.c_str(), "");
+}
+
+void UnknownFieldsTest() {
+ flatbuffers::IDLOptions opts;
+ opts.skip_unexpected_fields_in_json = true;
+ flatbuffers::Parser parser(opts);
+
+ TEST_EQ(parser.Parse("table T { str:string; i:int;}"
+ "root_type T;"
+ "{ str:\"test\","
+ "unknown_string:\"test\","
+ "\"unknown_string\":\"test\","
+ "unknown_int:10,"
+ "unknown_float:1.0,"
+ "unknown_array: [ 1, 2, 3, 4],"
+ "unknown_object: { i: 10 },"
+ "\"unknown_object\": { \"i\": 10 },"
+ "i:10}"),
+ true);
+
+ std::string jsongen;
+ parser.opts.indent_step = -1;
+ auto result =
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
+ TEST_EQ(result, true);
+ TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
+}
+
+void ParseUnionTest() {
+ // Unions must be parseable with the type field following the object.
+ flatbuffers::Parser parser;
+ TEST_EQ(parser.Parse("table T { A:int; }"
+ "union U { T }"
+ "table V { X:U; }"
+ "root_type V;"
+ "{ X:{ A:1 }, X_type: T }"),
+ true);
+ // Unions must be parsable with prefixed namespace.
+ flatbuffers::Parser parser2;
+ TEST_EQ(parser2.Parse("namespace N; table A {} namespace; union U { N.A }"
+ "table B { e:U; } root_type B;"
+ "{ e_type: N_A, e: {} }"),
+ true);
+}
+
+void InvalidNestedFlatbufferTest() {
+ // First, load and parse FlatBuffer schema (.fbs)
+ std::string schemafile;
+ TEST_EQ(flatbuffers::LoadFile((test_data_path + "monster_test.fbs").c_str(),
+ false, &schemafile),
+ true);
+ auto include_test_path =
+ flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = { test_data_path.c_str(),
+ include_test_path.c_str(), nullptr };
+ flatbuffers::Parser parser1;
+ TEST_EQ(parser1.Parse(schemafile.c_str(), include_directories), true);
+
+ // "color" inside nested flatbuffer contains invalid enum value
+ TEST_EQ(parser1.Parse("{ name: \"Bender\", testnestedflatbuffer: { name: "
+ "\"Leela\", color: \"nonexistent\"}}"),
+ false);
+ // Check that Parser is destroyed correctly after parsing invalid json
+}
+
+void UnionVectorTest() {
+ // load FlatBuffer fbs schema and json.
+ std::string schemafile, jsonfile;
+ TEST_EQ(flatbuffers::LoadFile(
+ (test_data_path + "union_vector/union_vector.fbs").c_str(),
+ false, &schemafile),
+ true);
+ TEST_EQ(flatbuffers::LoadFile(
+ (test_data_path + "union_vector/union_vector.json").c_str(),
+ false, &jsonfile),
+ true);
+
+ // parse schema.
+ flatbuffers::IDLOptions idl_opts;
+ idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kBinary;
+ flatbuffers::Parser parser(idl_opts);
+ TEST_EQ(parser.Parse(schemafile.c_str()), true);
+
+ flatbuffers::FlatBufferBuilder fbb;
+
+ // union types.
+ std::vector<uint8_t> types;
+ types.push_back(static_cast<uint8_t>(Character_Belle));
+ types.push_back(static_cast<uint8_t>(Character_MuLan));
+ types.push_back(static_cast<uint8_t>(Character_BookFan));
+ types.push_back(static_cast<uint8_t>(Character_Other));
+ types.push_back(static_cast<uint8_t>(Character_Unused));
+
+ // union values.
+ std::vector<flatbuffers::Offset<void>> characters;
+ characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
+ characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
+ characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
+ characters.push_back(fbb.CreateString("Other").Union());
+ characters.push_back(fbb.CreateString("Unused").Union());
+
+ // create Movie.
+ const auto movie_offset =
+ CreateMovie(fbb, Character_Rapunzel,
+ fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
+ fbb.CreateVector(types), fbb.CreateVector(characters));
+ FinishMovieBuffer(fbb, movie_offset);
+ auto buf = fbb.GetBufferPointer();
+
+ flatbuffers::Verifier verifier(buf, fbb.GetSize());
+ TEST_EQ(VerifyMovieBuffer(verifier), true);
+
+ auto flat_movie = GetMovie(buf);
+
+ auto TestMovie = [](const Movie *movie) {
+ TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
+
+ auto cts = movie->characters_type();
+ TEST_EQ(movie->characters_type()->size(), 5);
+ TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
+ TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
+ TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
+ TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
+ TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
+
+ auto rapunzel = movie->main_character_as_Rapunzel();
+ TEST_NOTNULL(rapunzel);
+ TEST_EQ(rapunzel->hair_length(), 6);
+
+ auto cs = movie->characters();
+ TEST_EQ(cs->size(), 5);
+ auto belle = cs->GetAs<BookReader>(0);
+ TEST_EQ(belle->books_read(), 7);
+ auto mu_lan = cs->GetAs<Attacker>(1);
+ TEST_EQ(mu_lan->sword_attack_damage(), 5);
+ auto book_fan = cs->GetAs<BookReader>(2);
+ TEST_EQ(book_fan->books_read(), 2);
+ auto other = cs->GetAsString(3);
+ TEST_EQ_STR(other->c_str(), "Other");
+ auto unused = cs->GetAsString(4);
+ TEST_EQ_STR(unused->c_str(), "Unused");
+ };
+
+ TestMovie(flat_movie);
+
+ // Also test the JSON we loaded above.
+ TEST_EQ(parser.Parse(jsonfile.c_str()), true);
+ auto jbuf = parser.builder_.GetBufferPointer();
+ flatbuffers::Verifier jverifier(jbuf, parser.builder_.GetSize());
+ TEST_EQ(VerifyMovieBuffer(jverifier), true);
+ TestMovie(GetMovie(jbuf));
+
+ auto movie_object = flat_movie->UnPack();
+ TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
+ TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
+ TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
+ TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
+ TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
+ TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
+
+ fbb.Clear();
+ fbb.Finish(Movie::Pack(fbb, movie_object));
+
+ delete movie_object;
+
+ auto repacked_movie = GetMovie(fbb.GetBufferPointer());
+
+ TestMovie(repacked_movie);
+
+ auto s =
+ flatbuffers::FlatBufferToString(fbb.GetBufferPointer(), MovieTypeTable());
+ TEST_EQ_STR(
+ s.c_str(),
+ "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
+ "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
+ "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
+ "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
+
+
+ flatbuffers::ToStringVisitor visitor("\n", true, " ");
+ IterateFlatBuffer(fbb.GetBufferPointer(), MovieTypeTable(), &visitor);
+ TEST_EQ_STR(
+ visitor.s.c_str(),
+ "{\n"
+ " \"main_character_type\": \"Rapunzel\",\n"
+ " \"main_character\": {\n"
+ " \"hair_length\": 6\n"
+ " },\n"
+ " \"characters_type\": [\n"
+ " \"Belle\",\n"
+ " \"MuLan\",\n"
+ " \"BookFan\",\n"
+ " \"Other\",\n"
+ " \"Unused\"\n"
+ " ],\n"
+ " \"characters\": [\n"
+ " {\n"
+ " \"books_read\": 7\n"
+ " },\n"
+ " {\n"
+ " \"sword_attack_damage\": 5\n"
+ " },\n"
+ " {\n"
+ " \"books_read\": 2\n"
+ " },\n"
+ " \"Other\",\n"
+ " \"Unused\"\n"
+ " ]\n"
+ "}");
+
+ flatbuffers::Parser parser2(idl_opts);
+ TEST_EQ(parser2.Parse("struct Bool { b:bool; }"
+ "union Any { Bool }"
+ "table Root { a:Any; }"
+ "root_type Root;"), true);
+ TEST_EQ(parser2.Parse("{a_type:Bool,a:{b:true}}"), true);
+}
+
+void ConformTest() {
+ flatbuffers::Parser parser;
+ TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
+
+ auto test_conform = [](flatbuffers::Parser &parser1, const char *test,
+ const char *expected_err) {
+ flatbuffers::Parser parser2;
+ TEST_EQ(parser2.Parse(test), true);
+ auto err = parser2.ConformTo(parser1);
+ TEST_NOTNULL(strstr(err.c_str(), expected_err));
+ };
+
+ test_conform(parser, "table T { A:byte; }", "types differ for field");
+ test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
+ test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
+ test_conform(parser, "table T { B:float; }",
+ "field renamed to different type");
+ test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
+}
+
+void ParseProtoBufAsciiTest() {
+ // We can put the parser in a mode where it will accept JSON that looks more
+ // like Protobuf ASCII, for users that have data in that format.
+ // This uses no "" for field names (which we already support by default,
+ // omits `,`, `:` before `{` and a couple of other features.
+ flatbuffers::Parser parser;
+ parser.opts.protobuf_ascii_alike = true;
+ TEST_EQ(
+ parser.Parse("table S { B:int; } table T { A:[int]; C:S; } root_type T;"),
+ true);
+ TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
+ // Similarly, in text output, it should omit these.
+ std::string text;
+ auto ok = flatbuffers::GenerateText(
+ parser, parser.builder_.GetBufferPointer(), &text);
+ TEST_EQ(ok, true);
+ TEST_EQ_STR(text.c_str(),
+ "{\n A [\n 1\n 2\n ]\n C {\n B: 2\n }\n}\n");
+}
+
+void FlexBuffersTest() {
+ flexbuffers::Builder slb(512,
+ flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
+
+ // Write the equivalent of:
+ // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ],
+ // foo: 100, bool: true, mymap: { foo: "Fred" } }
+ // clang-format off
+ #ifndef FLATBUFFERS_CPP98_STL
+ // It's possible to do this without std::function support as well.
+ slb.Map([&]() {
+ slb.Vector("vec", [&]() {
+ slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
+ slb += "Fred";
+ slb.IndirectFloat(4.0f);
+ uint8_t blob[] = { 77 };
+ slb.Blob(blob, 1);
+ slb += false;
+ });
+ int ints[] = { 1, 2, 3 };
+ slb.Vector("bar", ints, 3);
+ slb.FixedTypedVector("bar3", ints, 3);
+ bool bools[] = {true, false, true, false};
+ slb.Vector("bools", bools, 4);
+ slb.Bool("bool", true);
+ slb.Double("foo", 100);
+ slb.Map("mymap", [&]() {
+ slb.String("foo", "Fred"); // Testing key and string reuse.
+ });
+ });
+ slb.Finish();
+ #else
+ // It's possible to do this without std::function support as well.
+ slb.Map([](flexbuffers::Builder& slb2) {
+ slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
+ slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
+ slb3 += "Fred";
+ slb3.IndirectFloat(4.0f);
+ uint8_t blob[] = { 77 };
+ slb3.Blob(blob, 1);
+ slb3 += false;
+ }, slb2);
+ int ints[] = { 1, 2, 3 };
+ slb2.Vector("bar", ints, 3);
+ slb2.FixedTypedVector("bar3", ints, 3);
+ slb2.Bool("bool", true);
+ slb2.Double("foo", 100);
+ slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
+ slb3.String("foo", "Fred"); // Testing key and string reuse.
+ }, slb2);
+ }, slb);
+ slb.Finish();
+ #endif // FLATBUFFERS_CPP98_STL
+
+ #ifdef FLATBUFFERS_TEST_VERBOSE
+ for (size_t i = 0; i < slb.GetBuffer().size(); i++)
+ printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
+ printf("\n");
+ #endif
+ // clang-format on
+
+ auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
+ TEST_EQ(map.size(), 7);
+ auto vec = map["vec"].AsVector();
+ TEST_EQ(vec.size(), 5);
+ TEST_EQ(vec[0].AsInt64(), -100);
+ TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
+ TEST_EQ(vec[1].AsInt64(), 0); // Number parsing failed.
+ TEST_EQ(vec[2].AsDouble(), 4.0);
+ TEST_EQ(vec[2].AsString().IsTheEmptyString(), true); // Wrong Type.
+ TEST_EQ_STR(vec[2].AsString().c_str(), ""); // This still works though.
+ TEST_EQ_STR(vec[2].ToString().c_str(), "4.0"); // Or have it converted.
+
+ // Few tests for templated version of As.
+ TEST_EQ(vec[0].As<int64_t>(), -100);
+ TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
+ TEST_EQ(vec[1].As<int64_t>(), 0); // Number parsing failed.
+ TEST_EQ(vec[2].As<double>(), 4.0);
+
+ // Test that the blob can be accessed.
+ TEST_EQ(vec[3].IsBlob(), true);
+ auto blob = vec[3].AsBlob();
+ TEST_EQ(blob.size(), 1);
+ TEST_EQ(blob.data()[0], 77);
+ TEST_EQ(vec[4].IsBool(), true); // Check if type is a bool
+ TEST_EQ(vec[4].AsBool(), false); // Check if value is false
+ auto tvec = map["bar"].AsTypedVector();
+ TEST_EQ(tvec.size(), 3);
+ TEST_EQ(tvec[2].AsInt8(), 3);
+ auto tvec3 = map["bar3"].AsFixedTypedVector();
+ TEST_EQ(tvec3.size(), 3);
+ TEST_EQ(tvec3[2].AsInt8(), 3);
+ TEST_EQ(map["bool"].AsBool(), true);
+ auto tvecb = map["bools"].AsTypedVector();
+ TEST_EQ(tvecb.ElementType(), flexbuffers::FBT_BOOL);
+ TEST_EQ(map["foo"].AsUInt8(), 100);
+ TEST_EQ(map["unknown"].IsNull(), true);
+ auto mymap = map["mymap"].AsMap();
+ // These should be equal by pointer equality, since key and value are shared.
+ TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
+ TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
+ // We can mutate values in the buffer.
+ TEST_EQ(vec[0].MutateInt(-99), true);
+ TEST_EQ(vec[0].AsInt64(), -99);
+ TEST_EQ(vec[1].MutateString("John"), true); // Size must match.
+ TEST_EQ_STR(vec[1].AsString().c_str(), "John");
+ TEST_EQ(vec[1].MutateString("Alfred"), false); // Too long.
+ TEST_EQ(vec[2].MutateFloat(2.0f), true);
+ TEST_EQ(vec[2].AsFloat(), 2.0f);
+ TEST_EQ(vec[2].MutateFloat(3.14159), false); // Double does not fit in float.
+ TEST_EQ(vec[4].AsBool(), false); // Is false before change
+ TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
+ TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
+
+ // Parse from JSON:
+ flatbuffers::Parser parser;
+ slb.Clear();
+ auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
+ TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true);
+ auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
+ auto jmap = jroot.AsMap();
+ auto jvec = jmap["a"].AsVector();
+ TEST_EQ(jvec[0].AsInt64(), 123);
+ TEST_EQ(jvec[1].AsDouble(), 456.0);
+ TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
+ TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
+ TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
+ TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
+ TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
+ // And from FlexBuffer back to JSON:
+ auto jsonback = jroot.ToString();
+ TEST_EQ_STR(jsontest, jsonback.c_str());
+}
+
+void TypeAliasesTest() {
+ flatbuffers::FlatBufferBuilder builder;
+
+ builder.Finish(CreateTypeAliases(
+ builder, flatbuffers::numeric_limits<int8_t>::min(),
+ flatbuffers::numeric_limits<uint8_t>::max(),
+ flatbuffers::numeric_limits<int16_t>::min(),
+ flatbuffers::numeric_limits<uint16_t>::max(),
+ flatbuffers::numeric_limits<int32_t>::min(),
+ flatbuffers::numeric_limits<uint32_t>::max(),
+ flatbuffers::numeric_limits<int64_t>::min(),
+ flatbuffers::numeric_limits<uint64_t>::max(), 2.3f, 2.3));
+
+ auto p = builder.GetBufferPointer();
+ auto ta = flatbuffers::GetRoot<TypeAliases>(p);
+
+ TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
+ TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
+ TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
+ TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
+ TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
+ TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
+ TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
+ TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
+ TEST_EQ(ta->f32(), 2.3f);
+ TEST_EQ(ta->f64(), 2.3);
+ using namespace flatbuffers; // is_same
+ static_assert(is_same<decltype(ta->i8()), int8_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->i16()), int16_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->i32()), int32_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->i64()), int64_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->u8()), uint8_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->u16()), uint16_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->u32()), uint32_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->u64()), uint64_t>::value, "invalid type");
+ static_assert(is_same<decltype(ta->f32()), float>::value, "invalid type");
+ static_assert(is_same<decltype(ta->f64()), double>::value, "invalid type");
+}
+
+void EndianSwapTest() {
+ TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)), 0x3412);
+ TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
+ 0x78563412);
+ TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
+ 0xEFCDAB9078563412);
+ TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
+}
+
+void UninitializedVectorTest() {
+ flatbuffers::FlatBufferBuilder builder;
+
+ Test *buf = nullptr;
+ auto vector_offset = builder.CreateUninitializedVectorOfStructs<Test>(2, &buf);
+ TEST_NOTNULL(buf);
+ buf[0] = Test(10, 20);
+ buf[1] = Test(30, 40);
+
+ auto required_name = builder.CreateString("myMonster");
+ auto monster_builder = MonsterBuilder(builder);
+ monster_builder.add_name(required_name); // required field mandated for monster.
+ monster_builder.add_test4(vector_offset);
+ builder.Finish(monster_builder.Finish());
+
+ auto p = builder.GetBufferPointer();
+ auto uvt = flatbuffers::GetRoot<Monster>(p);
+ TEST_NOTNULL(uvt);
+ auto vec = uvt->test4();
+ TEST_NOTNULL(vec);
+ auto test_0 = vec->Get(0);
+ auto test_1 = vec->Get(1);
+ TEST_EQ(test_0->a(), 10);
+ TEST_EQ(test_0->b(), 20);
+ TEST_EQ(test_1->a(), 30);
+ TEST_EQ(test_1->b(), 40);
+}
+
+void EqualOperatorTest() {
+ MonsterT a;
+ MonsterT b;
+ TEST_EQ(b == a, true);
+ TEST_EQ(b != a, false);
+
+ b.mana = 33;
+ TEST_EQ(b == a, false);
+ TEST_EQ(b != a, true);
+ b.mana = 150;
+ TEST_EQ(b == a, true);
+ TEST_EQ(b != a, false);
+
+ b.inventory.push_back(3);
+ TEST_EQ(b == a, false);
+ TEST_EQ(b != a, true);
+ b.inventory.clear();
+ TEST_EQ(b == a, true);
+ TEST_EQ(b != a, false);
+
+ b.test.type = Any_Monster;
+ TEST_EQ(b == a, false);
+ TEST_EQ(b != a, true);
+}
+
+// For testing any binaries, e.g. from fuzzing.
+void LoadVerifyBinaryTest() {
+ std::string binary;
+ if (flatbuffers::LoadFile((test_data_path +
+ "fuzzer/your-filename-here").c_str(),
+ true, &binary)) {
+ flatbuffers::Verifier verifier(
+ reinterpret_cast<const uint8_t *>(binary.data()), binary.size());
+ TEST_EQ(VerifyMonsterBuffer(verifier), true);
+ }
+}
+
+void CreateSharedStringTest() {
+ flatbuffers::FlatBufferBuilder builder;
+ const auto one1 = builder.CreateSharedString("one");
+ const auto two = builder.CreateSharedString("two");
+ const auto one2 = builder.CreateSharedString("one");
+ TEST_EQ(one1.o, one2.o);
+ const auto onetwo = builder.CreateSharedString("onetwo");
+ TEST_EQ(onetwo.o != one1.o, true);
+ TEST_EQ(onetwo.o != two.o, true);
+
+ // Support for embedded nulls
+ const char chars_b[] = {'a', '\0', 'b'};
+ const char chars_c[] = {'a', '\0', 'c'};
+ const auto null_b1 = builder.CreateSharedString(chars_b, sizeof(chars_b));
+ const auto null_c = builder.CreateSharedString(chars_c, sizeof(chars_c));
+ const auto null_b2 = builder.CreateSharedString(chars_b, sizeof(chars_b));
+ TEST_EQ(null_b1.o != null_c.o, true); // Issue#5058 repro
+ TEST_EQ(null_b1.o, null_b2.o);
+
+ // Put the strings into an array for round trip verification.
+ const flatbuffers::Offset<flatbuffers::String> array[7] = { one1, two, one2, onetwo, null_b1, null_c, null_b2 };
+ const auto vector_offset = builder.CreateVector(array, flatbuffers::uoffset_t(7));
+ MonsterBuilder monster_builder(builder);
+ monster_builder.add_name(two);
+ monster_builder.add_testarrayofstring(vector_offset);
+ builder.Finish(monster_builder.Finish());
+
+ // Read the Monster back.
+ const auto *monster = flatbuffers::GetRoot<Monster>(builder.GetBufferPointer());
+ TEST_EQ_STR(monster->name()->c_str(), "two");
+ const auto *testarrayofstring = monster->testarrayofstring();
+ TEST_EQ(testarrayofstring->size(), flatbuffers::uoffset_t(7));
+ const auto &a = *testarrayofstring;
+ TEST_EQ_STR(a[0]->c_str(), "one");
+ TEST_EQ_STR(a[1]->c_str(), "two");
+ TEST_EQ_STR(a[2]->c_str(), "one");
+ TEST_EQ_STR(a[3]->c_str(), "onetwo");
+ TEST_EQ(a[4]->str(), (std::string(chars_b, sizeof(chars_b))));
+ TEST_EQ(a[5]->str(), (std::string(chars_c, sizeof(chars_c))));
+ TEST_EQ(a[6]->str(), (std::string(chars_b, sizeof(chars_b))));
+
+ // Make sure String::operator< works, too, since it is related to StringOffsetCompare.
+ TEST_EQ((*a[0]) < (*a[1]), true);
+ TEST_EQ((*a[1]) < (*a[0]), false);
+ TEST_EQ((*a[1]) < (*a[2]), false);
+ TEST_EQ((*a[2]) < (*a[1]), true);
+ TEST_EQ((*a[4]) < (*a[3]), true);
+ TEST_EQ((*a[5]) < (*a[4]), false);
+ TEST_EQ((*a[5]) < (*a[4]), false);
+ TEST_EQ((*a[6]) < (*a[5]), true);
+}
+
+void FixedLengthArrayTest() {
+ // VS10 does not support typed enums, exclude from tests
+#if !defined(_MSC_VER) || _MSC_VER >= 1700
+ // Generate an ArrayTable containing one ArrayStruct.
+ flatbuffers::FlatBufferBuilder fbb;
+ MyGame::Example::NestedStruct nStruct0(MyGame::Example::TestEnum::B);
+ TEST_NOTNULL(nStruct0.mutable_a());
+ nStruct0.mutable_a()->Mutate(0, 1);
+ nStruct0.mutable_a()->Mutate(1, 2);
+ TEST_NOTNULL(nStruct0.mutable_c());
+ nStruct0.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
+ nStruct0.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
+ MyGame::Example::NestedStruct nStruct1(MyGame::Example::TestEnum::C);
+ TEST_NOTNULL(nStruct1.mutable_a());
+ nStruct1.mutable_a()->Mutate(0, 3);
+ nStruct1.mutable_a()->Mutate(1, 4);
+ TEST_NOTNULL(nStruct1.mutable_c());
+ nStruct1.mutable_c()->Mutate(0, MyGame::Example::TestEnum::C);
+ nStruct1.mutable_c()->Mutate(1, MyGame::Example::TestEnum::A);
+ MyGame::Example::ArrayStruct aStruct(2, 12);
+ TEST_NOTNULL(aStruct.b());
+ TEST_NOTNULL(aStruct.mutable_b());
+ TEST_NOTNULL(aStruct.mutable_d());
+ for (int i = 0; i < aStruct.b()->size(); i++)
+ aStruct.mutable_b()->Mutate(i, i + 1);
+ aStruct.mutable_d()->Mutate(0, nStruct0);
+ aStruct.mutable_d()->Mutate(1, nStruct1);
+ auto aTable = MyGame::Example::CreateArrayTable(fbb, &aStruct);
+ fbb.Finish(aTable);
+
+ // Verify correctness of the ArrayTable.
+ flatbuffers::Verifier verifier(fbb.GetBufferPointer(), fbb.GetSize());
+ MyGame::Example::VerifyArrayTableBuffer(verifier);
+ auto p = MyGame::Example::GetMutableArrayTable(fbb.GetBufferPointer());
+ auto mArStruct = p->mutable_a();
+ TEST_NOTNULL(mArStruct);
+ TEST_NOTNULL(mArStruct->b());
+ TEST_NOTNULL(mArStruct->d());
+ TEST_NOTNULL(mArStruct->mutable_b());
+ TEST_NOTNULL(mArStruct->mutable_d());
+ mArStruct->mutable_b()->Mutate(14, -14);
+ TEST_EQ(mArStruct->a(), 2);
+ TEST_EQ(mArStruct->b()->size(), 15);
+ TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14);
+ TEST_EQ(mArStruct->c(), 12);
+ TEST_NOTNULL(mArStruct->d()->Get(0).a());
+ TEST_EQ(mArStruct->d()->Get(0).a()->Get(0), 1);
+ TEST_EQ(mArStruct->d()->Get(0).a()->Get(1), 2);
+ TEST_NOTNULL(mArStruct->d()->Get(1).a());
+ TEST_EQ(mArStruct->d()->Get(1).a()->Get(0), 3);
+ TEST_EQ(mArStruct->d()->Get(1).a()->Get(1), 4);
+ TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1));
+ TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a());
+ mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5);
+ TEST_EQ(mArStruct->d()->Get(1).a()->Get(1), 5);
+ TEST_EQ(mArStruct->d()->Get(0).b() == MyGame::Example::TestEnum::B, true);
+ TEST_NOTNULL(mArStruct->d()->Get(0).c());
+ TEST_EQ(mArStruct->d()->Get(0).c()->Get(0) == MyGame::Example::TestEnum::C,
+ true);
+ TEST_EQ(mArStruct->d()->Get(0).c()->Get(1) == MyGame::Example::TestEnum::A,
+ true);
+ TEST_EQ(mArStruct->d()->Get(1).b() == MyGame::Example::TestEnum::C, true);
+ TEST_NOTNULL(mArStruct->d()->Get(1).c());
+ TEST_EQ(mArStruct->d()->Get(1).c()->Get(0) == MyGame::Example::TestEnum::C,
+ true);
+ TEST_EQ(mArStruct->d()->Get(1).c()->Get(1) == MyGame::Example::TestEnum::A,
+ true);
+ for (int i = 0; i < mArStruct->b()->size() - 1; i++)
+ TEST_EQ(mArStruct->b()->Get(i), i + 1);
+#endif
+}
+
+void NativeTypeTest() {
+ const int N = 3;
+
+ Geometry::ApplicationDataT src_data;
+ src_data.vectors.reserve(N);
+
+ for (int i = 0; i < N; ++i) {
+ src_data.vectors.push_back (Native::Vector3D(10 * i + 0.1f, 10 * i + 0.2f, 10 * i + 0.3f));
+ }
+
+ flatbuffers::FlatBufferBuilder fbb;
+ fbb.Finish(Geometry::ApplicationData::Pack(fbb, &src_data));
+
+ auto dstDataT = Geometry::UnPackApplicationData(fbb.GetBufferPointer());
+
+ for (int i = 0; i < N; ++i) {
+ Native::Vector3D& v = dstDataT->vectors[i];
+ TEST_EQ(v.x, 10 * i + 0.1f);
+ TEST_EQ(v.y, 10 * i + 0.2f);
+ TEST_EQ(v.z, 10 * i + 0.3f);
+ }
+}
+
+void FixedLengthArrayJsonTest(bool binary) {
+ // VS10 does not support typed enums, exclude from tests
+#if !defined(_MSC_VER) || _MSC_VER >= 1700
+ // load FlatBuffer schema (.fbs) and JSON from disk
+ std::string schemafile;
+ std::string jsonfile;
+ TEST_EQ(
+ flatbuffers::LoadFile(
+ (test_data_path + "arrays_test." + (binary ? "bfbs" : "fbs")).c_str(),
+ binary, &schemafile),
+ true);
+ TEST_EQ(flatbuffers::LoadFile((test_data_path + "arrays_test.golden").c_str(),
+ false, &jsonfile),
+ true);
+
+ // parse schema first, so we can use it to parse the data after
+ flatbuffers::Parser parserOrg, parserGen;
+ if (binary) {
+ flatbuffers::Verifier verifier(
+ reinterpret_cast<const uint8_t *>(schemafile.c_str()),
+ schemafile.size());
+ TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
+ TEST_EQ(parserOrg.Deserialize((const uint8_t *)schemafile.c_str(),
+ schemafile.size()),
+ true);
+ TEST_EQ(parserGen.Deserialize((const uint8_t *)schemafile.c_str(),
+ schemafile.size()),
+ true);
+ } else {
+ TEST_EQ(parserOrg.Parse(schemafile.c_str()), true);
+ TEST_EQ(parserGen.Parse(schemafile.c_str()), true);
+ }
+ TEST_EQ(parserOrg.Parse(jsonfile.c_str()), true);
+
+ // First, verify it, just in case:
+ flatbuffers::Verifier verifierOrg(parserOrg.builder_.GetBufferPointer(),
+ parserOrg.builder_.GetSize());
+ TEST_EQ(VerifyArrayTableBuffer(verifierOrg), true);
+
+ // Export to JSON
+ std::string jsonGen;
+ TEST_EQ(
+ GenerateText(parserOrg, parserOrg.builder_.GetBufferPointer(), &jsonGen),
+ true);
+
+ // Import from JSON
+ TEST_EQ(parserGen.Parse(jsonGen.c_str()), true);
+
+ // Verify buffer from generated JSON
+ flatbuffers::Verifier verifierGen(parserGen.builder_.GetBufferPointer(),
+ parserGen.builder_.GetSize());
+ TEST_EQ(VerifyArrayTableBuffer(verifierGen), true);
+
+ // Compare generated buffer to original
+ TEST_EQ(parserOrg.builder_.GetSize(), parserGen.builder_.GetSize());
+ TEST_EQ(std::memcmp(parserOrg.builder_.GetBufferPointer(),
+ parserGen.builder_.GetBufferPointer(),
+ parserOrg.builder_.GetSize()),
+ 0);
+#else
+ (void)binary;
+#endif
+}
+
+int FlatBufferTests() {
+ // clang-format off
+
+ // Run our various test suites:
+
+ std::string rawbuf;
+ auto flatbuf1 = CreateFlatBufferTest(rawbuf);
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ auto flatbuf = std::move(flatbuf1); // Test move assignment.
+ #else
+ auto &flatbuf = flatbuf1;
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+
+ TriviallyCopyableTest();
+
+ AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
+ rawbuf.length());
+ AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
+
+ MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
+
+ ObjectFlatBuffersTest(flatbuf.data());
+
+ MiniReflectFlatBuffersTest(flatbuf.data());
+
+ SizePrefixedTest();
+
+ #ifndef FLATBUFFERS_NO_FILE_TESTS
+ #ifdef FLATBUFFERS_TEST_PATH_PREFIX
+ test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
+ test_data_path;
+ #endif
+ ParseAndGenerateTextTest(false);
+ ParseAndGenerateTextTest(true);
+ FixedLengthArrayJsonTest(false);
+ FixedLengthArrayJsonTest(true);
+ ReflectionTest(flatbuf.data(), flatbuf.size());
+ ParseProtoTest();
+ UnionVectorTest();
+ LoadVerifyBinaryTest();
+ GenerateTableTextTest();
+ #endif
+ // clang-format on
+
+ FuzzTest1();
+ FuzzTest2();
+
+ ErrorTest();
+ ValueTest();
+ EnumValueTest();
+ EnumStringsTest();
+ EnumNamesTest();
+ EnumOutOfRangeTest();
+ IntegerOutOfRangeTest();
+ IntegerBoundaryTest();
+ UnicodeTest();
+ UnicodeTestAllowNonUTF8();
+ UnicodeTestGenerateTextFailsOnNonUTF8();
+ UnicodeSurrogatesTest();
+ UnicodeInvalidSurrogatesTest();
+ InvalidUTF8Test();
+ UnknownFieldsTest();
+ ParseUnionTest();
+ InvalidNestedFlatbufferTest();
+ ConformTest();
+ ParseProtoBufAsciiTest();
+ TypeAliasesTest();
+ EndianSwapTest();
+ CreateSharedStringTest();
+ JsonDefaultTest();
+ JsonEnumsTest();
+ FlexBuffersTest();
+ UninitializedVectorTest();
+ EqualOperatorTest();
+ NumericUtilsTest();
+ IsAsciiUtilsTest();
+ ValidFloatTest();
+ InvalidFloatTest();
+ TestMonsterExtraFloats();
+ FixedLengthArrayTest();
+ NativeTypeTest();
+ return 0;
+}
+
+int main(int /*argc*/, const char * /*argv*/ []) {
+ InitTestEngine();
+
+ std::string req_locale;
+ if (flatbuffers::ReadEnvironmentVariable("FLATBUFFERS_TEST_LOCALE",
+ &req_locale)) {
+ TEST_OUTPUT_LINE("The environment variable FLATBUFFERS_TEST_LOCALE=%s",
+ req_locale.c_str());
+ req_locale = flatbuffers::RemoveStringQuotes(req_locale);
+ std::string the_locale;
+ TEST_ASSERT_FUNC(
+ flatbuffers::SetGlobalTestLocale(req_locale.c_str(), &the_locale));
+ TEST_OUTPUT_LINE("The global C-locale changed: %s", the_locale.c_str());
+ }
+
+ FlatBufferTests();
+ FlatBufferBuilderTest();
+
+ if (!testing_fails) {
+ TEST_OUTPUT_LINE("ALL TESTS PASSED");
+ } else {
+ TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails);
+ }
+ return CloseTestEngine();
+}
diff --git a/tests/test_assert.cpp b/tests/test_assert.cpp
new file mode 100644
index 0000000..794ffe7
--- /dev/null
+++ b/tests/test_assert.cpp
@@ -0,0 +1,69 @@
+#include "test_assert.h"
+
+#include <assert.h>
+
+#ifdef _MSC_VER
+# include <crtdbg.h>
+# include <windows.h>
+#endif
+
+int testing_fails = 0;
+static TestFailEventListener fail_listener_ = nullptr;
+
+void TestFail(const char *expval, const char *val, const char *exp,
+ const char *file, int line, const char *func) {
+ TEST_OUTPUT_LINE("VALUE: \"%s\"", expval);
+ TEST_OUTPUT_LINE("EXPECTED: \"%s\"", val);
+ TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s in %s", file, line, exp,
+ func ? func : "");
+ testing_fails++;
+
+ // Notify, emulate 'gtest::OnTestPartResult' event handler.
+ if (fail_listener_) (*fail_listener_)(expval, val, exp, file, line, func);
+
+ assert(0); // ignored in Release if NDEBUG defined
+}
+
+void TestEqStr(const char *expval, const char *val, const char *exp,
+ const char *file, int line) {
+ if (strcmp(expval, val) != 0) { TestFail(expval, val, exp, file, line); }
+}
+
+#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && defined(_MSC_VER) && \
+ defined(_DEBUG)
+#define FLATBUFFERS_MEMORY_LEAK_TRACKING_MSVC
+#endif
+
+void InitTestEngine(TestFailEventListener listener) {
+ testing_fails = 0;
+ // Disable stdout buffering to prevent information lost on assertion or core
+ // dump.
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ flatbuffers::SetupDefaultCRTReportMode();
+
+ // clang-format off
+
+ #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING_MSVC)
+ // For more thorough checking:
+ // _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF
+ auto flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ _CrtSetDbgFlag(flags | _CRTDBG_ALLOC_MEM_DF);
+ #endif
+ // clang-format on
+
+ fail_listener_ = listener;
+}
+
+int CloseTestEngine(bool force_report) {
+ if (!testing_fails || force_report) {
+ #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING_MSVC)
+ auto flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ flags &= ~_CRTDBG_DELAY_FREE_MEM_DF;
+ flags |= _CRTDBG_LEAK_CHECK_DF;
+ _CrtSetDbgFlag(flags);
+ #endif
+ }
+ return (0 != testing_fails);
+}
diff --git a/tests/test_assert.h b/tests/test_assert.h
new file mode 100644
index 0000000..883586b
--- /dev/null
+++ b/tests/test_assert.h
@@ -0,0 +1,68 @@
+#ifndef TEST_ASSERT_H
+#define TEST_ASSERT_H
+
+#include "flatbuffers/base.h"
+#include "flatbuffers/util.h"
+
+// clang-format off
+
+#ifdef __ANDROID__
+ #include <android/log.h>
+ #define TEST_OUTPUT_LINE(...) \
+ __android_log_print(ANDROID_LOG_INFO, "FlatBuffers", __VA_ARGS__)
+ #define FLATBUFFERS_NO_FILE_TESTS
+#else
+ #define TEST_OUTPUT_LINE(...) \
+ { printf(__VA_ARGS__); printf("\n"); }
+#endif
+
+#define TEST_EQ(exp, val) TestEq(exp, val, #exp, __FILE__, __LINE__)
+#define TEST_ASSERT(exp) TestEq(exp, true, #exp, __FILE__, __LINE__)
+#define TEST_NOTNULL(exp) TestEq(exp == NULL, false, #exp, __FILE__, __LINE__)
+#define TEST_EQ_STR(exp, val) TestEqStr(exp, val, #exp, __FILE__, __LINE__)
+
+#ifdef _WIN32
+ #define TEST_ASSERT_FUNC(exp) TestEq(exp, true, #exp, __FILE__, __LINE__, __FUNCTION__)
+ #define TEST_EQ_FUNC(exp, val) TestEq(exp, val, #exp, __FILE__, __LINE__, __FUNCTION__)
+#else
+ #define TEST_ASSERT_FUNC(exp) TestEq(exp, true, #exp, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+ #define TEST_EQ_FUNC(exp, val) TestEq(exp, val, #exp, __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#endif
+
+// clang-format on
+
+extern int testing_fails;
+
+// Listener of TestFail, like 'gtest::OnTestPartResult' event handler.
+// Called in TestFail after a failed assertion.
+typedef bool (*TestFailEventListener)(const char *expval, const char *val,
+ const char *exp, const char *file,
+ int line, const char *func);
+
+// Prepare test engine (MSVC assertion setup, etc).
+// listener - this function will be notified on each TestFail call.
+void InitTestEngine(TestFailEventListener listener = nullptr);
+
+// Release all test-engine resources.
+// Prints or schedule a debug report if all test passed.
+// Returns 0 if all tests passed or 1 otherwise.
+// Memory leak report: FLATBUFFERS_MEMORY_LEAK_TRACKING && _MSC_VER && _DEBUG.
+int CloseTestEngine(bool force_report = false);
+
+// Write captured state to a log and terminate test run.
+void TestFail(const char *expval, const char *val, const char *exp,
+ const char *file, int line, const char *func = 0);
+
+void TestEqStr(const char *expval, const char *val, const char *exp,
+ const char *file, int line);
+
+template<typename T, typename U>
+void TestEq(T expval, U val, const char *exp, const char *file, int line,
+ const char *func = 0) {
+ if (U(expval) != val) {
+ TestFail(flatbuffers::NumToString(expval).c_str(),
+ flatbuffers::NumToString(val).c_str(), exp, file, line, func);
+ }
+}
+
+#endif // !TEST_ASSERT_H
diff --git a/tests/test_builder.cpp b/tests/test_builder.cpp
new file mode 100644
index 0000000..8c070c1
--- /dev/null
+++ b/tests/test_builder.cpp
@@ -0,0 +1,148 @@
+#include "flatbuffers/stl_emulation.h"
+
+#include "monster_test_generated.h"
+#include "test_builder.h"
+
+using namespace MyGame::Example;
+
+const std::string m1_name = "Cyberdemon";
+const Color m1_color = Color_Red;
+const std::string m2_name = "Imp";
+const Color m2_color = Color_Green;
+
+struct OwnedAllocator : public flatbuffers::DefaultAllocator {};
+
+class TestHeapBuilder : public flatbuffers::FlatBufferBuilder {
+private:
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ TestHeapBuilder(const TestHeapBuilder &);
+ TestHeapBuilder &operator=(const TestHeapBuilder &);
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+public:
+ TestHeapBuilder()
+ : flatbuffers::FlatBufferBuilder(2048, new OwnedAllocator(), true) {}
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ TestHeapBuilder(TestHeapBuilder &&other)
+ : FlatBufferBuilder(std::move(other)) { }
+
+ TestHeapBuilder &operator=(TestHeapBuilder &&other) {
+ FlatBufferBuilder::operator=(std::move(other));
+ return *this;
+ }
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+};
+
+// This class simulates flatbuffers::grpc::detail::SliceAllocatorMember
+struct AllocatorMember {
+ flatbuffers::DefaultAllocator member_allocator_;
+};
+
+struct GrpcLikeMessageBuilder : private AllocatorMember,
+ public flatbuffers::FlatBufferBuilder {
+private:
+ GrpcLikeMessageBuilder(const GrpcLikeMessageBuilder &);
+ GrpcLikeMessageBuilder &operator=(const GrpcLikeMessageBuilder &);
+
+public:
+ GrpcLikeMessageBuilder()
+ : flatbuffers::FlatBufferBuilder(1024, &member_allocator_, false) {}
+
+ GrpcLikeMessageBuilder(GrpcLikeMessageBuilder &&other)
+ : FlatBufferBuilder(1024, &member_allocator_, false) {
+ // Default construct and swap idiom.
+ Swap(other);
+ }
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ GrpcLikeMessageBuilder &operator=(GrpcLikeMessageBuilder &&other) {
+ // Construct temporary and swap idiom
+ GrpcLikeMessageBuilder temp(std::move(other));
+ Swap(temp);
+ return *this;
+ }
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ void Swap(GrpcLikeMessageBuilder &other) {
+ // No need to swap member_allocator_ because it's stateless.
+ FlatBufferBuilder::Swap(other);
+ // After swapping the FlatBufferBuilder, we swap back the allocator, which restores
+ // the original allocator back in place. This is necessary because MessageBuilder's
+ // allocator is its own member (SliceAllocatorMember). The allocator passed to
+ // FlatBufferBuilder::vector_downward must point to this member.
+ buf_.swap_allocator(other.buf_);
+ }
+};
+
+flatbuffers::Offset<Monster> populate1(flatbuffers::FlatBufferBuilder &builder) {
+ auto name_offset = builder.CreateString(m1_name);
+ return CreateMonster(builder, nullptr, 0, 0, name_offset, 0, m1_color);
+}
+
+flatbuffers::Offset<Monster> populate2(flatbuffers::FlatBufferBuilder &builder) {
+ auto name_offset = builder.CreateString(m2_name);
+ return CreateMonster(builder, nullptr, 0, 0, name_offset, 0, m2_color);
+}
+
+uint8_t *release_raw_base(flatbuffers::FlatBufferBuilder &fbb, size_t &size, size_t &offset) {
+ return fbb.ReleaseRaw(size, offset);
+}
+
+void free_raw(flatbuffers::grpc::MessageBuilder &, uint8_t *) {
+ // release_raw_base calls FlatBufferBuilder::ReleaseRaw on the argument MessageBuilder.
+ // It's semantically wrong as MessageBuilder has its own ReleaseRaw member function that
+ // takes three arguments. In such cases though, ~MessageBuilder() invokes
+ // ~SliceAllocator() that takes care of deleting memory as it calls grpc_slice_unref.
+ // Obviously, this behavior is very surprising as the pointer returned by
+ // FlatBufferBuilder::ReleaseRaw is not valid as soon as MessageBuilder goes out of scope.
+ // This problem does not occur with FlatBufferBuilder.
+}
+
+void free_raw(flatbuffers::FlatBufferBuilder &, uint8_t *buf) {
+ flatbuffers::DefaultAllocator().deallocate(buf, 0);
+}
+
+bool verify(const flatbuffers::DetachedBuffer &buf, const std::string &expected_name, Color color) {
+ const Monster *monster = flatbuffers::GetRoot<Monster>(buf.data());
+ return (monster->name()->str() == expected_name) && (monster->color() == color);
+}
+
+bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name, Color color) {
+ const Monster *monster = flatbuffers::GetRoot<Monster>(buf+offset);
+ return (monster->name()->str() == expected_name) && (monster->color() == color);
+}
+
+bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb, const std::string &expected_name, Color color) {
+ flatbuffers::DetachedBuffer buf = fbb.Release();
+ return verify(buf, expected_name, color);
+}
+
+void FlatBufferBuilderTest() {
+ using flatbuffers::FlatBufferBuilder;
+
+ BuilderTests<FlatBufferBuilder>::all_tests();
+ BuilderTests<TestHeapBuilder>::all_tests();
+ BuilderTests<GrpcLikeMessageBuilder>::all_tests();
+
+ BuilderReuseTestSelector tests[4] = {
+ REUSABLE_AFTER_RELEASE,
+ REUSABLE_AFTER_RELEASE_RAW,
+ REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN,
+ REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN
+ };
+
+ BuilderReuseTests<FlatBufferBuilder, FlatBufferBuilder>::run_tests(TestSelector(tests, tests+4));
+ BuilderReuseTests<TestHeapBuilder, TestHeapBuilder>::run_tests(TestSelector(tests, tests+4));
+ BuilderReuseTests<GrpcLikeMessageBuilder, GrpcLikeMessageBuilder>::run_tests(TestSelector(tests, tests+4));
+}
diff --git a/tests/test_builder.h b/tests/test_builder.h
new file mode 100644
index 0000000..1e2fa0a
--- /dev/null
+++ b/tests/test_builder.h
@@ -0,0 +1,326 @@
+#ifndef TEST_BUILDER_H
+#define TEST_BUILDER_H
+
+#include <set>
+#include <type_traits>
+#include "monster_test_generated.h"
+#include "flatbuffers/flatbuffers.h"
+#include "test_assert.h"
+
+using MyGame::Example::Color;
+using MyGame::Example::Monster;
+
+namespace flatbuffers {
+namespace grpc {
+class MessageBuilder;
+}
+}
+
+template <class T, class U>
+struct is_same {
+ static const bool value = false;
+};
+
+template <class T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+extern const std::string m1_name;
+extern const Color m1_color;
+extern const std::string m2_name;
+extern const Color m2_color;
+
+flatbuffers::Offset<Monster> populate1(flatbuffers::FlatBufferBuilder &builder);
+flatbuffers::Offset<Monster> populate2(flatbuffers::FlatBufferBuilder &builder);
+
+uint8_t *release_raw_base(flatbuffers::FlatBufferBuilder &fbb, size_t &size, size_t &offset);
+
+void free_raw(flatbuffers::grpc::MessageBuilder &mbb, uint8_t *buf);
+void free_raw(flatbuffers::FlatBufferBuilder &fbb, uint8_t *buf);
+
+bool verify(const flatbuffers::DetachedBuffer &buf, const std::string &expected_name, Color color);
+bool verify(const uint8_t *buf, size_t offset, const std::string &expected_name, Color color);
+
+bool release_n_verify(flatbuffers::FlatBufferBuilder &fbb, const std::string &expected_name, Color color);
+bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, const std::string &expected_name, Color color);
+
+// clang-format off
+#if !defined(FLATBUFFERS_CPP98_STL)
+// clang-format on
+// Invokes this function when testing the following Builder types
+// FlatBufferBuilder, TestHeapBuilder, and GrpcLikeMessageBuilder
+template <class Builder>
+void builder_move_assign_after_releaseraw_test(Builder b1) {
+ auto root_offset1 = populate1(b1);
+ b1.Finish(root_offset1);
+ size_t size, offset;
+ std::shared_ptr<uint8_t> raw(b1.ReleaseRaw(size, offset), [size](uint8_t *ptr) {
+ flatbuffers::DefaultAllocator::dealloc(ptr, size);
+ });
+ Builder src;
+ auto root_offset2 = populate2(src);
+ src.Finish(root_offset2);
+ auto src_size = src.GetSize();
+ // Move into a released builder.
+ b1 = std::move(src);
+ TEST_EQ_FUNC(b1.GetSize(), src_size);
+ TEST_ASSERT_FUNC(release_n_verify(b1, m2_name, m2_color));
+ TEST_EQ_FUNC(src.GetSize(), 0);
+}
+// clang-format off
+#endif // !defined(FLATBUFFERS_CPP98_STL)
+// clang-format on
+
+void builder_move_assign_after_releaseraw_test(flatbuffers::grpc::MessageBuilder b1);
+
+template <class DestBuilder, class SrcBuilder = DestBuilder>
+struct BuilderTests {
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ static void empty_builder_movector_test() {
+ SrcBuilder src;
+ size_t src_size = src.GetSize();
+ DestBuilder dst(std::move(src));
+ size_t dst_size = dst.GetSize();
+ TEST_EQ_FUNC(src_size, 0);
+ TEST_EQ_FUNC(src_size, dst_size);
+ }
+
+ static void nonempty_builder_movector_test() {
+ SrcBuilder src;
+ populate1(src);
+ size_t src_size = src.GetSize();
+ DestBuilder dst(std::move(src));
+ TEST_EQ_FUNC(src_size, dst.GetSize());
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+
+ static void builder_movector_before_finish_test() {
+ SrcBuilder src;
+ auto root_offset1 = populate1(src);
+ DestBuilder dst(std::move(src));
+ dst.Finish(root_offset1);
+ TEST_ASSERT_FUNC(release_n_verify(dst, m1_name, m1_color));
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+
+ static void builder_movector_after_finish_test() {
+ SrcBuilder src;
+ auto root_offset1 = populate1(src);
+ src.Finish(root_offset1);
+ auto src_size = src.GetSize();
+ DestBuilder dst(std::move(src));
+ TEST_EQ_FUNC(dst.GetSize(), src_size);
+ TEST_ASSERT_FUNC(release_n_verify(dst, m1_name, m1_color));
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+
+ static void builder_move_assign_before_finish_test() {
+ SrcBuilder src;
+ auto root_offset1 = populate1(src);
+ DestBuilder dst;
+ populate2(dst);
+ dst = std::move(src);
+ dst.Finish(root_offset1);
+ TEST_ASSERT_FUNC(release_n_verify(dst, m1_name, m1_color));
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+
+ static void builder_move_assign_after_finish_test() {
+ SrcBuilder src;
+ auto root_offset1 = populate1(src);
+ src.Finish(root_offset1);
+ auto src_size = src.GetSize();
+ DestBuilder dst;
+ auto root_offset2 = populate2(dst);
+ dst.Finish(root_offset2);
+ dst = std::move(src);
+ TEST_EQ_FUNC(dst.GetSize(), src_size);
+ TEST_ASSERT_FUNC(release_n_verify(dst, m1_name, m1_color));
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+
+ static void builder_move_assign_after_release_test() {
+ DestBuilder dst;
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ {
+ flatbuffers::DetachedBuffer dst_detached = dst.Release();
+ // detached buffer is deleted
+ }
+ SrcBuilder src;
+ auto root_offset2 = populate2(src);
+ src.Finish(root_offset2);
+ auto src_size = src.GetSize();
+ // Move into a released builder.
+ dst = std::move(src);
+ TEST_EQ_FUNC(dst.GetSize(), src_size);
+ TEST_ASSERT_FUNC(release_n_verify(dst, m2_name, m2_color));
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ static void builder_swap_before_finish_test(bool run = is_same<DestBuilder, SrcBuilder>::value) {
+ /// Swap is allowed only when lhs and rhs are the same concrete type.
+ if(run) {
+ SrcBuilder src;
+ auto root_offset1 = populate1(src);
+ auto size1 = src.GetSize();
+ DestBuilder dst;
+ auto root_offset2 = populate2(dst);
+ auto size2 = dst.GetSize();
+ src.Swap(dst);
+ src.Finish(root_offset2);
+ dst.Finish(root_offset1);
+ TEST_EQ_FUNC(src.GetSize() > size2, true);
+ TEST_EQ_FUNC(dst.GetSize() > size1, true);
+ TEST_ASSERT_FUNC(release_n_verify(src, m2_name, m2_color));
+ TEST_ASSERT_FUNC(release_n_verify(dst, m1_name, m1_color));
+ }
+ }
+
+ static void builder_swap_after_finish_test(bool run = is_same<DestBuilder, SrcBuilder>::value) {
+ /// Swap is allowed only when lhs and rhs are the same concrete type.
+ if(run) {
+ SrcBuilder src;
+ auto root_offset1 = populate1(src);
+ src.Finish(root_offset1);
+ auto size1 = src.GetSize();
+ DestBuilder dst;
+ auto root_offset2 = populate2(dst);
+ dst.Finish(root_offset2);
+ auto size2 = dst.GetSize();
+ src.Swap(dst);
+ TEST_EQ_FUNC(src.GetSize(), size2);
+ TEST_EQ_FUNC(dst.GetSize(), size1);
+ TEST_ASSERT_FUNC(release_n_verify(src, m2_name, m2_color));
+ TEST_ASSERT_FUNC(release_n_verify(dst, m1_name, m1_color));
+ }
+ }
+
+ static void all_tests() {
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ empty_builder_movector_test();
+ nonempty_builder_movector_test();
+ builder_movector_before_finish_test();
+ builder_movector_after_finish_test();
+ builder_move_assign_before_finish_test();
+ builder_move_assign_after_finish_test();
+ builder_move_assign_after_release_test();
+ builder_move_assign_after_releaseraw_test(DestBuilder());
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ builder_swap_before_finish_test();
+ builder_swap_after_finish_test();
+ }
+};
+
+enum BuilderReuseTestSelector {
+ REUSABLE_AFTER_RELEASE = 1,
+ REUSABLE_AFTER_RELEASE_RAW = 2,
+ REUSABLE_AFTER_RELEASE_MESSAGE = 3,
+ REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN = 4,
+ REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN = 5,
+ REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN = 6
+};
+
+typedef std::set<BuilderReuseTestSelector> TestSelector;
+
+template <class DestBuilder, class SrcBuilder>
+struct BuilderReuseTests {
+ static void builder_reusable_after_release_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE)) {
+ return;
+ }
+
+ DestBuilder fbb;
+ std::vector<flatbuffers::DetachedBuffer> buffers;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(fbb);
+ fbb.Finish(root_offset1);
+ buffers.push_back(fbb.Release());
+ TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+ }
+ }
+
+ static void builder_reusable_after_releaseraw_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) {
+ return;
+ }
+
+ DestBuilder fbb;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(fbb);
+ fbb.Finish(root_offset1);
+ size_t size, offset;
+ uint8_t *buf = release_raw_base(fbb, size, offset);
+ TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
+ free_raw(fbb, buf);
+ }
+ }
+
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ static void builder_reusable_after_release_and_move_assign_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) {
+ return;
+ }
+
+ DestBuilder dst;
+ std::vector<flatbuffers::DetachedBuffer> buffers;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ buffers.push_back(dst.Release());
+ TEST_ASSERT_FUNC(verify(buffers[i], m1_name, m1_color));
+ SrcBuilder src;
+ dst = std::move(src);
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+ }
+
+ static void builder_reusable_after_releaseraw_and_move_assign_test(TestSelector selector) {
+ if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) {
+ return;
+ }
+
+ DestBuilder dst;
+ for (int i = 0; i < 5; ++i) {
+ auto root_offset1 = populate1(dst);
+ dst.Finish(root_offset1);
+ size_t size, offset;
+ uint8_t *buf = release_raw_base(dst, size, offset);
+ TEST_ASSERT_FUNC(verify(buf, offset, m1_name, m1_color));
+ free_raw(dst, buf);
+ SrcBuilder src;
+ dst = std::move(src);
+ TEST_EQ_FUNC(src.GetSize(), 0);
+ }
+ }
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+
+ static void run_tests(TestSelector selector) {
+ builder_reusable_after_release_test(selector);
+ builder_reusable_after_releaseraw_test(selector);
+ // clang-format off
+ #if !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ builder_reusable_after_release_and_move_assign_test(selector);
+ builder_reusable_after_releaseraw_and_move_assign_test(selector);
+ // clang-format off
+ #endif // !defined(FLATBUFFERS_CPP98_STL)
+ // clang-format on
+ }
+};
+
+#endif // TEST_BUILDER_H
diff --git a/tests/unicode_test.json b/tests/unicode_test.json
new file mode 100644
index 0000000..2894f0c
--- /dev/null
+++ b/tests/unicode_test.json
@@ -0,0 +1,31 @@
+{
+ "name": "unicode_test",
+ "testarrayofstring": [
+ "Цлїςσδε",
+ "フムアムカモケモ",
+ "フムヤムカモケモ",
+ "㊀㊁㊂㊃㊄",
+ "☳☶☲",
+ "𡇙𝌆"
+ ],
+ "testarrayoftables": [
+ {
+ "name": "Цлїςσδε"
+ },
+ {
+ "name": "フムアムカモケモ"
+ },
+ {
+ "name": "フムヤムカモケモ"
+ },
+ {
+ "name": "㊀㊁㊂㊃㊄"
+ },
+ {
+ "name": "☳☶☲"
+ },
+ {
+ "name": "𡇙𝌆"
+ }
+ ]
+}
diff --git a/tests/union_vector/Attacker.cs b/tests/union_vector/Attacker.cs
new file mode 100644
index 0000000..0e3300a
--- /dev/null
+++ b/tests/union_vector/Attacker.cs
@@ -0,0 +1,35 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Attacker : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static Attacker GetRootAsAttacker(ByteBuffer _bb) { return GetRootAsAttacker(_bb, new Attacker()); }
+ public static Attacker GetRootAsAttacker(ByteBuffer _bb, Attacker obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Attacker __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int SwordAttackDamage { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+ public bool MutateSwordAttackDamage(int sword_attack_damage) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, sword_attack_damage); return true; } else { return false; } }
+
+ public static Offset<Attacker> CreateAttacker(FlatBufferBuilder builder,
+ int sword_attack_damage = 0) {
+ builder.StartTable(1);
+ Attacker.AddSwordAttackDamage(builder, sword_attack_damage);
+ return Attacker.EndAttacker(builder);
+ }
+
+ public static void StartAttacker(FlatBufferBuilder builder) { builder.StartTable(1); }
+ public static void AddSwordAttackDamage(FlatBufferBuilder builder, int swordAttackDamage) { builder.AddInt(0, swordAttackDamage, 0); }
+ public static Offset<Attacker> EndAttacker(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<Attacker>(o);
+ }
+};
+
diff --git a/tests/union_vector/Attacker.java b/tests/union_vector/Attacker.java
new file mode 100644
index 0000000..afe6945
--- /dev/null
+++ b/tests/union_vector/Attacker.java
@@ -0,0 +1,33 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Attacker extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static Attacker getRootAsAttacker(ByteBuffer _bb) { return getRootAsAttacker(_bb, new Attacker()); }
+ public static Attacker getRootAsAttacker(ByteBuffer _bb, Attacker obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Attacker __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int swordAttackDamage() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+ public boolean mutateSwordAttackDamage(int sword_attack_damage) { int o = __offset(4); if (o != 0) { bb.putInt(o + bb_pos, sword_attack_damage); return true; } else { return false; } }
+
+ public static int createAttacker(FlatBufferBuilder builder,
+ int sword_attack_damage) {
+ builder.startTable(1);
+ Attacker.addSwordAttackDamage(builder, sword_attack_damage);
+ return Attacker.endAttacker(builder);
+ }
+
+ public static void startAttacker(FlatBufferBuilder builder) { builder.startTable(1); }
+ public static void addSwordAttackDamage(FlatBufferBuilder builder, int swordAttackDamage) { builder.addInt(0, swordAttackDamage, 0); }
+ public static int endAttacker(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+}
+
diff --git a/tests/union_vector/Attacker.kt b/tests/union_vector/Attacker.kt
new file mode 100644
index 0000000..7d3dc68
--- /dev/null
+++ b/tests/union_vector/Attacker.kt
@@ -0,0 +1,51 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Attacker : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Attacker {
+ __init(_i, _bb)
+ return this
+ }
+ val swordAttackDamage : Int
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.getInt(o + bb_pos) else 0
+ }
+ fun mutateSwordAttackDamage(swordAttackDamage: Int) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.putInt(o + bb_pos, swordAttackDamage)
+ true
+ } else {
+ false
+ }
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsAttacker(_bb: ByteBuffer): Attacker = getRootAsAttacker(_bb, Attacker())
+ fun getRootAsAttacker(_bb: ByteBuffer, obj: Attacker): Attacker {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun createAttacker(builder: FlatBufferBuilder, swordAttackDamage: Int) : Int {
+ builder.startTable(1)
+ addSwordAttackDamage(builder, swordAttackDamage)
+ return endAttacker(builder)
+ }
+ fun startAttacker(builder: FlatBufferBuilder) = builder.startTable(1)
+ fun addSwordAttackDamage(builder: FlatBufferBuilder, swordAttackDamage: Int) = builder.addInt(0, swordAttackDamage, 0)
+ fun endAttacker(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ }
+}
diff --git a/tests/union_vector/Attacker.php b/tests/union_vector/Attacker.php
new file mode 100644
index 0000000..e3ebfe6
--- /dev/null
+++ b/tests/union_vector/Attacker.php
@@ -0,0 +1,92 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Attacker extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Attacker
+ */
+ public static function getRootAsAttacker(ByteBuffer $bb)
+ {
+ $obj = new Attacker();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function AttackerIdentifier()
+ {
+ return "MOVI";
+ }
+
+ public static function AttackerBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::AttackerIdentifier());
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Attacker
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSwordAttackDamage()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startAttacker(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Attacker
+ */
+ public static function createAttacker(FlatBufferBuilder $builder, $sword_attack_damage)
+ {
+ $builder->startObject(1);
+ self::addSwordAttackDamage($builder, $sword_attack_damage);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int
+ * @return void
+ */
+ public static function addSwordAttackDamage(FlatBufferBuilder $builder, $swordAttackDamage)
+ {
+ $builder->addIntX(0, $swordAttackDamage, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endAttacker(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+}
diff --git a/tests/union_vector/BookReader.cs b/tests/union_vector/BookReader.cs
new file mode 100644
index 0000000..53fe736
--- /dev/null
+++ b/tests/union_vector/BookReader.cs
@@ -0,0 +1,24 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+using global::System;
+using global::FlatBuffers;
+
+public struct BookReader : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public BookReader __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int BooksRead { get { return __p.bb.GetInt(__p.bb_pos + 0); } }
+ public void MutateBooksRead(int books_read) { __p.bb.PutInt(__p.bb_pos + 0, books_read); }
+
+ public static Offset<BookReader> CreateBookReader(FlatBufferBuilder builder, int BooksRead) {
+ builder.Prep(4, 4);
+ builder.PutInt(BooksRead);
+ return new Offset<BookReader>(builder.Offset);
+ }
+};
+
diff --git a/tests/union_vector/BookReader.java b/tests/union_vector/BookReader.java
new file mode 100644
index 0000000..20ff9e2
--- /dev/null
+++ b/tests/union_vector/BookReader.java
@@ -0,0 +1,22 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class BookReader extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public BookReader __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int booksRead() { return bb.getInt(bb_pos + 0); }
+ public void mutateBooksRead(int books_read) { bb.putInt(bb_pos + 0, books_read); }
+
+ public static int createBookReader(FlatBufferBuilder builder, int booksRead) {
+ builder.prep(4, 4);
+ builder.putInt(booksRead);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/union_vector/BookReader.kt b/tests/union_vector/BookReader.kt
new file mode 100644
index 0000000..fc41473
--- /dev/null
+++ b/tests/union_vector/BookReader.kt
@@ -0,0 +1,27 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class BookReader : Struct() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : BookReader {
+ __init(_i, _bb)
+ return this
+ }
+ val booksRead : Int get() = bb.getInt(bb_pos + 0)
+ fun mutateBooksRead(booksRead: Int) : ByteBuffer = bb.putInt(bb_pos + 0, booksRead)
+ companion object {
+ fun createBookReader(builder: FlatBufferBuilder, booksRead: Int) : Int {
+ builder.prep(4, 4)
+ builder.putInt(booksRead)
+ return builder.offset()
+ }
+ }
+}
diff --git a/tests/union_vector/BookReader.php b/tests/union_vector/BookReader.php
new file mode 100644
index 0000000..1f8f8d8
--- /dev/null
+++ b/tests/union_vector/BookReader.php
@@ -0,0 +1,41 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class BookReader extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return BookReader
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function GetBooksRead()
+ {
+ return $this->bb->getInt($this->bb_pos + 0);
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createBookReader(FlatBufferBuilder $builder, $booksRead)
+ {
+ $builder->prep(4, 4);
+ $builder->putInt($booksRead);
+ return $builder->offset();
+ }
+}
diff --git a/tests/union_vector/Character.cs b/tests/union_vector/Character.cs
new file mode 100644
index 0000000..73a5cba
--- /dev/null
+++ b/tests/union_vector/Character.cs
@@ -0,0 +1,15 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+public enum Character : byte
+{
+ NONE = 0,
+ MuLan = 1,
+ Rapunzel = 2,
+ Belle = 3,
+ BookFan = 4,
+ Other = 5,
+ Unused = 6,
+};
+
diff --git a/tests/union_vector/Character.java b/tests/union_vector/Character.java
new file mode 100644
index 0000000..5d6c5b7
--- /dev/null
+++ b/tests/union_vector/Character.java
@@ -0,0 +1,17 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+public final class Character {
+ private Character() { }
+ public static final byte NONE = 0;
+ public static final byte MuLan = 1;
+ public static final byte Rapunzel = 2;
+ public static final byte Belle = 3;
+ public static final byte BookFan = 4;
+ public static final byte Other = 5;
+ public static final byte Unused = 6;
+
+ public static final String[] names = { "NONE", "MuLan", "Rapunzel", "Belle", "BookFan", "Other", "Unused", };
+
+ public static String name(int e) { return names[e]; }
+}
+
diff --git a/tests/union_vector/Character.kt b/tests/union_vector/Character.kt
new file mode 100644
index 0000000..ff7dd5e
--- /dev/null
+++ b/tests/union_vector/Character.kt
@@ -0,0 +1,17 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Character_ private constructor() {
+ companion object {
+ const val NONE: UByte = 0u
+ const val MuLan: UByte = 1u
+ const val Rapunzel: UByte = 2u
+ const val Belle: UByte = 3u
+ const val BookFan: UByte = 4u
+ const val Other: UByte = 5u
+ const val Unused: UByte = 6u
+ val names : Array<String> = arrayOf("NONE", "MuLan", "Rapunzel", "Belle", "BookFan", "Other", "Unused")
+ fun name(e: Int) : String = names[e]
+ }
+}
diff --git a/tests/union_vector/Character.php b/tests/union_vector/Character.php
new file mode 100644
index 0000000..755958b
--- /dev/null
+++ b/tests/union_vector/Character.php
@@ -0,0 +1,31 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+class Character
+{
+ const NONE = 0;
+ const MuLan = 1;
+ const Rapunzel = 2;
+ const Belle = 3;
+ const BookFan = 4;
+ const Other = 5;
+ const Unused = 6;
+
+ private static $names = array(
+ Character::NONE=>"NONE",
+ Character::MuLan=>"MuLan",
+ Character::Rapunzel=>"Rapunzel",
+ Character::Belle=>"Belle",
+ Character::BookFan=>"BookFan",
+ Character::Other=>"Other",
+ Character::Unused=>"Unused",
+ );
+
+ public static function Name($e)
+ {
+ if (!isset(self::$names[$e])) {
+ throw new \Exception();
+ }
+ return self::$names[$e];
+ }
+}
diff --git a/tests/union_vector/Movie.cs b/tests/union_vector/Movie.cs
new file mode 100644
index 0000000..13dbfac
--- /dev/null
+++ b/tests/union_vector/Movie.cs
@@ -0,0 +1,65 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Movie : IFlatbufferObject
+{
+ private Table __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_1_11_1(); }
+ public static Movie GetRootAsMovie(ByteBuffer _bb) { return GetRootAsMovie(_bb, new Movie()); }
+ public static Movie GetRootAsMovie(ByteBuffer _bb, Movie obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+ public static bool MovieBufferHasIdentifier(ByteBuffer _bb) { return Table.__has_identifier(_bb, "MOVI"); }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }
+ public Movie __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public Character MainCharacterType { get { int o = __p.__offset(4); return o != 0 ? (Character)__p.bb.Get(o + __p.bb_pos) : Character.NONE; } }
+ public bool MutateMainCharacterType(Character main_character_type) { int o = __p.__offset(4); if (o != 0) { __p.bb.Put(o + __p.bb_pos, (byte)main_character_type); return true; } else { return false; } }
+ public TTable? MainCharacter<TTable>() where TTable : struct, IFlatbufferObject { int o = __p.__offset(6); return o != 0 ? (TTable?)__p.__union<TTable>(o) : null; }
+ public Character CharactersType(int j) { int o = __p.__offset(8); return o != 0 ? (Character)__p.bb.Get(__p.__vector(o) + j * 1) : (Character)0; }
+ public int CharactersTypeLength { get { int o = __p.__offset(8); return o != 0 ? __p.__vector_len(o) : 0; } }
+#if ENABLE_SPAN_T
+ public Span<byte> GetCharactersTypeBytes() { return __p.__vector_as_span(8); }
+#else
+ public ArraySegment<byte>? GetCharactersTypeBytes() { return __p.__vector_as_arraysegment(8); }
+#endif
+ public Character[] GetCharactersTypeArray() { return __p.__vector_as_array<Character>(8); }
+ public bool MutateCharactersType(int j, Character characters_type) { int o = __p.__offset(8); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, (byte)characters_type); return true; } else { return false; } }
+ public TTable? Characters<TTable>(int j) where TTable : struct, IFlatbufferObject { int o = __p.__offset(10); return o != 0 ? (TTable?)__p.__union<TTable>(__p.__vector(o) + j * 4 - __p.bb_pos) : null; }
+ public int CharactersLength { get { int o = __p.__offset(10); return o != 0 ? __p.__vector_len(o) : 0; } }
+
+ public static Offset<Movie> CreateMovie(FlatBufferBuilder builder,
+ Character main_character_type = Character.NONE,
+ int main_characterOffset = 0,
+ VectorOffset characters_typeOffset = default(VectorOffset),
+ VectorOffset charactersOffset = default(VectorOffset)) {
+ builder.StartTable(4);
+ Movie.AddCharacters(builder, charactersOffset);
+ Movie.AddCharactersType(builder, characters_typeOffset);
+ Movie.AddMainCharacter(builder, main_characterOffset);
+ Movie.AddMainCharacterType(builder, main_character_type);
+ return Movie.EndMovie(builder);
+ }
+
+ public static void StartMovie(FlatBufferBuilder builder) { builder.StartTable(4); }
+ public static void AddMainCharacterType(FlatBufferBuilder builder, Character mainCharacterType) { builder.AddByte(0, (byte)mainCharacterType, 0); }
+ public static void AddMainCharacter(FlatBufferBuilder builder, int mainCharacterOffset) { builder.AddOffset(1, mainCharacterOffset, 0); }
+ public static void AddCharactersType(FlatBufferBuilder builder, VectorOffset charactersTypeOffset) { builder.AddOffset(2, charactersTypeOffset.Value, 0); }
+ public static VectorOffset CreateCharactersTypeVector(FlatBufferBuilder builder, Character[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte((byte)data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateCharactersTypeVectorBlock(FlatBufferBuilder builder, Character[] data) { builder.StartVector(1, data.Length, 1); builder.Add(data); return builder.EndVector(); }
+ public static void StartCharactersTypeVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+ public static void AddCharacters(FlatBufferBuilder builder, VectorOffset charactersOffset) { builder.AddOffset(3, charactersOffset.Value, 0); }
+ public static VectorOffset CreateCharactersVector(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i]); return builder.EndVector(); }
+ public static VectorOffset CreateCharactersVectorBlock(FlatBufferBuilder builder, int[] data) { builder.StartVector(4, data.Length, 4); builder.Add(data); return builder.EndVector(); }
+ public static void StartCharactersVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+ public static Offset<Movie> EndMovie(FlatBufferBuilder builder) {
+ int o = builder.EndTable();
+ return new Offset<Movie>(o);
+ }
+ public static void FinishMovieBuffer(FlatBufferBuilder builder, Offset<Movie> offset) { builder.Finish(offset.Value, "MOVI"); }
+ public static void FinishSizePrefixedMovieBuffer(FlatBufferBuilder builder, Offset<Movie> offset) { builder.FinishSizePrefixed(offset.Value, "MOVI"); }
+};
+
diff --git a/tests/union_vector/Movie.java b/tests/union_vector/Movie.java
new file mode 100644
index 0000000..0f6a19c
--- /dev/null
+++ b/tests/union_vector/Movie.java
@@ -0,0 +1,57 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Movie extends Table {
+ public static void ValidateVersion() { Constants.FLATBUFFERS_1_11_1(); }
+ public static Movie getRootAsMovie(ByteBuffer _bb) { return getRootAsMovie(_bb, new Movie()); }
+ public static Movie getRootAsMovie(ByteBuffer _bb, Movie obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+ public static boolean MovieBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MOVI"); }
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Movie __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public byte mainCharacterType() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }
+ public boolean mutateMainCharacterType(byte main_character_type) { int o = __offset(4); if (o != 0) { bb.put(o + bb_pos, main_character_type); return true; } else { return false; } }
+ public Table mainCharacter(Table obj) { int o = __offset(6); return o != 0 ? __union(obj, o) : null; }
+ public byte charactersType(int j) { int o = __offset(8); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
+ public int charactersTypeLength() { int o = __offset(8); return o != 0 ? __vector_len(o) : 0; }
+ public ByteBuffer charactersTypeAsByteBuffer() { return __vector_as_bytebuffer(8, 1); }
+ public ByteBuffer charactersTypeInByteBuffer(ByteBuffer _bb) { return __vector_in_bytebuffer(_bb, 8, 1); }
+ public boolean mutateCharactersType(int j, byte characters_type) { int o = __offset(8); if (o != 0) { bb.put(__vector(o) + j * 1, characters_type); return true; } else { return false; } }
+ public Table characters(Table obj, int j) { int o = __offset(10); return o != 0 ? __union(obj, __vector(o) + j * 4 - bb_pos) : null; }
+ public int charactersLength() { int o = __offset(10); return o != 0 ? __vector_len(o) : 0; }
+
+ public static int createMovie(FlatBufferBuilder builder,
+ byte main_character_type,
+ int main_characterOffset,
+ int characters_typeOffset,
+ int charactersOffset) {
+ builder.startTable(4);
+ Movie.addCharacters(builder, charactersOffset);
+ Movie.addCharactersType(builder, characters_typeOffset);
+ Movie.addMainCharacter(builder, main_characterOffset);
+ Movie.addMainCharacterType(builder, main_character_type);
+ return Movie.endMovie(builder);
+ }
+
+ public static void startMovie(FlatBufferBuilder builder) { builder.startTable(4); }
+ public static void addMainCharacterType(FlatBufferBuilder builder, byte mainCharacterType) { builder.addByte(0, mainCharacterType, 0); }
+ public static void addMainCharacter(FlatBufferBuilder builder, int mainCharacterOffset) { builder.addOffset(1, mainCharacterOffset, 0); }
+ public static void addCharactersType(FlatBufferBuilder builder, int charactersTypeOffset) { builder.addOffset(2, charactersTypeOffset, 0); }
+ public static int createCharactersTypeVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+ public static void startCharactersTypeVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+ public static void addCharacters(FlatBufferBuilder builder, int charactersOffset) { builder.addOffset(3, charactersOffset, 0); }
+ public static int createCharactersVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+ public static void startCharactersVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+ public static int endMovie(FlatBufferBuilder builder) {
+ int o = builder.endTable();
+ return o;
+ }
+ public static void finishMovieBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MOVI"); }
+ public static void finishSizePrefixedMovieBuffer(FlatBufferBuilder builder, int offset) { builder.finishSizePrefixed(offset, "MOVI"); }
+}
+
diff --git a/tests/union_vector/Movie.kt b/tests/union_vector/Movie.kt
new file mode 100644
index 0000000..b8a135b
--- /dev/null
+++ b/tests/union_vector/Movie.kt
@@ -0,0 +1,114 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Movie : Table() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Movie {
+ __init(_i, _bb)
+ return this
+ }
+ val mainCharacterType : UByte
+ get() {
+ val o = __offset(4)
+ return if(o != 0) bb.get(o + bb_pos).toUByte() else 0u
+ }
+ fun mutateMainCharacterType(mainCharacterType: UByte) : Boolean {
+ val o = __offset(4)
+ return if (o != 0) {
+ bb.put(o + bb_pos, mainCharacterType.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ fun mainCharacter(obj: Table) : Table? {
+ val o = __offset(6); return if (o != 0) __union(obj, o) else null
+ }
+ fun charactersType(j: Int) : UByte {
+ val o = __offset(8)
+ return if (o != 0) {
+ bb.get(__vector(o) + j * 1).toUByte()
+ } else {
+ 0u
+ }
+ }
+ val charactersTypeLength : Int
+ get() {
+ val o = __offset(8); return if (o != 0) __vector_len(o) else 0
+ }
+ val charactersTypeAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(8, 1)
+ fun charactersTypeInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 8, 1)
+ fun mutateCharactersType(j: Int, charactersType: UByte) : Boolean {
+ val o = __offset(8)
+ return if (o != 0) {
+ bb.put(__vector(o) + j * 1, charactersType.toByte())
+ true
+ } else {
+ false
+ }
+ }
+ fun characters(obj: Table, j: Int) : Table? {
+ val o = __offset(10)
+ return if (o != 0) {
+ __union(obj, __vector(o) + j * 4 - bb_pos)
+ } else {
+ null
+ }
+ }
+ val charactersLength : Int
+ get() {
+ val o = __offset(10); return if (o != 0) __vector_len(o) else 0
+ }
+ companion object {
+ fun validateVersion() = Constants.FLATBUFFERS_1_11_1()
+ fun getRootAsMovie(_bb: ByteBuffer): Movie = getRootAsMovie(_bb, Movie())
+ fun getRootAsMovie(_bb: ByteBuffer, obj: Movie): Movie {
+ _bb.order(ByteOrder.LITTLE_ENDIAN)
+ return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
+ }
+ fun MovieBufferHasIdentifier(_bb: ByteBuffer) : Boolean = __has_identifier(_bb, "MOVI")
+ fun createMovie(builder: FlatBufferBuilder, mainCharacterType: UByte, mainCharacterOffset: Int, charactersTypeOffset: Int, charactersOffset: Int) : Int {
+ builder.startTable(4)
+ addCharacters(builder, charactersOffset)
+ addCharactersType(builder, charactersTypeOffset)
+ addMainCharacter(builder, mainCharacterOffset)
+ addMainCharacterType(builder, mainCharacterType)
+ return endMovie(builder)
+ }
+ fun startMovie(builder: FlatBufferBuilder) = builder.startTable(4)
+ fun addMainCharacterType(builder: FlatBufferBuilder, mainCharacterType: UByte) = builder.addByte(0, mainCharacterType.toByte(), 0)
+ fun addMainCharacter(builder: FlatBufferBuilder, mainCharacter: Int) = builder.addOffset(1, mainCharacter, 0)
+ fun addCharactersType(builder: FlatBufferBuilder, charactersType: Int) = builder.addOffset(2, charactersType, 0)
+ fun createCharactersTypeVector(builder: FlatBufferBuilder, data: UByteArray) : Int {
+ builder.startVector(1, data.size, 1)
+ for (i in data.size - 1 downTo 0) {
+ builder.addByte(data[i].toByte())
+ }
+ return builder.endVector()
+ }
+ fun startCharactersTypeVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(1, numElems, 1)
+ fun addCharacters(builder: FlatBufferBuilder, characters: Int) = builder.addOffset(3, characters, 0)
+ fun createCharactersVector(builder: FlatBufferBuilder, data: IntArray) : Int {
+ builder.startVector(4, data.size, 4)
+ for (i in data.size - 1 downTo 0) {
+ builder.addOffset(data[i])
+ }
+ return builder.endVector()
+ }
+ fun startCharactersVector(builder: FlatBufferBuilder, numElems: Int) = builder.startVector(4, numElems, 4)
+ fun endMovie(builder: FlatBufferBuilder) : Int {
+ val o = builder.endTable()
+ return o
+ }
+ fun finishMovieBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset, "MOVI")
+ fun finishSizePrefixedMovieBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset, "MOVI")
+ }
+}
diff --git a/tests/union_vector/Movie.php b/tests/union_vector/Movie.php
new file mode 100644
index 0000000..216cd28
--- /dev/null
+++ b/tests/union_vector/Movie.php
@@ -0,0 +1,220 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Movie extends Table
+{
+ /**
+ * @param ByteBuffer $bb
+ * @return Movie
+ */
+ public static function getRootAsMovie(ByteBuffer $bb)
+ {
+ $obj = new Movie();
+ return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+ }
+
+ public static function MovieIdentifier()
+ {
+ return "MOVI";
+ }
+
+ public static function MovieBufferHasIdentifier(ByteBuffer $buf)
+ {
+ return self::__has_identifier($buf, self::MovieIdentifier());
+ }
+
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Movie
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return byte
+ */
+ public function getMainCharacterType()
+ {
+ $o = $this->__offset(4);
+ return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \Character::NONE;
+ }
+
+ /**
+ * @returnint
+ */
+ public function getMainCharacter($obj)
+ {
+ $o = $this->__offset(6);
+ return $o != 0 ? $this->__union($obj, $o) : null;
+ }
+
+ /**
+ * @param int offset
+ * @return byte
+ */
+ public function getCharactersType($j)
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : \Character::NONE;
+ }
+
+ /**
+ * @return int
+ */
+ public function getCharactersTypeLength()
+ {
+ $o = $this->__offset(8);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param int offset
+ * @return Table
+ */
+ public function getCharacters($j, $obj)
+ {
+ $o = $this->__offset(10);
+ return $o != 0 ? $this->__union($obj, $this->__vector($o) + $j * 4 - $this->bb_pos) : null;
+ }
+
+ /**
+ * @return int
+ */
+ public function getCharactersLength()
+ {
+ $o = $this->__offset(10);
+ return $o != 0 ? $this->__vector_len($o) : 0;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return void
+ */
+ public static function startMovie(FlatBufferBuilder $builder)
+ {
+ $builder->StartObject(4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return Movie
+ */
+ public static function createMovie(FlatBufferBuilder $builder, $main_character_type, $main_character, $characters_type, $characters)
+ {
+ $builder->startObject(4);
+ self::addMainCharacterType($builder, $main_character_type);
+ self::addMainCharacter($builder, $main_character);
+ self::addCharactersType($builder, $characters_type);
+ self::addCharacters($builder, $characters);
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param byte
+ * @return void
+ */
+ public static function addMainCharacterType(FlatBufferBuilder $builder, $mainCharacterType)
+ {
+ $builder->addByteX(0, $mainCharacterType, 0);
+ }
+
+ public static function addMainCharacter(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->addOffsetX(1, $offset, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addCharactersType(FlatBufferBuilder $builder, $charactersType)
+ {
+ $builder->addOffsetX(2, $charactersType, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createCharactersTypeVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(1, count($data), 1);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putByte($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startCharactersTypeVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(1, $numElems, 1);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param VectorOffset
+ * @return void
+ */
+ public static function addCharacters(FlatBufferBuilder $builder, $characters)
+ {
+ $builder->addOffsetX(3, $characters, 0);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param array offset array
+ * @return int vector offset
+ */
+ public static function createCharactersVector(FlatBufferBuilder $builder, array $data)
+ {
+ $builder->startVector(4, count($data), 4);
+ for ($i = count($data) - 1; $i >= 0; $i--) {
+ $builder->putOffset($data[$i]);
+ }
+ return $builder->endVector();
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @param int $numElems
+ * @return void
+ */
+ public static function startCharactersVector(FlatBufferBuilder $builder, $numElems)
+ {
+ $builder->startVector(4, $numElems, 4);
+ }
+
+ /**
+ * @param FlatBufferBuilder $builder
+ * @return int table offset
+ */
+ public static function endMovie(FlatBufferBuilder $builder)
+ {
+ $o = $builder->endObject();
+ return $o;
+ }
+
+ public static function finishMovieBuffer(FlatBufferBuilder $builder, $offset)
+ {
+ $builder->finish($offset, "MOVI");
+ }
+}
diff --git a/tests/union_vector/Rapunzel.cs b/tests/union_vector/Rapunzel.cs
new file mode 100644
index 0000000..cb05d4a
--- /dev/null
+++ b/tests/union_vector/Rapunzel.cs
@@ -0,0 +1,24 @@
+// <auto-generated>
+// automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Rapunzel : IFlatbufferObject
+{
+ private Struct __p;
+ public ByteBuffer ByteBuffer { get { return __p.bb; } }
+ public void __init(int _i, ByteBuffer _bb) { __p = new Struct(_i, _bb); }
+ public Rapunzel __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int HairLength { get { return __p.bb.GetInt(__p.bb_pos + 0); } }
+ public void MutateHairLength(int hair_length) { __p.bb.PutInt(__p.bb_pos + 0, hair_length); }
+
+ public static Offset<Rapunzel> CreateRapunzel(FlatBufferBuilder builder, int HairLength) {
+ builder.Prep(4, 4);
+ builder.PutInt(HairLength);
+ return new Offset<Rapunzel>(builder.Offset);
+ }
+};
+
diff --git a/tests/union_vector/Rapunzel.java b/tests/union_vector/Rapunzel.java
new file mode 100644
index 0000000..852c061
--- /dev/null
+++ b/tests/union_vector/Rapunzel.java
@@ -0,0 +1,22 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Rapunzel extends Struct {
+ public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
+ public Rapunzel __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+ public int hairLength() { return bb.getInt(bb_pos + 0); }
+ public void mutateHairLength(int hair_length) { bb.putInt(bb_pos + 0, hair_length); }
+
+ public static int createRapunzel(FlatBufferBuilder builder, int hairLength) {
+ builder.prep(4, 4);
+ builder.putInt(hairLength);
+ return builder.offset();
+ }
+}
+
diff --git a/tests/union_vector/Rapunzel.kt b/tests/union_vector/Rapunzel.kt
new file mode 100644
index 0000000..080a7f7
--- /dev/null
+++ b/tests/union_vector/Rapunzel.kt
@@ -0,0 +1,27 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import java.nio.*
+import kotlin.math.sign
+import com.google.flatbuffers.*
+
+@Suppress("unused")
+@ExperimentalUnsignedTypes
+class Rapunzel : Struct() {
+
+ fun __init(_i: Int, _bb: ByteBuffer) {
+ __reset(_i, _bb)
+ }
+ fun __assign(_i: Int, _bb: ByteBuffer) : Rapunzel {
+ __init(_i, _bb)
+ return this
+ }
+ val hairLength : Int get() = bb.getInt(bb_pos + 0)
+ fun mutateHairLength(hairLength: Int) : ByteBuffer = bb.putInt(bb_pos + 0, hairLength)
+ companion object {
+ fun createRapunzel(builder: FlatBufferBuilder, hairLength: Int) : Int {
+ builder.prep(4, 4)
+ builder.putInt(hairLength)
+ return builder.offset()
+ }
+ }
+}
diff --git a/tests/union_vector/Rapunzel.php b/tests/union_vector/Rapunzel.php
new file mode 100644
index 0000000..9842d95
--- /dev/null
+++ b/tests/union_vector/Rapunzel.php
@@ -0,0 +1,41 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Rapunzel extends Struct
+{
+ /**
+ * @param int $_i offset
+ * @param ByteBuffer $_bb
+ * @return Rapunzel
+ **/
+ public function init($_i, ByteBuffer $_bb)
+ {
+ $this->bb_pos = $_i;
+ $this->bb = $_bb;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function GetHairLength()
+ {
+ return $this->bb->getInt($this->bb_pos + 0);
+ }
+
+
+ /**
+ * @return int offset
+ */
+ public static function createRapunzel(FlatBufferBuilder $builder, $hairLength)
+ {
+ $builder->prep(4, 4);
+ $builder->putInt($hairLength);
+ return $builder->offset();
+ }
+}
diff --git a/tests/union_vector/union_vector.fbs b/tests/union_vector/union_vector.fbs
new file mode 100644
index 0000000..495076f
--- /dev/null
+++ b/tests/union_vector/union_vector.fbs
@@ -0,0 +1,31 @@
+// Demonstrates the ability to have vectors of unions, and also to
+// store structs and strings in unions.
+
+table Attacker {
+ sword_attack_damage: int;
+}
+
+struct Rapunzel {
+ hair_length: int;
+}
+
+struct BookReader {
+ books_read: int;
+}
+
+union Character {
+ MuLan: Attacker, // Can have name be different from type.
+ Rapunzel, // Or just both the same, as before.
+ Belle: BookReader,
+ BookFan: BookReader,
+ Other: string,
+ Unused: string
+}
+
+table Movie {
+ main_character: Character;
+ characters: [Character];
+}
+
+root_type Movie;
+file_identifier "MOVI";
diff --git a/tests/union_vector/union_vector.json b/tests/union_vector/union_vector.json
new file mode 100644
index 0000000..af0c9cb
--- /dev/null
+++ b/tests/union_vector/union_vector.json
@@ -0,0 +1,26 @@
+{
+ "main_character_type": "Rapunzel",
+ "main_character": {
+ "hair_length": 6
+ },
+ "characters_type": [
+ "Belle",
+ "MuLan",
+ "BookFan",
+ "Other",
+ "Unused"
+ ],
+ "characters": [
+ {
+ "books_read": 7
+ },
+ {
+ "sword_attack_damage": 5
+ },
+ {
+ "books_read": 2
+ },
+ "Other",
+ "Unused"
+ ]
+}
diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h
new file mode 100644
index 0000000..150c8f4
--- /dev/null
+++ b/tests/union_vector/union_vector_generated.h
@@ -0,0 +1,859 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+
+#ifndef FLATBUFFERS_GENERATED_UNIONVECTOR_H_
+#define FLATBUFFERS_GENERATED_UNIONVECTOR_H_
+
+#include "flatbuffers/flatbuffers.h"
+
+struct Attacker;
+struct AttackerT;
+
+struct Rapunzel;
+
+struct BookReader;
+
+struct Movie;
+struct MovieT;
+
+bool operator==(const AttackerT &lhs, const AttackerT &rhs);
+bool operator!=(const AttackerT &lhs, const AttackerT &rhs);
+bool operator==(const Rapunzel &lhs, const Rapunzel &rhs);
+bool operator!=(const Rapunzel &lhs, const Rapunzel &rhs);
+bool operator==(const BookReader &lhs, const BookReader &rhs);
+bool operator!=(const BookReader &lhs, const BookReader &rhs);
+bool operator==(const MovieT &lhs, const MovieT &rhs);
+bool operator!=(const MovieT &lhs, const MovieT &rhs);
+
+inline const flatbuffers::TypeTable *AttackerTypeTable();
+
+inline const flatbuffers::TypeTable *RapunzelTypeTable();
+
+inline const flatbuffers::TypeTable *BookReaderTypeTable();
+
+inline const flatbuffers::TypeTable *MovieTypeTable();
+
+enum Character {
+ Character_NONE = 0,
+ Character_MuLan = 1,
+ Character_Rapunzel = 2,
+ Character_Belle = 3,
+ Character_BookFan = 4,
+ Character_Other = 5,
+ Character_Unused = 6,
+ Character_MIN = Character_NONE,
+ Character_MAX = Character_Unused
+};
+
+inline const Character (&EnumValuesCharacter())[7] {
+ static const Character values[] = {
+ Character_NONE,
+ Character_MuLan,
+ Character_Rapunzel,
+ Character_Belle,
+ Character_BookFan,
+ Character_Other,
+ Character_Unused
+ };
+ return values;
+}
+
+inline const char * const *EnumNamesCharacter() {
+ static const char * const names[8] = {
+ "NONE",
+ "MuLan",
+ "Rapunzel",
+ "Belle",
+ "BookFan",
+ "Other",
+ "Unused",
+ nullptr
+ };
+ return names;
+}
+
+inline const char *EnumNameCharacter(Character e) {
+ if (e < Character_NONE || e > Character_Unused) return "";
+ const size_t index = static_cast<size_t>(e);
+ return EnumNamesCharacter()[index];
+}
+
+struct CharacterUnion {
+ Character type;
+ void *value;
+
+ CharacterUnion() : type(Character_NONE), value(nullptr) {}
+ CharacterUnion(CharacterUnion&& u) FLATBUFFERS_NOEXCEPT :
+ type(Character_NONE), value(nullptr)
+ { std::swap(type, u.type); std::swap(value, u.value); }
+ CharacterUnion(const CharacterUnion &) FLATBUFFERS_NOEXCEPT;
+ CharacterUnion &operator=(const CharacterUnion &u) FLATBUFFERS_NOEXCEPT
+ { CharacterUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+ CharacterUnion &operator=(CharacterUnion &&u) FLATBUFFERS_NOEXCEPT
+ { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+ ~CharacterUnion() { Reset(); }
+
+ void Reset();
+
+ static void *UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver);
+ flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+ AttackerT *AsMuLan() {
+ return type == Character_MuLan ?
+ reinterpret_cast<AttackerT *>(value) : nullptr;
+ }
+ const AttackerT *AsMuLan() const {
+ return type == Character_MuLan ?
+ reinterpret_cast<const AttackerT *>(value) : nullptr;
+ }
+ Rapunzel *AsRapunzel() {
+ return type == Character_Rapunzel ?
+ reinterpret_cast<Rapunzel *>(value) : nullptr;
+ }
+ const Rapunzel *AsRapunzel() const {
+ return type == Character_Rapunzel ?
+ reinterpret_cast<const Rapunzel *>(value) : nullptr;
+ }
+ BookReader *AsBelle() {
+ return type == Character_Belle ?
+ reinterpret_cast<BookReader *>(value) : nullptr;
+ }
+ const BookReader *AsBelle() const {
+ return type == Character_Belle ?
+ reinterpret_cast<const BookReader *>(value) : nullptr;
+ }
+ BookReader *AsBookFan() {
+ return type == Character_BookFan ?
+ reinterpret_cast<BookReader *>(value) : nullptr;
+ }
+ const BookReader *AsBookFan() const {
+ return type == Character_BookFan ?
+ reinterpret_cast<const BookReader *>(value) : nullptr;
+ }
+ std::string *AsOther() {
+ return type == Character_Other ?
+ reinterpret_cast<std::string *>(value) : nullptr;
+ }
+ const std::string *AsOther() const {
+ return type == Character_Other ?
+ reinterpret_cast<const std::string *>(value) : nullptr;
+ }
+ std::string *AsUnused() {
+ return type == Character_Unused ?
+ reinterpret_cast<std::string *>(value) : nullptr;
+ }
+ const std::string *AsUnused() const {
+ return type == Character_Unused ?
+ reinterpret_cast<const std::string *>(value) : nullptr;
+ }
+};
+
+
+inline bool operator==(const CharacterUnion &lhs, const CharacterUnion &rhs) {
+ if (lhs.type != rhs.type) return false;
+ switch (lhs.type) {
+ case Character_NONE: {
+ return true;
+ }
+ case Character_MuLan: {
+ return *(reinterpret_cast<const AttackerT *>(lhs.value)) ==
+ *(reinterpret_cast<const AttackerT *>(rhs.value));
+ }
+ case Character_Rapunzel: {
+ return *(reinterpret_cast<const Rapunzel *>(lhs.value)) ==
+ *(reinterpret_cast<const Rapunzel *>(rhs.value));
+ }
+ case Character_Belle: {
+ return *(reinterpret_cast<const BookReader *>(lhs.value)) ==
+ *(reinterpret_cast<const BookReader *>(rhs.value));
+ }
+ case Character_BookFan: {
+ return *(reinterpret_cast<const BookReader *>(lhs.value)) ==
+ *(reinterpret_cast<const BookReader *>(rhs.value));
+ }
+ case Character_Other: {
+ return *(reinterpret_cast<const std::string *>(lhs.value)) ==
+ *(reinterpret_cast<const std::string *>(rhs.value));
+ }
+ case Character_Unused: {
+ return *(reinterpret_cast<const std::string *>(lhs.value)) ==
+ *(reinterpret_cast<const std::string *>(rhs.value));
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+inline bool operator!=(const CharacterUnion &lhs, const CharacterUnion &rhs) {
+ return !(lhs == rhs);
+}
+
+bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type);
+bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) Rapunzel FLATBUFFERS_FINAL_CLASS {
+ private:
+ int32_t hair_length_;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return RapunzelTypeTable();
+ }
+ Rapunzel() {
+ memset(static_cast<void *>(this), 0, sizeof(Rapunzel));
+ }
+ Rapunzel(int32_t _hair_length)
+ : hair_length_(flatbuffers::EndianScalar(_hair_length)) {
+ }
+ int32_t hair_length() const {
+ return flatbuffers::EndianScalar(hair_length_);
+ }
+ void mutate_hair_length(int32_t _hair_length) {
+ flatbuffers::WriteScalar(&hair_length_, _hair_length);
+ }
+};
+FLATBUFFERS_STRUCT_END(Rapunzel, 4);
+
+inline bool operator==(const Rapunzel &lhs, const Rapunzel &rhs) {
+ return
+ (lhs.hair_length() == rhs.hair_length());
+}
+
+inline bool operator!=(const Rapunzel &lhs, const Rapunzel &rhs) {
+ return !(lhs == rhs);
+}
+
+
+FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(4) BookReader FLATBUFFERS_FINAL_CLASS {
+ private:
+ int32_t books_read_;
+
+ public:
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return BookReaderTypeTable();
+ }
+ BookReader() {
+ memset(static_cast<void *>(this), 0, sizeof(BookReader));
+ }
+ BookReader(int32_t _books_read)
+ : books_read_(flatbuffers::EndianScalar(_books_read)) {
+ }
+ int32_t books_read() const {
+ return flatbuffers::EndianScalar(books_read_);
+ }
+ void mutate_books_read(int32_t _books_read) {
+ flatbuffers::WriteScalar(&books_read_, _books_read);
+ }
+};
+FLATBUFFERS_STRUCT_END(BookReader, 4);
+
+inline bool operator==(const BookReader &lhs, const BookReader &rhs) {
+ return
+ (lhs.books_read() == rhs.books_read());
+}
+
+inline bool operator!=(const BookReader &lhs, const BookReader &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct AttackerT : public flatbuffers::NativeTable {
+ typedef Attacker TableType;
+ int32_t sword_attack_damage;
+ AttackerT()
+ : sword_attack_damage(0) {
+ }
+};
+
+inline bool operator==(const AttackerT &lhs, const AttackerT &rhs) {
+ return
+ (lhs.sword_attack_damage == rhs.sword_attack_damage);
+}
+
+inline bool operator!=(const AttackerT &lhs, const AttackerT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Attacker FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef AttackerT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return AttackerTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_SWORD_ATTACK_DAMAGE = 4
+ };
+ int32_t sword_attack_damage() const {
+ return GetField<int32_t>(VT_SWORD_ATTACK_DAMAGE, 0);
+ }
+ bool mutate_sword_attack_damage(int32_t _sword_attack_damage) {
+ return SetField<int32_t>(VT_SWORD_ATTACK_DAMAGE, _sword_attack_damage, 0);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<int32_t>(verifier, VT_SWORD_ATTACK_DAMAGE) &&
+ verifier.EndTable();
+ }
+ AttackerT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Attacker> Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct AttackerBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_sword_attack_damage(int32_t sword_attack_damage) {
+ fbb_.AddElement<int32_t>(Attacker::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0);
+ }
+ explicit AttackerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ AttackerBuilder &operator=(const AttackerBuilder &);
+ flatbuffers::Offset<Attacker> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Attacker>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Attacker> CreateAttacker(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ int32_t sword_attack_damage = 0) {
+ AttackerBuilder builder_(_fbb);
+ builder_.add_sword_attack_damage(sword_attack_damage);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<Attacker> CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct MovieT : public flatbuffers::NativeTable {
+ typedef Movie TableType;
+ CharacterUnion main_character;
+ std::vector<CharacterUnion> characters;
+ MovieT() {
+ }
+};
+
+inline bool operator==(const MovieT &lhs, const MovieT &rhs) {
+ return
+ (lhs.main_character == rhs.main_character) &&
+ (lhs.characters == rhs.characters);
+}
+
+inline bool operator!=(const MovieT &lhs, const MovieT &rhs) {
+ return !(lhs == rhs);
+}
+
+
+struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef MovieT NativeTableType;
+ static const flatbuffers::TypeTable *MiniReflectTypeTable() {
+ return MovieTypeTable();
+ }
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_MAIN_CHARACTER_TYPE = 4,
+ VT_MAIN_CHARACTER = 6,
+ VT_CHARACTERS_TYPE = 8,
+ VT_CHARACTERS = 10
+ };
+ Character main_character_type() const {
+ return static_cast<Character>(GetField<uint8_t>(VT_MAIN_CHARACTER_TYPE, 0));
+ }
+ bool mutate_main_character_type(Character _main_character_type) {
+ return SetField<uint8_t>(VT_MAIN_CHARACTER_TYPE, static_cast<uint8_t>(_main_character_type), 0);
+ }
+ const void *main_character() const {
+ return GetPointer<const void *>(VT_MAIN_CHARACTER);
+ }
+ const Attacker *main_character_as_MuLan() const {
+ return main_character_type() == Character_MuLan ? static_cast<const Attacker *>(main_character()) : nullptr;
+ }
+ const Rapunzel *main_character_as_Rapunzel() const {
+ return main_character_type() == Character_Rapunzel ? static_cast<const Rapunzel *>(main_character()) : nullptr;
+ }
+ const BookReader *main_character_as_Belle() const {
+ return main_character_type() == Character_Belle ? static_cast<const BookReader *>(main_character()) : nullptr;
+ }
+ const BookReader *main_character_as_BookFan() const {
+ return main_character_type() == Character_BookFan ? static_cast<const BookReader *>(main_character()) : nullptr;
+ }
+ const flatbuffers::String *main_character_as_Other() const {
+ return main_character_type() == Character_Other ? static_cast<const flatbuffers::String *>(main_character()) : nullptr;
+ }
+ const flatbuffers::String *main_character_as_Unused() const {
+ return main_character_type() == Character_Unused ? static_cast<const flatbuffers::String *>(main_character()) : nullptr;
+ }
+ void *mutable_main_character() {
+ return GetPointer<void *>(VT_MAIN_CHARACTER);
+ }
+ const flatbuffers::Vector<uint8_t> *characters_type() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CHARACTERS_TYPE);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_characters_type() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_CHARACTERS_TYPE);
+ }
+ const flatbuffers::Vector<flatbuffers::Offset<void>> *characters() const {
+ return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<void>> *>(VT_CHARACTERS);
+ }
+ flatbuffers::Vector<flatbuffers::Offset<void>> *mutable_characters() {
+ return GetPointer<flatbuffers::Vector<flatbuffers::Offset<void>> *>(VT_CHARACTERS);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint8_t>(verifier, VT_MAIN_CHARACTER_TYPE) &&
+ VerifyOffset(verifier, VT_MAIN_CHARACTER) &&
+ VerifyCharacter(verifier, main_character(), main_character_type()) &&
+ VerifyOffset(verifier, VT_CHARACTERS_TYPE) &&
+ verifier.VerifyVector(characters_type()) &&
+ VerifyOffset(verifier, VT_CHARACTERS) &&
+ verifier.VerifyVector(characters()) &&
+ VerifyCharacterVector(verifier, characters(), characters_type()) &&
+ verifier.EndTable();
+ }
+ MovieT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<Movie> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct MovieBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_main_character_type(Character main_character_type) {
+ fbb_.AddElement<uint8_t>(Movie::VT_MAIN_CHARACTER_TYPE, static_cast<uint8_t>(main_character_type), 0);
+ }
+ void add_main_character(flatbuffers::Offset<void> main_character) {
+ fbb_.AddOffset(Movie::VT_MAIN_CHARACTER, main_character);
+ }
+ void add_characters_type(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> characters_type) {
+ fbb_.AddOffset(Movie::VT_CHARACTERS_TYPE, characters_type);
+ }
+ void add_characters(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> characters) {
+ fbb_.AddOffset(Movie::VT_CHARACTERS, characters);
+ }
+ explicit MovieBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ MovieBuilder &operator=(const MovieBuilder &);
+ flatbuffers::Offset<Movie> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<Movie>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<Movie> CreateMovie(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ Character main_character_type = Character_NONE,
+ flatbuffers::Offset<void> main_character = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> characters_type = 0,
+ flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> characters = 0) {
+ MovieBuilder builder_(_fbb);
+ builder_.add_characters(characters);
+ builder_.add_characters_type(characters_type);
+ builder_.add_main_character(main_character);
+ builder_.add_main_character_type(main_character_type);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<Movie> CreateMovieDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ Character main_character_type = Character_NONE,
+ flatbuffers::Offset<void> main_character = 0,
+ const std::vector<uint8_t> *characters_type = nullptr,
+ const std::vector<flatbuffers::Offset<void>> *characters = nullptr) {
+ auto characters_type__ = characters_type ? _fbb.CreateVector<uint8_t>(*characters_type) : 0;
+ auto characters__ = characters ? _fbb.CreateVector<flatbuffers::Offset<void>>(*characters) : 0;
+ return CreateMovie(
+ _fbb,
+ main_character_type,
+ main_character,
+ characters_type__,
+ characters__);
+}
+
+flatbuffers::Offset<Movie> CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline AttackerT *Attacker::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new AttackerT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Attacker::UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = sword_attack_damage(); _o->sword_attack_damage = _e; };
+}
+
+inline flatbuffers::Offset<Attacker> Attacker::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateAttacker(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Attacker> CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AttackerT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _sword_attack_damage = _o->sword_attack_damage;
+ return CreateAttacker(
+ _fbb,
+ _sword_attack_damage);
+}
+
+inline MovieT *Movie::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new MovieT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void Movie::UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = main_character_type(); _o->main_character.type = _e; };
+ { auto _e = main_character(); if (_e) _o->main_character.value = CharacterUnion::UnPack(_e, main_character_type(), _resolver); };
+ { auto _e = characters_type(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].type = static_cast<Character>(_e->Get(_i)); } } };
+ { auto _e = characters(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].value = CharacterUnion::UnPack(_e->Get(_i), characters_type()->GetEnum<Character>(_i), _resolver); } } };
+}
+
+inline flatbuffers::Offset<Movie> Movie::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateMovie(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Movie> CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MovieT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+ auto _main_character_type = _o->main_character.type;
+ auto _main_character = _o->main_character.Pack(_fbb);
+ auto _characters_type = _o->characters.size() ? _fbb.CreateVector<uint8_t>(_o->characters.size(), [](size_t i, _VectorArgs *__va) { return static_cast<uint8_t>(__va->__o->characters[i].type); }, &_va) : 0;
+ auto _characters = _o->characters.size() ? _fbb.CreateVector<flatbuffers::Offset<void>>(_o->characters.size(), [](size_t i, _VectorArgs *__va) { return __va->__o->characters[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va) : 0;
+ return CreateMovie(
+ _fbb,
+ _main_character_type,
+ _main_character,
+ _characters_type,
+ _characters);
+}
+
+inline bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type) {
+ switch (type) {
+ case Character_NONE: {
+ return true;
+ }
+ case Character_MuLan: {
+ auto ptr = reinterpret_cast<const Attacker *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case Character_Rapunzel: {
+ return verifier.Verify<Rapunzel>(static_cast<const uint8_t *>(obj), 0);
+ }
+ case Character_Belle: {
+ return verifier.Verify<BookReader>(static_cast<const uint8_t *>(obj), 0);
+ }
+ case Character_BookFan: {
+ return verifier.Verify<BookReader>(static_cast<const uint8_t *>(obj), 0);
+ }
+ case Character_Other: {
+ auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+ return verifier.VerifyString(ptr);
+ }
+ case Character_Unused: {
+ auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+ return verifier.VerifyString(ptr);
+ }
+ default: return false;
+ }
+}
+
+inline bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) {
+ if (!values || !types) return !values && !types;
+ if (values->size() != types->size()) return false;
+ for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {
+ if (!VerifyCharacter(
+ verifier, values->Get(i), types->GetEnum<Character>(i))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline void *CharacterUnion::UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver) {
+ switch (type) {
+ case Character_MuLan: {
+ auto ptr = reinterpret_cast<const Attacker *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case Character_Rapunzel: {
+ auto ptr = reinterpret_cast<const Rapunzel *>(obj);
+ return new Rapunzel(*ptr);
+ }
+ case Character_Belle: {
+ auto ptr = reinterpret_cast<const BookReader *>(obj);
+ return new BookReader(*ptr);
+ }
+ case Character_BookFan: {
+ auto ptr = reinterpret_cast<const BookReader *>(obj);
+ return new BookReader(*ptr);
+ }
+ case Character_Other: {
+ auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+ return new std::string(ptr->c_str(), ptr->size());
+ }
+ case Character_Unused: {
+ auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+ return new std::string(ptr->c_str(), ptr->size());
+ }
+ default: return nullptr;
+ }
+}
+
+inline flatbuffers::Offset<void> CharacterUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+ switch (type) {
+ case Character_MuLan: {
+ auto ptr = reinterpret_cast<const AttackerT *>(value);
+ return CreateAttacker(_fbb, ptr, _rehasher).Union();
+ }
+ case Character_Rapunzel: {
+ auto ptr = reinterpret_cast<const Rapunzel *>(value);
+ return _fbb.CreateStruct(*ptr).Union();
+ }
+ case Character_Belle: {
+ auto ptr = reinterpret_cast<const BookReader *>(value);
+ return _fbb.CreateStruct(*ptr).Union();
+ }
+ case Character_BookFan: {
+ auto ptr = reinterpret_cast<const BookReader *>(value);
+ return _fbb.CreateStruct(*ptr).Union();
+ }
+ case Character_Other: {
+ auto ptr = reinterpret_cast<const std::string *>(value);
+ return _fbb.CreateString(*ptr).Union();
+ }
+ case Character_Unused: {
+ auto ptr = reinterpret_cast<const std::string *>(value);
+ return _fbb.CreateString(*ptr).Union();
+ }
+ default: return 0;
+ }
+}
+
+inline CharacterUnion::CharacterUnion(const CharacterUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+ switch (type) {
+ case Character_MuLan: {
+ value = new AttackerT(*reinterpret_cast<AttackerT *>(u.value));
+ break;
+ }
+ case Character_Rapunzel: {
+ value = new Rapunzel(*reinterpret_cast<Rapunzel *>(u.value));
+ break;
+ }
+ case Character_Belle: {
+ value = new BookReader(*reinterpret_cast<BookReader *>(u.value));
+ break;
+ }
+ case Character_BookFan: {
+ value = new BookReader(*reinterpret_cast<BookReader *>(u.value));
+ break;
+ }
+ case Character_Other: {
+ value = new std::string(*reinterpret_cast<std::string *>(u.value));
+ break;
+ }
+ case Character_Unused: {
+ value = new std::string(*reinterpret_cast<std::string *>(u.value));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+inline void CharacterUnion::Reset() {
+ switch (type) {
+ case Character_MuLan: {
+ auto ptr = reinterpret_cast<AttackerT *>(value);
+ delete ptr;
+ break;
+ }
+ case Character_Rapunzel: {
+ auto ptr = reinterpret_cast<Rapunzel *>(value);
+ delete ptr;
+ break;
+ }
+ case Character_Belle: {
+ auto ptr = reinterpret_cast<BookReader *>(value);
+ delete ptr;
+ break;
+ }
+ case Character_BookFan: {
+ auto ptr = reinterpret_cast<BookReader *>(value);
+ delete ptr;
+ break;
+ }
+ case Character_Other: {
+ auto ptr = reinterpret_cast<std::string *>(value);
+ delete ptr;
+ break;
+ }
+ case Character_Unused: {
+ auto ptr = reinterpret_cast<std::string *>(value);
+ delete ptr;
+ break;
+ }
+ default: break;
+ }
+ value = nullptr;
+ type = Character_NONE;
+}
+
+inline const flatbuffers::TypeTable *CharacterTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_SEQUENCE, 0, -1 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 1 },
+ { flatbuffers::ET_SEQUENCE, 0, 2 },
+ { flatbuffers::ET_SEQUENCE, 0, 2 },
+ { flatbuffers::ET_STRING, 0, -1 },
+ { flatbuffers::ET_STRING, 0, -1 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ AttackerTypeTable,
+ RapunzelTypeTable,
+ BookReaderTypeTable
+ };
+ static const char * const names[] = {
+ "NONE",
+ "MuLan",
+ "Rapunzel",
+ "Belle",
+ "BookFan",
+ "Other",
+ "Unused"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_UNION, 7, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *AttackerTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_INT, 0, -1 }
+ };
+ static const char * const names[] = {
+ "sword_attack_damage"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *RapunzelTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_INT, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 4 };
+ static const char * const names[] = {
+ "hair_length"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 1, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *BookReaderTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_INT, 0, -1 }
+ };
+ static const int64_t values[] = { 0, 4 };
+ static const char * const names[] = {
+ "books_read"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_STRUCT, 1, type_codes, nullptr, values, names
+ };
+ return &tt;
+}
+
+inline const flatbuffers::TypeTable *MovieTypeTable() {
+ static const flatbuffers::TypeCode type_codes[] = {
+ { flatbuffers::ET_UTYPE, 0, 0 },
+ { flatbuffers::ET_SEQUENCE, 0, 0 },
+ { flatbuffers::ET_UTYPE, 1, 0 },
+ { flatbuffers::ET_SEQUENCE, 1, 0 }
+ };
+ static const flatbuffers::TypeFunction type_refs[] = {
+ CharacterTypeTable
+ };
+ static const char * const names[] = {
+ "main_character_type",
+ "main_character",
+ "characters_type",
+ "characters"
+ };
+ static const flatbuffers::TypeTable tt = {
+ flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, names
+ };
+ return &tt;
+}
+
+inline const Movie *GetMovie(const void *buf) {
+ return flatbuffers::GetRoot<Movie>(buf);
+}
+
+inline const Movie *GetSizePrefixedMovie(const void *buf) {
+ return flatbuffers::GetSizePrefixedRoot<Movie>(buf);
+}
+
+inline Movie *GetMutableMovie(void *buf) {
+ return flatbuffers::GetMutableRoot<Movie>(buf);
+}
+
+inline const char *MovieIdentifier() {
+ return "MOVI";
+}
+
+inline bool MovieBufferHasIdentifier(const void *buf) {
+ return flatbuffers::BufferHasIdentifier(
+ buf, MovieIdentifier());
+}
+
+inline bool VerifyMovieBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifyBuffer<Movie>(MovieIdentifier());
+}
+
+inline bool VerifySizePrefixedMovieBuffer(
+ flatbuffers::Verifier &verifier) {
+ return verifier.VerifySizePrefixedBuffer<Movie>(MovieIdentifier());
+}
+
+inline void FinishMovieBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<Movie> root) {
+ fbb.Finish(root, MovieIdentifier());
+}
+
+inline void FinishSizePrefixedMovieBuffer(
+ flatbuffers::FlatBufferBuilder &fbb,
+ flatbuffers::Offset<Movie> root) {
+ fbb.FinishSizePrefixed(root, MovieIdentifier());
+}
+
+inline flatbuffers::unique_ptr<MovieT> UnPackMovie(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MovieT>(GetMovie(buf)->UnPack(res));
+}
+
+inline flatbuffers::unique_ptr<MovieT> UnPackSizePrefixedMovie(
+ const void *buf,
+ const flatbuffers::resolver_function_t *res = nullptr) {
+ return flatbuffers::unique_ptr<MovieT>(GetSizePrefixedMovie(buf)->UnPack(res));
+}
+
+#endif // FLATBUFFERS_GENERATED_UNIONVECTOR_H_
diff --git a/tests/union_vector/union_vector_generated.js b/tests/union_vector/union_vector_generated.js
new file mode 100644
index 0000000..406cb2f
--- /dev/null
+++ b/tests/union_vector/union_vector_generated.js
@@ -0,0 +1,505 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum {number}
+ */
+var Character = {
+ NONE: 0,
+ MuLan: 1,
+ Rapunzel: 2,
+ Belle: 3,
+ BookFan: 4,
+ Other: 5,
+ Unused: 6
+};
+
+/**
+ * @enum {string}
+ */
+var CharacterName = {
+ 0: 'NONE',
+ 1: 'MuLan',
+ 2: 'Rapunzel',
+ 3: 'Belle',
+ 4: 'BookFan',
+ 5: 'Other',
+ 6: 'Unused'
+};
+
+/**
+ * @constructor
+ */
+function Attacker() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Attacker}
+ */
+Attacker.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Attacker=} obj
+ * @returns {Attacker}
+ */
+Attacker.getRootAsAttacker = function(bb, obj) {
+ return (obj || new Attacker).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Attacker=} obj
+ * @returns {Attacker}
+ */
+Attacker.getSizePrefixedRootAsAttacker = function(bb, obj) {
+ return (obj || new Attacker).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+Attacker.prototype.swordAttackDamage = function() {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+Attacker.prototype.mutate_sword_attack_damage = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+Attacker.startAttacker = function(builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} swordAttackDamage
+ */
+Attacker.addSwordAttackDamage = function(builder, swordAttackDamage) {
+ builder.addFieldInt32(0, swordAttackDamage, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+Attacker.endAttacker = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} swordAttackDamage
+ * @returns {flatbuffers.Offset}
+ */
+Attacker.createAttacker = function(builder, swordAttackDamage) {
+ Attacker.startAttacker(builder);
+ Attacker.addSwordAttackDamage(builder, swordAttackDamage);
+ return Attacker.endAttacker(builder);
+}
+
+/**
+ * @constructor
+ */
+function Rapunzel() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Rapunzel}
+ */
+Rapunzel.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns {number}
+ */
+Rapunzel.prototype.hairLength = function() {
+ return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+Rapunzel.prototype.mutate_hair_length = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} hair_length
+ * @returns {flatbuffers.Offset}
+ */
+Rapunzel.createRapunzel = function(builder, hair_length) {
+ builder.prep(4, 4);
+ builder.writeInt32(hair_length);
+ return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+function BookReader() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {BookReader}
+ */
+BookReader.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns {number}
+ */
+BookReader.prototype.booksRead = function() {
+ return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+BookReader.prototype.mutate_books_read = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} books_read
+ * @returns {flatbuffers.Offset}
+ */
+BookReader.createBookReader = function(builder, books_read) {
+ builder.prep(4, 4);
+ builder.writeInt32(books_read);
+ return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+function Movie() {
+ /**
+ * @type {flatbuffers.ByteBuffer}
+ */
+ this.bb = null;
+
+ /**
+ * @type {number}
+ */
+ this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Movie}
+ */
+Movie.prototype.__init = function(i, bb) {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Movie=} obj
+ * @returns {Movie}
+ */
+Movie.getRootAsMovie = function(bb, obj) {
+ return (obj || new Movie).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Movie=} obj
+ * @returns {Movie}
+ */
+Movie.getSizePrefixedRootAsMovie = function(bb, obj) {
+ return (obj || new Movie).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {boolean}
+ */
+Movie.bufferHasIdentifier = function(bb) {
+ return bb.__has_identifier('MOVI');
+};
+
+/**
+ * @returns {Character}
+ */
+Movie.prototype.mainCharacterType = function() {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+ return offset ? /** @type {Character} */ (this.bb.readUint8(this.bb_pos + offset)) : Character.NONE;
+};
+
+/**
+ * @param {Character} value
+ * @returns {boolean}
+ */
+Movie.prototype.mutate_main_character_type = function(value) {
+ var offset = this.bb.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+Movie.prototype.mainCharacter = function(obj) {
+ var offset = this.bb.__offset(this.bb_pos, 6);
+ return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {Character}
+ */
+Movie.prototype.charactersType = function(index) {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? /** @type {Character} */ (this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index)) : /** @type {Character} */ (0);
+};
+
+/**
+ * @returns {number}
+ */
+Movie.prototype.charactersTypeLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+Movie.prototype.charactersTypeArray = function() {
+ var offset = this.bb.__offset(this.bb_pos, 8);
+ return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Table=} obj
+ * @returns {?flatbuffers.Table}
+ */
+Movie.prototype.characters = function(index, obj) {
+ var offset = this.bb.__offset(this.bb_pos, 10);
+ return offset ? this.bb.__union(obj, this.bb.__vector(this.bb_pos + offset) + index * 4) : null;
+};
+
+/**
+ * @returns {number}
+ */
+Movie.prototype.charactersLength = function() {
+ var offset = this.bb.__offset(this.bb_pos, 10);
+ return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+Movie.startMovie = function(builder) {
+ builder.startObject(4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Character} mainCharacterType
+ */
+Movie.addMainCharacterType = function(builder, mainCharacterType) {
+ builder.addFieldInt8(0, mainCharacterType, Character.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} mainCharacterOffset
+ */
+Movie.addMainCharacter = function(builder, mainCharacterOffset) {
+ builder.addFieldOffset(1, mainCharacterOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} charactersTypeOffset
+ */
+Movie.addCharactersType = function(builder, charactersTypeOffset) {
+ builder.addFieldOffset(2, charactersTypeOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<Character>} data
+ * @returns {flatbuffers.Offset}
+ */
+Movie.createCharactersTypeVector = function(builder, data) {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+Movie.startCharactersTypeVector = function(builder, numElems) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} charactersOffset
+ */
+Movie.addCharacters = function(builder, charactersOffset) {
+ builder.addFieldOffset(3, charactersOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+Movie.createCharactersVector = function(builder, data) {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+Movie.startCharactersVector = function(builder, numElems) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+Movie.endMovie = function(builder) {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+Movie.finishMovieBuffer = function(builder, offset) {
+ builder.finish(offset, 'MOVI');
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+Movie.finishSizePrefixedMovieBuffer = function(builder, offset) {
+ builder.finish(offset, 'MOVI', true);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Character} mainCharacterType
+ * @param {flatbuffers.Offset} mainCharacterOffset
+ * @param {flatbuffers.Offset} charactersTypeOffset
+ * @param {flatbuffers.Offset} charactersOffset
+ * @returns {flatbuffers.Offset}
+ */
+Movie.createMovie = function(builder, mainCharacterType, mainCharacterOffset, charactersTypeOffset, charactersOffset) {
+ Movie.startMovie(builder);
+ Movie.addMainCharacterType(builder, mainCharacterType);
+ Movie.addMainCharacter(builder, mainCharacterOffset);
+ Movie.addCharactersType(builder, charactersTypeOffset);
+ Movie.addCharacters(builder, charactersOffset);
+ return Movie.endMovie(builder);
+}
+
+// Exports for Node.js and RequireJS
+this.Character = Character;
+this.CharacterName = CharacterName;
+this.Attacker = Attacker;
+this.Rapunzel = Rapunzel;
+this.BookReader = BookReader;
+this.Movie = Movie;
diff --git a/tests/union_vector/union_vector_generated.ts b/tests/union_vector/union_vector_generated.ts
new file mode 100644
index 0000000..642f672
--- /dev/null
+++ b/tests/union_vector/union_vector_generated.ts
@@ -0,0 +1,442 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum {number}
+ */
+export enum Character{
+ NONE= 0,
+ MuLan= 1,
+ Rapunzel= 2,
+ Belle= 3,
+ BookFan= 4,
+ Other= 5,
+ Unused= 6
+};
+
+/**
+ * @constructor
+ */
+export class Attacker {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Attacker
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Attacker {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Attacker= obj
+ * @returns Attacker
+ */
+static getRootAsAttacker(bb:flatbuffers.ByteBuffer, obj?:Attacker):Attacker {
+ return (obj || new Attacker).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Attacker= obj
+ * @returns Attacker
+ */
+static getSizePrefixedRootAsAttacker(bb:flatbuffers.ByteBuffer, obj?:Attacker):Attacker {
+ return (obj || new Attacker).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns number
+ */
+swordAttackDamage():number {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_sword_attack_damage(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startAttacker(builder:flatbuffers.Builder) {
+ builder.startObject(1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number swordAttackDamage
+ */
+static addSwordAttackDamage(builder:flatbuffers.Builder, swordAttackDamage:number) {
+ builder.addFieldInt32(0, swordAttackDamage, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endAttacker(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+static createAttacker(builder:flatbuffers.Builder, swordAttackDamage:number):flatbuffers.Offset {
+ Attacker.startAttacker(builder);
+ Attacker.addSwordAttackDamage(builder, swordAttackDamage);
+ return Attacker.endAttacker(builder);
+}
+}
+/**
+ * @constructor
+ */
+export class Rapunzel {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Rapunzel
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Rapunzel {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns number
+ */
+hairLength():number {
+ return this.bb!.readInt32(this.bb_pos);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_hair_length(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number hair_length
+ * @returns flatbuffers.Offset
+ */
+static createRapunzel(builder:flatbuffers.Builder, hair_length: number):flatbuffers.Offset {
+ builder.prep(4, 4);
+ builder.writeInt32(hair_length);
+ return builder.offset();
+};
+
+}
+/**
+ * @constructor
+ */
+export class BookReader {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns BookReader
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):BookReader {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @returns number
+ */
+booksRead():number {
+ return this.bb!.readInt32(this.bb_pos);
+};
+
+/**
+ * @param number value
+ * @returns boolean
+ */
+mutate_books_read(value:number):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 0);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeInt32(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number books_read
+ * @returns flatbuffers.Offset
+ */
+static createBookReader(builder:flatbuffers.Builder, books_read: number):flatbuffers.Offset {
+ builder.prep(4, 4);
+ builder.writeInt32(books_read);
+ return builder.offset();
+};
+
+}
+/**
+ * @constructor
+ */
+export class Movie {
+ bb: flatbuffers.ByteBuffer|null = null;
+
+ bb_pos:number = 0;
+/**
+ * @param number i
+ * @param flatbuffers.ByteBuffer bb
+ * @returns Movie
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Movie {
+ this.bb_pos = i;
+ this.bb = bb;
+ return this;
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Movie= obj
+ * @returns Movie
+ */
+static getRootAsMovie(bb:flatbuffers.ByteBuffer, obj?:Movie):Movie {
+ return (obj || new Movie).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @param Movie= obj
+ * @returns Movie
+ */
+static getSizePrefixedRootAsMovie(bb:flatbuffers.ByteBuffer, obj?:Movie):Movie {
+ return (obj || new Movie).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param flatbuffers.ByteBuffer bb
+ * @returns boolean
+ */
+static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {
+ return bb.__has_identifier('MOVI');
+};
+
+/**
+ * @returns Character
+ */
+mainCharacterType():Character {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+ return offset ? /** */ (this.bb!.readUint8(this.bb_pos + offset)) : Character.NONE;
+};
+
+/**
+ * @param Character value
+ * @returns boolean
+ */
+mutate_main_character_type(value:Character):boolean {
+ var offset = this.bb!.__offset(this.bb_pos, 4);
+
+ if (offset === 0) {
+ return false;
+ }
+
+ this.bb!.writeUint8(this.bb_pos + offset, value);
+ return true;
+};
+
+/**
+ * @param flatbuffers.Table obj
+ * @returns ?flatbuffers.Table
+ */
+mainCharacter<T extends flatbuffers.Table>(obj:T):T|null {
+ var offset = this.bb!.__offset(this.bb_pos, 6);
+ return offset ? this.bb!.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param number index
+ * @returns Character
+ */
+charactersType(index: number):Character|null {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? /** */ (this.bb!.readUint8(this.bb!.__vector(this.bb_pos + offset) + index)) : /** */ (0);
+};
+
+/**
+ * @returns number
+ */
+charactersTypeLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns Uint8Array
+ */
+charactersTypeArray():Uint8Array|null {
+ var offset = this.bb!.__offset(this.bb_pos, 8);
+ return offset ? new Uint8Array(this.bb!.bytes().buffer, this.bb!.bytes().byteOffset + this.bb!.__vector(this.bb_pos + offset), this.bb!.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param number index
+ * @param flatbuffers.Table= obj
+ * @returns ?flatbuffers.Table
+ */
+characters<T extends flatbuffers.Table>(index: number, obj:T):T|null {
+ var offset = this.bb!.__offset(this.bb_pos, 10);
+ return offset ? this.bb!.__union(obj, this.bb!.__vector(this.bb_pos + offset) + index * 4) : null;
+};
+
+/**
+ * @returns number
+ */
+charactersLength():number {
+ var offset = this.bb!.__offset(this.bb_pos, 10);
+ return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ */
+static startMovie(builder:flatbuffers.Builder) {
+ builder.startObject(4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Character mainCharacterType
+ */
+static addMainCharacterType(builder:flatbuffers.Builder, mainCharacterType:Character) {
+ builder.addFieldInt8(0, mainCharacterType, Character.NONE);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset mainCharacterOffset
+ */
+static addMainCharacter(builder:flatbuffers.Builder, mainCharacterOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(1, mainCharacterOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset charactersTypeOffset
+ */
+static addCharactersType(builder:flatbuffers.Builder, charactersTypeOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(2, charactersTypeOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<Character> data
+ * @returns flatbuffers.Offset
+ */
+static createCharactersTypeVector(builder:flatbuffers.Builder, data:Character[]):flatbuffers.Offset {
+ builder.startVector(1, data.length, 1);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addInt8(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startCharactersTypeVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset charactersOffset
+ */
+static addCharacters(builder:flatbuffers.Builder, charactersOffset:flatbuffers.Offset) {
+ builder.addFieldOffset(3, charactersOffset, 0);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param Array.<flatbuffers.Offset> data
+ * @returns flatbuffers.Offset
+ */
+static createCharactersVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+ builder.startVector(4, data.length, 4);
+ for (var i = data.length - 1; i >= 0; i--) {
+ builder.addOffset(data[i]);
+ }
+ return builder.endVector();
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param number numElems
+ */
+static startCharactersVector(builder:flatbuffers.Builder, numElems:number) {
+ builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @returns flatbuffers.Offset
+ */
+static endMovie(builder:flatbuffers.Builder):flatbuffers.Offset {
+ var offset = builder.endObject();
+ return offset;
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset offset
+ */
+static finishMovieBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+ builder.finish(offset, 'MOVI');
+};
+
+/**
+ * @param flatbuffers.Builder builder
+ * @param flatbuffers.Offset offset
+ */
+static finishSizePrefixedMovieBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+ builder.finish(offset, 'MOVI', true);
+};
+
+static createMovie(builder:flatbuffers.Builder, mainCharacterType:Character, mainCharacterOffset:flatbuffers.Offset, charactersTypeOffset:flatbuffers.Offset, charactersOffset:flatbuffers.Offset):flatbuffers.Offset {
+ Movie.startMovie(builder);
+ Movie.addMainCharacterType(builder, mainCharacterType);
+ Movie.addMainCharacter(builder, mainCharacterOffset);
+ Movie.addCharactersType(builder, charactersTypeOffset);
+ Movie.addCharacters(builder, charactersOffset);
+ return Movie.endMovie(builder);
+}
+}