forked from BigfootDev/flatbuffers
Compare commits
157 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f94fb51b1 | ||
|
|
57f3752d5e | ||
|
|
f52f848b95 | ||
|
|
3c3742a54a | ||
|
|
f325cce6fd | ||
|
|
88a85ffbbd | ||
|
|
35cbd23f63 | ||
|
|
210a1ab969 | ||
|
|
90c8ded449 | ||
|
|
8f864aad7b | ||
|
|
dddd0865cb | ||
|
|
0a81eb6463 | ||
|
|
b1740688bf | ||
|
|
86b505e412 | ||
|
|
da67c0a71f | ||
|
|
dadd1a926e | ||
|
|
01c50d57a6 | ||
|
|
e9f1f4d9b7 | ||
|
|
dd05f3249a | ||
|
|
43611fcc0b | ||
|
|
642254bee6 | ||
|
|
22743ca45a | ||
|
|
fb87c0d3c6 | ||
|
|
398ae0cb6b | ||
|
|
aaf5598a03 | ||
|
|
3d2cf554d7 | ||
|
|
55dec4d2f8 | ||
|
|
0f5f7faa9f | ||
|
|
90daabd5b1 | ||
|
|
262e1d7bf9 | ||
|
|
c559eb451e | ||
|
|
6a7ec85e83 | ||
|
|
81ecc98e02 | ||
|
|
9aeeddf5ac | ||
|
|
c7bfe06c54 | ||
|
|
349a391208 | ||
|
|
9d01bfaea3 | ||
|
|
cfbab31fb1 | ||
|
|
cb2481efdc | ||
|
|
d7ac3788e8 | ||
|
|
a0a313b101 | ||
|
|
93c0960c3a | ||
|
|
04d734d6d2 | ||
|
|
8468ea1ab4 | ||
|
|
0920d663d5 | ||
|
|
bbb72f0b73 | ||
|
|
8f8a27d6e5 | ||
|
|
86777bd66b | ||
|
|
8b92122f33 | ||
|
|
e93a5652d0 | ||
|
|
0c80b3a7cc | ||
|
|
f52ddfbd68 | ||
|
|
808b44f87a | ||
|
|
340d1a3447 | ||
|
|
ba20d9bff3 | ||
|
|
370693a200 | ||
|
|
33932ceea4 | ||
|
|
fb03f78fb4 | ||
|
|
523f3833eb | ||
|
|
46497e4f9a | ||
|
|
b627b7c6c6 | ||
|
|
e093f72d00 | ||
|
|
728bb64fed | ||
|
|
a07f0d428d | ||
|
|
b90d4e049d | ||
|
|
b0752e179b | ||
|
|
1fc12e0e5b | ||
|
|
e6fa7b1133 | ||
|
|
28e7dbd3d3 | ||
|
|
adc50051e0 | ||
|
|
2aec880347 | ||
|
|
238a8ebb15 | ||
|
|
86992476da | ||
|
|
751aeabc80 | ||
|
|
b4bb1b103f | ||
|
|
cffd187fc7 | ||
|
|
ccfa317486 | ||
|
|
a5cc2092a6 | ||
|
|
89041a1686 | ||
|
|
7a36419f24 | ||
|
|
281284fa5d | ||
|
|
1a27c7017a | ||
|
|
b8f5f84437 | ||
|
|
f2071e4f80 | ||
|
|
9c25ecdcd1 | ||
|
|
1beed12e59 | ||
|
|
4cd71d67f1 | ||
|
|
d9bc5ec047 | ||
|
|
c04c143cf0 | ||
|
|
c6aae45364 | ||
|
|
7f2a1c90d5 | ||
|
|
f5387387de | ||
|
|
e7e4dc755d | ||
|
|
b8224809ad | ||
|
|
bb22fb5756 | ||
|
|
ff274771ba | ||
|
|
15bf626191 | ||
|
|
ac106e835c | ||
|
|
640b525e83 | ||
|
|
0b379211dc | ||
|
|
bb223da258 | ||
|
|
17c5f89d4f | ||
|
|
695d26183a | ||
|
|
f5120a2aaf | ||
|
|
037314a059 | ||
|
|
ebcfbbadf0 | ||
|
|
6561c7a31f | ||
|
|
a6d98fb067 | ||
|
|
3a2d3a232f | ||
|
|
cebdad4d23 | ||
|
|
d798100be9 | ||
|
|
1fb6b9ee6f | ||
|
|
2d6e8f096b | ||
|
|
ec8038cc3d | ||
|
|
2df3d1c965 | ||
|
|
2272229983 | ||
|
|
b7bfecb4ee | ||
|
|
c7c4bbfce2 | ||
|
|
d7ba17dfe5 | ||
|
|
60b11435e6 | ||
|
|
ed2110d7b3 | ||
|
|
a9514de978 | ||
|
|
c57ab92e60 | ||
|
|
f878024d0b | ||
|
|
aac6be1153 | ||
|
|
dabe030890 | ||
|
|
29574282a2 | ||
|
|
2dd6ba57d1 | ||
|
|
6cc2307c71 | ||
|
|
74c8c7137a | ||
|
|
f9055ff9a7 | ||
|
|
9b3d8b318a | ||
|
|
87e29b25de | ||
|
|
f7bc9bd51b | ||
|
|
3dee617c86 | ||
|
|
2fb25e2bb3 | ||
|
|
b395359b6e | ||
|
|
fd61d70205 | ||
|
|
4f4495a693 | ||
|
|
68bbe983e9 | ||
|
|
bbef92c17d | ||
|
|
25c884158f | ||
|
|
3f936c5655 | ||
|
|
42a265b419 | ||
|
|
4bc4979acc | ||
|
|
b095367d17 | ||
|
|
eac2905568 | ||
|
|
12fd0c6838 | ||
|
|
19101826a8 | ||
|
|
7b94eab2b1 | ||
|
|
1a21b54560 | ||
|
|
b55f18649a | ||
|
|
e2373668d9 | ||
|
|
8c1a723ba5 | ||
|
|
ab7949dc16 | ||
|
|
2c4dce5ba7 | ||
|
|
cc84240098 |
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -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!
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -48,6 +48,7 @@ tests/monsterdata_java_wire.mon
|
||||
tests/monsterdata_go_wire.mon
|
||||
tests/monsterdata_javascript_wire.mon
|
||||
tests/unicode_test.mon
|
||||
tests/ts/
|
||||
CMakeLists.txt.user
|
||||
CMakeScripts/**
|
||||
CTestTestfile.cmake
|
||||
@@ -66,3 +67,8 @@ build/VS2010/FlatBuffers.opensdf
|
||||
build/VS2010/ipch/**/*.ipch
|
||||
*.so
|
||||
Testing/Temporary
|
||||
.cproject
|
||||
.settings/
|
||||
.project
|
||||
net/**/obj
|
||||
node_modules/
|
||||
|
||||
@@ -24,12 +24,16 @@ endif()
|
||||
|
||||
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/flexbuffers.h
|
||||
include/flatbuffers/registry.h
|
||||
src/code_generators.cpp
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
src/reflection.cpp
|
||||
@@ -47,6 +51,7 @@ set(FlatBuffers_Compiler_SRCS
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_grpc.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
|
||||
@@ -62,7 +67,6 @@ set(FlatHash_SRCS
|
||||
set(FlatBuffers_Tests_SRCS
|
||||
${FlatBuffers_Library_SRCS}
|
||||
src/idl_gen_fbs.cpp
|
||||
src/idl_gen_general.cpp
|
||||
tests/test.cpp
|
||||
# file generate by running compiler on tests/monster_test.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
|
||||
@@ -76,13 +80,7 @@ set(FlatBuffers_Sample_Binary_SRCS
|
||||
)
|
||||
|
||||
set(FlatBuffers_Sample_Text_SRCS
|
||||
include/flatbuffers/flatbuffers.h
|
||||
include/flatbuffers/hash.h
|
||||
include/flatbuffers/idl.h
|
||||
include/flatbuffers/util.h
|
||||
src/idl_parser.cpp
|
||||
src/idl_gen_text.cpp
|
||||
src/util.cpp
|
||||
${FlatBuffers_Library_SRCS}
|
||||
samples/sample_text.cpp
|
||||
# file generated by running compiler on samples/monster.fbs
|
||||
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
|
||||
@@ -106,7 +104,7 @@ if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
|
||||
# is being configured externally
|
||||
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")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
|
||||
elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CYGWIN)
|
||||
set(CMAKE_CXX_FLAGS
|
||||
@@ -130,9 +128,14 @@ elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \
|
||||
-Wextra")
|
||||
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
|
||||
"${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror \
|
||||
-Wextra -Wno-unused-parameter")
|
||||
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()
|
||||
@@ -142,6 +145,11 @@ elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
|
||||
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)
|
||||
@@ -167,6 +175,10 @@ if(FLATBUFFERS_BUILD_FLATC)
|
||||
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)
|
||||
@@ -185,6 +197,7 @@ function(compile_flatbuffers_schema_to_cpp SRC_FBS)
|
||||
OUTPUT ${GEN_HEADER}
|
||||
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
|
||||
--gen-object-api -o "${SRC_FBS_DIR}"
|
||||
-I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||
DEPENDS flatc)
|
||||
endfunction()
|
||||
@@ -215,10 +228,10 @@ endif()
|
||||
|
||||
if(FLATBUFFERS_BUILD_GRPCTEST)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
|
||||
endif()
|
||||
add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
|
||||
target_link_libraries(grpctest grpc++_unsecure grpc pthread dl)
|
||||
target_link_libraries(grpctest grpc++_unsecure pthread dl)
|
||||
endif()
|
||||
|
||||
if(FLATBUFFERS_INSTALL)
|
||||
|
||||
@@ -25,7 +25,7 @@ use Github pull requests for this purpose.
|
||||
|
||||
Some tips for good pull requests:
|
||||
* Use our code
|
||||
[style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html).
|
||||
[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:
|
||||
|
||||
@@ -24,7 +24,9 @@ LOCAL_PATH := $(call realpath-portable,$(LOCAL_PATH))
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := flatbuffers
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
LOCAL_EXPORT_CPPFLAGS := -std=c++11 -fexceptions -Wall -Wno-literal-suffix
|
||||
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
|
||||
@@ -34,7 +36,8 @@ LOCAL_MODULE := flatbuffers_extra
|
||||
LOCAL_SRC_FILES := src/idl_parser.cpp \
|
||||
src/idl_gen_text.cpp \
|
||||
src/reflection.cpp \
|
||||
src/util.cpp
|
||||
src/util.cpp \
|
||||
src/code_generators.cpp
|
||||
LOCAL_STATIC_LIBRARIES := flatbuffers
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
|
||||
11
appveyor.yml
11
appveyor.yml
@@ -4,6 +4,11 @@ branches:
|
||||
|
||||
os: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- CMAKE_VS_VERSION: "10 2010"
|
||||
- CMAKE_VS_VERSION: "14 2015"
|
||||
|
||||
platform:
|
||||
- x86
|
||||
- x64
|
||||
@@ -13,7 +18,7 @@ configuration:
|
||||
- Release
|
||||
|
||||
before_build:
|
||||
- cmake -G"Visual Studio 10 2010"
|
||||
- cmake -G"Visual Studio %CMAKE_VS_VERSION%"
|
||||
# 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"
|
||||
|
||||
@@ -30,8 +35,8 @@ test_script:
|
||||
- "JavaTest.bat"
|
||||
- rem "---------------- JS -----------------"
|
||||
- "node --version"
|
||||
- "..\\%CONFIGURATION%\\flatc -b monster_test.fbs unicode_test.json"
|
||||
- "node JavaScriptTest"
|
||||
- "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
|
||||
- "node JavaScriptTest ./monster_test_generated"
|
||||
- rem "---------------- C# -----------------"
|
||||
# Have to compile this here rather than in "build" above because AppVeyor only
|
||||
# supports building one project??
|
||||
|
||||
@@ -1 +1 @@
|
||||
../../CONTRIBUTING
|
||||
../../CONTRIBUTING.md
|
||||
@@ -29,7 +29,7 @@ For any schema input files, one or more generators can be specified:
|
||||
|
||||
- `--python`, `-p`: Generate Python code.
|
||||
|
||||
- `--javascript`, `-s`: Generate JavaScript code.
|
||||
- `--js`, `-s`: Generate JavaScript code.
|
||||
|
||||
- `--php`: Generate PHP code.
|
||||
|
||||
@@ -93,6 +93,12 @@ Additional options:
|
||||
output (by default the case for C++ and JS), all code will end up in
|
||||
this one file.
|
||||
|
||||
- `--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).
|
||||
|
||||
- `--raw-binary` : Allow binaries without a file_indentifier to be read.
|
||||
This may crash flatc given a mismatched schema.
|
||||
|
||||
@@ -108,9 +114,16 @@ Additional options:
|
||||
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.
|
||||
|
||||
- `--include-prefix PATH` : Prefix this path to any generated include
|
||||
statements.
|
||||
|
||||
- `--keep-prefix` : Keep original prefix of schema include statement.
|
||||
|
||||
NOTE: short-form options for generators are deprecated, use the long form
|
||||
whenever possible.
|
||||
|
||||
@@ -85,7 +85,7 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
|
||||
|
||||
*Note: That we never stored a `mana` value, so it will return the default.*
|
||||
|
||||
## Object based API.
|
||||
## 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
|
||||
@@ -99,13 +99,79 @@ construction, access and mutation.
|
||||
To use:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
|
||||
auto monsterobj = UnpackMonster(buffer);
|
||||
// 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;
|
||||
CreateMonster(fbb, monsterobj.get()); // Serialize into new buffer.
|
||||
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_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.
|
||||
|
||||
# External references.
|
||||
|
||||
An additional feature of the object API is the ability to allow you to load
|
||||
@@ -134,6 +200,15 @@ 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.
|
||||
|
||||
|
||||
# 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() and T::length() as member functions.
|
||||
|
||||
## Reflection (& Resizing)
|
||||
|
||||
There is experimental support for reflection in FlatBuffers, allowing you to
|
||||
@@ -336,4 +411,22 @@ 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.
|
||||
|
||||
<br>
|
||||
|
||||
@@ -78,6 +78,9 @@ inefficiency, but also forces you to write *more* code to access data
|
||||
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).
|
||||
|
||||
@@ -138,6 +141,8 @@ sections provide a more in-depth usage guide.
|
||||
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.
|
||||
|
||||
|
||||
166
docs/source/FlexBuffers.md
Normal file
166
docs/source/FlexBuffers.md
Normal file
@@ -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](Internals.md#flexbuffers) 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.
|
||||
@@ -292,4 +292,148 @@ 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.
|
||||
|
||||
# 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.
|
||||
|
||||
### 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 indivual vector in code.
|
||||
|
||||
An example map { foo: 13, bar: 14 } would be encoded as:
|
||||
|
||||
0 : uint8_t 'f', 'o', 'o', 0
|
||||
4 : uint8_t 'b', 'a', 'r', 0
|
||||
8 : uint8_t 2 // key vector of size 2
|
||||
// key vector offset points here
|
||||
9 : uint8_t 9, 6 // offsets to foo_key and bar_key
|
||||
11: uint8_t 3, 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 13, 14 // 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>
|
||||
|
||||
@@ -147,19 +147,20 @@ To use it:
|
||||
array.
|
||||
- Instead of calling standard generated method,
|
||||
e.g.: `Monster.createTestarrayoftablesVector`,
|
||||
call `CreateMySortedVectorOfTables` in C# or
|
||||
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 `LookupByKey`
|
||||
to access elements of the vector, e.g.:
|
||||
`Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`,
|
||||
- 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.
|
||||
`LookupByKey` performs a binary search, so should have a similar speed to
|
||||
`Dictionary`, 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.
|
||||
`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
|
||||
|
||||
|
||||
@@ -158,6 +158,10 @@ 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
|
||||
@@ -298,6 +302,9 @@ Current understood attributes:
|
||||
(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.
|
||||
@@ -309,6 +316,10 @@ Current understood attributes:
|
||||
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
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ the `schema` that defines the template for our monsters:
|
||||
color:Color = Blue; // Enum.
|
||||
weapons:[Weapon]; // Vector of tables.
|
||||
equipped:Equipment; // Union.
|
||||
path:[Vec3]; // Vector of structs.
|
||||
}
|
||||
|
||||
table Weapon {
|
||||
@@ -799,6 +800,70 @@ 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 = fbb.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-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.Example.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.Example.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-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>
|
||||
|
||||
We have now serialized the non-scalar components of the orc, so we
|
||||
can serialize the monster itself:
|
||||
|
||||
@@ -812,7 +877,7 @@ can serialize the monster itself:
|
||||
// to set all fields.
|
||||
auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name,
|
||||
inventory, Color_Red, weapons, Equipment_Weapon,
|
||||
axe.Union());
|
||||
axe.Union(), path);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-java">
|
||||
@@ -827,6 +892,7 @@ can serialize the monster itself:
|
||||
Monster.addWeapons(builder, weapons);
|
||||
Monster.addEquippedType(builder, Equipment.Weapon);
|
||||
Monster.addEquipped(builder, axe);
|
||||
Monster.addPath(builder, path);
|
||||
int orc = Monster.endMonster(builder);
|
||||
~~~
|
||||
</div>
|
||||
@@ -842,6 +908,7 @@ can serialize the monster itself:
|
||||
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>
|
||||
@@ -857,6 +924,7 @@ can serialize the monster itself:
|
||||
sample.MonsterAddWeapons(builder, weapons)
|
||||
sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
|
||||
sample.MonsterAddEquipped(builder, axe)
|
||||
sample.MonsterAddPath(builder, path)
|
||||
orc := sample.MonsterEnd(builder)
|
||||
~~~
|
||||
</div>
|
||||
@@ -875,6 +943,7 @@ can serialize the monster itself:
|
||||
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>
|
||||
@@ -891,6 +960,7 @@ can serialize the monster itself:
|
||||
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>
|
||||
@@ -907,6 +977,7 @@ can serialize the monster itself:
|
||||
\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>
|
||||
@@ -921,7 +992,7 @@ can serialize the monster itself:
|
||||
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));
|
||||
weapons, equipped, path));
|
||||
~~~
|
||||
</div>
|
||||
|
||||
@@ -929,10 +1000,10 @@ 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**: you should not nest tables or any 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.
|
||||
**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
|
||||
@@ -1470,10 +1541,10 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
|
||||
</div>
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
var pos = monster.Pos
|
||||
var x = pos.X
|
||||
var y = pos.Y
|
||||
var z = pos.Z
|
||||
var pos = monster.Pos.Value;
|
||||
var x = pos.X;
|
||||
var y = pos.Y;
|
||||
var z = pos.Z;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
@@ -1547,7 +1618,7 @@ FlatBuffers `vector`.
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
int invLength = monster.InventoryLength;
|
||||
var thirdItem = monster.GetInventory(2);
|
||||
var thirdItem = monster.Inventory(2);
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
@@ -1604,8 +1675,8 @@ except your need to handle the result as a FlatBuffer `table`:
|
||||
<div class="language-csharp">
|
||||
~~~{.cs}
|
||||
int weaponsLength = monster.WeaponsLength;
|
||||
var secondWeaponName = monster.GetWeapons(1).Name;
|
||||
var secondWeaponDamage = monster.GetWeapons(1).Damage;
|
||||
var secondWeaponName = monster.Weapons(1).Name;
|
||||
var secondWeaponDamage = monster.Weapons(1).Damage;
|
||||
~~~
|
||||
</div>
|
||||
<div class="language-go">
|
||||
@@ -1687,8 +1758,7 @@ We can access the type to dynamically cast the data as needed (since the
|
||||
var unionType = monster.EquippedType;
|
||||
|
||||
if (unionType == Equipment.Weapon) {
|
||||
var weapon = (Weapon)monster.GetEquipped(new Weapon()); // Requires explicit cast
|
||||
// to `Weapon`.
|
||||
var weapon = monster.Equipped<Weapon>().Value;
|
||||
|
||||
var weaponName = weapon.Name; // "Axe"
|
||||
var weaponDamage = weapon.Damage; // 5
|
||||
|
||||
@@ -759,11 +759,13 @@ INPUT = "FlatBuffers.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" \
|
||||
@@ -882,21 +884,21 @@ EXCLUDE_SYMBOLS =
|
||||
# that contain example code fragments that are included (see the \include
|
||||
# command).
|
||||
|
||||
EXAMPLE_PATH = "GoApi_generated.txt"
|
||||
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 = *
|
||||
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 = 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
|
||||
|
||||
@@ -37,6 +37,12 @@
|
||||
title="Use in PHP"/>
|
||||
<tab type="user" url="@ref flatbuffers_guide_use_python"
|
||||
title="Use in Python"/>
|
||||
<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"/>
|
||||
|
||||
29
docs/source/gRPC/CppUsage.md
Normal file
29
docs/source/gRPC/CppUsage.md
Normal file
@@ -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
|
||||
@@ -1,7 +1,7 @@
|
||||
package flatbuffers
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -10,7 +10,7 @@ type Table struct {
|
||||
|
||||
// Offset provides access into the Table's vtable.
|
||||
//
|
||||
// Deprecated fields are ignored by checking against the vtable's length.
|
||||
// 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) {
|
||||
|
||||
14
grpc/samples/greeter/Makefile
Normal file
14
grpc/samples/greeter/Makefile
Normal file
@@ -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 $@
|
||||
85
grpc/samples/greeter/client.cpp
Normal file
85
grpc/samples/greeter/client.cpp
Normal file
@@ -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;
|
||||
}
|
||||
17
grpc/samples/greeter/greeter.fbs
Normal file
17
grpc/samples/greeter/greeter.fbs
Normal file
@@ -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");
|
||||
}
|
||||
80
grpc/samples/greeter/server.cpp
Normal file
80
grpc/samples/greeter/server.cpp
Normal file
@@ -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;
|
||||
}
|
||||
40
grpc/src/compiler/config.h
Normal file
40
grpc/src/compiler/config.h
Normal file
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,8 +41,20 @@
|
||||
#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.
|
||||
@@ -53,31 +65,73 @@ struct Parameters {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
|
||||
|
||||
@@ -44,13 +44,21 @@ grpc::string as_string(T 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] = std::tolower(s[0]);
|
||||
s[0] = static_cast<char>(std::tolower(s[0]));
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -58,7 +66,7 @@ grpc::string unexportName(grpc::string s) {
|
||||
grpc::string exportName(grpc::string s) {
|
||||
if (s.empty())
|
||||
return s;
|
||||
s[0] = std::toupper(s[0]);
|
||||
s[0] = static_cast<char>(std::toupper(s[0]));
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -70,8 +78,8 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
|
||||
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_imports() != "") {
|
||||
printer->Print(file->additional_imports().c_str());
|
||||
if (file->additional_headers() != "") {
|
||||
printer->Print(file->additional_headers().c_str());
|
||||
printer->Print("\n\n");
|
||||
}
|
||||
printer->Print("import (\n");
|
||||
@@ -86,11 +94,11 @@ void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printe
|
||||
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->input_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
|
||||
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 (method->ServerOnlyStreaming()) {
|
||||
} else if (ServerOnlyStreaming(method)) {
|
||||
printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
|
||||
} else {
|
||||
printer->Print(vars, "$Method$($Service$_$Method$Server) error");
|
||||
@@ -100,8 +108,8 @@ void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_ge
|
||||
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->input_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
|
||||
vars["Request"] = method->get_input_type_name();
|
||||
vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
|
||||
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
|
||||
if (method->NoStreaming()) {
|
||||
@@ -129,7 +137,7 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
|
||||
printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
|
||||
printer->Indent();
|
||||
if (method->ServerOnlyStreaming()) {
|
||||
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");
|
||||
@@ -139,9 +147,9 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming();
|
||||
bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming();
|
||||
bool genSendAndClose = method->ClientOnlyStreaming();
|
||||
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();
|
||||
@@ -194,12 +202,12 @@ void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
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->input_name() : vars["CustomMethodIO"]);
|
||||
if (method->ClientOnlyStreaming() || method->BidiStreaming()) {
|
||||
vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
|
||||
if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
|
||||
vars["Request"] = "";
|
||||
}
|
||||
vars["Response"] = "* " + method->output_name();
|
||||
if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) {
|
||||
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)");
|
||||
@@ -213,8 +221,8 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Print(" {\n");
|
||||
printer->Indent();
|
||||
vars["Method"] = exportName(method->name());
|
||||
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"];
|
||||
vars["Response"] = method->output_name();
|
||||
vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
|
||||
vars["Response"] = method->get_output_type_name();
|
||||
vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(vars, "out := new($Response$)\n");
|
||||
@@ -230,7 +238,7 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Print("if err != nil { return nil, err }\n");
|
||||
|
||||
printer->Print(vars, "x := &$StreamType${stream}\n");
|
||||
if (method->ServerOnlyStreaming()) {
|
||||
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");
|
||||
}
|
||||
@@ -238,9 +246,9 @@ void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
|
||||
bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming();
|
||||
bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming();
|
||||
bool genCloseAndRecv = method->ClientOnlyStreaming();
|
||||
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");
|
||||
@@ -396,9 +404,9 @@ void GenerateService(const grpc_generator::Service *service, grpc_generator::Pri
|
||||
printer->Indent();
|
||||
printer->Print(vars, "StreamName: \"$Method$\",\n");
|
||||
printer->Print(vars, "Handler: $Handler$, \n");
|
||||
if (method->ClientOnlyStreaming()) {
|
||||
if (ClientOnlyStreaming(method.get())) {
|
||||
printer->Print("ClientStreams: true,\n");
|
||||
} else if (method->ServerOnlyStreaming()) {
|
||||
} else if (ServerOnlyStreaming(method.get())) {
|
||||
printer->Print("ServerStreams: true,\n");
|
||||
} else {
|
||||
printer->Print("ServerStreams: true,\n");
|
||||
|
||||
@@ -43,12 +43,12 @@
|
||||
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;
|
||||
//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;
|
||||
//Package name for the service
|
||||
grpc::string package_name;
|
||||
};
|
||||
|
||||
// Return the source of the generated service file.
|
||||
|
||||
@@ -34,79 +34,93 @@
|
||||
#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
|
||||
|
||||
#include <map>
|
||||
#include "src/compiler/config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
#include <string>
|
||||
#define GRPC_CUSTOM_STRING std::string
|
||||
#endif
|
||||
#ifndef GRPC_CUSTOM_STRING
|
||||
#include <string>
|
||||
#define GRPC_CUSTOM_STRING std::string
|
||||
#endif
|
||||
|
||||
namespace grpc {
|
||||
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
typedef GRPC_CUSTOM_STRING string;
|
||||
|
||||
} // namespace grpc
|
||||
|
||||
namespace grpc_generator {
|
||||
|
||||
// An abstract interface representing a method.
|
||||
struct Method {
|
||||
virtual ~Method() {}
|
||||
// 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;
|
||||
};
|
||||
|
||||
virtual grpc::string name() const = 0;
|
||||
// An abstract interface representing a method.
|
||||
struct Method : public CommentHolder {
|
||||
virtual ~Method() {}
|
||||
|
||||
virtual grpc::string input_type_name() const = 0;
|
||||
virtual grpc::string output_type_name() const = 0;
|
||||
virtual grpc::string input_name() const = 0;
|
||||
virtual grpc::string output_name() const = 0;
|
||||
virtual grpc::string name() const = 0;
|
||||
|
||||
virtual bool NoStreaming() const = 0;
|
||||
virtual bool ClientOnlyStreaming() const = 0;
|
||||
virtual bool ServerOnlyStreaming() const = 0;
|
||||
virtual bool BidiStreaming() const = 0;
|
||||
};
|
||||
virtual grpc::string input_type_name() const = 0;
|
||||
virtual grpc::string output_type_name() const = 0;
|
||||
|
||||
// An abstract interface representing a service.
|
||||
struct Service {
|
||||
virtual ~Service() {}
|
||||
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 name() 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;
|
||||
};
|
||||
|
||||
virtual int method_count() const = 0;
|
||||
virtual std::unique_ptr<const Method> method(int i) const = 0;
|
||||
};
|
||||
// An abstract interface representing a service.
|
||||
struct Service : public CommentHolder {
|
||||
virtual ~Service() {}
|
||||
|
||||
struct Printer {
|
||||
virtual ~Printer() {}
|
||||
virtual grpc::string name() const = 0;
|
||||
|
||||
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;
|
||||
};
|
||||
virtual int method_count() const = 0;
|
||||
virtual std::unique_ptr<const Method> method(int i) const = 0;
|
||||
};
|
||||
|
||||
// An interface that allows the source generated to be output using various
|
||||
// libraries/idls/serializers.
|
||||
struct File {
|
||||
virtual ~File() {}
|
||||
struct Printer {
|
||||
virtual ~Printer() {}
|
||||
|
||||
virtual grpc::string filename() const = 0;
|
||||
virtual grpc::string filename_without_ext() const = 0;
|
||||
virtual grpc::string message_header_ext() const = 0;
|
||||
virtual grpc::string service_header_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 grpc::string additional_imports() const = 0;
|
||||
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;
|
||||
};
|
||||
|
||||
virtual int service_count() const = 0;
|
||||
virtual std::unique_ptr<const Service> service(int i) const = 0;
|
||||
// An interface that allows the source generated to be output using various
|
||||
// libraries/idls/serializers.
|
||||
struct File : public CommentHolder {
|
||||
virtual ~File() {}
|
||||
|
||||
virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
|
||||
};
|
||||
} // namespace grpc_generator
|
||||
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
|
||||
|
||||
@@ -27,31 +27,41 @@ using namespace MyGame::Example;
|
||||
// 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::BufferRef<Monster> *request,
|
||||
flatbuffers::BufferRef<Stat> *response)
|
||||
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);
|
||||
// Since we keep reusing the same FlatBufferBuilder, the memory it owns
|
||||
// remains valid until the next call (this BufferRef doesn't own the
|
||||
// memory it points to).
|
||||
*response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
|
||||
fbb_.GetSize());
|
||||
// Transfer ownership of the message to gRPC
|
||||
*response = fbb_.ReleaseMessage<Stat>();
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
|
||||
const flatbuffers::BufferRef<Stat> *request,
|
||||
::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer)
|
||||
override {
|
||||
assert(false); // We're not actually using this RPC.
|
||||
return grpc::Status::CANCELLED;
|
||||
const flatbuffers::grpc::Message<Stat> *request,
|
||||
::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer)
|
||||
override {
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
fbb_.Clear();
|
||||
// Create 10 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::FlatBufferBuilder fbb_;
|
||||
flatbuffers::grpc::MessageBuilder fbb_;
|
||||
};
|
||||
|
||||
// Track the server instance, so we can terminate it later.
|
||||
@@ -93,25 +103,55 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
grpc::InsecureChannelCredentials());
|
||||
auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
|
||||
|
||||
grpc::ClientContext context;
|
||||
|
||||
// Build a request with the name set.
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
|
||||
fbb.Finish(monster_offset);
|
||||
auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(),
|
||||
fbb.GetSize());
|
||||
flatbuffers::BufferRef<Stat> response;
|
||||
flatbuffers::grpc::MessageBuilder fbb;
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
// Build a request with the name set.
|
||||
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
|
||||
fbb.Finish(monster_offset);
|
||||
auto request = fbb.ReleaseMessage<Monster>();
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
|
||||
// The actual RPC.
|
||||
auto status = stub->Store(&context, request, &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;
|
||||
if (status.ok()) {
|
||||
auto resp = response.GetRoot()->id();
|
||||
std::cout << "RPC response: " << resp->str() << std::endl;
|
||||
} else {
|
||||
std::cout << "RPC failed" << std::endl;
|
||||
}
|
||||
}
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
fbb.Clear();
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
|
||||
fbb.Finish(stat_offset);
|
||||
auto request = 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;
|
||||
}
|
||||
}
|
||||
|
||||
#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();
|
||||
|
||||
@@ -121,4 +161,3 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
177
include/flatbuffers/base.h
Normal file
177
include/flatbuffers/base.h
Normal file
@@ -0,0 +1,177 @@
|
||||
#ifndef FLATBUFFERS_BASE_H_
|
||||
#define FLATBUFFERS_BASE_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef ARDUINO
|
||||
#include <cstdint>
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#ifndef ARDUINO
|
||||
#include <utility>
|
||||
#else
|
||||
#include <utility.h>
|
||||
#endif
|
||||
#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
|
||||
|
||||
/// @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__)
|
||||
#ifdef __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 7
|
||||
#define FLATBUFFERS_VERSION_REVISION 0
|
||||
#define FLATBUFFERS_STRING_EXPAND(X) #X
|
||||
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
|
||||
#define FLATBUFFERS_FINAL_CLASS final
|
||||
#define FLATBUFFERS_OVERRIDE override
|
||||
#else
|
||||
#define FLATBUFFERS_FINAL_CLASS
|
||||
#define FLATBUFFERS_OVERRIDE
|
||||
#endif
|
||||
|
||||
#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
|
||||
(!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
|
||||
#define FLATBUFFERS_CONSTEXPR constexpr
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR
|
||||
#endif
|
||||
|
||||
#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
|
||||
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
|
||||
#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))
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) func = delete;
|
||||
#else
|
||||
#define FLATBUFFERS_DELETE_FUNC(func) private: func;
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127) // C4127: conditional expression is constant
|
||||
#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
|
||||
|
||||
template<typename T> T EndianScalar(T t) {
|
||||
#if FLATBUFFERS_LITTLEENDIAN
|
||||
return t;
|
||||
#else
|
||||
return EndianSwap(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T> T ReadScalar(const void *p) {
|
||||
return EndianScalar(*reinterpret_cast<const T *>(p));
|
||||
}
|
||||
|
||||
template<typename T> void WriteScalar(void *p, T t) {
|
||||
*reinterpret_cast<T *>(p) = EndianScalar(t);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
#endif // FLATBUFFERS_BASE_H_
|
||||
@@ -17,25 +17,63 @@
|
||||
#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;
|
||||
// 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() {}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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(); }
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> value_map_;
|
||||
std::stringstream stream_;
|
||||
};
|
||||
|
||||
class BaseGenerator {
|
||||
public:
|
||||
virtual bool generate() = 0;
|
||||
|
||||
static const std::string NamespaceDir(const Parser &parser,
|
||||
const std::string &path,
|
||||
const Namespace &ns) {
|
||||
EnsureDirExists(path.c_str());
|
||||
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.c_str());
|
||||
}
|
||||
return namespace_dir;
|
||||
}
|
||||
static std::string NamespaceDir(const Parser &parser,
|
||||
const std::string &path,
|
||||
const Namespace &ns);
|
||||
|
||||
protected:
|
||||
BaseGenerator(const Parser &parser, const std::string &path,
|
||||
@@ -46,71 +84,35 @@ class BaseGenerator {
|
||||
path_(path),
|
||||
file_name_(file_name),
|
||||
qualifying_start_(qualifying_start),
|
||||
qualifying_separator_(qualifying_separator){};
|
||||
virtual ~BaseGenerator(){};
|
||||
qualifying_separator_(qualifying_separator) {}
|
||||
virtual ~BaseGenerator() {}
|
||||
|
||||
// No copy/assign.
|
||||
BaseGenerator &operator=(const BaseGenerator &);
|
||||
BaseGenerator(const BaseGenerator &);
|
||||
|
||||
const std::string NamespaceDir(const Namespace &ns) {
|
||||
return BaseGenerator::NamespaceDir(parser_, path_, ns);
|
||||
}
|
||||
std::string NamespaceDir(const Namespace &ns) const;
|
||||
|
||||
const char *FlatBuffersGeneratedWarning() {
|
||||
return "automatically generated by the FlatBuffers compiler,"
|
||||
" do not modify\n\n";
|
||||
}
|
||||
static const char *FlatBuffersGeneratedWarning();
|
||||
|
||||
bool IsEverythingGenerated() {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
if (!(*it)->generated) return false;
|
||||
}
|
||||
for (auto it = parser_.structs_.vec.begin();
|
||||
it != parser_.structs_.vec.end(); ++it) {
|
||||
if (!(*it)->generated) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static std::string FullNamespace(const char *separator, const Namespace &ns);
|
||||
|
||||
std::string 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;
|
||||
}
|
||||
|
||||
const std::string LastNamespacePart(const Namespace &ns) {
|
||||
auto &namespaces = ns.components;
|
||||
if (namespaces.size())
|
||||
return *(namespaces.end() - 1);
|
||||
else
|
||||
return std::string("");
|
||||
}
|
||||
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() { return nullptr; }
|
||||
virtual const Namespace *CurrentNameSpace() const { return nullptr; }
|
||||
|
||||
// Ensure that a type is prefixed with its namespace whenever it is used
|
||||
// outside of its namespace.
|
||||
std::string WrapInNameSpace(const Namespace *ns, const std::string &name) {
|
||||
if (CurrentNameSpace() == ns) return name;
|
||||
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 WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) const;
|
||||
|
||||
std::string WrapInNameSpace(const Definition &def) {
|
||||
return WrapInNameSpace(def.defined_namespace, def.name);
|
||||
}
|
||||
std::string WrapInNameSpace(const Definition &def) const;
|
||||
|
||||
std::string GetNameSpace(const Definition &def) const;
|
||||
|
||||
const Parser &parser_;
|
||||
const std::string &path_;
|
||||
@@ -119,6 +121,17 @@ class BaseGenerator {
|
||||
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 = "");
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_CODE_GENERATORS_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
97
include/flatbuffers/flatc.h
Normal file
97
include/flatbuffers/flatc.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#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& params) : 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 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_
|
||||
1399
include/flatbuffers/flexbuffers.h
Normal file
1399
include/flatbuffers/flexbuffers.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,51 +19,234 @@
|
||||
|
||||
// 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;
|
||||
|
||||
virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
|
||||
|
||||
virtual uint8_t *allocate(size_t size) override {
|
||||
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 {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
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) override {
|
||||
assert(old_p == GRPC_SLICE_START_PTR(slice_));
|
||||
assert(old_size == GRPC_SLICE_LENGTH(slice_));
|
||||
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(new_p + (new_size - old_size), old_p, old_size);
|
||||
slice_ = new_slice;
|
||||
grpc_slice_unref(old_slice);
|
||||
return new_p;
|
||||
}
|
||||
|
||||
private:
|
||||
grpc_slice &get_slice(uint8_t *p, size_t size) {
|
||||
assert(p == GRPC_SLICE_START_PTR(slice_));
|
||||
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_;
|
||||
};
|
||||
}
|
||||
|
||||
// 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() {}
|
||||
|
||||
// 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_.buf(); // 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
|
||||
assert(msg_data);
|
||||
assert(msg_size);
|
||||
assert(msg_data >= buf_data);
|
||||
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<T, typename std::enable_if<std::is_base_of<
|
||||
flatbuffers::BufferRefBase, T>::value>::type> {
|
||||
class SerializationTraits<flatbuffers::grpc::Message<T>> {
|
||||
public:
|
||||
// The type we're passing here is a BufferRef, which is already serialized
|
||||
// FlatBuffer data, which then gets passed to GRPC.
|
||||
static grpc::Status Serialize(const T& msg,
|
||||
grpc_byte_buffer **buffer,
|
||||
bool *own_buffer) {
|
||||
// TODO(wvo): make this work without copying.
|
||||
auto slice = gpr_slice_from_copied_buffer(
|
||||
reinterpret_cast<const char *>(msg.buf), msg.len);
|
||||
*buffer = grpc_raw_byte_buffer_create(&slice, 1);
|
||||
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();
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
// There is no de-serialization step in FlatBuffers, so we just receive
|
||||
// the data from GRPC.
|
||||
// Deserialize by pulling the
|
||||
static grpc::Status Deserialize(grpc_byte_buffer *buffer,
|
||||
T *msg,
|
||||
int max_message_size) {
|
||||
// TODO(wvo): make this more efficient / zero copy when possible.
|
||||
auto len = grpc_byte_buffer_length(buffer);
|
||||
msg->buf = reinterpret_cast<uint8_t *>(malloc(len));
|
||||
msg->len = static_cast<flatbuffers::uoffset_t>(len);
|
||||
msg->must_free = true;
|
||||
uint8_t *current = msg->buf;
|
||||
grpc_byte_buffer_reader reader;
|
||||
grpc_byte_buffer_reader_init(&reader, buffer);
|
||||
gpr_slice slice;
|
||||
while (grpc_byte_buffer_reader_next(&reader, &slice)) {
|
||||
memcpy(current, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
|
||||
current += GPR_SLICE_LENGTH(slice);
|
||||
gpr_slice_unref(slice);
|
||||
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);
|
||||
}
|
||||
GPR_ASSERT(current == msg->buf + msg->len);
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
grpc_byte_buffer_destroy(buffer);
|
||||
return grpc::Status();
|
||||
#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
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/hash.h"
|
||||
#include "flatbuffers/reflection.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
|
||||
// This file defines the data types representing a parsed IDL (Interface
|
||||
// Definition Language) / schema file.
|
||||
@@ -226,18 +227,20 @@ struct Definition {
|
||||
};
|
||||
|
||||
struct FieldDef : public Definition {
|
||||
FieldDef() : deprecated(false), required(false), key(false), padding(0) {}
|
||||
FieldDef() : deprecated(false), required(false), key(false),
|
||||
flexbuffer(false), padding(0) {}
|
||||
|
||||
Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
|
||||
const Parser &parser) const;
|
||||
|
||||
Value value;
|
||||
bool deprecated; // Field is allowed to be present in old data, but can't be
|
||||
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 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.
|
||||
size_t padding; // Bytes to always pad after this field.
|
||||
};
|
||||
|
||||
@@ -283,18 +286,18 @@ inline size_t InlineAlignment(const Type &type) {
|
||||
|
||||
struct EnumVal {
|
||||
EnumVal(const std::string &_name, int64_t _val)
|
||||
: name(_name), value(_val), struct_def(nullptr) {}
|
||||
: name(_name), value(_val) {}
|
||||
|
||||
Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
|
||||
|
||||
std::string name;
|
||||
std::vector<std::string> doc_comment;
|
||||
int64_t value;
|
||||
StructDef *struct_def; // only set if this is a union
|
||||
Type union_type;
|
||||
};
|
||||
|
||||
struct EnumDef : public Definition {
|
||||
EnumDef() : is_union(false) {}
|
||||
EnumDef() : is_union(false), uses_type_aliases(false) {}
|
||||
|
||||
EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) {
|
||||
for (auto it = vals.vec.begin() + static_cast<int>(is_union &&
|
||||
@@ -312,6 +315,7 @@ struct EnumDef : public Definition {
|
||||
|
||||
SymbolTable<EnumVal> vals;
|
||||
bool is_union;
|
||||
bool uses_type_aliases;
|
||||
Type underlying_type;
|
||||
};
|
||||
|
||||
@@ -337,6 +341,7 @@ struct ServiceDef : public Definition {
|
||||
struct IDLOptions {
|
||||
bool strict_json;
|
||||
bool skip_js_exports;
|
||||
bool use_goog_js_export_format;
|
||||
bool output_default_scalars_in_json;
|
||||
int indent_step;
|
||||
bool output_enum_identifiers;
|
||||
@@ -352,17 +357,42 @@ struct IDLOptions {
|
||||
bool escape_proto_identifiers;
|
||||
bool generate_object_based_api;
|
||||
std::string cpp_object_api_pointer_type;
|
||||
std::string cpp_object_api_string_type;
|
||||
bool union_value_namespacing;
|
||||
bool allow_non_utf8;
|
||||
std::string include_prefix;
|
||||
bool keep_include_path;
|
||||
bool binary_schema_comments;
|
||||
bool skip_flatbuffers_import;
|
||||
std::string go_namespace;
|
||||
bool reexport_ts_modules;
|
||||
bool protobuf_ascii_alike;
|
||||
|
||||
// Possible options for the more general generator below.
|
||||
enum Language { kJava, kCSharp, kGo, kMAX };
|
||||
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,
|
||||
kMAX
|
||||
};
|
||||
|
||||
Language lang;
|
||||
|
||||
// The corresponding language bit will be set if a language is included
|
||||
// for code generation.
|
||||
unsigned long lang_to_generate;
|
||||
|
||||
IDLOptions()
|
||||
: strict_json(false),
|
||||
skip_js_exports(false),
|
||||
use_goog_js_export_format(false),
|
||||
output_default_scalars_in_json(false),
|
||||
indent_step(2),
|
||||
output_enum_identifiers(true), prefixed_enums(true), scoped_enums(false),
|
||||
@@ -378,7 +408,13 @@ struct IDLOptions {
|
||||
cpp_object_api_pointer_type("std::unique_ptr"),
|
||||
union_value_namespacing(true),
|
||||
allow_non_utf8(false),
|
||||
lang(IDLOptions::kJava) {}
|
||||
keep_include_path(false),
|
||||
binary_schema_comments(false),
|
||||
skip_flatbuffers_import(false),
|
||||
reexport_ts_modules(true),
|
||||
protobuf_ascii_alike(false),
|
||||
lang(IDLOptions::kJava),
|
||||
lang_to_generate(0) {}
|
||||
};
|
||||
|
||||
// This encapsulates where the parser is in the current source file.
|
||||
@@ -440,6 +476,7 @@ class Parser : public ParserState {
|
||||
explicit Parser(const IDLOptions &options = IDLOptions())
|
||||
: root_struct_def_(nullptr),
|
||||
opts(options),
|
||||
uses_flexbuffers_(false),
|
||||
source_(nullptr),
|
||||
anonymous_counter(0) {
|
||||
// Just in case none are declared:
|
||||
@@ -458,7 +495,11 @@ class Parser : public ParserState {
|
||||
known_attributes_["idempotent"] = true;
|
||||
known_attributes_["cpp_type"] = true;
|
||||
known_attributes_["cpp_ptr_type"] = true;
|
||||
known_attributes_["cpp_str_type"] = true;
|
||||
known_attributes_["native_inline"] = true;
|
||||
known_attributes_["native_type"] = true;
|
||||
known_attributes_["native_default"] = true;
|
||||
known_attributes_["flexbuffer"] = true;
|
||||
}
|
||||
|
||||
~Parser() {
|
||||
@@ -476,6 +517,8 @@ class Parser : public ParserState {
|
||||
// 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);
|
||||
|
||||
@@ -498,11 +541,16 @@ class Parser : public ParserState {
|
||||
// of the schema provided. Returns non-empty error on any problems.
|
||||
std::string ConformTo(const Parser &base);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits);
|
||||
// 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);
|
||||
|
||||
FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
|
||||
|
||||
private:
|
||||
FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, int64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
|
||||
FLATBUFFERS_CHECKED_ERROR Next();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
|
||||
bool Is(int t);
|
||||
@@ -517,18 +565,26 @@ private:
|
||||
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);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
const std::function<CheckedError(const std::string &name)> &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 AddVector(bool sortbysize, int count);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(size_t &count,
|
||||
const std::function<CheckedError()> &body);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
|
||||
FLATBUFFERS_CHECKED_ERROR TryTypedValue(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(Value &e);
|
||||
FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
|
||||
StructDef *LookupCreateStruct(const std::string &name,
|
||||
@@ -548,18 +604,20 @@ private:
|
||||
FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
|
||||
FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonObject();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonArray();
|
||||
FLATBUFFERS_CHECKED_ERROR SkipJsonString();
|
||||
FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
|
||||
FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
|
||||
const char *source_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
|
||||
const char **include_paths,
|
||||
const char *source_filename);
|
||||
const char *source_filename,
|
||||
const char *include_filename);
|
||||
FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
|
||||
StructDef *struct_def,
|
||||
const char *suffix,
|
||||
BaseType baseType);
|
||||
|
||||
public:
|
||||
SymbolTable<Type> types_;
|
||||
SymbolTable<StructDef> structs_;
|
||||
SymbolTable<EnumDef> enums_;
|
||||
SymbolTable<ServiceDef> services_;
|
||||
@@ -571,12 +629,14 @@ private:
|
||||
std::string file_identifier_;
|
||||
std::string file_extension_;
|
||||
|
||||
std::map<std::string, bool> included_files_;
|
||||
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_;
|
||||
@@ -592,13 +652,6 @@ private:
|
||||
|
||||
extern std::string MakeCamel(const std::string &in, bool first = true);
|
||||
|
||||
struct CommentConfig;
|
||||
|
||||
extern void GenComment(const std::vector<std::string> &dc,
|
||||
std::string *code_ptr,
|
||||
const CommentConfig *config,
|
||||
const char *prefix = "");
|
||||
|
||||
// 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,
|
||||
@@ -629,7 +682,7 @@ extern bool GenerateCPP(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate JavaScript code from the definitions in the Parser object.
|
||||
// Generate JavaScript or TypeScript code from the definitions in the Parser object.
|
||||
// See idl_gen_js.
|
||||
extern std::string GenerateJS(const Parser &parser);
|
||||
extern bool GenerateJS(const Parser &parser,
|
||||
@@ -680,7 +733,7 @@ extern bool GenerateFBS(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
|
||||
// Generate a make rule for the generated JavaScript code.
|
||||
// Generate a make rule for the generated JavaScript or TypeScript code.
|
||||
// See idl_gen_js.cpp.
|
||||
extern std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
@@ -725,4 +778,3 @@ bool GenerateGoGRPC(const Parser &parser,
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_IDL_H_
|
||||
|
||||
|
||||
@@ -30,6 +30,15 @@ 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.
|
||||
@@ -58,6 +67,18 @@ 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) {
|
||||
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) {
|
||||
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) {
|
||||
@@ -242,8 +263,19 @@ template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
|
||||
// Set any scalar field, if you know its exact type.
|
||||
template<typename T> bool SetField(Table *table, const reflection::Field &field,
|
||||
T val) {
|
||||
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
|
||||
return table->SetField(field.offset(), val);
|
||||
reflection::BaseType type = field.type()->base_type();
|
||||
if (!IsScalar(type)) {
|
||||
return false;
|
||||
}
|
||||
assert(sizeof(T) == GetTypeSize(type));
|
||||
T def;
|
||||
if (IsInteger(type)) {
|
||||
def = GetFieldDefaultI<T>(field);
|
||||
} else {
|
||||
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
|
||||
@@ -258,7 +290,7 @@ void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
|
||||
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
|
||||
int64_t val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
|
||||
SetAnyValueI(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
@@ -267,7 +299,7 @@ inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
|
||||
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
|
||||
double val) {
|
||||
auto field_ptr = table->GetAddressOf(field.offset());
|
||||
if (!field_ptr) return false;
|
||||
if (!field_ptr) return val == GetFieldDefaultF<double>(field);
|
||||
SetAnyValueF(field.type()->base_type(), field_ptr, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_
|
||||
|
||||
@@ -42,11 +43,33 @@ enum BaseType {
|
||||
};
|
||||
|
||||
inline const char **EnumNamesBaseType() {
|
||||
static const char *names[] = { "None", "UType", "Bool", "Byte", "UByte", "Short", "UShort", "Int", "UInt", "Long", "ULong", "Float", "Double", "String", "Vector", "Obj", "Union", nullptr };
|
||||
static const char *names[] = {
|
||||
"None",
|
||||
"UType",
|
||||
"Bool",
|
||||
"Byte",
|
||||
"UByte",
|
||||
"Short",
|
||||
"UShort",
|
||||
"Int",
|
||||
"UInt",
|
||||
"Long",
|
||||
"ULong",
|
||||
"Float",
|
||||
"Double",
|
||||
"String",
|
||||
"Vector",
|
||||
"Obj",
|
||||
"Union",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameBaseType(BaseType e) { return EnumNamesBaseType()[static_cast<int>(e)]; }
|
||||
inline const char *EnumNameBaseType(BaseType e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesBaseType()[index];
|
||||
}
|
||||
|
||||
struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
@@ -54,9 +77,15 @@ struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_ELEMENT = 6,
|
||||
VT_INDEX = 8
|
||||
};
|
||||
BaseType base_type() const { return static_cast<BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0)); }
|
||||
BaseType element() const { return static_cast<BaseType>(GetField<int8_t>(VT_ELEMENT, 0)); }
|
||||
int32_t index() const { return GetField<int32_t>(VT_INDEX, -1); }
|
||||
BaseType base_type() const {
|
||||
return static_cast<BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0));
|
||||
}
|
||||
BaseType element() const {
|
||||
return static_cast<BaseType>(GetField<int8_t>(VT_ELEMENT, 0));
|
||||
}
|
||||
int32_t index() const {
|
||||
return GetField<int32_t>(VT_INDEX, -1);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<int8_t>(verifier, VT_BASE_TYPE) &&
|
||||
@@ -69,18 +98,29 @@ struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct TypeBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_base_type(BaseType base_type) { fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0); }
|
||||
void add_element(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); }
|
||||
TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_base_type(BaseType base_type) {
|
||||
fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0);
|
||||
}
|
||||
void add_element(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);
|
||||
}
|
||||
TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
TypeBuilder &operator=(const TypeBuilder &);
|
||||
flatbuffers::Offset<Type> Finish() {
|
||||
auto o = flatbuffers::Offset<Type>(fbb_.EndTable(start_, 3));
|
||||
const auto end = fbb_.EndTable(start_, 3);
|
||||
auto o = flatbuffers::Offset<Type>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Type> CreateType(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Type> CreateType(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
BaseType base_type = None,
|
||||
BaseType element = None,
|
||||
int32_t index = -1) {
|
||||
@@ -96,15 +136,23 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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); }
|
||||
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) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_KEY) &&
|
||||
VerifyOffsetRequired(verifier, VT_KEY) &&
|
||||
verifier.Verify(key()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
|
||||
VerifyOffset(verifier, VT_VALUE) &&
|
||||
verifier.Verify(value()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -113,18 +161,27 @@ struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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); }
|
||||
KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
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);
|
||||
}
|
||||
KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
KeyValueBuilder &operator=(const KeyValueBuilder &);
|
||||
flatbuffers::Offset<KeyValue> Finish() {
|
||||
auto o = flatbuffers::Offset<KeyValue>(fbb_.EndTable(start_, 2));
|
||||
fbb_.Required(o, KeyValue::VT_KEY); // key
|
||||
const auto end = fbb_.EndTable(start_, 2);
|
||||
auto o = flatbuffers::Offset<KeyValue>(end);
|
||||
fbb_.Required(o, KeyValue::VT_KEY);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValue(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValue(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> key = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> value = 0) {
|
||||
KeyValueBuilder builder_(_fbb);
|
||||
@@ -133,30 +190,57 @@ inline flatbuffers::Offset<KeyValue> CreateKeyValue(flatbuffers::FlatBufferBuild
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *key = nullptr,
|
||||
const char *value = nullptr) {
|
||||
return CreateKeyValue(_fbb, key ? _fbb.CreateString(key) : 0, value ? _fbb.CreateString(value) : 0);
|
||||
return reflection::CreateKeyValue(
|
||||
_fbb,
|
||||
key ? _fbb.CreateString(key) : 0,
|
||||
value ? _fbb.CreateString(value) : 0);
|
||||
}
|
||||
|
||||
struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
enum {
|
||||
VT_NAME = 4,
|
||||
VT_VALUE = 6,
|
||||
VT_OBJECT = 8
|
||||
VT_OBJECT = 8,
|
||||
VT_UNION_TYPE = 10
|
||||
};
|
||||
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 value() < val ? -1 : value() > val; }
|
||||
const Object *object() const { return GetPointer<const Object *>(VT_OBJECT); }
|
||||
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 {
|
||||
const auto key = value();
|
||||
if (key < val) {
|
||||
return -1;
|
||||
} else if (key > val) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
const Object *object() const {
|
||||
return GetPointer<const Object *>(VT_OBJECT);
|
||||
}
|
||||
const Type *union_type() const {
|
||||
return GetPointer<const Type *>(VT_UNION_TYPE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<int64_t>(verifier, VT_VALUE) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_OBJECT) &&
|
||||
VerifyOffset(verifier, VT_OBJECT) &&
|
||||
verifier.VerifyTable(object()) &&
|
||||
VerifyOffset(verifier, VT_UNION_TYPE) &&
|
||||
verifier.VerifyTable(union_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -164,34 +248,57 @@ struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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<Object> object) { fbb_.AddOffset(EnumVal::VT_OBJECT, object); }
|
||||
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
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<Object> object) {
|
||||
fbb_.AddOffset(EnumVal::VT_OBJECT, object);
|
||||
}
|
||||
void add_union_type(flatbuffers::Offset<Type> union_type) {
|
||||
fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
|
||||
}
|
||||
EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
EnumValBuilder &operator=(const EnumValBuilder &);
|
||||
flatbuffers::Offset<EnumVal> Finish() {
|
||||
auto o = flatbuffers::Offset<EnumVal>(fbb_.EndTable(start_, 3));
|
||||
fbb_.Required(o, EnumVal::VT_NAME); // name
|
||||
const auto end = fbb_.EndTable(start_, 4);
|
||||
auto o = flatbuffers::Offset<EnumVal>(end);
|
||||
fbb_.Required(o, EnumVal::VT_NAME);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumVal(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumVal(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0) {
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
EnumValBuilder builder_(_fbb);
|
||||
builder_.add_value(value);
|
||||
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,
|
||||
inline flatbuffers::Offset<EnumVal> CreateEnumValDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int64_t value = 0,
|
||||
flatbuffers::Offset<Object> object = 0) {
|
||||
return CreateEnumVal(_fbb, name ? _fbb.CreateString(name) : 0, value, object);
|
||||
flatbuffers::Offset<Object> object = 0,
|
||||
flatbuffers::Offset<Type> union_type = 0) {
|
||||
return reflection::CreateEnumVal(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
value,
|
||||
object,
|
||||
union_type);
|
||||
}
|
||||
|
||||
struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -200,28 +307,49 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_VALUES = 6,
|
||||
VT_IS_UNION = 8,
|
||||
VT_UNDERLYING_TYPE = 10,
|
||||
VT_ATTRIBUTES = 12
|
||||
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<EnumVal>> *values() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(VT_VALUES); }
|
||||
bool is_union() const { return GetField<uint8_t>(VT_IS_UNION, 0) != 0; }
|
||||
const Type *underlying_type() const { return GetPointer<const Type *>(VT_UNDERLYING_TYPE); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES); }
|
||||
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<EnumVal>> *values() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<EnumVal>> *>(VT_VALUES);
|
||||
}
|
||||
bool is_union() const {
|
||||
return GetField<uint8_t>(VT_IS_UNION, 0) != 0;
|
||||
}
|
||||
const Type *underlying_type() const {
|
||||
return GetPointer<const Type *>(VT_UNDERLYING_TYPE);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_VALUES) &&
|
||||
VerifyOffsetRequired(verifier, VT_VALUES) &&
|
||||
verifier.Verify(values()) &&
|
||||
verifier.VerifyVectorOfTables(values()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_UNDERLYING_TYPE) &&
|
||||
VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
|
||||
verifier.VerifyTable(underlying_type()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -229,29 +357,49 @@ struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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<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<Type> underlying_type) { fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type); }
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes) { fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes); }
|
||||
EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Enum::VT_NAME, name);
|
||||
}
|
||||
void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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<Type> underlying_type) {
|
||||
fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type);
|
||||
}
|
||||
void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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);
|
||||
}
|
||||
EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
EnumBuilder &operator=(const EnumBuilder &);
|
||||
flatbuffers::Offset<Enum> Finish() {
|
||||
auto o = flatbuffers::Offset<Enum>(fbb_.EndTable(start_, 5));
|
||||
fbb_.Required(o, Enum::VT_NAME); // name
|
||||
fbb_.Required(o, Enum::VT_VALUES); // values
|
||||
fbb_.Required(o, Enum::VT_UNDERLYING_TYPE); // underlying_type
|
||||
const auto end = fbb_.EndTable(start_, 6);
|
||||
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,
|
||||
inline flatbuffers::Offset<Enum> CreateEnum(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<EnumVal>>> values = 0,
|
||||
bool is_union = false,
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0) {
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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);
|
||||
@@ -260,13 +408,22 @@ inline flatbuffers::Offset<Enum> CreateEnum(flatbuffers::FlatBufferBuilder &_fbb
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Enum> CreateEnumDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Enum> CreateEnumDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<EnumVal>> *values = nullptr,
|
||||
bool is_union = false,
|
||||
flatbuffers::Offset<Type> underlying_type = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
|
||||
return CreateEnum(_fbb, name ? _fbb.CreateString(name) : 0, values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0, is_union, underlying_type, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateEnum(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
values ? _fbb.CreateVector<flatbuffers::Offset<EnumVal>>(*values) : 0,
|
||||
is_union,
|
||||
underlying_type,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -280,25 +437,53 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_DEPRECATED = 16,
|
||||
VT_REQUIRED = 18,
|
||||
VT_KEY = 20,
|
||||
VT_ATTRIBUTES = 22
|
||||
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 Type *type() const { return GetPointer<const 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<KeyValue>> *attributes() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES); }
|
||||
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 Type *type() const {
|
||||
return GetPointer<const 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<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_TYPE) &&
|
||||
VerifyOffsetRequired(verifier, VT_TYPE) &&
|
||||
verifier.VerifyTable(type()) &&
|
||||
VerifyField<uint16_t>(verifier, VT_ID) &&
|
||||
VerifyField<uint16_t>(verifier, VT_OFFSET) &&
|
||||
@@ -307,9 +492,12 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VerifyField<uint8_t>(verifier, VT_DEPRECATED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
|
||||
VerifyField<uint8_t>(verifier, VT_KEY) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -317,27 +505,55 @@ struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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<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<KeyValue>>> attributes) { fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes); }
|
||||
FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Field::VT_NAME, name);
|
||||
}
|
||||
void add_type(flatbuffers::Offset<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<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);
|
||||
}
|
||||
FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
FieldBuilder &operator=(const FieldBuilder &);
|
||||
flatbuffers::Offset<Field> Finish() {
|
||||
auto o = flatbuffers::Offset<Field>(fbb_.EndTable(start_, 10));
|
||||
fbb_.Required(o, Field::VT_NAME); // name
|
||||
fbb_.Required(o, Field::VT_TYPE); // type
|
||||
const auto end = fbb_.EndTable(start_, 11);
|
||||
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,
|
||||
inline flatbuffers::Offset<Field> CreateField(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
@@ -347,10 +563,12 @@ inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_f
|
||||
bool deprecated = false,
|
||||
bool required = false,
|
||||
bool key = false,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0) {
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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);
|
||||
@@ -362,7 +580,8 @@ inline flatbuffers::Offset<Field> CreateField(flatbuffers::FlatBufferBuilder &_f
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Field> CreateFieldDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Field> CreateFieldDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
flatbuffers::Offset<Type> type = 0,
|
||||
uint16_t id = 0,
|
||||
@@ -372,8 +591,21 @@ inline flatbuffers::Offset<Field> CreateFieldDirect(flatbuffers::FlatBufferBuild
|
||||
bool deprecated = false,
|
||||
bool required = false,
|
||||
bool key = false,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
|
||||
return CreateField(_fbb, name ? _fbb.CreateString(name) : 0, type, id, offset, default_integer, default_real, deprecated, required, key, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateField(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
type,
|
||||
id,
|
||||
offset,
|
||||
default_integer,
|
||||
default_real,
|
||||
deprecated,
|
||||
required,
|
||||
key,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -383,29 +615,52 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_IS_STRUCT = 8,
|
||||
VT_MINALIGN = 10,
|
||||
VT_BYTESIZE = 12,
|
||||
VT_ATTRIBUTES = 14
|
||||
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<Field>> *fields() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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<KeyValue>> *attributes() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<KeyValue>> *>(VT_ATTRIBUTES); }
|
||||
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<Field>> *fields() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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<KeyValue>> *attributes() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffsetRequired(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_FIELDS) &&
|
||||
VerifyOffsetRequired(verifier, VT_FIELDS) &&
|
||||
verifier.Verify(fields()) &&
|
||||
verifier.VerifyVectorOfTables(fields()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
|
||||
VerifyField<int32_t>(verifier, VT_MINALIGN) &&
|
||||
VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
|
||||
VerifyOffset(verifier, VT_ATTRIBUTES) &&
|
||||
verifier.Verify(attributes()) &&
|
||||
verifier.VerifyVectorOfTables(attributes()) &&
|
||||
VerifyOffset(verifier, VT_DOCUMENTATION) &&
|
||||
verifier.Verify(documentation()) &&
|
||||
verifier.VerifyVectorOfStrings(documentation()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
@@ -413,30 +668,52 @@ struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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<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<KeyValue>>> attributes) { fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes); }
|
||||
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_name(flatbuffers::Offset<flatbuffers::String> name) {
|
||||
fbb_.AddOffset(Object::VT_NAME, name);
|
||||
}
|
||||
void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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<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);
|
||||
}
|
||||
ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
ObjectBuilder &operator=(const ObjectBuilder &);
|
||||
flatbuffers::Offset<Object> Finish() {
|
||||
auto o = flatbuffers::Offset<Object>(fbb_.EndTable(start_, 6));
|
||||
fbb_.Required(o, Object::VT_NAME); // name
|
||||
fbb_.Required(o, Object::VT_FIELDS); // fields
|
||||
const auto end = fbb_.EndTable(start_, 7);
|
||||
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,
|
||||
inline flatbuffers::Offset<Object> CreateObject(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Field>>> fields = 0,
|
||||
bool is_struct = false,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<KeyValue>>> attributes = 0) {
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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);
|
||||
@@ -446,14 +723,24 @@ inline flatbuffers::Offset<Object> CreateObject(flatbuffers::FlatBufferBuilder &
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Object> CreateObjectDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Object> CreateObjectDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
const std::vector<flatbuffers::Offset<Field>> *fields = nullptr,
|
||||
bool is_struct = false,
|
||||
int32_t minalign = 0,
|
||||
int32_t bytesize = 0,
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr) {
|
||||
return CreateObject(_fbb, name ? _fbb.CreateString(name) : 0, fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0, is_struct, minalign, bytesize, attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0);
|
||||
const std::vector<flatbuffers::Offset<KeyValue>> *attributes = nullptr,
|
||||
const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) {
|
||||
return reflection::CreateObject(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
fields ? _fbb.CreateVector<flatbuffers::Offset<Field>>(*fields) : 0,
|
||||
is_struct,
|
||||
minalign,
|
||||
bytesize,
|
||||
attributes ? _fbb.CreateVector<flatbuffers::Offset<KeyValue>>(*attributes) : 0,
|
||||
documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0);
|
||||
}
|
||||
|
||||
struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -464,24 +751,34 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_FILE_EXT = 10,
|
||||
VT_ROOT_TABLE = 12
|
||||
};
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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 Object *root_table() const { return GetPointer<const Object *>(VT_ROOT_TABLE); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Object>> *objects() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Object>> *>(VT_OBJECTS);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Enum>> *enums() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<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 Object *root_table() const {
|
||||
return GetPointer<const Object *>(VT_ROOT_TABLE);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_OBJECTS) &&
|
||||
VerifyOffsetRequired(verifier, VT_OBJECTS) &&
|
||||
verifier.Verify(objects()) &&
|
||||
verifier.VerifyVectorOfTables(objects()) &&
|
||||
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_ENUMS) &&
|
||||
VerifyOffsetRequired(verifier, VT_ENUMS) &&
|
||||
verifier.Verify(enums()) &&
|
||||
verifier.VerifyVectorOfTables(enums()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_IDENT) &&
|
||||
VerifyOffset(verifier, VT_FILE_IDENT) &&
|
||||
verifier.Verify(file_ident()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_EXT) &&
|
||||
VerifyOffset(verifier, VT_FILE_EXT) &&
|
||||
verifier.Verify(file_ext()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_ROOT_TABLE) &&
|
||||
VerifyOffset(verifier, VT_ROOT_TABLE) &&
|
||||
verifier.VerifyTable(root_table()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
@@ -490,22 +787,37 @@ struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
struct SchemaBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) { fbb_.AddOffset(Schema::VT_OBJECTS, objects); }
|
||||
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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<Object> root_table) { fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table); }
|
||||
SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects) {
|
||||
fbb_.AddOffset(Schema::VT_OBJECTS, objects);
|
||||
}
|
||||
void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<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<Object> root_table) {
|
||||
fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table);
|
||||
}
|
||||
SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
SchemaBuilder &operator=(const SchemaBuilder &);
|
||||
flatbuffers::Offset<Schema> Finish() {
|
||||
auto o = flatbuffers::Offset<Schema>(fbb_.EndTable(start_, 5));
|
||||
fbb_.Required(o, Schema::VT_OBJECTS); // objects
|
||||
fbb_.Required(o, Schema::VT_ENUMS); // enums
|
||||
const auto end = fbb_.EndTable(start_, 5);
|
||||
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,
|
||||
inline flatbuffers::Offset<Schema> CreateSchema(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Object>>> objects = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Enum>>> enums = 0,
|
||||
flatbuffers::Offset<flatbuffers::String> file_ident = 0,
|
||||
@@ -520,13 +832,20 @@ inline flatbuffers::Offset<Schema> CreateSchema(flatbuffers::FlatBufferBuilder &
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Schema> CreateSchemaDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Schema> CreateSchemaDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<flatbuffers::Offset<Object>> *objects = nullptr,
|
||||
const std::vector<flatbuffers::Offset<Enum>> *enums = nullptr,
|
||||
const char *file_ident = nullptr,
|
||||
const char *file_ext = nullptr,
|
||||
flatbuffers::Offset<Object> root_table = 0) {
|
||||
return CreateSchema(_fbb, objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0, enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0, file_ident ? _fbb.CreateString(file_ident) : 0, file_ext ? _fbb.CreateString(file_ext) : 0, root_table);
|
||||
return reflection::CreateSchema(
|
||||
_fbb,
|
||||
objects ? _fbb.CreateVector<flatbuffers::Offset<Object>>(*objects) : 0,
|
||||
enums ? _fbb.CreateVector<flatbuffers::Offset<Enum>>(*enums) : 0,
|
||||
file_ident ? _fbb.CreateString(file_ident) : 0,
|
||||
file_ext ? _fbb.CreateString(file_ext) : 0,
|
||||
root_table);
|
||||
}
|
||||
|
||||
inline const reflection::Schema *GetSchema(const void *buf) {
|
||||
@@ -538,16 +857,22 @@ inline const char *SchemaIdentifier() {
|
||||
}
|
||||
|
||||
inline bool SchemaBufferHasIdentifier(const void *buf) {
|
||||
return flatbuffers::BufferHasIdentifier(buf, SchemaIdentifier());
|
||||
return flatbuffers::BufferHasIdentifier(
|
||||
buf, SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline bool VerifySchemaBuffer(flatbuffers::Verifier &verifier) {
|
||||
inline bool VerifySchemaBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier());
|
||||
}
|
||||
|
||||
inline const char *SchemaExtension() { return "bfbs"; }
|
||||
inline const char *SchemaExtension() {
|
||||
return "bfbs";
|
||||
}
|
||||
|
||||
inline void FinishSchemaBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<reflection::Schema> root) {
|
||||
inline void FinishSchemaBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<reflection::Schema> root) {
|
||||
fbb.Finish(root, SchemaIdentifier());
|
||||
}
|
||||
|
||||
|
||||
131
include/flatbuffers/registry.h
Normal file
131
include/flatbuffers/registry.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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_.ReleaseBufferPointer();
|
||||
}
|
||||
|
||||
// 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(), include_paths_.data(),
|
||||
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_
|
||||
@@ -40,7 +40,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/base.h"
|
||||
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -71,9 +72,8 @@ template<> inline std::string NumToString<double>(double t) {
|
||||
// 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) {
|
||||
s.resize(p + 1); // Strip trailing zeroes.
|
||||
if (s[s.size() - 1] == '.')
|
||||
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
|
||||
// Strip trailing zeroes. If it is a whole number, keep one zero.
|
||||
s.resize(p + (s[p] == '.' ? 2 : 1));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -95,7 +95,8 @@ inline std::string IntToStringHex(int i, int xdigits) {
|
||||
}
|
||||
|
||||
// Portable implementation of strtoll().
|
||||
inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base = 10) {
|
||||
inline int64_t StringToInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
#ifdef _MSC_VER
|
||||
return _strtoi64(str, endptr, base);
|
||||
#else
|
||||
@@ -104,7 +105,8 @@ inline int64_t StringToInt(const char *str, char **endptr = nullptr, int base =
|
||||
}
|
||||
|
||||
// Portable implementation of strtoull().
|
||||
inline int64_t StringToUInt(const char *str, char **endptr = nullptr, int base = 10) {
|
||||
inline uint64_t StringToUInt(const char *str, char **endptr = nullptr,
|
||||
int base = 10) {
|
||||
#ifdef _MSC_VER
|
||||
return _strtoui64(str, endptr, base);
|
||||
#else
|
||||
@@ -155,16 +157,20 @@ 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:
|
||||
// Functionality for minimalistic portable path handling.
|
||||
|
||||
static const char kPosixPathSeparator = '/';
|
||||
#ifdef _WIN32
|
||||
static const char kPathSeparator = '\\';
|
||||
// The functions below behave correctly regardless of whether posix ('/') or
|
||||
// Windows ('/' or '\\') separators are used.
|
||||
|
||||
// Any new separators inserted are always posix.
|
||||
|
||||
// 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 kPathSeparator = '/';
|
||||
static const char kPathSeparatorWindows = '\\';
|
||||
static const char *PathSeparatorSet = "\\/"; // Intentionally no ':'
|
||||
#else
|
||||
static const char kPathSeparator = kPosixPathSeparator;
|
||||
static const char *PathSeparatorSet = "/";
|
||||
#endif // _WIN32
|
||||
|
||||
// Returns the path with the extension, if any, removed.
|
||||
inline std::string StripExtension(const std::string &filepath) {
|
||||
@@ -195,13 +201,24 @@ inline std::string StripFileName(const std::string &filepath) {
|
||||
inline std::string ConCatPathFileName(const std::string &path,
|
||||
const std::string &filename) {
|
||||
std::string filepath = path;
|
||||
if (path.length() && path[path.size() - 1] != kPathSeparator &&
|
||||
path[path.size() - 1] != kPosixPathSeparator)
|
||||
filepath += kPathSeparator;
|
||||
if (filepath.length()) {
|
||||
if (filepath.back() == kPathSeparatorWindows) {
|
||||
filepath.back() = kPathSeparator;
|
||||
} else if (filepath.back() != kPathSeparator) {
|
||||
filepath += kPathSeparator;
|
||||
}
|
||||
}
|
||||
filepath += filename;
|
||||
return filepath;
|
||||
}
|
||||
|
||||
// Replaces any '\\' separators with '/'
|
||||
inline std::string PosixPath(const char *path) {
|
||||
std::string p = path;
|
||||
std::replace(p.begin(), p.end(), '\\', '/');
|
||||
return p;
|
||||
}
|
||||
|
||||
// This function ensure a directory exists, by recursively
|
||||
// creating dirs for any parts of the path that don't exist yet.
|
||||
inline void EnsureDirExists(const std::string &filepath) {
|
||||
@@ -343,6 +360,72 @@ inline std::string WordWrap(const std::string in, size_t max_length,
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
inline bool EscapeString(const char *s, size_t length, std::string *_text,
|
||||
bool allow_non_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 (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;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_UTIL_H_
|
||||
|
||||
@@ -106,6 +106,22 @@ public class FlatBufferBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/// @cond FLATBUFFERS_INTERNAL
|
||||
/**
|
||||
* Create a `ByteBuffer` with a given capacity.
|
||||
|
||||
@@ -2,6 +2,15 @@
|
||||
/// @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
|
||||
@@ -106,7 +115,7 @@ flatbuffers.Long.create = function(low, high) {
|
||||
* @returns {number}
|
||||
*/
|
||||
flatbuffers.Long.prototype.toFloat64 = function() {
|
||||
return this.low + this.high * 0x100000000;
|
||||
return (this.low >>> 0) + this.high * 0x100000000;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -530,6 +539,10 @@ flatbuffers.Builder.prototype.offset = function() {
|
||||
* @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();
|
||||
@@ -931,9 +944,17 @@ flatbuffers.ByteBuffer.prototype.readFloat64 = function(offset) {
|
||||
|
||||
/**
|
||||
* @param {number} offset
|
||||
* @param {number} value
|
||||
* @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;
|
||||
};
|
||||
|
||||
@@ -946,6 +967,15 @@ flatbuffers.ByteBuffer.prototype.writeInt16 = function(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
|
||||
@@ -957,6 +987,17 @@ flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) {
|
||||
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
|
||||
@@ -966,6 +1007,15 @@ flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) {
|
||||
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
|
||||
|
||||
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "flatbuffers",
|
||||
"version": "1.7.0",
|
||||
"description": "Memory Efficient Serialization Library",
|
||||
"files": ["js/flatbuffers.js"],
|
||||
"main": "js/flatbuffers.js",
|
||||
"directories": {
|
||||
"doc": "docs",
|
||||
"test": "tests"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tests/JavaScriptTest.sh"
|
||||
},
|
||||
"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/"
|
||||
}
|
||||
2
pom.xml
2
pom.xml
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.google.flatbuffers</groupId>
|
||||
<artifactId>flatbuffers-java</artifactId>
|
||||
<version>1.5.0-SNAPSHOT</version>
|
||||
<version>1.7.0-SNAPSHOT</version>
|
||||
<packaging>bundle</packaging>
|
||||
<name>FlatBuffers Java API</name>
|
||||
<description>
|
||||
|
||||
@@ -54,6 +54,6 @@ you would leave it in.
|
||||
[`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://www.stackoverflow.com
|
||||
[stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
|
||||
[landing page]: http://google.github.io/flatbuffers
|
||||
[LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt
|
||||
|
||||
@@ -42,7 +42,8 @@ table KeyValue {
|
||||
table EnumVal {
|
||||
name:string (required);
|
||||
value:long (key);
|
||||
object:Object; // Only if part of a union.
|
||||
object:Object; // Will be deprecated in favor of union_type in the future.
|
||||
union_type:Type;
|
||||
}
|
||||
|
||||
table Enum {
|
||||
@@ -51,6 +52,7 @@ table Enum {
|
||||
is_union:bool = false;
|
||||
underlying_type:Type (required);
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Field {
|
||||
@@ -64,6 +66,7 @@ table Field {
|
||||
required:bool = false;
|
||||
key:bool = false;
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Object { // Used for both tables and structs.
|
||||
@@ -73,6 +76,7 @@ table Object { // Used for both tables and structs.
|
||||
minalign:int;
|
||||
bytesize:int; // For structs.
|
||||
attributes:[KeyValue];
|
||||
documentation:[string];
|
||||
}
|
||||
|
||||
table Schema {
|
||||
|
||||
@@ -81,22 +81,19 @@ class SampleBinary
|
||||
Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color),
|
||||
Convert.ToString(Color.Red));
|
||||
|
||||
// C# also allows you to use performance-enhanced methods to fill an object that has already
|
||||
// been created. These functions are prefixed with "Get". For example: `monster.GetPos()`.
|
||||
var myAlreadyCreatedVector = new Vec3();
|
||||
monster.GetPos(myAlreadyCreatedVector); // Instead of `var myNewVec3 = monster.Pos`.
|
||||
Assert(myAlreadyCreatedVector.X == 1.0f, "myAlreadyCreatedVector.X",
|
||||
Convert.ToString(myAlreadyCreatedVector.X), Convert.ToString(1.0f));
|
||||
Assert(myAlreadyCreatedVector.Y == 2.0f, "myAlreadyCreatedVector.Y",
|
||||
Convert.ToString(myAlreadyCreatedVector.Y), Convert.ToString(2.0f));
|
||||
Assert(myAlreadyCreatedVector.Z == 3.0f, "myAlreadyCreatedVector.Z",
|
||||
Convert.ToString(myAlreadyCreatedVector.Z), Convert.ToString(3.0f));
|
||||
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.GetInventory(i) == i, "monster.GetInventory",
|
||||
Convert.ToString(monster.GetInventory(i)), Convert.ToString(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.
|
||||
@@ -104,17 +101,17 @@ class SampleBinary
|
||||
var expectedWeaponDamages = new short[] {3, 5};
|
||||
for (int i = 0; i < monster.WeaponsLength; i++)
|
||||
{
|
||||
Assert(monster.GetWeapons(i).Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
|
||||
"monster.GetWeapons", monster.GetWeapons(i).Name, expectedWeaponNames[i]);
|
||||
Assert(monster.GetWeapons(i).Damage == expectedWeaponDamages[i], "monster.GetWeapons",
|
||||
Convert.ToString(monster.GetWeapons(i).Damage),
|
||||
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 = (Weapon)monster.GetEquipped(new 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),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
|
||||
#define FLATBUFFERS_GENERATED_MONSTER_MYGAME_SAMPLE_H_
|
||||
|
||||
@@ -24,12 +25,29 @@ enum Color {
|
||||
Color_MAX = Color_Blue
|
||||
};
|
||||
|
||||
inline Color (&EnumValuesColor())[3] {
|
||||
static Color values[] = {
|
||||
Color_Red,
|
||||
Color_Green,
|
||||
Color_Blue
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char **EnumNamesColor() {
|
||||
static const char *names[] = { "Red", "Green", "Blue", nullptr };
|
||||
static const char *names[] = {
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameColor(Color e) { return EnumNamesColor()[static_cast<int>(e)]; }
|
||||
inline const char *EnumNameColor(Color e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesColor()[index];
|
||||
}
|
||||
|
||||
enum Equipment {
|
||||
Equipment_NONE = 0,
|
||||
@@ -38,12 +56,27 @@ enum Equipment {
|
||||
Equipment_MAX = Equipment_Weapon
|
||||
};
|
||||
|
||||
inline Equipment (&EnumValuesEquipment())[2] {
|
||||
static Equipment values[] = {
|
||||
Equipment_NONE,
|
||||
Equipment_Weapon
|
||||
};
|
||||
return values;
|
||||
}
|
||||
|
||||
inline const char **EnumNamesEquipment() {
|
||||
static const char *names[] = { "NONE", "Weapon", nullptr };
|
||||
static const char *names[] = {
|
||||
"NONE",
|
||||
"Weapon",
|
||||
nullptr
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
inline const char *EnumNameEquipment(Equipment e) { return EnumNamesEquipment()[static_cast<int>(e)]; }
|
||||
inline const char *EnumNameEquipment(Equipment e) {
|
||||
const size_t index = static_cast<int>(e);
|
||||
return EnumNamesEquipment()[index];
|
||||
}
|
||||
|
||||
template<typename T> struct EquipmentTraits {
|
||||
static const Equipment enum_value = Equipment_NONE;
|
||||
@@ -55,30 +88,41 @@ template<> struct EquipmentTraits<Weapon> {
|
||||
|
||||
struct EquipmentUnion {
|
||||
Equipment type;
|
||||
void *value;
|
||||
|
||||
flatbuffers::NativeTable *table;
|
||||
EquipmentUnion() : type(Equipment_NONE), table(nullptr) {}
|
||||
EquipmentUnion(const EquipmentUnion &);
|
||||
EquipmentUnion &operator=(const EquipmentUnion &);
|
||||
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();
|
||||
|
||||
template <typename T>
|
||||
void Set(T&& value) {
|
||||
void Set(T&& val) {
|
||||
Reset();
|
||||
type = EquipmentTraits<typename T::TableType>::enum_value;
|
||||
if (type != Equipment_NONE) {
|
||||
table = new T(std::forward<T>(value));
|
||||
value = new T(std::forward<T>(val));
|
||||
}
|
||||
}
|
||||
|
||||
static flatbuffers::NativeTable *UnPack(const void *union_obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
|
||||
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *rehasher = nullptr) const;
|
||||
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;
|
||||
|
||||
WeaponT *AsWeapon() { return type == Equipment_Weapon ? reinterpret_cast<WeaponT *>(table) : nullptr; }
|
||||
WeaponT *AsWeapon() {
|
||||
return type == Equipment_Weapon ?
|
||||
reinterpret_cast<WeaponT *>(value) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type);
|
||||
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);
|
||||
|
||||
MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
private:
|
||||
@@ -87,17 +131,35 @@ MANUALLY_ALIGNED_STRUCT(4) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
float z_;
|
||||
|
||||
public:
|
||||
Vec3() { memset(this, 0, sizeof(Vec3)); }
|
||||
Vec3(const Vec3 &_o) { memcpy(this, &_o, sizeof(Vec3)); }
|
||||
Vec3() {
|
||||
memset(this, 0, sizeof(Vec3));
|
||||
}
|
||||
Vec3(const Vec3 &_o) {
|
||||
memcpy(this, &_o, 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); }
|
||||
: 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);
|
||||
}
|
||||
};
|
||||
STRUCT_END(Vec3, 12);
|
||||
|
||||
@@ -112,9 +174,10 @@ struct MonsterT : public flatbuffers::NativeTable {
|
||||
std::vector<std::unique_ptr<WeaponT>> weapons;
|
||||
EquipmentUnion equipped;
|
||||
MonsterT()
|
||||
: mana(150),
|
||||
hp(100),
|
||||
color(Color_Blue) {}
|
||||
: mana(150),
|
||||
hp(100),
|
||||
color(Color_Blue) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -130,67 +193,135 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
VT_EQUIPPED_TYPE = 20,
|
||||
VT_EQUIPPED = 22
|
||||
};
|
||||
const Vec3 *pos() const { return GetStruct<const Vec3 *>(VT_POS); }
|
||||
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(VT_POS); }
|
||||
int16_t mana() const { return GetField<int16_t>(VT_MANA, 150); }
|
||||
bool mutate_mana(int16_t _mana) { return SetField(VT_MANA, _mana); }
|
||||
int16_t hp() const { return GetField<int16_t>(VT_HP, 100); }
|
||||
bool mutate_hp(int16_t _hp) { return SetField(VT_HP, _hp); }
|
||||
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); }
|
||||
Color color() const { return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2)); }
|
||||
bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast<int8_t>(_color)); }
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS); }
|
||||
flatbuffers::Vector<flatbuffers::Offset<Weapon>> *mutable_weapons() { return GetPointer<flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS); }
|
||||
Equipment equipped_type() const { return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0)); }
|
||||
bool mutate_equipped_type(Equipment _equipped_type) { return SetField(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type)); }
|
||||
const void *equipped() const { return GetPointer<const void *>(VT_EQUIPPED); }
|
||||
void *mutable_equipped() { return GetPointer<void *>(VT_EQUIPPED); }
|
||||
const Vec3 *pos() const {
|
||||
return GetStruct<const Vec3 *>(VT_POS);
|
||||
}
|
||||
Vec3 *mutable_pos() {
|
||||
return GetStruct<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);
|
||||
}
|
||||
Color color() const {
|
||||
return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
|
||||
}
|
||||
bool mutate_color(Color _color) {
|
||||
return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
|
||||
}
|
||||
flatbuffers::Vector<flatbuffers::Offset<Weapon>> *mutable_weapons() {
|
||||
return GetPointer<flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
|
||||
}
|
||||
Equipment equipped_type() const {
|
||||
return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0));
|
||||
}
|
||||
bool mutate_equipped_type(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 Weapon *equipped_as_Weapon() const {
|
||||
return equipped_type() == Equipment_Weapon ? static_cast<const Weapon *>(equipped()) : nullptr;
|
||||
}
|
||||
void *mutable_equipped() {
|
||||
return GetPointer<void *>(VT_EQUIPPED);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyField<Vec3>(verifier, VT_POS) &&
|
||||
VerifyField<int16_t>(verifier, VT_MANA) &&
|
||||
VerifyField<int16_t>(verifier, VT_HP) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffset(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_INVENTORY) &&
|
||||
VerifyOffset(verifier, VT_INVENTORY) &&
|
||||
verifier.Verify(inventory()) &&
|
||||
VerifyField<int8_t>(verifier, VT_COLOR) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_WEAPONS) &&
|
||||
VerifyOffset(verifier, VT_WEAPONS) &&
|
||||
verifier.Verify(weapons()) &&
|
||||
verifier.VerifyVectorOfTables(weapons()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_EQUIPPED) &&
|
||||
VerifyOffset(verifier, VT_EQUIPPED) &&
|
||||
VerifyEquipment(verifier, equipped(), equipped_type()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
MonsterT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
|
||||
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 Weapon *Monster::equipped_as<Weapon>() const {
|
||||
return equipped_as_Weapon();
|
||||
}
|
||||
|
||||
struct MonsterBuilder {
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_pos(const 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(Color color) { fbb_.AddElement<int8_t>(Monster::VT_COLOR, static_cast<int8_t>(color), 2); }
|
||||
void add_weapons(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons) { fbb_.AddOffset(Monster::VT_WEAPONS, weapons); }
|
||||
void add_equipped_type(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); }
|
||||
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
void add_pos(const 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(Color color) {
|
||||
fbb_.AddElement<int8_t>(Monster::VT_COLOR, static_cast<int8_t>(color), 2);
|
||||
}
|
||||
void add_weapons(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Weapon>>> weapons) {
|
||||
fbb_.AddOffset(Monster::VT_WEAPONS, weapons);
|
||||
}
|
||||
void add_equipped_type(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);
|
||||
}
|
||||
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
MonsterBuilder &operator=(const MonsterBuilder &);
|
||||
flatbuffers::Offset<Monster> Finish() {
|
||||
auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 10));
|
||||
const auto end = fbb_.EndTable(start_, 10);
|
||||
auto o = flatbuffers::Offset<Monster>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const Vec3 *pos = 0,
|
||||
int16_t mana = 150,
|
||||
int16_t hp = 100,
|
||||
@@ -213,7 +344,8 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonsterDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Monster> CreateMonsterDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const Vec3 *pos = 0,
|
||||
int16_t mana = 150,
|
||||
int16_t hp = 100,
|
||||
@@ -223,17 +355,28 @@ inline flatbuffers::Offset<Monster> CreateMonsterDirect(flatbuffers::FlatBufferB
|
||||
const std::vector<flatbuffers::Offset<Weapon>> *weapons = nullptr,
|
||||
Equipment equipped_type = Equipment_NONE,
|
||||
flatbuffers::Offset<void> equipped = 0) {
|
||||
return CreateMonster(_fbb, pos, mana, hp, name ? _fbb.CreateString(name) : 0, inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0, color, weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0, equipped_type, equipped);
|
||||
return MyGame::Sample::CreateMonster(
|
||||
_fbb,
|
||||
pos,
|
||||
mana,
|
||||
hp,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
inventory ? _fbb.CreateVector<uint8_t>(*inventory) : 0,
|
||||
color,
|
||||
weapons ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(*weapons) : 0,
|
||||
equipped_type,
|
||||
equipped);
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
|
||||
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) {}
|
||||
: damage(0) {
|
||||
}
|
||||
};
|
||||
|
||||
struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
@@ -242,35 +385,53 @@ struct Weapon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
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(VT_DAMAGE, _damage); }
|
||||
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) &&
|
||||
VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
|
||||
VerifyOffset(verifier, VT_NAME) &&
|
||||
verifier.Verify(name()) &&
|
||||
VerifyField<int16_t>(verifier, VT_DAMAGE) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
WeaponT *UnPack(const flatbuffers::resolver_function_t *resolver = nullptr) const;
|
||||
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); }
|
||||
WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
|
||||
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);
|
||||
}
|
||||
WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
WeaponBuilder &operator=(const WeaponBuilder &);
|
||||
flatbuffers::Offset<Weapon> Finish() {
|
||||
auto o = flatbuffers::Offset<Weapon>(fbb_.EndTable(start_, 2));
|
||||
const auto end = fbb_.EndTable(start_, 2);
|
||||
auto o = flatbuffers::Offset<Weapon>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::String> name = 0,
|
||||
int16_t damage = 0) {
|
||||
WeaponBuilder builder_(_fbb);
|
||||
@@ -279,96 +440,160 @@ inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Weapon> CreateWeaponDirect(flatbuffers::FlatBufferBuilder &_fbb,
|
||||
inline flatbuffers::Offset<Weapon> CreateWeaponDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const char *name = nullptr,
|
||||
int16_t damage = 0) {
|
||||
return CreateWeapon(_fbb, name ? _fbb.CreateString(name) : 0, damage);
|
||||
return MyGame::Sample::CreateWeapon(
|
||||
_fbb,
|
||||
name ? _fbb.CreateString(name) : 0,
|
||||
damage);
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *rehasher = nullptr);
|
||||
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 {
|
||||
(void)resolver;
|
||||
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 = std::unique_ptr<Vec3>(new 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) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } } };
|
||||
{ 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) { for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(resolver))); } } };
|
||||
{ auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver)); } } };
|
||||
{ auto _e = equipped_type(); _o->equipped.type = _e; };
|
||||
{ auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(), resolver); };
|
||||
return _o;
|
||||
{ auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _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;
|
||||
return CreateMonster(_fbb,
|
||||
_o->pos ? _o->pos.get() : 0,
|
||||
_o->mana,
|
||||
_o->hp,
|
||||
_o->name.size() ? _fbb.CreateString(_o->name) : 0,
|
||||
_o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0,
|
||||
_o->color,
|
||||
_o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get(), rehasher); }) : 0,
|
||||
_o->equipped.type,
|
||||
_o->equipped.Pack(_fbb));
|
||||
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
(void)_rehasher;
|
||||
(void)_o;
|
||||
auto _pos = _o->pos ? _o->pos.get() : 0;
|
||||
auto _mana = _o->mana;
|
||||
auto _hp = _o->hp;
|
||||
auto _name = _o->name.size() ? _fbb.CreateString(_o->name) : 0;
|
||||
auto _inventory = _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0;
|
||||
auto _color = _o->color;
|
||||
auto _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get(), _rehasher); }) : 0;
|
||||
auto _equipped_type = _o->equipped.type;
|
||||
auto _equipped = _o->equipped.Pack(_fbb);
|
||||
return MyGame::Sample::CreateMonster(
|
||||
_fbb,
|
||||
_pos,
|
||||
_mana,
|
||||
_hp,
|
||||
_name,
|
||||
_inventory,
|
||||
_color,
|
||||
_weapons,
|
||||
_equipped_type,
|
||||
_equipped);
|
||||
}
|
||||
|
||||
inline WeaponT *Weapon::UnPack(const flatbuffers::resolver_function_t *resolver) const {
|
||||
(void)resolver;
|
||||
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; };
|
||||
return _o;
|
||||
}
|
||||
|
||||
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;
|
||||
return CreateWeapon(_fbb,
|
||||
_o->name.size() ? _fbb.CreateString(_o->name) : 0,
|
||||
_o->damage);
|
||||
inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
|
||||
(void)_rehasher;
|
||||
(void)_o;
|
||||
auto _name = _o->name.size() ? _fbb.CreateString(_o->name) : 0;
|
||||
auto _damage = _o->damage;
|
||||
return MyGame::Sample::CreateWeapon(
|
||||
_fbb,
|
||||
_name,
|
||||
_damage);
|
||||
}
|
||||
|
||||
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *union_obj, Equipment type) {
|
||||
inline bool VerifyEquipment(flatbuffers::Verifier &verifier, const void *obj, Equipment type) {
|
||||
switch (type) {
|
||||
case Equipment_NONE: return true;
|
||||
case Equipment_Weapon: return verifier.VerifyTable(reinterpret_cast<const Weapon *>(union_obj));
|
||||
case Equipment_NONE: {
|
||||
return true;
|
||||
}
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const Weapon *>(obj);
|
||||
return verifier.VerifyTable(ptr);
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *union_obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
|
||||
inline bool VerifyEquipmentVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *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_NONE: return nullptr;
|
||||
case Equipment_Weapon: return reinterpret_cast<const Weapon *>(union_obj)->UnPack(resolver);
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const 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 {
|
||||
inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
|
||||
switch (type) {
|
||||
case Equipment_NONE: return 0;
|
||||
case Equipment_Weapon: return CreateWeapon(_fbb, reinterpret_cast<const WeaponT *>(table), rehasher).Union();
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<const 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 WeaponT(*reinterpret_cast<WeaponT *>(u.value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void EquipmentUnion::Reset() {
|
||||
switch (type) {
|
||||
case Equipment_Weapon: delete reinterpret_cast<WeaponT *>(table); break;
|
||||
case Equipment_Weapon: {
|
||||
auto ptr = reinterpret_cast<WeaponT *>(value);
|
||||
delete ptr;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
table = nullptr;
|
||||
value = nullptr;
|
||||
type = Equipment_NONE;
|
||||
}
|
||||
|
||||
@@ -380,16 +605,21 @@ inline Monster *GetMutableMonster(void *buf) {
|
||||
return flatbuffers::GetMutableRoot<Monster>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyMonsterBuffer(flatbuffers::Verifier &verifier) {
|
||||
inline bool VerifyMonsterBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<MyGame::Sample::Monster>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishMonsterBuffer(flatbuffers::FlatBufferBuilder &fbb, flatbuffers::Offset<MyGame::Sample::Monster> root) {
|
||||
inline void FinishMonsterBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<MyGame::Sample::Monster> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline std::unique_ptr<MonsterT> UnPackMonster(const void *buf, const flatbuffers::resolver_function_t *resolver = nullptr) {
|
||||
return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(resolver));
|
||||
inline std::unique_ptr<MonsterT> UnPackMonster(
|
||||
const void *buf,
|
||||
const flatbuffers::resolver_function_t *res = nullptr) {
|
||||
return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
|
||||
}
|
||||
|
||||
} // namespace Sample
|
||||
|
||||
@@ -19,147 +19,147 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
flatbuffers "github.com/google/flatbuffers/go"
|
||||
"fmt"
|
||||
"strconv"
|
||||
sample "MyGame/Sample"
|
||||
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)
|
||||
builder := flatbuffers.NewBuilder(0)
|
||||
|
||||
// Create some weapons for our Monster ("Sword" and "Axe").
|
||||
weaponOne := builder.CreateString("Sword")
|
||||
weaponTwo := builder.CreateString("Axe")
|
||||
// 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, weaponOne)
|
||||
sample.WeaponAddDamage(builder, 3)
|
||||
sword := sample.WeaponEnd(builder)
|
||||
|
||||
sample.WeaponStart(builder)
|
||||
sample.WeaponAddName(builder, weaponTwo)
|
||||
sample.WeaponAddDamage(builder, 5)
|
||||
axe := 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")
|
||||
// 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.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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
builder.Finish(orc)
|
||||
|
||||
// We now have a FlatBuffer that we could store on disk or send over a network.
|
||||
// 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...
|
||||
// ...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).
|
||||
// Instead, we are going to access this buffer right away (as if we just received it).
|
||||
|
||||
buf := builder.FinishedBytes()
|
||||
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 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: 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")
|
||||
// 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))))
|
||||
}
|
||||
// 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]))
|
||||
}
|
||||
}
|
||||
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)))
|
||||
// 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)
|
||||
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))
|
||||
}
|
||||
}
|
||||
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")
|
||||
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 + ".")
|
||||
}
|
||||
if assertPassed == false {
|
||||
panic("Assert failed! " + codeExecuted + " (" + actualValue +
|
||||
") was not equal to " + expectedValue + ".")
|
||||
}
|
||||
}
|
||||
|
||||
170
src/code_generators.cpp
Normal file
170
src/code_generators.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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/util.h"
|
||||
|
||||
#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) {
|
||||
|
||||
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 {
|
||||
assert(false && "could not find key");
|
||||
stream_ << key;
|
||||
}
|
||||
|
||||
// Update the text to everything after the }}.
|
||||
text = text.substr(end + 2);
|
||||
}
|
||||
if (!text.empty() && text.back() == '\\') {
|
||||
text.pop_back();
|
||||
stream_ << text;
|
||||
} else {
|
||||
stream_ << text << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
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.c_str());
|
||||
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.c_str());
|
||||
}
|
||||
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 whenever it is used
|
||||
// outside of its namespace.
|
||||
std::string BaseGenerator::WrapInNameSpace(const Namespace *ns,
|
||||
const std::string &name) const {
|
||||
if (CurrentNameSpace() == ns) return name;
|
||||
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 (std::next(it) != 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";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
402
src/flatc.cpp
402
src/flatc.cpp
@@ -14,105 +14,52 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include <limits>
|
||||
#include "flatbuffers/flatc.h"
|
||||
|
||||
#define FLATC_VERSION "1.5.0 (" __DATE__ ")"
|
||||
#include <list>
|
||||
|
||||
static void Error(const std::string &err, bool usage = false,
|
||||
bool show_exe_name = true);
|
||||
#define FLATC_VERSION "1.7.0 (" __DATE__ ")"
|
||||
|
||||
// This struct allows us to create a table of all possible output generators
|
||||
// for the various programming languages and formats we support.
|
||||
struct Generator {
|
||||
bool (*generate)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
const char *generator_opt_short;
|
||||
const char *generator_opt_long;
|
||||
const char *lang_name;
|
||||
bool (*generateGRPC)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
flatbuffers::IDLOptions::Language lang;
|
||||
const char *generator_help;
|
||||
namespace flatbuffers {
|
||||
|
||||
std::string (*make_rule)(const flatbuffers::Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name);
|
||||
};
|
||||
|
||||
const Generator generators[] = {
|
||||
{ flatbuffers::GenerateBinary, "-b", "--binary", "binary",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate wire format binaries for any data definitions",
|
||||
flatbuffers::BinaryMakeRule },
|
||||
{ flatbuffers::GenerateTextFile, "-t", "--json", "text",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate text output for any data definitions",
|
||||
flatbuffers::TextMakeRule },
|
||||
{ flatbuffers::GenerateCPP, "-c", "--cpp", "C++",
|
||||
flatbuffers::GenerateCppGRPC,
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate C++ headers for tables/structs",
|
||||
flatbuffers::CPPMakeRule },
|
||||
{ flatbuffers::GenerateGo, "-g", "--go", "Go",
|
||||
flatbuffers::GenerateGoGRPC,
|
||||
flatbuffers::IDLOptions::kGo,
|
||||
"Generate Go files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-j", "--java", "Java",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateGeneral, "-n", "--csharp", "C#",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kCSharp,
|
||||
"Generate C# classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePython, "-p", "--python", "Python",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate Python files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kMAX,
|
||||
"Generate PHP files for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
};
|
||||
|
||||
const char *g_program_name = nullptr;
|
||||
flatbuffers::Parser *g_parser = nullptr;
|
||||
|
||||
static void Warn(const std::string &warn, bool show_exe_name = true) {
|
||||
if (show_exe_name) printf("%s: ", g_program_name);
|
||||
printf("warning: %s\n", warn.c_str());
|
||||
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);
|
||||
include_directories.pop_back();
|
||||
include_directories.pop_back();
|
||||
}
|
||||
|
||||
static void Error(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("usage: %s [OPTION]... FILE... [-- FILE...]\n", g_program_name);
|
||||
for (size_t i = 0; i < sizeof(generators) / sizeof(generators[0]); ++i)
|
||||
printf(" %-12s %s %s.\n",
|
||||
generators[i].generator_opt_long,
|
||||
generators[i].generator_opt_short
|
||||
? generators[i].generator_opt_short
|
||||
: " ",
|
||||
generators[i].generator_help);
|
||||
printf(
|
||||
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";
|
||||
}
|
||||
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"
|
||||
@@ -141,78 +88,96 @@ static void Error(const std::string &err, bool usage, bool show_exe_name) {
|
||||
" --escape-proto-ids Disable appending '_' in namespaces names.\n"
|
||||
" --gen-object-api Generate an additional object-based API.\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() and T::length() must be supported\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"
|
||||
" --go-namespace Generate the overrided namespace in Golang.\n"
|
||||
" --raw-binary Allow binaries without file_indentifier to be read.\n"
|
||||
" This may crash flatc given a mismatched schema.\n"
|
||||
" --proto Input is a .proto, translate to .fbs.\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"
|
||||
" --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\n"
|
||||
" 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"
|
||||
"FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
|
||||
"FILEs after the -- must be 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: %s -c -b schema1.fbs schema2.fbs data.json\n",
|
||||
g_program_name);
|
||||
"example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
int FlatCompiler::Compile(int argc, const char** argv) {
|
||||
if (params_.generators == nullptr || params_.num_generators == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (g_parser) delete g_parser;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void ParseFile(flatbuffers::Parser &parser, const std::string &filename,
|
||||
const std::string &contents,
|
||||
std::vector<const char *> &include_directories) {
|
||||
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);
|
||||
include_directories.pop_back();
|
||||
include_directories.pop_back();
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
g_program_name = argv[0];
|
||||
flatbuffers::IDLOptions opts;
|
||||
std::string output_path;
|
||||
const size_t num_generators = sizeof(generators) / sizeof(generators[0]);
|
||||
bool generator_enabled[num_generators] = { false };
|
||||
|
||||
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 = 1; argi < argc; argi++) {
|
||||
|
||||
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(argv[argi], "");
|
||||
output_path = flatbuffers::ConCatPathFileName(
|
||||
flatbuffers::PosixPath(argv[argi]), "");
|
||||
} else if(arg == "-I") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
include_directories.push_back(argv[argi]);
|
||||
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 = argv[argi];
|
||||
conform_to_schema = flatbuffers::PosixPath(argv[argi]);
|
||||
} else if (arg == "--conform-includes") {
|
||||
if (++argi >= argc) Error("missing path following" + arg, true);
|
||||
conform_include_directories.push_back(argv[argi]);
|
||||
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 == "--no-js-exports") {
|
||||
opts.skip_js_exports = true;
|
||||
} else if(arg == "--goog-js-export") {
|
||||
opts.use_goog_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 == "--defaults-json") {
|
||||
opts.output_default_scalars_in_json = true;
|
||||
} else if (arg == "--unknown-json") {
|
||||
@@ -233,6 +198,9 @@ int main(int argc, const char *argv[]) {
|
||||
} 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 == "--gen-all") {
|
||||
opts.generate_all = true;
|
||||
opts.include_dependence_headers = false;
|
||||
@@ -260,13 +228,20 @@ int main(int argc, const char *argv[]) {
|
||||
exit(0);
|
||||
} else if(arg == "--grpc") {
|
||||
grpc_enabled = true;
|
||||
} else if(arg == "--bfbs-comments") {
|
||||
opts.binary_schema_comments = true;
|
||||
} else if(arg == "--no-fb-import") {
|
||||
opts.skip_flatbuffers_import = true;
|
||||
} else if(arg == "--no-ts-reexport") {
|
||||
opts.reexport_ts_modules = false;
|
||||
} else {
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
if (arg == generators[i].generator_opt_long ||
|
||||
(generators[i].generator_opt_short &&
|
||||
arg == generators[i].generator_opt_short)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -274,7 +249,7 @@ int main(int argc, const char *argv[]) {
|
||||
found:;
|
||||
}
|
||||
} else {
|
||||
filenames.push_back(argv[argi]);
|
||||
filenames.push_back(flatbuffers::PosixPath(argv[argi]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,109 +271,110 @@ int main(int argc, const char *argv[]) {
|
||||
conform_include_directories);
|
||||
}
|
||||
|
||||
// Now process the files:
|
||||
g_parser = new flatbuffers::Parser(opts);
|
||||
std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts));
|
||||
|
||||
for (auto file_it = filenames.begin();
|
||||
file_it != filenames.end();
|
||||
++file_it) {
|
||||
std::string contents;
|
||||
if (!flatbuffers::LoadFile(file_it->c_str(), true, &contents))
|
||||
Error("unable to load file: " + *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;
|
||||
if (is_binary) {
|
||||
g_parser->builder_.Clear();
|
||||
g_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 (!g_parser->file_identifier_.length()) {
|
||||
Error("current schema has no file_identifier: cannot test if \"" +
|
||||
*file_it +
|
||||
"\" matches the schema, use --raw-binary to read this file"
|
||||
" anyway.");
|
||||
} else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
|
||||
g_parser->file_identifier_.c_str())) {
|
||||
Error("binary \"" +
|
||||
*file_it +
|
||||
"\" does not have expected file_identifier \"" +
|
||||
g_parser->file_identifier_ +
|
||||
"\", use --raw-binary to read this file anyway.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check if file contains 0 bytes.
|
||||
if (contents.length() != strlen(contents.c_str())) {
|
||||
Error("input file appears to be binary: " + *file_it, true);
|
||||
}
|
||||
auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs";
|
||||
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.
|
||||
delete g_parser;
|
||||
g_parser = new flatbuffers::Parser(opts);
|
||||
}
|
||||
ParseFile(*g_parser, *file_it, contents, include_directories);
|
||||
if (is_schema && !conform_to_schema.empty()) {
|
||||
auto err = g_parser->ConformTo(conform_parser);
|
||||
if (!err.empty()) Error("schemas don\'t conform: " + err);
|
||||
}
|
||||
if (schema_binary) {
|
||||
g_parser->Serialize();
|
||||
g_parser->file_extension_ = reflection::SchemaExtension();
|
||||
bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
|
||||
binary_files_from;
|
||||
auto is_schema = flatbuffers::GetExtension(filename) == "fbs";
|
||||
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())) {
|
||||
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 (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));
|
||||
}
|
||||
ParseFile(*parser.get(), filename, contents, include_directories);
|
||||
if (is_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(*file_it));
|
||||
std::string filebase = flatbuffers::StripPath(
|
||||
flatbuffers::StripExtension(filename));
|
||||
|
||||
for (size_t i = 0; i < num_generators; ++i) {
|
||||
g_parser->opts.lang = generators[i].lang;
|
||||
if (generator_enabled[i]) {
|
||||
if (!print_make_rules) {
|
||||
flatbuffers::EnsureDirExists(output_path);
|
||||
if (!generators[i].generate(*g_parser, output_path, filebase)) {
|
||||
Error(std::string("Unable to generate ") +
|
||||
generators[i].lang_name +
|
||||
" for " +
|
||||
filebase);
|
||||
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) &&
|
||||
!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 {
|
||||
std::string make_rule = generators[i].make_rule(
|
||||
*g_parser, output_path, *file_it);
|
||||
if (!make_rule.empty())
|
||||
printf("%s\n", flatbuffers::WordWrap(
|
||||
make_rule, 80, " ", " \\").c_str());
|
||||
}
|
||||
if (grpc_enabled) {
|
||||
if (generators[i].generateGRPC != nullptr) {
|
||||
if (!generators[i].generateGRPC(*g_parser, output_path,
|
||||
filebase)) {
|
||||
Error(std::string("Unable to generate GRPC interface for") +
|
||||
generators[i].lang_name);
|
||||
}
|
||||
} else {
|
||||
Warn(std::string("GRPC interface generator not implemented for ")
|
||||
+ generators[i].lang_name);
|
||||
}
|
||||
Warn(std::string("GRPC interface generator not implemented for ")
|
||||
+ params_.generators[i].lang_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.proto_mode) GenerateFBS(*g_parser, output_path, filebase);
|
||||
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.
|
||||
g_parser->MarkGenerated();
|
||||
// We do not want to generate code for the definitions in this file
|
||||
// in any files coming up next.
|
||||
parser->MarkGenerated();
|
||||
}
|
||||
|
||||
delete g_parser;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
109
src/flatc_main.cpp
Normal file
109
src/flatc_main.cpp
Normal file
@@ -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"
|
||||
|
||||
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[]) {
|
||||
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,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJava,
|
||||
"Generate Java classes for tables/structs",
|
||||
flatbuffers::GeneralMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-s", "--js", "JavaScript", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kJs,
|
||||
"Generate JavaScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ flatbuffers::GenerateJS, "-T", "--ts", "TypeScript", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kTs,
|
||||
"Generate TypeScript code for tables/structs",
|
||||
flatbuffers::JSMakeRule },
|
||||
{ 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::GeneratePhp, nullptr, "--php", "PHP", true,
|
||||
nullptr,
|
||||
flatbuffers::IDLOptions::kPhp,
|
||||
"Generate PHP files for tables/structs",
|
||||
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);
|
||||
}
|
||||
2534
src/idl_gen_cpp.cpp
2534
src/idl_gen_cpp.cpp
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -71,12 +72,12 @@ std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
|
||||
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->first));
|
||||
if (basename != file_name) {
|
||||
schema += "include \"" + basename + ".fbs\";\n";
|
||||
num_includes++;
|
||||
}
|
||||
flatbuffers::StripExtension(it->second));
|
||||
schema += "include \"" + basename + ".fbs\";\n";
|
||||
num_includes++;
|
||||
}
|
||||
if (num_includes) schema += "\n";
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/code_generators.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -39,37 +38,6 @@ std::string MakeCamel(const std::string &in, bool first) {
|
||||
return s;
|
||||
}
|
||||
|
||||
struct CommentConfig {
|
||||
const char *first_line;
|
||||
const char *content_line_prefix;
|
||||
const char *last_line;
|
||||
};
|
||||
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
|
||||
// These arrays need to correspond to the IDLOptions::k enum.
|
||||
|
||||
struct LanguageParameters {
|
||||
@@ -101,108 +69,80 @@ struct LanguageParameters {
|
||||
CommentConfig comment_config;
|
||||
};
|
||||
|
||||
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.*;\n"
|
||||
"import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
|
||||
const LanguageParameters& GetLangParams(IDLOptions::Language lang) {
|
||||
static 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.*;\n"
|
||||
"import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
|
||||
{
|
||||
"/**",
|
||||
" *",
|
||||
" */",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
IDLOptions::kCSharp,
|
||||
true,
|
||||
".cs",
|
||||
"string",
|
||||
"bool ",
|
||||
"\n{\n",
|
||||
"struct ",
|
||||
" readonly ",
|
||||
"",
|
||||
"enum ",
|
||||
",\n",
|
||||
" { get",
|
||||
"} ",
|
||||
" : ",
|
||||
"namespace ",
|
||||
"\n{",
|
||||
"\n}\n",
|
||||
"",
|
||||
"Position",
|
||||
"Offset",
|
||||
"__p.",
|
||||
"Table.",
|
||||
"?",
|
||||
"using System;\nusing FlatBuffers;\n\n",
|
||||
{
|
||||
nullptr,
|
||||
"///",
|
||||
nullptr,
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
// TODO: add Go support to the general generator.
|
||||
// WARNING: this is currently only used for generating make rules for Go.
|
||||
{
|
||||
IDLOptions::kGo,
|
||||
true,
|
||||
".go",
|
||||
"string",
|
||||
"bool ",
|
||||
"\n{\n",
|
||||
"class ",
|
||||
"const ",
|
||||
" ",
|
||||
"class ",
|
||||
";\n",
|
||||
"()",
|
||||
"",
|
||||
"",
|
||||
"package ",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"position()",
|
||||
"offset()",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"import (\n\tflatbuffers \"github.com/google/flatbuffers/go\"\n)",
|
||||
{
|
||||
nullptr,
|
||||
"///",
|
||||
nullptr,
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(language_parameters) / sizeof(LanguageParameters) ==
|
||||
IDLOptions::kMAX,
|
||||
"Please add extra elements to the arrays above.");
|
||||
if (lang == IDLOptions::kJava) {
|
||||
return language_parameters[0];
|
||||
} else {
|
||||
assert(lang == IDLOptions::kCSharp);
|
||||
return language_parameters[1];
|
||||
}
|
||||
}
|
||||
|
||||
namespace general {
|
||||
class GeneralGenerator : public BaseGenerator {
|
||||
@@ -210,10 +150,10 @@ class GeneralGenerator : public BaseGenerator {
|
||||
GeneralGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "", "."),
|
||||
lang_(language_parameters[parser_.opts.lang]),
|
||||
lang_(GetLangParams(parser_.opts.lang)),
|
||||
cur_name_space_( nullptr ) {
|
||||
assert(parser_.opts.lang <= IDLOptions::kMAX);
|
||||
};
|
||||
}
|
||||
|
||||
GeneralGenerator &operator=(const GeneralGenerator &);
|
||||
bool generate() {
|
||||
std::string one_file_code;
|
||||
@@ -263,7 +203,14 @@ class GeneralGenerator : public BaseGenerator {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
std::string code;
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
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;
|
||||
@@ -276,7 +223,7 @@ class GeneralGenerator : public BaseGenerator {
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
const Namespace *CurrentNameSpace() { return cur_name_space_; }
|
||||
const Namespace *CurrentNameSpace() const { return cur_name_space_; }
|
||||
|
||||
std::string FunctionStart(char upper) {
|
||||
return std::string() + (lang_.language == IDLOptions::kJava
|
||||
@@ -289,9 +236,16 @@ static bool IsEnum(const Type& type) {
|
||||
}
|
||||
|
||||
std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
|
||||
static const char *gtypename[] = {
|
||||
static const char *java_typename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#JTYPE, #NTYPE, #GTYPE,
|
||||
#JTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
|
||||
static const char *csharp_typename[] = {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
|
||||
#NTYPE,
|
||||
FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
};
|
||||
@@ -305,7 +259,12 @@ std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
|
||||
}
|
||||
}
|
||||
|
||||
return gtypename[type.base_type * IDLOptions::kMAX + lang_.language];
|
||||
if (lang_.language == IDLOptions::kJava) {
|
||||
return java_typename[type.base_type];
|
||||
} else {
|
||||
assert(lang_.language == IDLOptions::kCSharp);
|
||||
return csharp_typename[type.base_type];
|
||||
}
|
||||
}
|
||||
|
||||
std::string GenTypeBasic(const Type &type) {
|
||||
@@ -348,7 +307,7 @@ Type DestinationType(const Type &type, bool vectorelem) {
|
||||
case BASE_TYPE_VECTOR:
|
||||
if (vectorelem)
|
||||
return DestinationType(type.VectorType(), vectorelem);
|
||||
// else fall thru:
|
||||
// else fall thru
|
||||
default: return type;
|
||||
}
|
||||
}
|
||||
@@ -395,7 +354,7 @@ std::string DestinationMask(const Type &type, bool vectorelem) {
|
||||
case BASE_TYPE_VECTOR:
|
||||
if (vectorelem)
|
||||
return DestinationMask(type.VectorType(), vectorelem);
|
||||
// else fall thru:
|
||||
// else fall thru
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
@@ -495,7 +454,7 @@ std::string GenDefaultValue(const Value &value, bool enableLangOverrides) {
|
||||
switch (value.type.base_type) {
|
||||
case BASE_TYPE_FLOAT: return value.constant + "f";
|
||||
case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
|
||||
case BASE_TYPE_ULONG:
|
||||
case BASE_TYPE_ULONG:
|
||||
{
|
||||
if (lang_.language != IDLOptions::kJava)
|
||||
return value.constant;
|
||||
@@ -634,6 +593,22 @@ std::string GenGetter(const Type &type) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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) {
|
||||
@@ -746,12 +721,11 @@ std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) {
|
||||
key_getter += GenOffsetGetter(key_field);
|
||||
key_getter += ", byteKey, bb);\n";
|
||||
} else {
|
||||
auto get_val = GenGetter(key_field->value.type) +
|
||||
"(" + GenOffsetGetter(key_field) + ")";
|
||||
auto get_val = GenGetterForLookupByKey(key_field, "bb");
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
|
||||
} else {
|
||||
key_getter += GenTypeGet(key_field->value.type) + " val = ";
|
||||
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";
|
||||
}
|
||||
@@ -775,20 +749,17 @@ std::string GenKeyGetter(flatbuffers::FieldDef *key_field) {
|
||||
key_getter += ";";
|
||||
}
|
||||
else {
|
||||
auto field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
|
||||
"(" + GenOffsetGetter(key_field, "o1") + ")";
|
||||
auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
|
||||
if (lang_.language == IDLOptions::kCSharp) {
|
||||
key_getter += field_getter;
|
||||
field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
|
||||
"(" + GenOffsetGetter(key_field, "o2") + ")";
|
||||
field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
|
||||
key_getter += ".CompareTo(" + field_getter + ")";
|
||||
}
|
||||
else {
|
||||
key_getter += "\n " + GenTypeGet(key_field->value.type) + " val_1 = ";
|
||||
key_getter += field_getter + ";\n " + GenTypeGet(key_field->value.type);
|
||||
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 = data_buffer + GenGetter(key_field->value.type).substr(2) +
|
||||
"(" + GenOffsetGetter(key_field, "o2") + ")";
|
||||
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 ";
|
||||
}
|
||||
@@ -1040,6 +1011,26 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
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) {
|
||||
code += " public " + sd.name + lang_.optional_suffix + " ";
|
||||
code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
|
||||
code += GenTypeNameDest(key_field.value.type) + " key)";
|
||||
code += offset_prefix;
|
||||
code += sd.name + ".__lookup_by_key(";
|
||||
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 &&
|
||||
@@ -1326,7 +1317,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
code += "); }\n";
|
||||
}
|
||||
}
|
||||
if (struct_def.has_key) {
|
||||
// Only generate key compare function for table,
|
||||
// because `key_field` is not set for struct
|
||||
if (struct_def.has_key && !struct_def.fixed) {
|
||||
if (lang_.language == IDLOptions::kJava) {
|
||||
code += "\n @Override\n protected int keysCompare(";
|
||||
code += "Integer o1, Integer o2, ByteBuffer _bb) {";
|
||||
@@ -1335,7 +1328,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
}
|
||||
else {
|
||||
code += "\n public static VectorOffset ";
|
||||
code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, ";
|
||||
code += "CreateSortedVectorOf" + struct_def.name;
|
||||
code += "(FlatBufferBuilder builder, ";
|
||||
code += "Offset<" + struct_def.name + ">";
|
||||
code += "[] offsets) {\n";
|
||||
code += " Array.Sort(offsets, (Offset<" + struct_def.name +
|
||||
@@ -1345,8 +1339,8 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
}
|
||||
|
||||
code += "\n public static " + struct_def.name + lang_.optional_suffix;
|
||||
code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType();
|
||||
code += " vectorOffset, " + GenTypeGet(key_field->value.type);
|
||||
code += " __lookup_by_key(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 = ";
|
||||
@@ -1355,13 +1349,9 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
else
|
||||
code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
|
||||
}
|
||||
code += " int vectorLocation = " + GenByteBufferLength("bb");
|
||||
code += " - vectorOffset";
|
||||
if (lang_.language == IDLOptions::kCSharp) code += ".Value";
|
||||
code += ";\n int span = ";
|
||||
code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n";
|
||||
code += " int span = ";
|
||||
code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
|
||||
code += " int start = 0;\n";
|
||||
code += " vectorLocation += 4;\n";
|
||||
code += " while (span != 0) {\n";
|
||||
code += " int middle = span / 2;\n";
|
||||
code += GenLookupKeyGetter(key_field);
|
||||
@@ -1383,7 +1373,7 @@ void GenStruct(StructDef &struct_def, std::string *code_ptr) {
|
||||
code += (lang_.language != IDLOptions::kJava) ? ";" : "";
|
||||
code += "\n\n";
|
||||
}
|
||||
const LanguageParameters & lang_;
|
||||
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_;
|
||||
};
|
||||
@@ -1398,7 +1388,7 @@ bool GenerateGeneral(const Parser &parser, const std::string &path,
|
||||
std::string GeneralMakeRule(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
assert(parser.opts.lang <= IDLOptions::kMAX);
|
||||
auto lang = language_parameters[parser.opts.lang];
|
||||
const auto &lang = GetLangParams(parser.opts.lang);
|
||||
|
||||
std::string make_rule;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
@@ -35,6 +36,13 @@
|
||||
namespace flatbuffers {
|
||||
namespace go {
|
||||
|
||||
// see https://golang.org/ref/spec#Keywords
|
||||
static const char *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 GenGetter(const Type &type);
|
||||
static std::string GenMethod(const FieldDef &field);
|
||||
static void GenStructBuilder(const StructDef &struct_def,
|
||||
@@ -43,6 +51,15 @@ static void GenReceiver(const StructDef &struct_def, std::string *code_ptr);
|
||||
static std::string GenTypeBasic(const Type &type);
|
||||
static std::string GenTypeGet(const Type &type);
|
||||
static std::string TypeName(const FieldDef &field);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// Most field accessors need to retrieve and test the field offset first,
|
||||
@@ -368,7 +385,7 @@ static void StructBuilderArgs(const StructDef &struct_def,
|
||||
} else {
|
||||
std::string &code = *code_ptr;
|
||||
code += (std::string)", " + nameprefix;
|
||||
code += MakeCamel(field.name, false);
|
||||
code += GoIdentity(field.name);
|
||||
code += " " + GenTypeBasic(field.value.type);
|
||||
}
|
||||
}
|
||||
@@ -400,7 +417,7 @@ static void StructBuilderBody(const StructDef &struct_def,
|
||||
code_ptr);
|
||||
} else {
|
||||
code += "\tbuilder.Prepend" + GenMethod(field) + "(";
|
||||
code += nameprefix + MakeCamel(field.name, false) + ")\n";
|
||||
code += nameprefix + GoIdentity(field.name) + ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,7 +447,7 @@ static void BuildFieldOfTable(const StructDef &struct_def,
|
||||
std::string &code = *code_ptr;
|
||||
code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
|
||||
code += "(builder *flatbuffers.Builder, ";
|
||||
code += MakeCamel(field.name, false) + " ";
|
||||
code += GoIdentity(field.name) + " ";
|
||||
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
|
||||
code += "flatbuffers.UOffsetT";
|
||||
} else {
|
||||
@@ -443,9 +460,9 @@ static void BuildFieldOfTable(const StructDef &struct_def,
|
||||
if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
|
||||
code += "flatbuffers.UOffsetT";
|
||||
code += "(";
|
||||
code += MakeCamel(field.name, false) + ")";
|
||||
code += GoIdentity(field.name) + ")";
|
||||
} else {
|
||||
code += MakeCamel(field.name, false);
|
||||
code += GoIdentity(field.name);
|
||||
}
|
||||
code += ", " + field.value.constant;
|
||||
code += ")\n}\n";
|
||||
@@ -724,9 +741,15 @@ static void GenStructBuilder(const StructDef &struct_def,
|
||||
class GoGenerator : public BaseGenerator {
|
||||
public:
|
||||
GoGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, file_name, "" /* not used*/,
|
||||
"" /* not used */){};
|
||||
const std::string &file_name, const std::string &go_namespace)
|
||||
: BaseGenerator(parser, path, file_name, "" /* not used*/, "" /* not used */) {
|
||||
std::istringstream iss(go_namespace);
|
||||
std::string component;
|
||||
while (std::getline(iss, component, '.')) {
|
||||
go_namespace_.components.push_back(component);
|
||||
}
|
||||
}
|
||||
|
||||
bool generate() {
|
||||
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
|
||||
++it) {
|
||||
@@ -750,7 +773,7 @@ class GoGenerator : public BaseGenerator {
|
||||
void BeginFile(const std::string name_space_name, const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
code += "package " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import (\n";
|
||||
@@ -764,19 +787,22 @@ class GoGenerator : public BaseGenerator {
|
||||
bool needs_imports) {
|
||||
if (!classcode.length()) return true;
|
||||
|
||||
Namespace& ns = go_namespace_.components.empty() ? *def.defined_namespace : go_namespace_;
|
||||
std::string code = "";
|
||||
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
|
||||
BeginFile(LastNamespacePart(ns), needs_imports, &code);
|
||||
code += classcode;
|
||||
std::string filename =
|
||||
NamespaceDir(*def.defined_namespace) + def.name + ".go";
|
||||
NamespaceDir(ns) + def.name + ".go";
|
||||
return SaveFile(filename.c_str(), code, false);
|
||||
}
|
||||
|
||||
Namespace go_namespace_;
|
||||
};
|
||||
} // namespace go
|
||||
|
||||
bool GenerateGo(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name) {
|
||||
go::GoGenerator generator(parser, path, file_name);
|
||||
go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
|
||||
return generator.generate();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
#include "src/compiler/cpp_generator.h"
|
||||
#include "src/compiler/go_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 {
|
||||
@@ -41,30 +46,52 @@ class FlatBufMethod : public grpc_generator::Method {
|
||||
}
|
||||
}
|
||||
|
||||
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 name() const { return method_->name; }
|
||||
|
||||
std::string GRPCType(const StructDef &sd) const {
|
||||
return "flatbuffers::BufferRef<" + sd.name + ">";
|
||||
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);
|
||||
}
|
||||
|
||||
std::string input_name() const {
|
||||
return (*method_->request).name;
|
||||
}
|
||||
|
||||
std::string output_name() const {
|
||||
return (*method_->response).name;
|
||||
}
|
||||
|
||||
bool NoStreaming() const { return streaming_ == kNone; }
|
||||
bool ClientOnlyStreaming() const { return streaming_ == kClient; }
|
||||
bool ServerOnlyStreaming() const { return streaming_ == kServer; }
|
||||
bool ClientStreaming() const { return streaming_ == kClient; }
|
||||
bool ServerStreaming() const { return streaming_ == kServer; }
|
||||
bool BidiStreaming() const { return streaming_ == kBiDi; }
|
||||
|
||||
private:
|
||||
@@ -76,6 +103,16 @@ 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 std::vector<grpc::string>();
|
||||
}
|
||||
|
||||
std::string name() const { return service_->name; }
|
||||
|
||||
int method_count() const {
|
||||
@@ -117,6 +154,9 @@ class FlatBufPrinter : public grpc_generator::Printer {
|
||||
}
|
||||
|
||||
void Print(const char *s) {
|
||||
if (s == nullptr || std::strlen(s) == 0) {
|
||||
return;
|
||||
}
|
||||
// Add this string, but for each part separated by \n, add indentation.
|
||||
for (;;) {
|
||||
// Current indentation.
|
||||
@@ -145,10 +185,26 @@ class FlatBufPrinter : public grpc_generator::Printer {
|
||||
|
||||
class FlatBufFile : public grpc_generator::File {
|
||||
public:
|
||||
FlatBufFile(const Parser &parser, const std::string &file_name)
|
||||
: parser_(parser), file_name_(file_name) {}
|
||||
enum Language {
|
||||
kLanguageGo,
|
||||
kLanguageCpp
|
||||
};
|
||||
|
||||
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_);
|
||||
@@ -166,11 +222,15 @@ class FlatBufFile : public grpc_generator::File {
|
||||
}
|
||||
|
||||
std::string additional_headers() const {
|
||||
return "#include \"flatbuffers/grpc.h\"\n";
|
||||
}
|
||||
|
||||
std::string additional_imports() const {
|
||||
return "import \"github.com/google/flatbuffers/go\"";
|
||||
switch (language_) {
|
||||
case kLanguageCpp: {
|
||||
return "#include \"flatbuffers/grpc.h\"\n";
|
||||
}
|
||||
case kLanguageGo: {
|
||||
return "import \"github.com/google/flatbuffers/go\"";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
int service_count() const {
|
||||
@@ -190,6 +250,7 @@ class FlatBufFile : public grpc_generator::File {
|
||||
private:
|
||||
const Parser &parser_;
|
||||
const std::string &file_name_;
|
||||
const Language language_;
|
||||
};
|
||||
|
||||
class GoGRPCGenerator : public flatbuffers::BaseGenerator {
|
||||
@@ -200,7 +261,7 @@ class GoGRPCGenerator : public flatbuffers::BaseGenerator {
|
||||
parser_(parser), path_(path), file_name_(file_name) {}
|
||||
|
||||
bool generate() {
|
||||
FlatBufFile file(parser_, file_name_);
|
||||
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++) {
|
||||
@@ -233,7 +294,7 @@ bool GenerateGoGRPC(const Parser &parser,
|
||||
}
|
||||
|
||||
bool GenerateCppGRPC(const Parser &parser,
|
||||
const std::string &/*path*/,
|
||||
const std::string &path,
|
||||
const std::string &file_name) {
|
||||
|
||||
int nservices = 0;
|
||||
@@ -247,7 +308,7 @@ bool GenerateCppGRPC(const Parser &parser,
|
||||
// TODO(wvo): make the other parameters in this struct configurable.
|
||||
generator_parameters.use_system_headers = true;
|
||||
|
||||
FlatBufFile fbfile(parser, file_name);
|
||||
FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
|
||||
|
||||
std::string header_code =
|
||||
grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
|
||||
@@ -261,11 +322,15 @@ bool GenerateCppGRPC(const Parser &parser,
|
||||
grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
|
||||
grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
|
||||
|
||||
return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
|
||||
return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
|
||||
header_code, false) &&
|
||||
flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
|
||||
flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
|
||||
source_code, false);
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*/
|
||||
|
||||
// independent from idl_parser, since this code is not needed for most clients
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <cassert>
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
@@ -23,9 +26,43 @@
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
const std::string kGeneratedFileNamePostfix = "_generated";
|
||||
|
||||
struct JsLanguageParameters {
|
||||
IDLOptions::Language language;
|
||||
std::string file_extension;
|
||||
};
|
||||
|
||||
struct ReexportDescription {
|
||||
std::string symbol;
|
||||
std::string source_namespace;
|
||||
std::string target_namespace;
|
||||
};
|
||||
|
||||
const JsLanguageParameters& GetJsLangParams(IDLOptions::Language lang) {
|
||||
static JsLanguageParameters js_language_parameters[] = {
|
||||
{
|
||||
IDLOptions::kJs,
|
||||
".js",
|
||||
},
|
||||
{
|
||||
IDLOptions::kTs,
|
||||
".ts",
|
||||
},
|
||||
};
|
||||
|
||||
if (lang == IDLOptions::kJs) {
|
||||
return js_language_parameters[0];
|
||||
} else {
|
||||
assert(lang == IDLOptions::kTs);
|
||||
return js_language_parameters[1];
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GeneratedFileName(const std::string &path,
|
||||
const std::string &file_name) {
|
||||
return path + file_name + "_generated.js";
|
||||
const std::string &file_name,
|
||||
const JsLanguageParameters &lang) {
|
||||
return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
@@ -33,56 +70,127 @@ namespace js {
|
||||
// and tables) and output them to a single file.
|
||||
class JsGenerator : public BaseGenerator {
|
||||
public:
|
||||
typedef std::unordered_set<std::string> imported_fileset;
|
||||
typedef std::unordered_multimap<std::string, ReexportDescription>
|
||||
reexport_map;
|
||||
|
||||
JsGenerator(const Parser &parser, const std::string &path,
|
||||
const std::string &file_name)
|
||||
: BaseGenerator(parser, path, 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() {
|
||||
if (IsEverythingGenerated()) return true;
|
||||
imported_fileset imported_files;
|
||||
reexport_map reexports;
|
||||
|
||||
std::string enum_code, struct_code, exports_code, code;
|
||||
generateEnums(&enum_code, &exports_code);
|
||||
generateStructs(&struct_code, &exports_code);
|
||||
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();
|
||||
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 (!exports_code.empty() && !parser_.opts.skip_js_exports) {
|
||||
if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
|
||||
!parser_.opts.skip_js_exports) {
|
||||
code += "// Exports for Node.js and RequireJS\n";
|
||||
code += exports_code;
|
||||
}
|
||||
|
||||
return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
|
||||
return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
|
||||
false);
|
||||
}
|
||||
|
||||
private:
|
||||
JsLanguageParameters 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_) {
|
||||
const auto file_name = basename + kGeneratedFileNamePostfix;
|
||||
code += GenPrefixedImport(file, file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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_) {
|
||||
const auto file_name = basename + kGeneratedFileNamePostfix;
|
||||
|
||||
if (imported_files.find(file.first) == imported_files.end()) {
|
||||
code += GenPrefixedImport(file.first, file_name);
|
||||
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) {
|
||||
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);
|
||||
GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate code for all structs.
|
||||
void generateStructs(std::string *decl_code_ptr,
|
||||
std::string *exports_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);
|
||||
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();
|
||||
@@ -110,12 +218,23 @@ class JsGenerator : public BaseGenerator {
|
||||
std::string &exports = *exports_ptr;
|
||||
for (auto it = sorted_namespaces.begin();
|
||||
it != sorted_namespaces.end(); it++) {
|
||||
code += "/**\n * @const\n * @namespace\n */\n";
|
||||
if (it->find('.') == std::string::npos) {
|
||||
code += "var ";
|
||||
exports += "this." + *it + " = " + *it + ";\n";
|
||||
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 {
|
||||
exports += "this." + *it + " = " + *it + ";\n";
|
||||
}
|
||||
}
|
||||
code += *it + " = " + *it + " || {};\n\n";
|
||||
}
|
||||
code += *it + " = " + *it + " || {};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,16 +284,26 @@ static void GenDocComment(std::string *code_ptr,
|
||||
|
||||
// Generate an enum declaration and an enum string lookup table.
|
||||
void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
std::string *exports_ptr) {
|
||||
std::string *exports_ptr, reexport_map &reexports) {
|
||||
if (enum_def.generated) return;
|
||||
std::string &code = *code_ptr;
|
||||
std::string &exports = *exports_ptr;
|
||||
GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
|
||||
if (enum_def.defined_namespace->components.empty()) {
|
||||
code += "var ";
|
||||
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "export namespace " + GetNameSpace(enum_def) + "{\n" +
|
||||
"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 {
|
||||
exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
|
||||
}
|
||||
}
|
||||
code += WrapInNameSpace(enum_def) + " = {\n";
|
||||
}
|
||||
code += WrapInNameSpace(enum_def) + " = {\n";
|
||||
for (auto it = enum_def.vals.vec.begin();
|
||||
it != enum_def.vals.vec.end(); ++it) {
|
||||
auto &ev = **it;
|
||||
@@ -184,10 +313,27 @@ void GenEnum(EnumDef &enum_def, std::string *code_ptr,
|
||||
}
|
||||
GenDocComment(ev.doc_comment, code_ptr, "", " ");
|
||||
}
|
||||
code += " " + ev.name + ": " + NumToString(ev.value);
|
||||
code += " " + ev.name;
|
||||
code += lang_.language == IDLOptions::kTs ? "= " : ": ";
|
||||
code += NumToString(ev.value);
|
||||
code += (it + 1) != enum_def.vals.vec.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) {
|
||||
code += "}};\n\n";
|
||||
} else {
|
||||
code += "};\n\n";
|
||||
}
|
||||
code += "};\n\n";
|
||||
}
|
||||
|
||||
static std::string GenType(const Type &type) {
|
||||
@@ -235,7 +381,15 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
|
||||
if (value.type.enum_def) {
|
||||
if (auto val = value.type.enum_def->ReverseLookup(
|
||||
atoi(value.constant.c_str()), false)) {
|
||||
return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
|
||||
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 "/** @type {" + WrapInNameSpace(*value.type.enum_def) + "} */ ("
|
||||
+ value.constant + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,13 +412,16 @@ std::string GenDefaultValue(const Value &value, const std::string &context) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GenTypeName(const Type &type, bool input) {
|
||||
std::string GenTypeName(const Type &type, bool input, bool allowNull = false) {
|
||||
if (!input) {
|
||||
if (type.base_type == BASE_TYPE_STRING) {
|
||||
return "string|Uint8Array";
|
||||
}
|
||||
if (type.base_type == BASE_TYPE_STRUCT) {
|
||||
return WrapInNameSpace(*type.struct_def);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +467,28 @@ static std::string MaybeScale(T value) {
|
||||
return value != 1 ? " * " + NumToString(value) : "";
|
||||
}
|
||||
|
||||
static std::string GenFileNamespacePrefix(const std::string &file) {
|
||||
return "NS" + std::to_string(
|
||||
static_cast<unsigned long long>(std::hash<std::string>()(file)));
|
||||
}
|
||||
|
||||
static std::string GenPrefixedImport(const std::string &full_file_name,
|
||||
const std::string &base_file_name) {
|
||||
return "import * as "+ GenFileNamespacePrefix(full_file_name) +
|
||||
" from \"./" + base_file_name + "\";\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_) {
|
||||
return typeName;
|
||||
}
|
||||
return GenFileNamespacePrefix(file) + "." + typeName;
|
||||
}
|
||||
|
||||
void GenStructArgs(const StructDef &struct_def,
|
||||
std::string *annotations,
|
||||
std::string *arguments,
|
||||
@@ -326,7 +505,13 @@ void GenStructArgs(const StructDef &struct_def,
|
||||
} else {
|
||||
*annotations += "@param {" + GenTypeName(field.value.type, true);
|
||||
*annotations += "} " + nameprefix + field.name + "\n";
|
||||
*arguments += ", " + nameprefix + field.name;
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
*arguments += ", " + nameprefix + field.name + ": " +
|
||||
GenTypeName(field.value.type, true);
|
||||
} else {
|
||||
*arguments += ", " + nameprefix + field.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,32 +546,59 @@ static void GenStructBody(const StructDef &struct_def,
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
|
||||
// Emit constructor
|
||||
bool isStatement = struct_def.defined_namespace->components.empty();
|
||||
std::string object_name = WrapInNameSpace(struct_def);
|
||||
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
|
||||
if (isStatement) {
|
||||
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
|
||||
code += "function " + object_name;
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
object_name = struct_def.name;
|
||||
std::string object_namespace = GetNameSpace(struct_def);
|
||||
GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
|
||||
code += "export namespace " + object_namespace + "{\n";
|
||||
code += "export class " + struct_def.name;
|
||||
code += " {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " bb: flatbuffers.ByteBuffer;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
code += " */\n";
|
||||
code += " bb_pos:number = 0;\n";
|
||||
} else {
|
||||
code += object_name + " = function";
|
||||
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 {
|
||||
exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
|
||||
}
|
||||
code += "function " + object_name;
|
||||
} else {
|
||||
code += object_name + " = function";
|
||||
}
|
||||
code += "() {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb = null;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb_pos = 0;\n";
|
||||
code += isStatement ? "}\n\n" : "};\n\n";
|
||||
}
|
||||
code += "() {\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {flatbuffers.ByteBuffer}\n";
|
||||
code += " */\n";
|
||||
code += " this.bb = null;\n";
|
||||
code += "\n";
|
||||
code += " /**\n";
|
||||
code += " * @type {number}\n";
|
||||
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.
|
||||
@@ -395,7 +607,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
code += " * @param {flatbuffers.ByteBuffer} bb\n";
|
||||
code += " * @returns {" + object_name + "}\n";
|
||||
code += " */\n";
|
||||
code += object_name + ".prototype.__init = function(i, bb) {\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";
|
||||
@@ -408,8 +627,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@param {" + object_name + "=} obj\n"
|
||||
"@returns {" + object_name + "}");
|
||||
code += object_name + ".getRootAs" + struct_def.name;
|
||||
code += " = function(bb, obj) {\n";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static getRootAs" + struct_def.name;
|
||||
code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" +
|
||||
object_name + " {\n";
|
||||
} else {
|
||||
code += object_name + ".getRootAs" + struct_def.name;
|
||||
code += " = function(bb, obj) {\n";
|
||||
}
|
||||
code += " return (obj || new " + object_name;
|
||||
code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
|
||||
code += "};\n\n";
|
||||
@@ -420,7 +645,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.ByteBuffer} bb\n"
|
||||
"@returns {boolean}");
|
||||
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
|
||||
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";
|
||||
}
|
||||
@@ -440,13 +671,33 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
std::string(field.value.type.base_type == BASE_TYPE_STRING ?
|
||||
"@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
|
||||
"@returns {" + GenTypeName(field.value.type, false) + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(";
|
||||
if (field.value.type.base_type == BASE_TYPE_STRING) {
|
||||
code += "optionalEncoding";
|
||||
"@returns {" + GenTypeName(field.value.type, false, true) + "}");
|
||||
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";
|
||||
} 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";
|
||||
}
|
||||
code += ") {\n";
|
||||
|
||||
if (struct_def.fixed) {
|
||||
code += " return " + GenGetter(field.value.type, "(this.bb_pos" +
|
||||
MaybeAdd(field.value.offset) + ")") + ";\n";
|
||||
@@ -467,9 +718,16 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
case BASE_TYPE_STRUCT: {
|
||||
auto type = WrapInNameSpace(*field.value.type.struct_def);
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
"@param {" + type + "=} obj\n@returns {" + type + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
"@param {" + type + "=} obj\n@returns {" + type + "|null}");
|
||||
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";
|
||||
@@ -481,6 +739,11 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
: "this.bb.__indirect(this.bb_pos + offset)";
|
||||
code += ", this.bb) : null;\n";
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
imported_files.insert(field.value.type.struct_def->file);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -498,14 +761,34 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
}
|
||||
GenDocComment(field.doc_comment, code_ptr, args +
|
||||
"@returns {" + vectortypename + "}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(index";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += ", obj";
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += ", optionalEncoding";
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string prefix = MakeCamel(field.name, false);
|
||||
prefix += "(index: number";
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
vectortypename = GenPrefixedTypeName(vectortypename,
|
||||
vectortype.struct_def->file);
|
||||
code += prefix + ", obj?:" + vectortypename;
|
||||
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) {
|
||||
code += ", obj";
|
||||
} else if (vectortype.base_type == BASE_TYPE_STRING) {
|
||||
code += ", optionalEncoding";
|
||||
}
|
||||
code += ") {\n";
|
||||
}
|
||||
code += ") {\n";
|
||||
|
||||
if (vectortype.base_type == BASE_TYPE_STRUCT) {
|
||||
code += offset_prefix + "(obj || new " + vectortypename;
|
||||
code += ").__init(";
|
||||
@@ -526,7 +809,13 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
field.value.type.element == BASE_TYPE_ULONG) {
|
||||
code += "this.bb.createLong(0, 0)";
|
||||
} else if (IsScalar(field.value.type.element)) {
|
||||
code += "0";
|
||||
if (field.value.type.enum_def) {
|
||||
code += "/** @type {" +
|
||||
WrapInNameSpace(*field.value.type.enum_def) + "} */ (" +
|
||||
field.value.constant + ")";
|
||||
} else {
|
||||
code += "0";
|
||||
}
|
||||
} else {
|
||||
code += "null";
|
||||
}
|
||||
@@ -538,8 +827,14 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(field.doc_comment, code_ptr,
|
||||
"@param {flatbuffers.Table} obj\n"
|
||||
"@returns {?flatbuffers.Table}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += " = function(obj) {\n";
|
||||
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;
|
||||
@@ -550,39 +845,102 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
}
|
||||
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 = "@param {" + GenTypeName(field.value.type, true) + "} value\n";
|
||||
std::string annotations =
|
||||
"@param {" + GenTypeName(field.value.type, true) + "} value\n";
|
||||
GenDocComment(code_ptr, annotations +
|
||||
"@returns {boolean}");
|
||||
|
||||
code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n";
|
||||
code += " var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n";
|
||||
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 = this.bb.__offset(this.bb_pos, " +
|
||||
NumToString(field.value.offset) + ");\n\n";
|
||||
code += " if (offset === 0) {\n";
|
||||
code += " return false;\n";
|
||||
code += " }\n\n";
|
||||
code += " this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, value);\n";
|
||||
|
||||
// special case for bools, which are treated as uint8
|
||||
code += " this.bb.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, "@returns {number}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Length = function() {\n" + offset_prefix;
|
||||
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 += "this.bb.__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, "@returns {" + GenType(vectorType) + "Array}");
|
||||
code += object_name + ".prototype." + MakeCamel(field.name, false);
|
||||
code += "Array = function() {\n" + offset_prefix;
|
||||
|
||||
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(this.bb.bytes().buffer, "
|
||||
"this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), "
|
||||
"this.bb.__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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,16 +952,30 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenStructArgs(struct_def, &annotations, &arguments, "");
|
||||
GenDocComment(code_ptr, annotations +
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".create" + struct_def.name + " = function(builder";
|
||||
code += arguments + ") {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static create" + struct_def.name + "(builder:flatbuffers.Builder";
|
||||
code += arguments + "):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code += object_name + ".create" + struct_def.name + " = 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,
|
||||
"@param {flatbuffers.Builder} builder");
|
||||
code += object_name + ".start" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static start" + struct_def.name;
|
||||
code += "(builder:flatbuffers.Builder) {\n";
|
||||
} else {
|
||||
code += object_name + ".start" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
}
|
||||
|
||||
code += " builder.startObject(" + NumToString(
|
||||
struct_def.fields.vec.size()) + ");\n";
|
||||
code += "};\n\n";
|
||||
@@ -623,8 +995,24 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {" + GenTypeName(field.value.type, true) + "} " +
|
||||
argname);
|
||||
code += object_name + ".add" + MakeCamel(field.name);
|
||||
code += " = function(builder, " + argname + ") {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
std::string argType;
|
||||
if (field.value.type.enum_def) {
|
||||
argType = GenPrefixedTypeName(GenTypeName(field.value.type, true),
|
||||
field.value.type.enum_def->file);
|
||||
} else {
|
||||
argType = GenTypeName(field.value.type, true);
|
||||
}
|
||||
|
||||
code += "static add" + MakeCamel(field.name);
|
||||
code += "(builder:flatbuffers.Builder, " + argname + ":" + argType +
|
||||
") {\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) {
|
||||
@@ -653,8 +1041,20 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
"@param {Array.<" + GenTypeName(vector_type, true) +
|
||||
">} data\n"
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".create" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, data) {\n";
|
||||
|
||||
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";
|
||||
@@ -672,8 +1072,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {number} numElems");
|
||||
code += object_name + ".start" + MakeCamel(field.name);
|
||||
code += "Vector = function(builder, numElems) {\n";
|
||||
|
||||
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";
|
||||
@@ -684,8 +1091,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@returns {flatbuffers.Offset}");
|
||||
code += object_name + ".end" + struct_def.name;
|
||||
code += " = function(builder) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static end" + struct_def.name;
|
||||
code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
|
||||
} else {
|
||||
code += object_name + ".end" + struct_def.name;
|
||||
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) {
|
||||
@@ -704,8 +1118,15 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
GenDocComment(code_ptr,
|
||||
"@param {flatbuffers.Builder} builder\n"
|
||||
"@param {flatbuffers.Offset} offset");
|
||||
code += object_name + ".finish" + struct_def.name + "Buffer";
|
||||
code += " = function(builder, offset) {\n";
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "static finish" + struct_def.name + "Buffer";
|
||||
code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
|
||||
} else {
|
||||
code += object_name + ".finish" + struct_def.name + "Buffer";
|
||||
code += " = function(builder, offset) {\n";
|
||||
}
|
||||
|
||||
code += " builder.finish(offset";
|
||||
if (!parser_.file_identifier_.empty()) {
|
||||
code += ", '" + parser_.file_identifier_ + "'";
|
||||
@@ -714,6 +1135,10 @@ void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_pt
|
||||
code += "};\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (lang_.language == IDLOptions::kTs) {
|
||||
code += "}\n}\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace js
|
||||
@@ -727,15 +1152,19 @@ bool GenerateJS(const Parser &parser, const std::string &path,
|
||||
std::string JSMakeRule(const Parser &parser,
|
||||
const std::string &path,
|
||||
const std::string &file_name) {
|
||||
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) + ": ";
|
||||
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;
|
||||
return make_rule;
|
||||
}
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace php {
|
||||
const bool needs_imports, std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code += "<?php\n";
|
||||
code = code + "// " + FlatBuffersGeneratedWarning();
|
||||
code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
code += "namespace " + name_space_name + ";\n\n";
|
||||
|
||||
if (needs_imports) {
|
||||
|
||||
@@ -630,7 +630,7 @@ class PythonGenerator : public BaseGenerator {
|
||||
void BeginFile(const std::string name_space_name, const bool needs_imports,
|
||||
std::string *code_ptr) {
|
||||
std::string &code = *code_ptr;
|
||||
code = code + "# " + FlatBuffersGeneratedWarning();
|
||||
code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
|
||||
code += "# namespace: " + name_space_name + "\n\n";
|
||||
if (needs_imports) {
|
||||
code += "import flatbuffers\n\n";
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "flatbuffers/idl.h"
|
||||
#include "flatbuffers/util.h"
|
||||
#include "flatbuffers/flexbuffers.h"
|
||||
|
||||
namespace flatbuffers {
|
||||
|
||||
@@ -49,7 +50,7 @@ void OutputIdentifier(const std::string &name, const IDLOptions &opts,
|
||||
// for a single FlatBuffer value into JSON format.
|
||||
// The general case for scalars:
|
||||
template<typename T> bool Print(T val, Type type, int /*indent*/,
|
||||
StructDef * /*union_sd*/,
|
||||
Type * /*union_type*/,
|
||||
const IDLOptions &opts,
|
||||
std::string *_text) {
|
||||
std::string &text = *_text;
|
||||
@@ -79,7 +80,7 @@ template<typename T> bool PrintVector(const Vector<T> &v, Type type,
|
||||
text += NewLine(opts);
|
||||
for (uoffset_t i = 0; i < v.size(); i++) {
|
||||
if (i) {
|
||||
text += ",";
|
||||
if (!opts.protobuf_ascii_alike) text += ",";
|
||||
text += NewLine(opts);
|
||||
}
|
||||
text.append(indent + Indent(opts), ' ');
|
||||
@@ -101,90 +102,19 @@ template<typename T> bool PrintVector(const Vector<T> &v, Type type,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool EscapeString(const String &s, std::string *_text, const IDLOptions& opts) {
|
||||
std::string &text = *_text;
|
||||
text += "\"";
|
||||
for (uoffset_t i = 0; i < s.size(); 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.c_str() + i;
|
||||
int ucc = FromUTF8(&utf8);
|
||||
if (ucc < 0) {
|
||||
if (opts.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 (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.c_str() - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
text += "\"";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Specialization of Print above for pointer types.
|
||||
template<> bool Print<const void *>(const void *val,
|
||||
Type type, int indent,
|
||||
StructDef *union_sd,
|
||||
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.
|
||||
assert(union_sd);
|
||||
if (!GenStruct(*union_sd,
|
||||
reinterpret_cast<const Table *>(val),
|
||||
indent,
|
||||
opts,
|
||||
_text)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
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),
|
||||
@@ -195,7 +125,8 @@ template<> bool Print<const void *>(const void *val,
|
||||
}
|
||||
break;
|
||||
case BASE_TYPE_STRING: {
|
||||
if (!EscapeString(*reinterpret_cast<const String *>(val), _text, opts)) {
|
||||
auto s = reinterpret_cast<const String *>(val);
|
||||
if (!EscapeString(s->c_str(), s->Length(), _text, opts.allow_non_utf8)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -236,7 +167,7 @@ template<typename T> static bool GenField(const FieldDef &fd,
|
||||
|
||||
// Generate text for non-scalar field.
|
||||
static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
int indent, StructDef *union_sd,
|
||||
int indent, Type *union_type,
|
||||
const IDLOptions &opts, std::string *_text) {
|
||||
const void *val = nullptr;
|
||||
if (fixed) {
|
||||
@@ -244,12 +175,17 @@ static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
|
||||
assert(IsStruct(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, false, *_text);
|
||||
return true;
|
||||
} 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_sd, opts, _text);
|
||||
return Print(val, fd.value.type, indent, union_type, opts, _text);
|
||||
}
|
||||
|
||||
// Generate text for a struct or table, values separated by commas, indented,
|
||||
@@ -260,7 +196,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
|
||||
std::string &text = *_text;
|
||||
text += "{";
|
||||
int fieldout = 0;
|
||||
StructDef *union_sd = nullptr;
|
||||
Type *union_type = nullptr;
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end();
|
||||
++it) {
|
||||
@@ -271,12 +207,15 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
|
||||
!fd.deprecated;
|
||||
if (is_present || output_anyway) {
|
||||
if (fieldout++) {
|
||||
text += ",";
|
||||
if (!opts.protobuf_ascii_alike) text += ",";
|
||||
}
|
||||
text += NewLine(opts);
|
||||
text.append(indent + Indent(opts), ' ');
|
||||
OutputIdentifier(fd.name, opts, _text);
|
||||
text += ": ";
|
||||
if (!opts.protobuf_ascii_alike ||
|
||||
(fd.value.type.base_type != BASE_TYPE_STRUCT &&
|
||||
fd.value.type.base_type != BASE_TYPE_VECTOR)) text += ":";
|
||||
text += " ";
|
||||
if (is_present) {
|
||||
switch (fd.value.type.base_type) {
|
||||
#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
|
||||
@@ -296,7 +235,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
|
||||
FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
|
||||
#undef FLATBUFFERS_TD
|
||||
if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
|
||||
union_sd, opts, _text)) {
|
||||
union_type, opts, _text)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -305,7 +244,7 @@ static bool GenStruct(const StructDef &struct_def, const Table *table,
|
||||
auto enum_val = fd.value.type.enum_def->ReverseLookup(
|
||||
table->GetField<uint8_t>(fd.value.offset, 0));
|
||||
assert(enum_val);
|
||||
union_sd = enum_val->struct_def;
|
||||
union_type = &enum_val->union_type;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -86,29 +86,38 @@ CheckedError Parser::Error(const std::string &msg) {
|
||||
|
||||
inline CheckedError NoError() { return CheckedError(false); }
|
||||
|
||||
inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
|
||||
int64_t limit) {
|
||||
const std::string cause = NumToString(val) + op + NumToString(limit);
|
||||
return "constant does not fit (" + cause + ")";
|
||||
}
|
||||
|
||||
// Ensure that integer values we parse fit inside the declared integer type.
|
||||
CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) {
|
||||
// Left-shifting a 64-bit value by 64 bits or more is undefined
|
||||
// behavior (C99 6.5.7), so check *before* we shift.
|
||||
if (bits < 64) {
|
||||
// Bits we allow to be used.
|
||||
auto mask = static_cast<int64_t>((1ull << bits) - 1);
|
||||
if ((val & ~mask) != 0 && // Positive or unsigned.
|
||||
(val | mask) != -1) // Negative.
|
||||
return Error("constant does not fit in a " + NumToString(bits) +
|
||||
"-bit field");
|
||||
}
|
||||
return NoError();
|
||||
CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
|
||||
if (val < min)
|
||||
return Error(OutOfRangeErrorMsg(val, " < ", min));
|
||||
else if (val > max)
|
||||
return Error(OutOfRangeErrorMsg(val, " > ", max));
|
||||
else
|
||||
return NoError();
|
||||
}
|
||||
|
||||
// atot: templated 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) {
|
||||
int64_t i = StringToInt(s);
|
||||
ECHECK(parser.CheckBitsFit(i, sizeof(T) * 8));
|
||||
const int64_t min = std::numeric_limits<T>::min();
|
||||
const int64_t max = std::numeric_limits<T>::max();
|
||||
ECHECK(parser.CheckInRange(i, min, max));
|
||||
*val = (T)i;
|
||||
return NoError();
|
||||
}
|
||||
template<> inline CheckedError atot<uint64_t>(const char *s, Parser &parser,
|
||||
uint64_t *val) {
|
||||
(void)parser;
|
||||
*val = StringToUInt(s);
|
||||
return NoError();
|
||||
}
|
||||
template<> inline CheckedError atot<bool>(const char *s, Parser &parser,
|
||||
bool *val) {
|
||||
(void)parser;
|
||||
@@ -149,8 +158,7 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
||||
}
|
||||
stream << components[i];
|
||||
}
|
||||
|
||||
stream << "." << name;
|
||||
if (name.length()) stream << "." << name;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
@@ -175,7 +183,8 @@ std::string Namespace::GetFullyQualifiedName(const std::string &name,
|
||||
TD(Include, 269, "include") \
|
||||
TD(Attribute, 270, "attribute") \
|
||||
TD(Null, 271, "null") \
|
||||
TD(Service, 272, "rpc_service")
|
||||
TD(Service, 272, "rpc_service") \
|
||||
TD(NativeInclude, 273, "native_include")
|
||||
#ifdef __GNUC__
|
||||
__extension__ // Stop GCC complaining about trailing comma with -Wpendantic.
|
||||
#endif
|
||||
@@ -213,7 +222,7 @@ std::string Parser::TokenToStringId(int t) {
|
||||
}
|
||||
|
||||
// Parses exactly nibbles worth of hex digits into a number, or error.
|
||||
CheckedError Parser::ParseHexNum(int nibbles, int64_t *val) {
|
||||
CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) {
|
||||
for (int i = 0; i < nibbles; i++)
|
||||
if (!isxdigit(static_cast<const unsigned char>(cursor_[i])))
|
||||
return Error("escape code must be followed by " + NumToString(nibbles) +
|
||||
@@ -280,14 +289,14 @@ CheckedError Parser::Next() {
|
||||
case '/': attribute_ += '/'; cursor_++; break;
|
||||
case 'x': { // Not in the JSON standard
|
||||
cursor_++;
|
||||
int64_t val;
|
||||
uint64_t val;
|
||||
ECHECK(ParseHexNum(2, &val));
|
||||
attribute_ += static_cast<char>(val);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
cursor_++;
|
||||
int64_t val;
|
||||
uint64_t val;
|
||||
ECHECK(ParseHexNum(4, &val));
|
||||
if (val >= 0xD800 && val <= 0xDBFF) {
|
||||
if (unicode_high_surrogate != -1) {
|
||||
@@ -433,12 +442,17 @@ CheckedError Parser::Next() {
|
||||
token_ = kTokenService;
|
||||
return NoError();
|
||||
}
|
||||
if (attribute_ == "native_include") {
|
||||
token_ = kTokenNativeInclude;
|
||||
return NoError();
|
||||
}
|
||||
// If not, it is a user-defined identifier:
|
||||
token_ = kTokenIdentifier;
|
||||
return NoError();
|
||||
} else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
|
||||
const char *start = cursor_ - 1;
|
||||
if (c == '-' && *cursor_ == '0' && (cursor_[1] == 'x' || cursor_[1] == 'X')) {
|
||||
if (c == '-' && *cursor_ == '0' &&
|
||||
(cursor_[1] == 'x' || cursor_[1] == 'X')) {
|
||||
++start;
|
||||
++cursor_;
|
||||
attribute_.append(&c, &c + 1);
|
||||
@@ -448,7 +462,8 @@ CheckedError Parser::Next() {
|
||||
cursor_++;
|
||||
while (isxdigit(static_cast<unsigned char>(*cursor_))) cursor_++;
|
||||
attribute_.append(start + 2, cursor_);
|
||||
attribute_ = NumToString(StringToUInt(attribute_.c_str(), nullptr, 16));
|
||||
attribute_ = NumToString(static_cast<int64_t>(
|
||||
StringToUInt(attribute_.c_str(), nullptr, 16)));
|
||||
token_ = kTokenIntegerConstant;
|
||||
return NoError();
|
||||
}
|
||||
@@ -550,12 +565,6 @@ CheckedError Parser::ParseType(Type &type) {
|
||||
return Error(
|
||||
"nested vector types not supported (wrap in table first).");
|
||||
}
|
||||
if (subtype.base_type == BASE_TYPE_UNION) {
|
||||
// We could support this if we stored a struct of 2 elements per
|
||||
// union element.
|
||||
return Error(
|
||||
"vector of union types not supported (wrap in table first).");
|
||||
}
|
||||
type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
|
||||
type.element = subtype.base_type;
|
||||
EXPECT(']');
|
||||
@@ -592,6 +601,10 @@ CheckedError Parser::AddField(StructDef &struct_def, const std::string &name,
|
||||
|
||||
CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
std::string name = attribute_;
|
||||
|
||||
if (name == struct_def.name)
|
||||
return Error("field name can not be the same as table/struct name");
|
||||
|
||||
std::vector<std::string> dc = doc_comment_;
|
||||
EXPECT(kTokenIdentifier);
|
||||
EXPECT(':');
|
||||
@@ -607,6 +620,19 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
// 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 supports the union vector feature so far.
|
||||
if (opts.lang_to_generate != IDLOptions::kCpp) {
|
||||
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;
|
||||
@@ -699,6 +725,15 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
LookupCreateStruct(nested->constant);
|
||||
}
|
||||
|
||||
if (field->attributes.Lookup("flexbuffer")) {
|
||||
field->flexbuffer = true;
|
||||
uses_flexbuffers_ = true;
|
||||
if (field->value.type.base_type != BASE_TYPE_VECTOR ||
|
||||
field->value.type.element != BASE_TYPE_UCHAR)
|
||||
return Error(
|
||||
"flexbuffer attribute may only apply to a vector of ubyte");
|
||||
}
|
||||
|
||||
if (typefield) {
|
||||
// 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).
|
||||
@@ -716,6 +751,18 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
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) {
|
||||
@@ -723,8 +770,17 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
case BASE_TYPE_UNION: {
|
||||
assert(field);
|
||||
std::string constant;
|
||||
if (!parent_fieldn ||
|
||||
field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) {
|
||||
// Find corresponding type field we may have already parsed.
|
||||
for (auto elem = field_stack_.rbegin();
|
||||
elem != field_stack_.rbegin() + parent_fieldn; ++elem) {
|
||||
auto &type = elem->second->value.type;
|
||||
if (type.base_type == BASE_TYPE_UTYPE &&
|
||||
type.enum_def == val.type.enum_def) {
|
||||
constant = elem->first.constant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (constant.empty()) {
|
||||
// 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.
|
||||
@@ -735,7 +791,7 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
// Remember where we are in the source file, so we can come back here.
|
||||
auto backup = *static_cast<ParserState *>(this);
|
||||
ECHECK(SkipAnyJsonValue()); // The table.
|
||||
EXPECT(',');
|
||||
ECHECK(ParseComma());
|
||||
auto next_name = attribute_;
|
||||
if (Is(kTokenStringConstant)) {
|
||||
NEXT();
|
||||
@@ -751,27 +807,35 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
constant = type_val.constant;
|
||||
// Got the information we needed, now rewind:
|
||||
*static_cast<ParserState *>(this) = backup;
|
||||
} else {
|
||||
constant = field_stack_.back().first.constant;
|
||||
}
|
||||
uint8_t enum_idx;
|
||||
ECHECK(atot(constant.c_str(), *this, &enum_idx));
|
||||
auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
|
||||
if (!enum_val) return Error("illegal type id for: " + field->name);
|
||||
ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr));
|
||||
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 {
|
||||
assert(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_STRUCT:
|
||||
ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
|
||||
break;
|
||||
case BASE_TYPE_STRING: {
|
||||
auto s = attribute_;
|
||||
EXPECT(kTokenStringConstant);
|
||||
val.constant = NumToString(builder_.CreateString(s).o);
|
||||
ECHECK(ParseString(val));
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_VECTOR: {
|
||||
EXPECT('[');
|
||||
uoffset_t off;
|
||||
ECHECK(ParseVector(val.type.VectorType(), &off));
|
||||
val.constant = NumToString(off);
|
||||
@@ -804,48 +868,114 @@ void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) {
|
||||
builder_.AddStructOffset(val.offset, builder_.GetSize());
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
|
||||
const StructDef *struct_def,
|
||||
const std::function<CheckedError(const std::string &name)> &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));
|
||||
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) {
|
||||
EXPECT('{');
|
||||
size_t fieldn = 0;
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !fieldn) && Is('}')) { NEXT(); break; }
|
||||
std::string name = attribute_;
|
||||
if (Is(kTokenStringConstant)) {
|
||||
NEXT();
|
||||
} else {
|
||||
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
|
||||
}
|
||||
auto err = ParseTableDelimiters(fieldn, &struct_def,
|
||||
[&](const std::string &name) -> CheckedError {
|
||||
auto field = struct_def.fields.Lookup(name);
|
||||
if (!field) {
|
||||
if (!opts.skip_unexpected_fields_in_json) {
|
||||
return Error("unknown field: " + name);
|
||||
} else {
|
||||
EXPECT(':');
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
}
|
||||
} else {
|
||||
EXPECT(':');
|
||||
if (Is(kTokenNull)) {
|
||||
NEXT(); // Ignore this field.
|
||||
} else {
|
||||
Value val = field->value;
|
||||
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
|
||||
size_t i = field_stack_.size();
|
||||
if (field->flexbuffer) {
|
||||
flexbuffers::Builder builder(1024,
|
||||
flexbuffers::BUILDER_FLAG_SHARE_ALL);
|
||||
ECHECK(ParseFlexBufferValue(&builder));
|
||||
builder.Finish();
|
||||
auto off = builder_.CreateVector(builder.GetBuffer());
|
||||
val.constant = NumToString(off.o);
|
||||
} else {
|
||||
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
|
||||
}
|
||||
// Hardcoded insertion-sort with error-check.
|
||||
// If fields are specified in order, then this loop exits immediately.
|
||||
for (; i > field_stack_.size() - fieldn; i--) {
|
||||
auto existing_field = field_stack_[i - 1].second;
|
||||
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;
|
||||
}
|
||||
field_stack_.insert(field_stack_.begin() + i, std::make_pair(val, field));
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
if (Is('}')) { NEXT(); break; }
|
||||
EXPECT(',');
|
||||
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;
|
||||
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 != struct_def.fields.vec.size())
|
||||
@@ -923,22 +1053,34 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
|
||||
int count = 0;
|
||||
CheckedError Parser::ParseVectorDelimiters(size_t &count,
|
||||
const std::function<CheckedError()> &body) {
|
||||
EXPECT('[');
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; }
|
||||
if ((!opts.strict_json || !count) && Is(']')) break;
|
||||
ECHECK(body());
|
||||
count++;
|
||||
if (Is(']')) break;
|
||||
ECHECK(ParseComma());
|
||||
}
|
||||
NEXT();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
|
||||
size_t count = 0;
|
||||
auto err = ParseVectorDelimiters(count, [&]() -> CheckedError {
|
||||
Value val;
|
||||
val.type = type;
|
||||
ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
|
||||
field_stack_.push_back(std::make_pair(val, nullptr));
|
||||
count++;
|
||||
if (Is(']')) { NEXT(); break; }
|
||||
EXPECT(',');
|
||||
}
|
||||
return NoError();
|
||||
});
|
||||
ECHECK(err);
|
||||
|
||||
builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
|
||||
InlineAlignment(type));
|
||||
for (int i = 0; i < count; i++) {
|
||||
for (size_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) {
|
||||
@@ -1049,14 +1191,24 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
|
||||
assert(field);
|
||||
Value *hash_name = field->attributes.Lookup("hash");
|
||||
switch (e.type.base_type) {
|
||||
case BASE_TYPE_INT:
|
||||
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:
|
||||
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());
|
||||
@@ -1070,6 +1222,11 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::TokenError() {
|
||||
return Error("cannot parse value starting with: " +
|
||||
TokenToStringId(token_));
|
||||
}
|
||||
|
||||
CheckedError Parser::ParseSingleValue(Value &e) {
|
||||
// First see if this could be a conversion function:
|
||||
if (token_ == kTokenIdentifier && *cursor_ == '(') {
|
||||
@@ -1136,9 +1293,7 @@ CheckedError Parser::ParseSingleValue(Value &e) {
|
||||
e,
|
||||
BASE_TYPE_STRING,
|
||||
&match));
|
||||
if (!match)
|
||||
return Error("cannot parse value starting with: " +
|
||||
TokenToStringId(token_));
|
||||
if (!match) return TokenError();
|
||||
}
|
||||
return NoError();
|
||||
}
|
||||
@@ -1262,7 +1417,16 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
|
||||
return Error("enum value already exists: " + value_name);
|
||||
ev.doc_comment = value_comment;
|
||||
if (is_union) {
|
||||
ev.struct_def = LookupCreateStruct(full_name);
|
||||
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");
|
||||
enum_def.uses_type_aliases = true;
|
||||
} else {
|
||||
ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
|
||||
}
|
||||
}
|
||||
if (Is('=')) {
|
||||
NEXT();
|
||||
@@ -1272,6 +1436,10 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
|
||||
enum_def.vals.vec[prevsize - 1]->value >= ev.value)
|
||||
return Error("enum values must be specified in ascending order");
|
||||
}
|
||||
if (is_union) {
|
||||
if (ev.value < 0 || ev.value >= 256)
|
||||
return Error("union enum value must fit in a ubyte");
|
||||
}
|
||||
if (opts.proto_mode && Is('[')) {
|
||||
NEXT();
|
||||
// ignore attributes on enums.
|
||||
@@ -1294,6 +1462,8 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
|
||||
}
|
||||
}
|
||||
if (dest) *dest = &enum_def;
|
||||
types_.Add(namespaces_.back()->GetFullyQualifiedName(enum_def.name),
|
||||
new Type(BASE_TYPE_UNION, nullptr, &enum_def));
|
||||
return NoError();
|
||||
}
|
||||
|
||||
@@ -1305,7 +1475,7 @@ CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
|
||||
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.
|
||||
*remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
|
||||
*std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
|
||||
*dest = &struct_def;
|
||||
return NoError();
|
||||
}
|
||||
@@ -1399,6 +1569,8 @@ CheckedError Parser::ParseDecl() {
|
||||
ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
|
||||
ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
|
||||
EXPECT('}');
|
||||
types_.Add(namespaces_.back()->GetFullyQualifiedName(struct_def->name),
|
||||
new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
|
||||
return NoError();
|
||||
}
|
||||
|
||||
@@ -1748,14 +1920,21 @@ CheckedError Parser::ParseTypeFromProtoType(Type *type) {
|
||||
|
||||
CheckedError Parser::SkipAnyJsonValue() {
|
||||
switch (token_) {
|
||||
case '{':
|
||||
ECHECK(SkipJsonObject());
|
||||
break;
|
||||
case '{': {
|
||||
size_t fieldn = 0;
|
||||
return ParseTableDelimiters(fieldn, nullptr,
|
||||
[&](const std::string &) -> CheckedError {
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
fieldn++;
|
||||
return NoError();
|
||||
});
|
||||
}
|
||||
case '[': {
|
||||
size_t count = 0;
|
||||
return ParseVectorDelimiters(count, [&]() { return SkipAnyJsonValue(); });
|
||||
}
|
||||
case kTokenStringConstant:
|
||||
ECHECK(SkipJsonString());
|
||||
break;
|
||||
case '[':
|
||||
ECHECK(SkipJsonArray());
|
||||
EXPECT(kTokenStringConstant);
|
||||
break;
|
||||
case kTokenIntegerConstant:
|
||||
EXPECT(kTokenIntegerConstant);
|
||||
@@ -1764,84 +1943,98 @@ CheckedError Parser::SkipAnyJsonValue() {
|
||||
EXPECT(kTokenFloatConstant);
|
||||
break;
|
||||
default:
|
||||
return Error(std::string("Unexpected token:") + std::string(1, static_cast<char>(token_)));
|
||||
return TokenError();
|
||||
}
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::SkipJsonObject() {
|
||||
EXPECT('{');
|
||||
size_t fieldn = 0;
|
||||
|
||||
for (;;) {
|
||||
if ((!opts.strict_json || !fieldn) && Is('}')) break;
|
||||
|
||||
if (!Is(kTokenStringConstant)) {
|
||||
EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
|
||||
CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
|
||||
switch (token_) {
|
||||
case '{': {
|
||||
auto start = builder->StartMap();
|
||||
size_t fieldn = 0;
|
||||
auto err = ParseTableDelimiters(fieldn, nullptr,
|
||||
[&](const std::string &name) -> CheckedError {
|
||||
builder->Key(name);
|
||||
ECHECK(ParseFlexBufferValue(builder));
|
||||
fieldn++;
|
||||
return NoError();
|
||||
});
|
||||
ECHECK(err);
|
||||
builder->EndMap(start);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
NEXT();
|
||||
case '[':{
|
||||
auto start = builder->StartVector();
|
||||
size_t count = 0;
|
||||
ECHECK(ParseVectorDelimiters(count, [&]() {
|
||||
return ParseFlexBufferValue(builder);
|
||||
}));
|
||||
builder->EndVector(start, false, false);
|
||||
break;
|
||||
}
|
||||
|
||||
EXPECT(':');
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
fieldn++;
|
||||
|
||||
if (Is('}')) break;
|
||||
EXPECT(',');
|
||||
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:
|
||||
return TokenError();
|
||||
}
|
||||
|
||||
NEXT();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::SkipJsonArray() {
|
||||
EXPECT('[');
|
||||
|
||||
for (;;) {
|
||||
if (Is(']')) break;
|
||||
|
||||
ECHECK(SkipAnyJsonValue());
|
||||
|
||||
if (Is(']')) break;
|
||||
EXPECT(',');
|
||||
}
|
||||
|
||||
NEXT();
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::SkipJsonString() {
|
||||
EXPECT(kTokenStringConstant);
|
||||
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) {
|
||||
return !DoParse(source, include_paths, source_filename).Check();
|
||||
return !DoParse(source, include_paths, source_filename, nullptr).Check();
|
||||
}
|
||||
|
||||
CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
|
||||
file_being_parsed_ = source_filename ? source_filename : "";
|
||||
source_ = cursor_ = source;
|
||||
line_ = 1;
|
||||
error_.clear();
|
||||
ECHECK(SkipByteOrderMark());
|
||||
NEXT();
|
||||
if (Is(kTokenEof))
|
||||
return Error("input file is empty");
|
||||
return NoError();
|
||||
}
|
||||
|
||||
CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
const char *source_filename) {
|
||||
file_being_parsed_ = source_filename ? source_filename : "";
|
||||
const char *source_filename,
|
||||
const char *include_filename) {
|
||||
if (source_filename &&
|
||||
included_files_.find(source_filename) == included_files_.end()) {
|
||||
included_files_[source_filename] = true;
|
||||
included_files_[source_filename] = include_filename ? include_filename : "";
|
||||
files_included_per_file_[source_filename] = std::set<std::string>();
|
||||
}
|
||||
if (!include_paths) {
|
||||
static const char *current_directory[] = { "", nullptr };
|
||||
include_paths = current_directory;
|
||||
}
|
||||
source_ = cursor_ = source;
|
||||
line_ = 1;
|
||||
error_.clear();
|
||||
field_stack_.clear();
|
||||
builder_.Clear();
|
||||
// Start with a blank namespace just in case this file doesn't have one.
|
||||
namespaces_.push_back(new Namespace());
|
||||
ECHECK(SkipByteOrderMark());
|
||||
NEXT();
|
||||
|
||||
ECHECK(StartParseFile(source, source_filename));
|
||||
|
||||
// Includes must come before type declarations:
|
||||
for (;;) {
|
||||
// Parse pre-include proto statements if any:
|
||||
@@ -1849,13 +2042,17 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
(attribute_ == "option" || attribute_ == "syntax" ||
|
||||
attribute_ == "package")) {
|
||||
ECHECK(ParseProtoDecl());
|
||||
} else if (Is(kTokenNativeInclude)) {
|
||||
NEXT();
|
||||
native_included_files_.emplace_back(attribute_);
|
||||
EXPECT(kTokenStringConstant);
|
||||
} else if (Is(kTokenInclude) ||
|
||||
(opts.proto_mode &&
|
||||
attribute_ == "import" &&
|
||||
Is(kTokenIdentifier))) {
|
||||
NEXT();
|
||||
if (opts.proto_mode && attribute_ == "public") NEXT();
|
||||
auto name = attribute_;
|
||||
auto name = flatbuffers::PosixPath(attribute_.c_str());
|
||||
EXPECT(kTokenStringConstant);
|
||||
// Look for the file in include_paths.
|
||||
std::string filepath;
|
||||
@@ -1873,7 +2070,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
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()));
|
||||
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();
|
||||
// This is the easiest way to continue this file after an include:
|
||||
@@ -1883,7 +2081,7 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
// entered into included_files_.
|
||||
// This is recursive, but only go as deep as the number of include
|
||||
// statements.
|
||||
return DoParse(source, include_paths, source_filename);
|
||||
return DoParse(source, include_paths, source_filename, include_filename);
|
||||
}
|
||||
EXPECT(';');
|
||||
} else {
|
||||
@@ -1954,6 +2152,8 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
return Error("type referenced but not defined: " + (*it)->name);
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
@@ -1961,8 +2161,11 @@ CheckedError Parser::DoParse(const char *source, const char **include_paths,
|
||||
val_it != enum_def.vals.vec.end();
|
||||
++val_it) {
|
||||
auto &val = **val_it;
|
||||
if (val.struct_def && val.struct_def->fixed)
|
||||
return Error("only tables can be union elements: " + val.name);
|
||||
if (opts.lang_to_generate != IDLOptions::kCpp &&
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2050,7 +2253,11 @@ Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder,
|
||||
fixed,
|
||||
static_cast<int>(minalign),
|
||||
static_cast<int>(bytesize),
|
||||
SerializeAttributes(builder, parser));
|
||||
SerializeAttributes(builder, parser),
|
||||
parser.opts.binary_schema_comments
|
||||
? builder->CreateVectorOfStrings(
|
||||
doc_comment)
|
||||
: 0);
|
||||
}
|
||||
|
||||
Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
|
||||
@@ -2070,7 +2277,10 @@ Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder,
|
||||
deprecated,
|
||||
required,
|
||||
key,
|
||||
SerializeAttributes(builder, parser));
|
||||
SerializeAttributes(builder, parser),
|
||||
parser.opts.binary_schema_comments
|
||||
? builder->CreateVectorOfStrings(doc_comment)
|
||||
: 0);
|
||||
// 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.
|
||||
}
|
||||
@@ -2087,7 +2297,10 @@ Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder,
|
||||
builder->CreateVector(enumval_offsets),
|
||||
is_union,
|
||||
underlying_type.Serialize(builder),
|
||||
SerializeAttributes(builder, parser));
|
||||
SerializeAttributes(builder, parser),
|
||||
parser.opts.binary_schema_comments
|
||||
? builder->CreateVectorOfStrings(doc_comment)
|
||||
: 0);
|
||||
}
|
||||
|
||||
Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
|
||||
@@ -2095,9 +2308,11 @@ Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder) const
|
||||
return reflection::CreateEnumVal(*builder,
|
||||
builder->CreateString(name),
|
||||
value,
|
||||
struct_def
|
||||
? struct_def->serialized_location
|
||||
: 0);
|
||||
union_type.struct_def
|
||||
? union_type.struct_def->
|
||||
serialized_location
|
||||
: 0,
|
||||
union_type.Serialize(builder));
|
||||
}
|
||||
|
||||
Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
|
||||
|
||||
@@ -87,8 +87,11 @@ std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data,
|
||||
auto &fielddef = **it;
|
||||
if (!table_field->CheckField(fielddef.offset())) continue;
|
||||
auto val = GetAnyFieldS(*table_field, fielddef, schema);
|
||||
if (fielddef.type()->base_type() == reflection::String)
|
||||
val = "\"" + val + "\""; // Doesn't deal with escape codes etc.
|
||||
if (fielddef.type()->base_type() == reflection::String) {
|
||||
std::string esc;
|
||||
flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true);
|
||||
val = esc;
|
||||
}
|
||||
s += fielddef.name()->str();
|
||||
s += ": ";
|
||||
s += val;
|
||||
@@ -420,8 +423,8 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
offset = fbb.CreateVector(elements).o;
|
||||
break;
|
||||
}
|
||||
// FALL-THRU:
|
||||
}
|
||||
// FALL-THRU
|
||||
default: { // Scalars and structs.
|
||||
auto element_size = GetTypeSize(element_base_type);
|
||||
if (elemobjectdef && elemobjectdef->is_struct())
|
||||
@@ -458,8 +461,8 @@ Offset<const Table *> CopyTable(FlatBufferBuilder &fbb,
|
||||
subobjectdef.bytesize());
|
||||
break;
|
||||
}
|
||||
// else: FALL-THRU:
|
||||
}
|
||||
// ELSE FALL-THRU
|
||||
case reflection::Union:
|
||||
case reflection::String:
|
||||
case reflection::Vector:
|
||||
|
||||
@@ -80,6 +80,9 @@
|
||||
<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="..\namespace_test\NamespaceA\NamespaceB\EnumInNestedNS.cs">
|
||||
<Link>NamespaceA\NamespaceB\EnumInNestedNS.cs</Link>
|
||||
</Compile>
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace FlatBuffers.Test
|
||||
Monster.StartMonster(fbb);
|
||||
Monster.AddName(fbb, names[2]);
|
||||
off[2] = Monster.EndMonster(fbb);
|
||||
var sortMons = Monster.CreateMySortedVectorOfTables(fbb, off);
|
||||
var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off);
|
||||
|
||||
// We set up the same values as monsterdata.json:
|
||||
|
||||
@@ -123,9 +123,9 @@ namespace FlatBuffers.Test
|
||||
Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
|
||||
|
||||
// Example of searching for a table by the key
|
||||
Assert.IsTrue(Monster.LookupByKey(sortMons, "Frodo", fbb.DataBuffer) != null);
|
||||
Assert.IsTrue(Monster.LookupByKey(sortMons, "Barney", fbb.DataBuffer) != null);
|
||||
Assert.IsTrue(Monster.LookupByKey(sortMons, "Wilma", fbb.DataBuffer)!= null);
|
||||
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);
|
||||
|
||||
9
tests/FlatBuffers.Test/NetTest.sh
Normal file
9
tests/FlatBuffers.Test/NetTest.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Testing C# on Linux using Mono.
|
||||
|
||||
mcs -out:fbnettest.exe ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs
|
||||
./fbnettest.exe
|
||||
rm fbnettest.exe
|
||||
rm Resources/monsterdata_cstest.mon
|
||||
|
||||
@@ -20,7 +20,7 @@ go_path=${test_dir}/go_gen
|
||||
go_src=${go_path}/src
|
||||
|
||||
# Emit Go code for the example schema in the test dir:
|
||||
../flatc -g monster_test.fbs
|
||||
../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
|
||||
|
||||
@@ -3,7 +3,7 @@ var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
|
||||
var flatbuffers = require('../js/flatbuffers').flatbuffers;
|
||||
var MyGame = require('./monster_test_generated').MyGame;
|
||||
var MyGame = require(process.argv[2]).MyGame;
|
||||
|
||||
function main() {
|
||||
|
||||
@@ -67,7 +67,7 @@ function main() {
|
||||
// Tests mutation first. This will verify that we did not trample any other
|
||||
// part of the byte buffer.
|
||||
testMutation(fbb.dataBuffer());
|
||||
|
||||
|
||||
testBuffer(fbb.dataBuffer());
|
||||
|
||||
test64bit();
|
||||
@@ -156,7 +156,8 @@ function test64bit() {
|
||||
var mon2 = MyGame.Example.Monster.endMonster(fbb);
|
||||
|
||||
MyGame.Example.Stat.startStat(fbb);
|
||||
MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x12345678, 0x23456789));
|
||||
// 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);
|
||||
@@ -177,8 +178,7 @@ function test64bit() {
|
||||
var stat = mon.testempty();
|
||||
assert.strictEqual(stat != null, true);
|
||||
assert.strictEqual(stat.val() != null, true);
|
||||
assert.strictEqual(stat.val().low, 0x12345678);
|
||||
assert.strictEqual(stat.val().high, 0x23456789);
|
||||
assert.strictEqual(stat.val().toFloat64(), 2541551405100253985);
|
||||
|
||||
var mon2 = mon.enemy();
|
||||
assert.strictEqual(mon2 != null, true);
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
# limitations under the License.
|
||||
|
||||
pushd "$(dirname $0)" >/dev/null
|
||||
../flatc -b monster_test.fbs unicode_test.json
|
||||
node JavaScriptTest
|
||||
../flatc -b -I include_test monster_test.fbs unicode_test.json
|
||||
node JavaScriptTest ./monster_test_generated
|
||||
|
||||
@@ -63,7 +63,7 @@ class JavaTest {
|
||||
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");
|
||||
@@ -135,16 +135,16 @@ class JavaTest {
|
||||
// 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.lookupByKey(sortMons, "Frodo", fbb.dataBuffer()).name(), "Frodo");
|
||||
TestEq(Monster.lookupByKey(sortMons, "Barney", fbb.dataBuffer()).name(), "Barney");
|
||||
TestEq(Monster.lookupByKey(sortMons, "Wilma", fbb.dataBuffer()).name(), "Wilma");
|
||||
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);
|
||||
@@ -201,7 +201,7 @@ class JavaTest {
|
||||
|
||||
static void TestBuffer(ByteBuffer bb) {
|
||||
TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
|
||||
|
||||
|
||||
Monster monster = Monster.getRootAsMonster(bb);
|
||||
|
||||
TestEq(monster.hp(), (short)80);
|
||||
@@ -259,25 +259,25 @@ class JavaTest {
|
||||
|
||||
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.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);
|
||||
@@ -288,8 +288,8 @@ class JavaTest {
|
||||
Monster.finishMonsterBuffer(fbb1, monster1);
|
||||
byte[] fbb1Bytes = fbb1.sizedByteArray();
|
||||
fbb1 = null;
|
||||
|
||||
FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
|
||||
|
||||
FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
|
||||
int str2 = fbb2.createString("My Monster");
|
||||
int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
|
||||
Monster.startMonster(fbb2);
|
||||
@@ -299,7 +299,7 @@ class JavaTest {
|
||||
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();
|
||||
|
||||
@@ -14,31 +14,30 @@
|
||||
# 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`)
|
||||
thisdir=$(readlink -fn `pwd`)
|
||||
testdir="$(readlink -fn "$(dirname "$0")")"
|
||||
|
||||
targetdir=${testdir}/target
|
||||
|
||||
if [[ "$testdir" != "$thisdir" ]]; then
|
||||
echo error: must be run from inside the ${testdir} directory
|
||||
echo you ran it from ${thisdir}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find .. -type f -name "*.class" -exec rm {} \;
|
||||
targetdir="${testdir}/target"
|
||||
|
||||
if [[ -e "${targetdir}" ]]; then
|
||||
echo "clean target"
|
||||
rm -rf ${targetdir}
|
||||
echo "cleaning target"
|
||||
rm -rf "${targetdir}"
|
||||
fi
|
||||
|
||||
mkdir ${targetdir}
|
||||
mkdir -v "${targetdir}"
|
||||
|
||||
javac -d ${targetdir} -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java
|
||||
java -classpath ${targetdir} JavaTest
|
||||
if ! find "${testdir}/../java" -type f -name "*.class" -delete; then
|
||||
echo "failed to clean .class files from java directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf ${targetdir}
|
||||
javac -d "${targetdir}" -classpath "${testdir}/../java:${testdir}:${testdir}/namespace_test" "${testdir}/JavaTest.java"
|
||||
|
||||
(cd "${testdir}" && java -classpath "${targetdir}" JavaTest )
|
||||
|
||||
rm -rf "${targetdir}"
|
||||
|
||||
32
tests/MyGame/Example/Ability.cs
Normal file
32
tests/MyGame/Example/Ability.cs
Normal file
@@ -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.bb_pos = _i; __p.bb = _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<Ability> CreateAbility(FlatBufferBuilder builder, uint Id, uint Distance) {
|
||||
builder.Prep(4, 8);
|
||||
builder.PutUint(Distance);
|
||||
builder.PutUint(Id);
|
||||
return new Offset<Ability>(builder.Offset);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
41
tests/MyGame/Example/Ability.go
Normal file
41
tests/MyGame/Example/Ability.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
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()
|
||||
}
|
||||
27
tests/MyGame/Example/Ability.java
Normal file
27
tests/MyGame/Example/Ability.java
Normal file
@@ -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) { bb_pos = _i; bb = _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();
|
||||
}
|
||||
}
|
||||
|
||||
52
tests/MyGame/Example/Ability.php
Normal file
52
tests/MyGame/Example/Ability.php
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
23
tests/MyGame/Example/Ability.py
Normal file
23
tests/MyGame/Example/Ability.py
Normal file
@@ -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()
|
||||
@@ -1,4 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
/// an example documentation comment: monster object
|
||||
public struct Monster : IFlatbufferObject
|
||||
@@ -41,6 +43,7 @@ public struct Monster : IFlatbufferObject
|
||||
/// multiline too
|
||||
public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new 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 Monster? TestarrayoftablesByKey(string key) { int o = __p.__offset(26); return o != 0 ? Monster.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
|
||||
public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new 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; } }
|
||||
@@ -78,8 +81,14 @@ public struct Monster : IFlatbufferObject
|
||||
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 Ability? Testarrayofsortedstruct(int j) { int o = __p.__offset(62); return o != 0 ? (Ability?)(new 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; } }
|
||||
public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(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 static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); }
|
||||
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(31); }
|
||||
public static void AddPos(FlatBufferBuilder builder, Offset<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); }
|
||||
@@ -121,6 +130,11 @@ public struct Monster : IFlatbufferObject
|
||||
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 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 void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
|
||||
public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
|
||||
int o = builder.EndObject();
|
||||
builder.Required(o, 10); // name
|
||||
@@ -128,17 +142,15 @@ public struct Monster : IFlatbufferObject
|
||||
}
|
||||
public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
|
||||
|
||||
public static VectorOffset CreateMySortedVectorOfTables(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
|
||||
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? LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) {
|
||||
public static Monster? __lookup_by_key(int vectorLocation, string key, ByteBuffer bb) {
|
||||
byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
|
||||
int vectorLocation = bb.Length - vectorOffset.Value;
|
||||
int span = bb.GetInt(vectorLocation);
|
||||
int span = bb.GetInt(vectorLocation - 4);
|
||||
int start = 0;
|
||||
vectorLocation += 4;
|
||||
while (span != 0) {
|
||||
int middle = span / 2;
|
||||
int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
|
||||
|
||||
@@ -419,8 +419,52 @@ func (rcv *Monster) Testarrayofstring2Length() int {
|
||||
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 MonsterStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(29)
|
||||
builder.StartObject(31)
|
||||
}
|
||||
func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
|
||||
builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0)
|
||||
@@ -527,6 +571,18 @@ func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstrin
|
||||
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 MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ public final class Monster extends Table {
|
||||
public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); }
|
||||
public Monster testarrayoftables(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 Monster testarrayoftablesByKey(String key) { int o = __offset(26); return o != 0 ? Monster.__lookup_by_key(__vector(o), key, bb) : null; }
|
||||
public Monster enemy() { return enemy(new Monster()); }
|
||||
public Monster enemy(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; }
|
||||
@@ -87,8 +88,15 @@ public final class Monster extends Table {
|
||||
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 Ability testarrayofsortedstruct(int j) { return testarrayofsortedstruct(new Ability(), j); }
|
||||
public Ability testarrayofsortedstruct(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 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 static void startMonster(FlatBufferBuilder builder) { builder.startObject(29); }
|
||||
public static void startMonster(FlatBufferBuilder builder) { builder.startObject(31); }
|
||||
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); }
|
||||
@@ -130,6 +138,11 @@ public final class Monster extends Table {
|
||||
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 int endMonster(FlatBufferBuilder builder) {
|
||||
int o = builder.endObject();
|
||||
builder.required(o, 10); // name
|
||||
@@ -140,12 +153,10 @@ public final class Monster extends Table {
|
||||
@Override
|
||||
protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); }
|
||||
|
||||
public static Monster lookupByKey(int vectorOffset, String key, ByteBuffer bb) {
|
||||
public static Monster __lookup_by_key(int vectorLocation, String key, ByteBuffer bb) {
|
||||
byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get());
|
||||
int vectorLocation = bb.array().length - vectorOffset;
|
||||
int span = bb.getInt(vectorLocation);
|
||||
int span = bb.getInt(vectorLocation - 4);
|
||||
int start = 0;
|
||||
vectorLocation += 4;
|
||||
while (span != 0) {
|
||||
int middle = span / 2;
|
||||
int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);
|
||||
|
||||
@@ -379,22 +379,68 @@ class Monster extends Table
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FlatBufferBuilder $builder
|
||||
* @return void
|
||||
*/
|
||||
public static function startMonster(FlatBufferBuilder $builder)
|
||||
{
|
||||
$builder->StartObject(29);
|
||||
$builder->StartObject(31);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
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)
|
||||
{
|
||||
$builder->startObject(29);
|
||||
$builder->startObject(31);
|
||||
self::addPos($builder, $pos);
|
||||
self::addMana($builder, $mana);
|
||||
self::addHp($builder, $hp);
|
||||
@@ -423,6 +469,8 @@ class Monster extends Table
|
||||
self::addTestf2($builder, $testf2);
|
||||
self::addTestf3($builder, $testf3);
|
||||
self::addTestarrayofstring2($builder, $testarrayofstring2);
|
||||
self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct);
|
||||
self::addFlex($builder, $flex);
|
||||
$o = $builder->endObject();
|
||||
$builder->required($o, 10); // name
|
||||
return $o;
|
||||
@@ -871,6 +919,74 @@ class Monster extends Table
|
||||
$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->addOffset($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->addByte($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
|
||||
* @return int table offset
|
||||
|
||||
@@ -297,7 +297,41 @@ class Monster(object):
|
||||
return self._tab.VectorLen(o)
|
||||
return 0
|
||||
|
||||
def MonsterStart(builder): builder.StartObject(29)
|
||||
# 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 FlexLength(self):
|
||||
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
|
||||
if o != 0:
|
||||
return self._tab.VectorLen(o)
|
||||
return 0
|
||||
|
||||
def MonsterStart(builder): builder.StartObject(31)
|
||||
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)
|
||||
@@ -333,4 +367,8 @@ def MonsterAddTestf2(builder, testf2): builder.PrependFloat32Slot(26, testf2, 3.
|
||||
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 MonsterEnd(builder): return builder.EndObject()
|
||||
|
||||
@@ -16,7 +16,7 @@ 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) (* Monster, error)
|
||||
opts... grpc.CallOption) (MonsterStorage_RetrieveClient, error)
|
||||
}
|
||||
|
||||
type monsterStorageClient struct {
|
||||
@@ -36,17 +36,34 @@ func (c *monsterStorageClient) Store(ctx context.Context, in *flatbuffers.Builde
|
||||
}
|
||||
|
||||
func (c *monsterStorageClient) Retrieve(ctx context.Context, in *flatbuffers.Builder,
|
||||
opts... grpc.CallOption) (* Monster, error) {
|
||||
out := new(Monster)
|
||||
err := grpc.Invoke(ctx, "/Example.MonsterStorage/Retrieve", in, out, c.cc, opts...)
|
||||
opts... grpc.CallOption) (MonsterStorage_RetrieveClient, error) {
|
||||
stream, err := grpc.NewClientStream(ctx, &_MonsterStorage_serviceDesc.Streams[0], c.cc, "/Example.MonsterStorage/Retrieve", opts...)
|
||||
if err != nil { return nil, err }
|
||||
return out, nil
|
||||
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
|
||||
}
|
||||
|
||||
// Server API for MonsterStorage service
|
||||
type MonsterStorageServer interface {
|
||||
Store(context.Context, *Monster) (*flatbuffers.Builder, error)
|
||||
Retrieve(context.Context, *Stat) (*flatbuffers.Builder, error)
|
||||
Retrieve(*Stat, MonsterStorage_RetrieveServer) error
|
||||
}
|
||||
|
||||
func RegisterMonsterStorageServer(s *grpc.Server, srv MonsterStorageServer) {
|
||||
@@ -70,20 +87,23 @@ func _MonsterStorage_Store_Handler(srv interface{}, ctx context.Context,
|
||||
}
|
||||
|
||||
|
||||
func _MonsterStorage_Retrieve_Handler(srv interface{}, ctx context.Context,
|
||||
dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Stat)
|
||||
if err := dec(in); err != nil { return nil, err }
|
||||
if interceptor == nil { return srv.(MonsterStorageServer).Retrieve(ctx, in) }
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Example.MonsterStorage/Retrieve",
|
||||
}
|
||||
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MonsterStorageServer).Retrieve(ctx, req.(* Stat))
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -95,12 +115,13 @@ var _MonsterStorage_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Store",
|
||||
Handler: _MonsterStorage_Store_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Retrieve",
|
||||
Handler: _MonsterStorage_Retrieve_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Retrieve",
|
||||
Handler: _MonsterStorage_Retrieve_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
public struct Stat : IFlatbufferObject
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
public struct Test : IFlatbufferObject
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
public partial struct TestSimpleTableWithEnum : IFlatbufferObject
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
public struct Vec3 : IFlatbufferObject
|
||||
{
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// <auto-generated>
|
||||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
// </auto-generated>
|
||||
|
||||
namespace MyGame.Example2
|
||||
{
|
||||
|
||||
using System;
|
||||
using FlatBuffers;
|
||||
using global::System;
|
||||
using global::FlatBuffers;
|
||||
|
||||
public struct Monster : IFlatbufferObject
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ 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} monster_test.fbs
|
||||
${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>
|
||||
|
||||
43
tests/TestAll.sh
Normal file
43
tests/TestAll.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
echo "************************ Java:"
|
||||
|
||||
sh JavaTest.sh
|
||||
|
||||
echo "************************ Go:"
|
||||
|
||||
sh GoTest.sh
|
||||
|
||||
echo "************************ Python:"
|
||||
|
||||
sh PythonTest.sh
|
||||
|
||||
echo "************************ JavaScript:"
|
||||
|
||||
sh JavaScriptTest.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
|
||||
|
||||
echo "************************ C:"
|
||||
|
||||
echo "(in a different repo)"
|
||||
|
||||
echo "************************ Swift:"
|
||||
|
||||
echo "(in a different repo)"
|
||||
23
tests/TypeScriptTest.sh
Executable file
23
tests/TypeScriptTest.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/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 --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
|
||||
npm install @types/flatbuffers
|
||||
tsc --strict --noUnusedParameters --noUnusedLocals --noImplicitReturns --strictNullChecks ts/monster_test_generated.ts
|
||||
npm uninstall @types/flatbuffers
|
||||
node JavaScriptTest ./ts/monster_test_generated
|
||||
@@ -15,6 +15,6 @@
|
||||
set buildtype=Release
|
||||
if "%1"=="-b" set buildtype=%2
|
||||
|
||||
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
|
||||
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes -I include_test monster_test.fbs monsterdata_test.json
|
||||
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
|
||||
..\%buildtype%\flatc.exe --binary --schema monster_test.fbs
|
||||
..\%buildtype%\flatc.exe --binary --schema -I include_test monster_test.fbs
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
|
||||
../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
|
||||
../flatc --binary --schema monster_test.fbs
|
||||
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --gen-object-api --no-includes --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
|
||||
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --no-fb-import -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
|
||||
../flatc --cpp --gen-mutable --gen-object-api -o union_vector ./union_vector/union_vector.fbs
|
||||
../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
|
||||
cd ../samples
|
||||
../flatc --cpp --gen-mutable --gen-object-api monster.fbs
|
||||
cd ../reflection
|
||||
sh generate_code.sh
|
||||
|
||||
@@ -1251,9 +1251,9 @@ func CheckVtableDeduplication(fail func(string, ...interface{})) {
|
||||
len(want), want, len(got), got)
|
||||
}
|
||||
|
||||
table0 := &flatbuffers.Table{b.Bytes, flatbuffers.UOffsetT(len(b.Bytes)) - obj0}
|
||||
table1 := &flatbuffers.Table{b.Bytes, flatbuffers.UOffsetT(len(b.Bytes)) - obj1}
|
||||
table2 := &flatbuffers.Table{b.Bytes, flatbuffers.UOffsetT(len(b.Bytes)) - obj2}
|
||||
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
|
||||
|
||||
5
tests/include_test/include_test1.fbs
Normal file
5
tests/include_test/include_test1.fbs
Normal file
@@ -0,0 +1,5 @@
|
||||
include "sub/include_test2.fbs";
|
||||
include "sub/include_test2.fbs"; // should be skipped
|
||||
include "include_test1.fbs"; // should be skipped
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
include "include_test2.fbs"; // should be skipped
|
||||
include "sub/include_test2.fbs"; // should be skipped
|
||||
|
||||
namespace MyGame.OtherNameSpace;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user