Compare commits

..

66 Commits

Author SHA1 Message Date
dependabot[bot]
7ffc8d8346 Bump softprops/action-gh-release from 2 to 3
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-08 01:50:55 +00:00
mustiikhalil
392165432a [Swift] Migrate to use Swift Testing (#9076)
* Migrating from Xctests to swift testing

This migrates to the new Swift testing framework,
which would allow us to always use the latest tech
from swift moving forward.

* Updates flag to make sure that Wasm testing works
2026-05-07 21:49:41 -04:00
mustiikhalil
e6bbb3d22e [Swift] Migrate to swift 6.0 and Implements support gRPC v2 (#8983)
* Migrate to swift 6.0 & swift-gRPC 2.0

The following migrates to swift 6.0, and also
migrate to swift-grpc 2.0 that uses swift-nio
under the hood to provide nicer API and async await

Adds sendable to enum & update @_implementationOnly imports to use internal imports

* Address PR comments regarding misspelling & proper method naming.
2026-05-06 04:39:53 +02:00
Rifat Al Jubayer
a6979fe14a Fix logic inversion in FlexBuffers VerifyKey() (#9072)
VerifyKey() returns true on the first non-zero byte instead of
checking for a null terminator. This causes VerifyBuffer() to accept
FlexBuffers with non-null-terminated keys. Subsequent access to those
keys via strlen()/strcmp() reads out of bounds.

The condition if (*p++) should be if (!*p++) — return true
when a null terminator is found, not when any non-zero byte is found.

Confirmed with AddressSanitizer: heap-buffer-overflow in strlen()
after VerifyBuffer() returns true on a corrupted buffer.
2026-05-04 22:11:30 -04:00
Zen Dodd
bab10754d9 Stage the Python license file during builds (#9015)
Copy the repo-root LICENSE into the Python package directory for the duration of setup() so license_files = LICENSE remains valid without using deprecated parent-directory paths.

Remove the staged copy after the build completes.
2026-04-17 20:30:06 -04:00
Felix
ac7ef1176a Fix typo in generated header name (#9034) 2026-04-18 00:09:10 +00:00
Felix
d6444fb7fc Fix indention level for --no-python-gen-numpy (#9049) 2026-04-17 16:50:03 -04:00
Felix
e223d69b36 [Python] Extend GRPC Typing (#9007)
Extend function calls with optional type infos for checking
and discovering.

e838ba8a71/src/python/grpcio/grpc/__init__.py (L680)
2026-04-03 14:12:08 +00:00
Tulgaaaaaaaa
05cc7a2eff fix: correct operator precedence in ForAllFields reverse iteration (#8991)
* fix: correct operator precedence in ForAllFields reverse iteration

The expression `size() - i + 1` evaluates as `(size() - i) + 1` due to
left-to-right associativity, producing an out-of-bounds index when
reverse=true. For a vector of size N, the first iteration (i=0) accesses
index N+1, which is 2 past the last valid index.

Changed to `size() - (i + 1)` to match the correct implementation
already present in bfbs_gen.h:192.

Bug: CWE-125 (Out-of-bounds Read), CWE-783 (Operator Precedence Error)

* test: add ForAllFieldsReverseTest for reverse iteration correctness

Verify that ForAllFields with reverse=true iterates fields in
descending ID order. Tests both Stat (3 fields) and Monster
(many fields with non-sequential definition order) tables.

---------

Co-authored-by: Tulgaa <tulgaa.kek@gmail.com>
2026-04-02 10:14:27 +00:00
Noam ismach moshe
8a12183c3b Fix out-of-bounds vector access in StructDef::Deserialize (#8988)
* Fix out-of-bounds vector access in StructDef::Deserialize

* Fix syntax: use error_ instead of error()
2026-04-02 08:03:03 +00:00
Renzo
21b706b62d fix: swapped argument order in new_inconsistent_union calls (#9001) (#9010) 2026-04-02 07:05:58 +00:00
Tomasz Andrzejak
c5f151ab33 Add fallible try_* API for rust FlatBufferBuilder (#8918)
* Add fallible try_* API for FlatBufferBuilder

This is to support error propagation from Allocator trait. The Allocator
grow_downwards() method returns Result<(), Self::Error>, but
FlatBufferBuilder panics via .expect() when allocation fails instead of
propagating the error.

* Add rust fallible API docs
2026-04-02 06:49:51 +00:00
Björn Harrtell
3860f1cf7f [TS] Fixup TS test run at CI (#9004) 2026-03-30 13:32:24 +01:00
Thomas Köppe
4e582b0c1d [flexbuffers] Add "AlignedBlob", a version of "Blob" with explicit alignment. (#8993)
A blob is an array of bytes and has no intrinsic alignment (i.e. the
alignment is 1). The alignment of the existing flexbuffers blob is
solely affected by the width of the integer needed to store the blob's
size: that integer's width becomes the alignment of the blob.

The proposed AlignedBlob function here piggybacks on this effect and
simply uses a user-defined alignment for the width of the integer that
stores the blob's size; this automatically imparts that same alignment
on the blob itself. (The width is bounded below by the actual width
needed to store the blob's size.)

The ability to control the alignment of a blob is important for use
cases in which the blob itself stores structured data that we want to
access without further copies (e.g. other flatbuffer messages).
2026-03-23 10:28:03 -07:00
Fedor Osetrov
8396e00dd8 allow to use reflection in constant time evaluation (#8978)
* Update reflection.h

allow to use reflection in constant time evaluation

* make GetTypeSize constexpr

* fix clang-format
2026-03-20 02:01:45 +00:00
dependabot[bot]
48babd417d Bump flatted in the npm_and_yarn group across 1 directory (#8989)
Bumps the npm_and_yarn group with 1 update in the / directory: [flatted](https://github.com/WebReflection/flatted).


Updates `flatted` from 3.3.1 to 3.4.2
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.1...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-19 21:48:28 -04:00
tmimmanuel
22770f7e85 Fix inconsistent Python union creator function naming (#8981) 2026-03-19 12:36:37 +00:00
Dexter.k
21b033227e Add bounds check for root offset in AddFlatBuffer (#8982) 2026-03-19 08:22:26 -04:00
dataCenter430
93f587a6d3 fix: annotated output for size-prefixed binaries (#8976) 2026-03-18 22:54:46 -04:00
Kevin Zhao
8afb68f074 codegen: escape string default values to prevent code injection (#8964)
String default values parsed from .fbs schemas are un-escaped by the IDL
parser (e.g., \x22 becomes a raw " byte), but code generators embed these
raw values directly into generated source code string literals. This allows
specially crafted .fbs files to break out of string literals and inject
arbitrary code into generated C++, Rust, TypeScript, and Swift source.

Fix by adding EscapeCodeGenString() helper that re-escapes string content
before embedding, and applying it to all 7 affected injection points across
5 code generators (C++, Rust, TypeScript, Swift, FBS).

Resolves the TODO comments in idl_gen_cpp.cpp and idl_gen_rust.cpp.
2026-03-18 22:01:23 -04:00
Derek Bailey
2e07f269b9 Update build.yml
Remove 64-core windows github action runner as it is a charged product we need to do expense
2026-03-17 09:58:26 -07:00
Renzo
10c994155c Fix: allow flexbuffers alloc check test (#8972)
* Fix: allow flexbuffers alloc check test

* fix: flaky CI failure

* fix: set flexbuffers alloc check false
2026-03-12 09:44:32 -04:00
dataCenter430
fc9909c30a fix: infinite loop in proto reserved range parser (CWE-835) (#8966) 2026-03-11 22:23:32 -04:00
tmimmanuel
e35817577c Fix missing namespace qualifier in Pack() (#8967)
* Fix missing namespace qualifier in Pack() for cross-namespace table references

* Fix missing namespace qualifier in Pack()

* Add cross_namespace_pack_test to Bazel build
2026-03-11 22:11:06 -04:00
Moritz Walker
9e3fe5d3f6 rust: add secondary function with preallocated internal vecs (#8936)
* rust: add secondary function with preallocated internal vecs

* docs: document pre allocation feature for rust implementation
2026-03-11 15:26:23 +00:00
statxc
dc9217347e fix: add missing bracket (#8969) 2026-03-11 02:42:46 +00:00
statxc
a7fed2ce67 feat: add lookup_index_by_key to Rust Vector for index-based search (#8959)
* feat: add lookup_index_by_key to Rust Vector for index-based binary search

* fix: remove duplicated code
2026-03-11 02:15:21 +00:00
statxc
de3b97355d feat: use HashMap for create_shared_string to fix O(N²) performance (#8958)
* feat: use HashMap for create_shared_string to fix O(N²) performance

* refactor: clean up no_std binary_search_by with direct slice comparison
2026-03-10 21:56:34 -04:00
Renzo
8aa7084f01 Fix flaky flexbuffers_alloc_check test in cargo test (#8965) 2026-03-08 23:43:07 -04:00
Justin Davis
0f469cad54 Revert "fix using null string in vector (#7872)" (#8879)
This reverts commit 1cb1c4baee.
2026-03-07 13:19:34 +00:00
dependabot[bot]
72e51c61f7 Bump actions/upload-artifact from 6 to 7 (#8963)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-06 22:18:54 -05:00
Sutou Kouhei
31590a8a3b Enable Dependabot for GitHub Actions (#8778)
Our workflows use old GitHub Actions. For example, we use
`actions/checkout@v3` but `actions/checkout@v5` is the latest version:

599847236c/.github/workflows/build.yml (L33)

https://github.com/actions/checkout/releases

How about enabling Dependabot? If we enable Dependabot, Dependabot
opens PRs that update old GitHub Actions.

Dependabot document:
https://docs.github.com/en/code-security/dependabot

Dependabot configuration document:
https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference
2026-03-06 22:12:18 -05:00
Felix
24c2432d99 [Python]: Modernize setup and drop Python 2 (#8955) 2026-03-06 20:49:58 +00:00
Renzo
292870612c fix(flatbuffers): use manual impl Default for struct object types (#8947)
* fix(flatbuffers): use manual impl Default for struct object types

* fix: handle bool and float zero literals in struct object Default impl

* fix: regenerate all test bindings with generate_code.py

* fix: data type check on swift build

* fix: test large array on struct and enum
2026-03-06 11:20:32 -08:00
Cameron Mulhern
57659d9f38 Updates Rust codegen to use proper indentation (#8952)
* Fixes identation of generated Rust code

* Regenerates generated schemas
2026-03-05 14:04:55 +00:00
Udaya Prakash
2b8e4d3af0 build: Upgrade rules_swift to 3.1.2 and grpc to 1.76.0 (#8909) 2026-03-05 13:26:33 +00:00
Cameron Mulhern
08b6372a36 Generate better formatted Rust code (#8919)
* Cleans up Rust formatting

* Regenerates generated schemas
2026-03-05 02:49:46 +00:00
dependabot[bot]
9c383559e0 Bump minimatch in the npm_and_yarn group across 1 directory (#8951)
Bumps the npm_and_yarn group with 1 update in the / directory: [minimatch](https://github.com/isaacs/minimatch).


Updates `minimatch` from 3.1.2 to 3.1.5
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 02:43:14 +00:00
Salman Chishti
c13c3bf956 Upgrade GitHub Actions for Node 24 compatibility (#8934)
Signed-off-by: Salman Muin Kayser Chishti <13schishti@gmail.com>
2026-03-04 21:36:59 -05:00
dependabot[bot]
47eeb8f4e9 Bump ajv in the npm_and_yarn group across 1 directory (#8933)
Bumps the npm_and_yarn group with 1 update in the / directory: [ajv](https://github.com/ajv-validator/ajv).


Updates `ajv` from 6.12.6 to 6.14.0
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0)

---
updated-dependencies:
- dependency-name: ajv
  dependency-version: 6.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 02:28:53 +00:00
Uwe (ObjectBox)
e7c6874192 [Dart] Actually use resized FlexBuffers buffer (#8935)
When building a FlexBuffer using the Builder and adding data that exceeds the default buffer size (2048 bytes), in _newOffset() a larger buffer is created, but never used. This results in a RangeError.

Resolve by actually replacing the too small with the new larger buffer. Add a test that verifies this by adding multiple large strings to a vector.
2026-03-05 02:15:45 +00:00
RCRalph
8d2c333b36 fix: Added return value to non type-prefixed create vector function (#8945)
* fix: Added return value to non type-prefixed create vector function

* chore: Added generated code
2026-03-05 02:09:09 +00:00
Damian Sypniewski
abc9bfebff Update Go support for Optional Scalars (#8946) 2026-03-04 21:03:49 -05:00
Abhay Agarwal
94d6b8086b Ensure optional arrays, arrays with defaults, and strings with defaults are supported (#8896)
Fixing issues with generated ts/js
2026-02-23 08:55:37 +01:00
dependabot[bot]
fa709636b4 Bump lodash (#8913)
Bumps the npm_and_yarn group with 1 update in the /tests/ts/bazel_repository_test_dir directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.21 to 4.17.23
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-19 01:09:46 +00:00
Stevan Coroller
60463e25a8 Remove empty 'required' section from schema.md (#8900)
There is a typo in the schema.md file in documentation. An empty 'required' section was added right before the 'required' item in the middle of the attributes list. It even appears in the table of content, which might confuse readers, making it look like following attributes might be required while they are not. You can notice the issue there: https://flatbuffers.dev/schema/#attributes.

I did check that `mkdocs serve -f mkdocs.yml` does produce the expected output (the same attributes list without that extra empty `required` section in the middle) with my changes.
2026-02-18 20:03:01 -05:00
Austin Chick
b8e3d215b8 [TS] Fix relative import paths of generated TypeScript code (#8880)
* Refactor logic that generates import paths in AddImport

* Add new tests to validate relative import path fix

* Generate goldens

* Generate example code

* Format TS generator file

* Revert "Format TS generator file"

This reverts commit 0f0b24aee9.

* Fix merge conflicts

---------

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
2026-02-17 10:22:32 +01:00
mustiikhalil
d71c0ab4ac Moves the internal stack to use a pointer stack instead of the native array for improved performance (#8891)
Remove custom flags for native arrays when using flexbuffers on Wasm

Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2026-02-12 19:42:21 +01:00
mustiikhalil
fcf75449b8 [Swift] Moves VTs from enums to structs to prevent empty enum generation
Moves VTs from enums to structs to prevent empty enum generation, which would usually cause a compilation error.
2026-02-12 08:04:26 -10:00
Sebastian Barfurth
c21bda1649 Remove root_package from npm_translate_lock. (#8921)
This attribute is removed in the next major version of `aspect_rules_js`. It's
not actually needed here [according to](https://github.com/aspect-build/rules_js/pull/2709#issuecomment-3855183151)
a maintainer of `aspect_rules_js`.
2026-02-07 08:04:22 +00:00
Marcel
03fffb25e2 Set max_compatibility_level=3 for rules_swift (#8920)
This is necessary to be compatible with both rules_swift 2.x and 3.x.
2026-02-05 09:57:00 -08:00
bigjt
1a7495a6dd [C#] Add GetBytes methods for fixed arrays (#8633)
* [C#] Add GetBytes methods for fixed arrays

I wanted to direct access to fixed array bytes. I made some changes to the idl generator to create GetBytes functions following the same naming conventions used for vectors of scalar types. There was not a 'Length' field present to bound the existing index accessor so I added that too.

+ Add generic GetBytes for fixed length arrays of scalar types
+ Implement conditional compilation for ENABLE_SPAN_T:
  - ENABLE_SPAN_T: Returns `Span<T>` using `MemoryMarshal.Cast<byte, T>()` as needed.
  - Else: Returns `ArraySegment<byte>?` for raw byte access
+ Added tests reusing arrays_test.fbs definitions
+ Added const int Length field to support existing index based accessors

* [C#] Sync generated code for after adding GetBytes methods for fixed arrays

---------

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
2026-02-04 23:13:32 +00:00
Fawdlstty
3c1bb67ae1 sync human-readable value (#8859)
Co-authored-by: Justin Davis <jtdavis777@gmail.com>
2026-02-04 15:43:19 +00:00
Cameron Mulhern
5b9de8b6c0 Fixes Rust code generation for single file output when using namespaces (#8877)
* Adds tests for Rust single file mode

All existing tests only compile Rust code using --rust-module-root-file.

* Adds standalone include tests for Rust

The imports for these tests have been moved to their own file, as the existing intergration_test.rs file hides compilation issues from code generation due to symbols brought into scope outside of the generated code (e.g. `extern crate alloc`).

* Declare alloc crate in every Rust namespace

When performing code generation within a single file, extern crate alloc needs to be delcared to bring alloc into scope within every inner namespace.

* Regenerates generated schemas
2026-02-04 15:28:18 +00:00
Justin Davis
ea0a73d168 disallow circular struct references (#8851)
* detect and fail for circular struct dependencies

* pr comments

* pr comment
2026-02-04 15:15:05 +00:00
souma987
4623cfa4bc Opt in to using experimental Kotlin Native APIs to suppress build warnings (#8885)
- fixes #8846
2026-02-04 14:54:08 +00:00
Peter Shih
9c2c56dc6a Fix typo in comment in idl.h (#8907)
Co-authored-by: Justin Davis <jtdavis777@gmail.com>
2026-02-04 14:12:50 +00:00
brianmacy
429c28c783 fix(rust): Zero vtable memory in write_vtable to prevent uninitialized data (#8898)
The write_vtable() function's comment claimed to "fill the WIP vtable
with zeros" but make_space() only reserves memory without initializing
it. When using custom allocators with non-zeroed buffers, unset vtable
field entries would contain garbage instead of zero (which indicates
"use default value").

This fix explicitly zeros the vtable memory after reserving space,
matching the C++ implementation's buf_.fill_big() behavior.

Added regression test using a garbage-filled allocator (0xAA) that
verifies vtable entries for unset fields are properly zeroed.

Fixes #8894
2026-02-04 09:00:44 -05:00
Markus Junginger
e5a9ff757f flatbuffers.h: fix C++11 compilation (#8857) (#8858)
This constexpr officially works only with C++14 (assignment to lhs, 2 statements) and actually broke some C++11 compilers
2026-02-04 13:34:55 +00:00
Justin Davis
e53732b9b9 Feature: lua now file_ident aware (#8850)
* lua code not file ident aware

* update genned code

* make mac happy

* pr comments
2026-02-04 13:05:08 +00:00
Thiébaud Weksteen
b84b676c89 Fix example of JSON export with flatc (#8892)
Binary files should be placed after "--". Also add a note about missing
file_identifier and --raw-binary.
2026-02-04 07:51:49 -05:00
Iñaki Baz Castillo
3211f857d1 Add --ts-undefined-for-optionals command line option (#8861)
* Add --ts-undefined-for-optionals command line option

# Details

- Fixes #7656
- Added a new `--ts-undefined-for-optionals` command line option for `flatc`.
- If enabled, generated TypeScript code uses `undefined` for optional fields rather than `null`.

* Also add TS generated test files

* Run `sh scripts/clang-format-git.sh`

* also add tests/ts/lalala-options.ts to the repo

* move new tests to tests/ts/optional_values dir

* add tests/ts/optional_values/optional_values_generated.cjs to the repo

* reuse existing optional_scalars.fbs and add new test

* add comma

* sh scripts/clang-format-git.sh

* remove comma

* sh scripts/clang-format-git.sh

* trying things

* sh scripts/clang-format-git.sh

* done

* address feedback

* sh scripts/clang-format-git.sh

* run `sh scripts/clang-format-git.sh`

* remove uneeded `eslint-disable @typescript-eslint/no-namespace` line

---------

Co-authored-by: José Luis Millán <jmillan@aliax.net>
2026-02-04 13:37:41 +01:00
Stefan F.
95ff1f1d80 [c#] Fix Table __vector_as_array correct len calc (#8911)
* fix for https://github.com/google/flatbuffers/issues/8759
__vector_as_array<T> calling ByteBuffer.ToArray<T> with the length in bytes by multiplying len with ByteBuffer.Sizeof<T> and FlatBuffersExampleTests extended to call GetVectorOfLongsArray/GetVectorOfDoublesArray which failed without the fix

* first try to repair build-dotnet-windows

* syntax error fixed

* Update solution creation command in build workflow

add --format sln to the dotnet new command, maybe it is currently creating a .slnx instead?
2026-02-04 13:13:01 +01:00
Jacob Abrams
af8997b567 [Python] Improve python API (#8781)
* Fix generate_code script path

* [Python] Make StartVector public

Make StartVector vector public since it is already being used in
generated code

* [Python] Improve vector creation for Python API

Makes Python API for vectors cleaner like Rust and Swift

---------

Co-authored-by: Derek Bailey <derekbailey@google.com>
2026-01-21 01:01:20 +00:00
Derek Bailey
0d67abde45 MODULE.bazel: Upgrade rules_swift version (#8908) 2026-01-20 16:56:11 -08:00
razvanalex
d74e2945f7 [C++] Check for case insensitive keywords (#8420)
* chore(idl): Check for case insensitive keywords

Most languages are not affected by this change. In PHP, some names such
as Bool cannot be used because it is a reserved keyword for to the bool
data type. The field `keywords_casing` in the configs enables checking
all characters in lowercase against every keyword. This should be safe
as flatbuffers does not allow non-ASCII characters in its grammar.

* chore: Fix formatting to follow google's coding style for enums

* chore: Extract convert case to lower when CaseInsensitive

---------

Co-authored-by: Justin Davis <jtdavis777@gmail.com>
Co-authored-by: Derek Bailey <derekbailey@google.com>
2026-01-20 16:06:07 -08:00
344 changed files with 40514 additions and 19394 deletions

6
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -42,7 +42,7 @@ jobs:
chmod +x flatc
./flatc --version
- name: upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Linux flatc binary ${{ matrix.cxx }}
path: flatc
@@ -51,7 +51,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
run: zip Linux.flatc.binary.${{ matrix.cxx }}.zip flatc
- name: Release zip file
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
files: Linux.flatc.binary.${{ matrix.cxx }}.zip
@@ -170,7 +170,7 @@ jobs:
- name: test
run: Release\flattests.exe
- name: upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Windows flatc binary
path: Release\flatc.exe
@@ -179,7 +179,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
run: move Release/flatc.exe . && Compress-Archive flatc.exe Windows.flatc.binary.zip
- name: Release binary
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
files: Windows.flatc.binary.zip
@@ -191,14 +191,13 @@ jobs:
build-dotnet-windows:
name: Build .NET Windows
runs-on: windows-2022-64core
runs-on: windows-2022
strategy:
matrix:
configuration: [
'',
'-p:UnsafeByteBuffer=true',
# Fails two tests currently.
#'-p:EnableSpanT=true,UnsafeByteBuffer=true'
'-p:EnableSpanT=true,UnsafeByteBuffer=true'
]
steps:
- uses: actions/checkout@v6
@@ -209,7 +208,7 @@ jobs:
- name: Build
run: |
cd tests\FlatBuffers.Test
dotnet new sln --force --name FlatBuffers.Test
dotnet new sln --force --name FlatBuffers.Test --format sln
dotnet sln FlatBuffers.Test.sln add FlatBuffers.Test.csproj
dotnet build -c Release ${{matrix.configuration}} FlatBuffers.Test.sln
- name: Run net6.0
@@ -247,7 +246,7 @@ jobs:
chmod +x Release/flatc
Release/flatc --version
- name: upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Mac flatc binary Intel
path: Release/flatc
@@ -256,7 +255,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
run: mv Release/flatc . && zip MacIntel.flatc.binary.zip flatc
- name: Release binary
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
files: MacIntel.flatc.binary.zip
@@ -290,7 +289,7 @@ jobs:
chmod +x Release/flatc
Release/flatc --version
- name: upload build artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Mac flatc binary Universal
path: Release/flatc
@@ -299,7 +298,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
run: mv Release/flatc . && zip Mac.flatc.binary.zip flatc
- name: Release binary
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
files: Mac.flatc.binary.zip
@@ -315,7 +314,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- name: set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 17
@@ -374,7 +373,7 @@ jobs:
- name: Run benchmarks
run: ./flatbenchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true --benchmark_out_format=console --benchmark_out=benchmarks/results_${{matrix.cxx}}
- name: Upload benchmarks results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: Linux flatbenchmark results ${{matrix.cxx}}
path: benchmarks/results_${{matrix.cxx}}
@@ -395,7 +394,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
- name: set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 17
@@ -418,7 +417,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v6
- name: set up Java
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 17
@@ -447,7 +446,7 @@ jobs:
build-rust-windows:
name: Build Rust Windows
runs-on: windows-2022-64core
runs-on: windows-2022
steps:
- uses: actions/checkout@v6
- name: test
@@ -496,7 +495,7 @@ jobs:
name: Test Swift Linux
strategy:
matrix:
swift: ["5.10", "6.1", "6.2"]
swift: ["6.0", "6.1", "6.2"]
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
@@ -535,7 +534,7 @@ jobs:
run: |
swift sdk list
swift build --build-tests --swift-sdk swift-6.2.1-RELEASE_wasm
wasmtime --dir . .build/wasm32-unknown-wasip1/debug/FlatBuffers.Test.Swift.WasmPackageTests.xctest
wasmtime --dir . .build/wasm32-unknown-wasip1/debug/FlatBuffers.Test.Swift.WasmPackageTests.xctest --testing-library swift-testing
build-ts:
name: Build TS
@@ -546,7 +545,7 @@ jobs:
# FIXME: make test script not rely on flatc
run: cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_INSTALL=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . && make -j
- name: pnpm
run: npm install -g pnpm esbuild
run: npm install -g pnpm
- name: deps
run: pnpm i
- name: compile
@@ -592,11 +591,16 @@ jobs:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
# Explicitly use 8.5.1 until we can update or https://github.com/actions/runner-images/issues/13564 is fixed.
- name: Set env
run: >
echo "USE_BAZEL_VERSION=8.5.1" >> $GITHUB_ENV
- name: bazel build
run: >
bazel build
//:flatc
//:flatbuffers
//tests:flatbuffers_test
- name: bazel test
run: >
bazel test

View File

@@ -21,11 +21,11 @@ jobs:
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: 3.x
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
- uses: actions/cache@v5
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache

View File

@@ -27,7 +27,7 @@ jobs:
language: c++
fuzz-seconds: 60
- name: Upload Crash
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v3
- uses: actions/setup-node@v6
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
@@ -30,7 +30,7 @@ jobs:
working-directory: ./python
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v4
- uses: actions/setup-python@v6
with:
python-version: '3.10'

View File

@@ -515,13 +515,13 @@ function(compile_schema SRC_FBS OPT SUFFIX OUT_GEN_FILE)
endfunction()
function(compile_schema_for_test SRC_FBS OPT)
compile_schema("${SRC_FBS}" "${OPT}" ".fbs" GEN_FILE)
compile_schema("${SRC_FBS}" "${OPT}" "_generated" GEN_FILE)
target_sources(flattests PRIVATE ${GEN_FILE})
endfunction()
function(compile_schema_for_test_17 SRC_FBS OPT)
function(compile_schema_for_test_fbsh SRC_FBS OPT)
compile_schema("${SRC_FBS}" "${OPT}" ".fbs" GEN_FILE)
target_sources(flattests_cpp17 PRIVATE ${GEN_FILE})
target_sources(flattests PRIVATE ${GEN_FILE})
endfunction()
function(compile_schema_for_samples SRC_FBS OPT)
@@ -548,26 +548,18 @@ if(FLATBUFFERS_BUILD_TESTS)
# The flattest target needs some generated files
SET(FLATC_OPT_COMP --cpp --gen-compare --gen-mutable --gen-object-api --reflect-names)
SET(FLATC_OPT_SCOPED_ENUMS ${FLATC_OPT_COMP};--scoped-enums)
SET(FLATC_OPT_NAKED_PTR ${FLATC_OPT_COMP} --cpp-ptr-type naked)
compile_schema_for_test(tests/alignment_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/default_vectors_strings_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/monster_extra.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test_fbsh(tests/default_vectors_strings_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/arrays_test.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/native_inline_table_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/native_type_test.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/optional_scalars.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/key_field/key_field_sample.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/64bit/test_64bit.fbs "${FLATC_OPT_COMP};--bfbs-gen-embed")
compile_schema_for_test(tests/64bit/evolution/v1.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/64bit/evolution/v2.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/union_underlying_type_test.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/evolution_test/evolution_v1.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/evolution_test/evolution_v2.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/vector_table_naked_ptr.fbs "${FLATC_OPT_NAKED_PTR}")
compile_schema_for_test(tests/namespace_test/namespace_test1.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/namespace_test/namespace_test2.fbs "${FLATC_OPT_SCOPED_ENUMS}")
compile_schema_for_test(tests/union_vector/union_vector.fbs "${FLATC_OPT_COMP}")
compile_schema_for_test(tests/cross_namespace_pack_test.fbs "${FLATC_OPT_COMP}")
if(FLATBUFFERS_CODE_SANITIZE)
add_fsanitize_to_target(flattests ${FLATBUFFERS_CODE_SANITIZE})
@@ -597,19 +589,9 @@ if(FLATBUFFERS_BUILD_TESTS)
if(FLATBUFFERS_BUILD_CPP17)
add_executable(flattests_cpp17 ${FlatBuffers_Tests_CPP17_SRCS})
target_link_libraries(flattests_cpp17 PRIVATE $<BUILD_INTERFACE:ProjectConfig>)
target_include_directories(flattests_cpp17 PUBLIC
# Ideally everything is fully qualified from the root directories
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
# TODO(derekbailey): update includes to fully qualify src/ and tests/
src
tests
${CMAKE_CURRENT_BINARY_DIR}/tests
)
target_include_directories(flattests_cpp17 PUBLIC src tests)
target_compile_features(flattests_cpp17 PRIVATE cxx_std_17) # requires cmake 3.8
compile_schema_for_test_17(tests/optional_scalars.fbs "${FLATC_OPT_COMP}")
if(FLATBUFFERS_CODE_SANITIZE)
add_fsanitize_to_target(flattests_cpp17 ${FLATBUFFERS_CODE_SANITIZE})
endif()

View File

@@ -7,7 +7,7 @@ module(
bazel_dep(
name = "aspect_bazel_lib",
version = "2.11.0",
version = "2.14.0",
)
bazel_dep(
name = "aspect_rules_esbuild",
@@ -23,16 +23,16 @@ bazel_dep(
)
bazel_dep(
name = "grpc",
version = "1.70.1",
version = "1.76.0",
repo_name = "com_github_grpc_grpc",
)
bazel_dep(
name = "platforms",
version = "0.0.10",
version = "0.0.11",
)
bazel_dep(
name = "rules_cc",
version = "0.0.16",
version = "0.1.1",
)
bazel_dep(
name = "rules_go",
@@ -49,7 +49,8 @@ bazel_dep(
)
bazel_dep(
name = "rules_swift",
version = "2.1.1",
version = "3.1.2",
max_compatibility_level = 3,
repo_name = "build_bazel_rules_swift",
)
bazel_dep(
@@ -62,9 +63,6 @@ npm.npm_translate_lock(
name = "flatbuffers_npm",
npmrc = "//:.npmrc",
pnpm_lock = "//ts:pnpm-lock.yaml",
# Override the Bazel package where pnpm-lock.yaml is located and link
# to the specified package instead.
root_package = "ts",
verify_node_modules_ignored = "//:.bazelignore",
)
use_repo(npm, "flatbuffers_npm")

View File

@@ -1,4 +1,4 @@
// swift-tools-version:5.10
// swift-tools-version:6.0
/*
* Copyright 2020 Google Inc. All rights reserved.
*
@@ -36,14 +36,17 @@ let package = Package(
.target(
name: "FlatBuffers",
dependencies: ["Common"],
path: "swift/Sources/FlatBuffers"),
path: "swift/Sources/FlatBuffers",
swiftSettings: .settings),
.target(
name: "FlexBuffers",
dependencies: ["Common"],
path: "swift/Sources/FlexBuffers"),
path: "swift/Sources/FlexBuffers",
swiftSettings: .settings),
.target(
name: "Common",
path: "swift/Sources/Common"),
path: "swift/Sources/Common",
swiftSettings: .settings),
.testTarget(
name: "FlatbuffersTests",
dependencies: .dependencies,
@@ -52,7 +55,14 @@ let package = Package(
name: "FlexbuffersTests",
dependencies: ["FlexBuffers"],
path: "tests/swift/Tests/Flexbuffers"),
])
],
swiftLanguageModes: [.v6])
extension Array where Element == SwiftSetting {
static var settings: [SwiftSetting] {
[.enableUpcomingFeature("ExistentialAny")]
}
}
extension Array where Element == Package.Dependency {
static var dependencies: [Package.Dependency] {
@@ -60,7 +70,12 @@ extension Array where Element == Package.Dependency {
[]
#else
// Test only Dependency
[.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.4.1")]
[
.package(url: "https://github.com/grpc/grpc-swift-2.git", from: "2.0.0"),
.package(
url: "https://github.com/grpc/grpc-swift-nio-transport.git",
from: "2.0.0"),
]
#endif
}
}
@@ -72,7 +87,10 @@ extension Array where Element == PackageDescription.Target.Dependency {
#else
// Test only Dependency
[
.product(name: "GRPC", package: "grpc-swift"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(
name: "GRPCNIOTransportHTTP2",
package: "grpc-swift-nio-transport"),
"FlatBuffers",
]
#endif

View File

@@ -5,7 +5,7 @@ import 'types.dart';
/// The main builder class for creation of a FlexBuffer.
class Builder {
final ByteData _buffer;
ByteData _buffer;
List<_StackValue> _stack = [];
List<_StackPointer> _stackPointers = [];
int _offset = 0;
@@ -506,6 +506,7 @@ class Builder {
if (prevSize < size) {
final newBuf = ByteData(size);
newBuf.buffer.asUint8List().setAll(0, _buffer.buffer.asUint8List());
_buffer = newBuf;
}
return newOffset;
}

View File

@@ -318,6 +318,21 @@ void main() {
1,
]);
}
{
// Default buffer is 2048 bytes, add 2300 bytes of strings that force it
// to grow.
final s1 = 'A' * 1000;
final s2 = 'B' * 800;
final s3 = 'C' * 500;
var flx = Builder()
..startVector()
..addString(s1)
..addString(s2)
..addString(s3)
..end();
expect(flx.finish().length, 2323);
}
});
test('build map', () {

View File

@@ -79,11 +79,12 @@ list of `FILES...`.
`myschema.fbs` to JSON:
```sh
flatc --json myschema.fbs mydata.bin
flatc --json myschema.fbs -- mydata.bin
```
This will generate a `mydata.json` file.
This will generate a `mydata.json` file. If there is no
[`file_identifier`](schema.md/#file-identification-and-extension) defined
for this schema, you will need to use the `--raw-binary` option.
### Additional options

View File

@@ -57,7 +57,7 @@ a `char *` array, which you pass to `GetMonster()`.
```cpp
#include "flatbuffers/flatbuffers.h"
#include "monster_test_generate.h"
#include "monster_test_generated.h"
#include <iostream> // C++ header file for printing
#include <fstream> // C++ header file for file access

View File

@@ -97,6 +97,61 @@ convenient accessors for all fields, e.g. `hp()`, `mana()`, etc:
*Note: That we never stored a `mana` value, so it will return the default.*
## Fallible API and Custom Allocators
Every `FlatBufferBuilder` method that may allocate has a `try_*` counterpart
(e.g. `try_create_string`, `try_push`, `try_finish`) that returns
`Result<T, A::Error>` instead of panicking. This is useful when allocation
failures must be handled gracefully: for example in `no_std` environments or
with fixed-capacity buffers.
The existing panicking methods are unchanged and remain the simplest option
when using the default allocator.
#### Custom allocators
Implement the `Allocator` trait and pass it to `FlatBufferBuilder::new_in()`:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
use flatbuffers::{Allocator, FlatBufferBuilder};
struct MyAllocator { /* ... */ }
unsafe impl Allocator for MyAllocator {
type Error = MyError;
fn grow_downwards(&mut self) -> Result<(), Self::Error> { /* ... */ }
fn len(&self) -> usize { /* ... */ }
}
let alloc = MyAllocator::new(/* ... */);
let mut builder = FlatBufferBuilder::new_in(alloc);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The built-in `DefaultAllocator` uses `Vec<u8>` and sets `Error = Infallible`,
so the `try_*` methods on a default builder can never fail.
#### Example: building a buffer with error propagation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
fn build<A: flatbuffers::Allocator>(
builder: &mut FlatBufferBuilder<A>,
) -> Result<(), A::Error> {
let name = builder.try_create_string("Orc")?;
let inventory = builder.try_create_vector(&[0u8, 1, 2, 3, 4])?;
let table_start = builder.start_table();
builder.try_push_slot_always(Monster::VT_NAME, name)?;
builder.try_push_slot_always(Monster::VT_INVENTORY, inventory)?;
builder.try_push_slot(Monster::VT_HP, 80i16, 100)?;
let root = builder.try_end_table(table_start)?;
builder.try_finish(root, None)?;
Ok(())
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See the `FlatBufferBuilder` rustdoc for the full list of `try_*` methods.
## Direct memory access
As you can see from the above examples, all elements in a buffer are
@@ -205,6 +260,47 @@ And example of usage, for the time being, can be found in
- Safe getters in [SafeBuffer](https://docs.rs/flatbuffers-reflection/latest/flatbuffers_reflection/struct.SafeBuffer.html),
which does verification when constructed so you can use it for any data source
## Buffer pre allocation in a latency-sensitive context
In latency-sensitive applications, dynamic memory allocations can introduce unpredictable latency spikes. The `FlatBufferBuilder` internally uses several `Vec`s that may reallocate during serialization:
- The backing buffer for the FlatBuffer data
- `field_locs` for tracking field locations within tables
- `written_vtable_revpos` for deduplicating vtables
- `strings_pool` for shared string interning
To avoid allocations during serialization, you can preallocate all internal vectors upfront using the `with_internal_capacity` constructor:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
// Preallocate: 1KB buffer, 8 field locations, 16 vtables, 32 shared strings
let mut builder = FlatBufferBuilder::with_internal_capacity(1024, 8, 16, 32);
// All subsequent operations will not allocate (if capacities are sufficient)
let name = builder.create_shared_string("MyMonster");
// ... build your FlatBuffer ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are three variants available:
- `with_internal_capacity(size, field_locs, vtables, strings)` - Creates a new builder with all capacities preallocated
- `from_vec_with_internal_capacity(buffer, field_locs, vtables, strings)` - Reuses an existing `Vec<u8>` as the backing buffer
- `new_in_with_internal_capacity(allocator, field_locs, vtables, strings)` - Uses a custom `Allocator` with preallocated internal vecs
When combined with `reset()`, you can reuse the same builder across multiple serializations without any allocations after the initial setup:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.rs}
let mut builder = FlatBufferBuilder::with_internal_capacity(1024, 8, 16, 32);
loop {
// Build a FlatBuffer (allocation-free if capacities are sufficient)
let data = build_message(&mut builder);
send(data);
// Reset for reuse - clears state but retains allocated capacity
builder.reset();
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
## Useful tools created by others
* [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler

View File

@@ -427,9 +427,6 @@ Current understood attributes:
it won't be accessible anymore by newer code. Note that if you deprecate a
field that was previous required, old code may fail to validate new data (when
using the optional verifier).
### `required`
- `required` (on a non-scalar table field): this field must always be set. By
default, fields do not need to be present in the binary. This is desirable, as
it helps with forwards/backwards compatibility, and flexibility of data

View File

@@ -26,7 +26,7 @@ Simple mutation | Yes | Yes | Yes | Yes | No | No
Reflection | Yes | No | No | No | No | No | No | Basic | No | No | No | No | No
Buffer verifier | Yes | No | No | No | No | No | No | Yes | No | No | No | No | Yes
Native Object API | Yes | No | Yes | Yes | Yes | Yes | Yes | No | No | Yes | No | No | Yes
Optional Scalars | Yes | Yes | Yes | No | No | Yes | Yes | Yes | No | No | Yes | Yes | Yes
Optional Scalars | Yes | Yes | Yes | Yes | No | Yes | Yes | Yes | No | No | Yes | Yes | Yes
Flexbuffers | Yes | Yes | ? | ? | ? | ? | ? | ? | ? | ? | ? | Yes | Yes
Testing: basic | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | ? | Yes | Yes | Yes | Yes
Testing: fuzz | Yes | No | No | Yes | Yes | No | No | No | ? | No | No | Yes | No

View File

@@ -1134,12 +1134,8 @@ The Builder provides multiple ways to create `vectors`.
=== "Python"
```py
# Create a FlatBuffer vector and prepend the weapons.
# Note: Since we prepend the data, prepend them in reverse order.
MyGame.Sample.Monster.StartWeaponsVector(builder, 2)
builder.PrependUOffsetTRelative(axe)
builder.PrependUOffsetTRelative(sword)
weapons = builder.EndVector()
# Use the generated helper to create the weapons vector from offsets.
weapons = MyGame.Sample.Monster.CreateWeaponsVector(builder, [sword, axe])
```
=== "Rust"
@@ -1352,16 +1348,13 @@ bit more directly.
```py
# Create a `vector` representing the inventory of the Orc. Each number
# could correspond to an item that can be claimed after he is slain.
# Note: Since we prepend the bytes, this loop iterates in reverse.
MyGame.Sample.Monster.StartInventoryVector(builder, 10)
for i in reversed(range(0, 10)):
builder.PrependByte(i)
inv = builder.EndVector()
inv = MyGame.Sample.Monster.CreateInventoryVector(builder, range(0, 10))
MyGame.Sample.Monster.StartPathVector(builder, 2)
MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
path = builder.EndVector()
path_points = [
MyGame.Sample.Vec3T(x=1.0, y=2.0, z=3.0),
MyGame.Sample.Vec3T(x=4.0, y=5.0, z=6.0),
]
path = MyGame.Sample.Monster.CreatePathVector(builder, path_points)
```
=== "Rust"

View File

@@ -80,6 +80,12 @@ def UniverseStartGalaxiesVector(builder, numElems):
def StartGalaxiesVector(builder, numElems):
return UniverseStartGalaxiesVector(builder, numElems)
def UniverseCreateGalaxiesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateGalaxiesVector(builder, data):
UniverseCreateGalaxiesVector(builder, data)
def UniverseEnd(builder):
return builder.EndObject()

View File

@@ -2,294 +2,321 @@
// @generated
extern crate alloc;
#[allow(unused_imports, dead_code)]
pub mod flatbuffers {
extern crate alloc;
#[allow(unused_imports, dead_code)]
pub mod goldens {
#[allow(unused_imports, dead_code)]
pub mod goldens {
extern crate alloc;
pub enum GalaxyOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct Galaxy<'a> {
pub _tab: ::flatbuffers::Table<'a>,
}
impl<'a> ::flatbuffers::Follow<'a> for Galaxy<'a> {
type Inner = Galaxy<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
}
impl<'a> Galaxy<'a> {
pub const VT_NUM_STARS: ::flatbuffers::VOffsetT = 4;
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Galaxy { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args GalaxyArgs
) -> ::flatbuffers::WIPOffset<Galaxy<'bldr>> {
let mut builder = GalaxyBuilder::new(_fbb);
builder.add_num_stars(args.num_stars);
builder.finish()
}
pub enum GalaxyOffset {}
#[derive(Copy, Clone, PartialEq)]
#[inline]
pub fn num_stars(&self) -> i64 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i64>(Galaxy::VT_NUM_STARS, Some(0)).unwrap()}
}
}
pub struct Galaxy<'a> {
pub _tab: ::flatbuffers::Table<'a>,
}
impl ::flatbuffers::Verifiable for Galaxy<'_> {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<i64>("num_stars", Self::VT_NUM_STARS, false)?
.finish();
Ok(())
}
}
impl<'a> ::flatbuffers::Follow<'a> for Galaxy<'a> {
type Inner = Galaxy<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
}
pub struct GalaxyArgs {
pub num_stars: i64,
}
impl<'a> Galaxy<'a> {
pub const VT_NUM_STARS: ::flatbuffers::VOffsetT = 4;
impl<'a> Default for GalaxyArgs {
#[inline]
fn default() -> Self {
GalaxyArgs {
num_stars: 0,
}
}
}
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Galaxy { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args GalaxyArgs
) -> ::flatbuffers::WIPOffset<Galaxy<'bldr>> {
let mut builder = GalaxyBuilder::new(_fbb);
builder.add_num_stars(args.num_stars);
builder.finish()
}
pub struct GalaxyBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> {
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> GalaxyBuilder<'a, 'b, A> {
#[inline]
pub fn add_num_stars(&mut self, num_stars: i64) {
self.fbb_.push_slot::<i64>(Galaxy::VT_NUM_STARS, num_stars, 0);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> GalaxyBuilder<'a, 'b, A> {
let start = _fbb.start_table();
GalaxyBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Galaxy<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
impl ::core::fmt::Debug for Galaxy<'_> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Galaxy");
ds.field("num_stars", &self.num_stars());
ds.finish()
}
}
pub enum UniverseOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct Universe<'a> {
pub _tab: ::flatbuffers::Table<'a>,
}
impl<'a> ::flatbuffers::Follow<'a> for Universe<'a> {
type Inner = Universe<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
}
impl<'a> Universe<'a> {
pub const VT_AGE: ::flatbuffers::VOffsetT = 4;
pub const VT_GALAXIES: ::flatbuffers::VOffsetT = 6;
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Universe { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args UniverseArgs<'args>
) -> ::flatbuffers::WIPOffset<Universe<'bldr>> {
let mut builder = UniverseBuilder::new(_fbb);
builder.add_age(args.age);
if let Some(x) = args.galaxies { builder.add_galaxies(x); }
builder.finish()
}
#[inline]
pub fn num_stars(&self) -> i64 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i64>(Galaxy::VT_NUM_STARS, Some(0)).unwrap()}
}
}
#[inline]
pub fn age(&self) -> f64 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<f64>(Universe::VT_AGE, Some(0.0)).unwrap()}
}
impl ::flatbuffers::Verifiable for Galaxy<'_> {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<i64>("num_stars", Self::VT_NUM_STARS, false)?
.finish();
Ok(())
}
}
pub struct GalaxyArgs {
pub num_stars: i64,
}
impl<'a> Default for GalaxyArgs {
#[inline]
fn default() -> Self {
GalaxyArgs {
num_stars: 0,
}
}
}
#[inline]
pub fn galaxies(&self) -> Option<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Galaxy<'a>>>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Galaxy>>>>(Universe::VT_GALAXIES, None)}
}
}
pub struct GalaxyBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> {
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> GalaxyBuilder<'a, 'b, A> {
#[inline]
pub fn add_num_stars(&mut self, num_stars: i64) {
self.fbb_.push_slot::<i64>(Galaxy::VT_NUM_STARS, num_stars, 0);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> GalaxyBuilder<'a, 'b, A> {
let start = _fbb.start_table();
GalaxyBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Galaxy<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
impl ::flatbuffers::Verifiable for Universe<'_> {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<f64>("age", Self::VT_AGE, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, ::flatbuffers::ForwardsUOffset<Galaxy>>>>("galaxies", Self::VT_GALAXIES, false)?
.finish();
Ok(())
}
}
impl ::core::fmt::Debug for Galaxy<'_> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Galaxy");
ds.field("num_stars", &self.num_stars());
ds.finish()
}
}
pub enum UniverseOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct UniverseArgs<'a> {
pub age: f64,
pub galaxies: Option<::flatbuffers::WIPOffset<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Galaxy<'a>>>>>,
}
pub struct Universe<'a> {
pub _tab: ::flatbuffers::Table<'a>,
}
impl<'a> Default for UniverseArgs<'a> {
#[inline]
fn default() -> Self {
UniverseArgs {
age: 0.0,
galaxies: None,
}
}
}
impl<'a> ::flatbuffers::Follow<'a> for Universe<'a> {
type Inner = Universe<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
}
pub struct UniverseBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> {
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a> Universe<'a> {
pub const VT_AGE: ::flatbuffers::VOffsetT = 4;
pub const VT_GALAXIES: ::flatbuffers::VOffsetT = 6;
impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> UniverseBuilder<'a, 'b, A> {
#[inline]
pub fn add_age(&mut self, age: f64) {
self.fbb_.push_slot::<f64>(Universe::VT_AGE, age, 0.0);
}
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Universe { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args UniverseArgs<'args>
) -> ::flatbuffers::WIPOffset<Universe<'bldr>> {
let mut builder = UniverseBuilder::new(_fbb);
builder.add_age(args.age);
if let Some(x) = args.galaxies { builder.add_galaxies(x); }
builder.finish()
}
#[inline]
pub fn add_galaxies(&mut self, galaxies: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , ::flatbuffers::ForwardsUOffset<Galaxy<'b >>>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Universe::VT_GALAXIES, galaxies);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> UniverseBuilder<'a, 'b, A> {
let start = _fbb.start_table();
UniverseBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn age(&self) -> f64 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<f64>(Universe::VT_AGE, Some(0.0)).unwrap()}
}
#[inline]
pub fn galaxies(&self) -> Option<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Galaxy<'a>>>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Galaxy>>>>(Universe::VT_GALAXIES, None)}
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Universe<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
impl ::flatbuffers::Verifiable for Universe<'_> {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<f64>("age", Self::VT_AGE, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, ::flatbuffers::ForwardsUOffset<Galaxy>>>>("galaxies", Self::VT_GALAXIES, false)?
.finish();
Ok(())
}
}
pub struct UniverseArgs<'a> {
pub age: f64,
pub galaxies: Option<::flatbuffers::WIPOffset<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Galaxy<'a>>>>>,
}
impl<'a> Default for UniverseArgs<'a> {
#[inline]
fn default() -> Self {
UniverseArgs {
age: 0.0,
galaxies: None,
}
}
}
impl ::core::fmt::Debug for Universe<'_> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Universe");
ds.field("age", &self.age());
ds.field("galaxies", &self.galaxies());
ds.finish()
}
}
pub struct UniverseBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> {
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> UniverseBuilder<'a, 'b, A> {
#[inline]
pub fn add_age(&mut self, age: f64) {
self.fbb_.push_slot::<f64>(Universe::VT_AGE, age, 0.0);
}
#[inline]
pub fn add_galaxies(&mut self, galaxies: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , ::flatbuffers::ForwardsUOffset<Galaxy<'b >>>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Universe::VT_GALAXIES, galaxies);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> UniverseBuilder<'a, 'b, A> {
let start = _fbb.start_table();
UniverseBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Universe<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
/// Verifies that a buffer of bytes contains a `Universe`
/// and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_universe_unchecked`.
#[inline]
pub fn root_as_universe(buf: &[u8]) -> Result<Universe<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root::<Universe>(buf)
}
impl ::core::fmt::Debug for Universe<'_> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Universe");
ds.field("age", &self.age());
ds.field("galaxies", &self.galaxies());
ds.finish()
}
}
#[inline]
/// Verifies that a buffer of bytes contains a `Universe`
/// and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_universe_unchecked`.
pub fn root_as_universe(buf: &[u8]) -> Result<Universe<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root::<Universe>(buf)
}
#[inline]
/// Verifies that a buffer of bytes contains a size prefixed
/// `Universe` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `size_prefixed_root_as_universe_unchecked`.
pub fn size_prefixed_root_as_universe(buf: &[u8]) -> Result<Universe<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root::<Universe>(buf)
}
#[inline]
/// Verifies, with the given options, that a buffer of bytes
/// contains a `Universe` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_universe_unchecked`.
pub fn root_as_universe_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Universe<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root_with_opts::<Universe<'b>>(opts, buf)
}
#[inline]
/// Verifies, with the given verifier options, that a buffer of
/// bytes contains a size prefixed `Universe` and returns
/// it. Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_universe_unchecked`.
pub fn size_prefixed_root_as_universe_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Universe<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root_with_opts::<Universe<'b>>(opts, buf)
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a Universe and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `Universe`.
pub unsafe fn root_as_universe_unchecked(buf: &[u8]) -> Universe<'_> {
unsafe { ::flatbuffers::root_unchecked::<Universe>(buf) }
}
#[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed Universe and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `Universe`.
pub unsafe fn size_prefixed_root_as_universe_unchecked(buf: &[u8]) -> Universe<'_> {
unsafe { ::flatbuffers::size_prefixed_root_unchecked::<Universe>(buf) }
}
#[inline]
pub fn finish_universe_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(
fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
root: ::flatbuffers::WIPOffset<Universe<'a>>) {
fbb.finish(root, None);
}
/// Verifies that a buffer of bytes contains a size prefixed
/// `Universe` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `size_prefixed_root_as_universe_unchecked`.
#[inline]
pub fn size_prefixed_root_as_universe(buf: &[u8]) -> Result<Universe<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root::<Universe>(buf)
}
#[inline]
pub fn finish_size_prefixed_universe_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>, root: ::flatbuffers::WIPOffset<Universe<'a>>) {
fbb.finish_size_prefixed(root, None);
}
} // pub mod goldens
} // pub mod flatbuffers
/// Verifies, with the given options, that a buffer of bytes
/// contains a `Universe` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_universe_unchecked`.
#[inline]
pub fn root_as_universe_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Universe<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root_with_opts::<Universe<'b>>(opts, buf)
}
/// Verifies, with the given verifier options, that a buffer of
/// bytes contains a size prefixed `Universe` and returns
/// it. Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_universe_unchecked`.
#[inline]
pub fn size_prefixed_root_as_universe_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Universe<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root_with_opts::<Universe<'b>>(opts, buf)
}
/// Assumes, without verification, that a buffer of bytes contains a Universe and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `Universe`.
#[inline]
pub unsafe fn root_as_universe_unchecked(buf: &[u8]) -> Universe<'_> {
unsafe { ::flatbuffers::root_unchecked::<Universe>(buf) }
}
/// Assumes, without verification, that a buffer of bytes contains a size prefixed Universe and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `Universe`.
#[inline]
pub unsafe fn size_prefixed_root_as_universe_unchecked(buf: &[u8]) -> Universe<'_> {
unsafe { ::flatbuffers::size_prefixed_root_unchecked::<Universe>(buf) }
}
#[inline]
pub fn finish_universe_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(
fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
root: ::flatbuffers::WIPOffset<Universe<'a>>
) {
fbb.finish(root, None);
}
#[inline]
pub fn finish_size_prefixed_universe_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(
fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
root: ::flatbuffers::WIPOffset<Universe<'a>>
) {
fbb.finish_size_prefixed(root, None);
}
} // pub mod goldens
} // pub mod flatbuffers

View File

@@ -4,7 +4,7 @@
import * as flatbuffers from 'flatbuffers';
import { Galaxy } from '../../flatbuffers/goldens/galaxy.js';
import { Galaxy } from './galaxy.js';
export class Universe {

View File

@@ -0,0 +1,16 @@
namespace models;
table HelloResponse {
message:string;
}
table HelloRequest {
name:string;
}
rpc_service Greeter {
Get(HelloRequest):HelloResponse;
Collect(HelloRequest):HelloResponse (streaming: "client");
Expand(HelloRequest):HelloResponse (streaming: "server");
Update(HelloRequest):HelloResponse (streaming: "bidi");
}

View File

@@ -1,4 +1,4 @@
// swift-tools-version:5.10
// swift-tools-version:6.2
/*
* Copyright 2020 Google Inc. All rights reserved.
*
@@ -20,39 +20,43 @@ import PackageDescription
let package = Package(
name: "Greeter",
platforms: [
.iOS(.v12),
.macOS(.v10_14),
.iOS(.v18),
.macOS(.v15),
],
dependencies: [
.package(path: "../../../../swift"),
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0"),
.package(path: "../../../.."),
.package(url: "https://github.com/grpc/grpc-swift-2.git", from: "2.0.0"),
.package(
url: "https://github.com/grpc/grpc-swift-nio-transport.git",
from: "2.0.0"),
.package(
url: "https://github.com/apple/swift-argument-parser.git",
from: "1.5.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "Model",
name: "Models",
dependencies: [
"GRPC",
"FlatBuffers",
],
path: "Sources/Model"),
.product(name: "FlatBuffers", package: "flatbuffers"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(
name: "GRPCNIOTransportHTTP2",
package: "grpc-swift-nio-transport"),
]),
// Client for the Greeter example
.target(
name: "Client",
.executableTarget(
name: "Commands",
dependencies: [
"GRPC",
"Model",
],
path: "Sources/client"),
// Server for the Greeter example
.target(
name: "Server",
dependencies: [
"GRPC",
"Model",
],
path: "Sources/server"),
.product(name: "GRPCCore", package: "grpc-swift-2"),
.product(
name: "GRPCNIOTransportHTTP2",
package: "grpc-swift-nio-transport"),
.product(
name: "ArgumentParser",
package: "swift-argument-parser"),
"Models",
]),
])

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ArgumentParser
let port = 3000
@main
struct GreeterCommand: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "greeter",
abstract: "A multi-tool to run an echo server and execute RPCs against it.",
subcommands: [ServerCommand.self, ClientCommand.self])
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import FlatBuffers
import GRPCCore
import Models
struct GreeterService: models_Greeter.SimpleServiceProtocol {
func Get(
request: GRPCMessage<models_HelloResponse>,
context: GRPCCore
.ServerContext) async throws -> GRPCMessage<models_HelloResponse>
{
let model = try request.decode()
print("## GreeterService.Get: \(model.message)")
var builder = FlatBufferBuilder(initialSize: 128)
let off = builder.create(string: "Hello \(model.message ?? "Unknown")")
let root = models_HelloResponse.createHelloResponse(
&builder,
messageOffset: off)
builder.finish(offset: root)
return try GRPCMessage<models_HelloResponse>(builder: &builder)
}
func Collect(
request: GRPCCore.RPCAsyncSequence<
GRPCMessage<models_HelloResponse>,
any Swift.Error
>,
context: GRPCCore
.ServerContext) async throws -> GRPCMessage<models_HelloResponse>
{
let messages: [String] = try await request
.reduce(into: []) { array, message in
let model = try message.decode()
return array.append(model.message ?? "Unknown")
}
let joined = messages.joined(separator: ", ")
print("## GreeterService.Collect: \(joined)")
var builder = FlatBufferBuilder(initialSize: 128)
let off = builder.create(string: "Hello \(joined)")
let root = models_HelloResponse.createHelloResponse(
&builder,
messageOffset: off)
builder.finish(offset: root)
return try GRPCMessage<models_HelloResponse>(builder: &builder)
}
func Expand(
request: GRPCMessage<models_HelloResponse>,
response: GRPCCore.RPCWriter<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext) async throws
{
let model = try request.decode()
print("## GreeterService.Expand: \(model.message)")
let message = model.message ?? "Unknown"
let stream = AsyncThrowingStream<
GRPCMessage<models_HelloResponse>,
Error
> { continuation in
var builder = FlatBufferBuilder(initialSize: 128)
for char in message {
let off = builder.create(string: "\(char)")
let root = models_HelloResponse.createHelloResponse(
&builder,
messageOffset: off)
builder.finish(offset: root)
do {
continuation
.yield(try GRPCMessage<models_HelloResponse>(builder: &builder))
} catch {
continuation.finish(throwing: error)
}
}
continuation.finish()
}
try await response.write(contentsOf: stream)
}
func Update(
request: GRPCCore.RPCAsyncSequence<
GRPCMessage<models_HelloResponse>,
any Swift.Error
>,
response: GRPCCore.RPCWriter<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext) async throws
{
for try await message in request {
let model = try message.decode()
print("## GreeterService.Update: \(model.message)")
var builder = FlatBufferBuilder(initialSize: 128)
let off = builder.create(string: "Hello \(model.message ?? "Unknown")")
let root = models_HelloResponse.createHelloResponse(
&builder,
messageOffset: off)
builder.finish(offset: root)
try await response
.write(try GRPCMessage<models_HelloResponse>(builder: &builder))
}
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ArgumentParser
import FlatBuffers
import GRPCCore
import GRPCNIOTransportHTTP2
import Models
enum ClientRequest: String, ExpressibleByArgument {
case get, expand, collect, update
}
struct ClientCommand: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "client")
@Option(help: "Name to send to the server")
var name: String
@Option(help: "request type")
var request: ClientRequest
func run() async throws {
try await withGRPCClient(
transport: .http2NIOPosix(
target: .dns(host: "localhost", port: port),
transportSecurity: .plaintext))
{
let client = models_Greeter.Client(wrapping: $0)
switch request {
case .get: try await get(client: client)
case .expand: try await expand(client: client)
case .collect: try await collect(client: client)
case .update: try await update(client: client)
}
}
}
func get(
client: models_Greeter
.Client<HTTP2ClientTransport.Posix>) async throws
{
for _ in 0..<3 {
var builder = FlatBufferBuilder(initialSize: 64)
let off = builder.create(string: name)
let root = models_HelloRequest.createHelloRequest(
&builder,
nameOffset: off)
builder.finish(offset: root)
let response = try await client
.Get(GRPCMessage(builder: &builder))
let message = try? response.decode().message
print("get message: \(message ?? "nil")")
}
}
func expand(
client: models_Greeter
.Client<HTTP2ClientTransport.Posix>) async throws
{
for _ in 0..<3 {
var builder = FlatBufferBuilder(initialSize: 64)
let off = builder.create(string: name)
let root = models_HelloRequest.createHelloRequest(
&builder,
nameOffset: off)
builder.finish(offset: root)
try await client.Expand(GRPCMessage(builder: &builder)) { response in
for try await message in response.messages {
let message = try? message.decode().message
print("expand message: \(message ?? "nil")")
}
}
}
}
func collect(
client: models_Greeter
.Client<HTTP2ClientTransport.Posix>) async throws
{
for _ in 0..<3 {
let response = try await client.Collect { writer in
for part in name {
print("collect sending: \(part)")
var builder = FlatBufferBuilder(initialSize: 64)
let off = builder.create(string: String(part))
let root = models_HelloRequest.createHelloRequest(
&builder,
nameOffset: off)
builder.finish(offset: root)
try await writer.write(GRPCMessage(builder: &builder))
}
}
let message = try response.decode().message
print("collect message: \(message ?? "nil")")
}
}
func update(
client: models_Greeter
.Client<HTTP2ClientTransport.Posix>) async throws
{
for _ in 0..<3 {
try await client.Update { writer in
for part in name {
print("update sending: \(part)")
var builder = FlatBufferBuilder(initialSize: 64)
let off = builder.create(string: String(part))
let root = models_HelloRequest.createHelloRequest(
&builder,
nameOffset: off)
builder.finish(offset: root)
try await writer.write(GRPCMessage(builder: &builder))
}
} onResponse: { response in
for try await message in response.messages {
let message = try message.decode().message
print("collect message: \(message ?? "nil")")
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ArgumentParser
import GRPCCore
import GRPCNIOTransportHTTP2
struct ServerCommand: AsyncParsableCommand {
static let configuration = CommandConfiguration(
commandName: "serve")
func run() async throws {
let server = GRPCServer(
transport: .http2NIOPosix(
address: .ipv4(host: "127.0.0.1", port: port),
transportSecurity: .plaintext),
services: [GreeterService()])
try await withThrowingDiscardingTaskGroup { group in
group.addTask { try await server.serve() }
if let address = try await server.listeningAddress {
print("Echo listening on \(address)")
}
}
}
}

View File

@@ -1,147 +0,0 @@
// Generated GRPC code for FlatBuffers swift!
/// The following code is generated by the Flatbuffers library which might not be in sync with grpc-swift
/// in case of an issue please open github issue, though it would be maintained
// swiftlint:disable all
// swiftformat:disable all
#if !os(Windows)
import Foundation
import GRPC
import NIO
import NIOHTTP1
import FlatBuffers
public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage {}
public extension GRPCFlatBufPayload {
init(serializedByteBuffer: inout NIO.ByteBuffer) throws {
self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes))
}
func serialize(into buffer: inout NIO.ByteBuffer) throws {
withUnsafeReadableBytes { buffer.writeBytes($0) }
}
}
extension Message: GRPCFlatBufPayload {}
/// Usage: instantiate models_GreeterServiceClient, then call methods of this protocol to make API calls.
public protocol models_GreeterClientProtocol: GRPCClient {
var serviceName: String { get }
var interceptors: models_GreeterClientInterceptorFactoryProtocol? { get }
func SayHello(
_ request: Message<models_HelloRequest>
, callOptions: CallOptions?
) -> UnaryCall<Message<models_HelloRequest>, Message<models_HelloReply>>
func SayManyHellos(
_ request: Message<models_HelloRequest>
, callOptions: CallOptions?,
handler: @escaping (Message<models_HelloReply>) -> Void
) -> ServerStreamingCall<Message<models_HelloRequest>, Message<models_HelloReply>>
}
extension models_GreeterClientProtocol {
public var serviceName: String { "models.Greeter" }
public func SayHello(
_ request: Message<models_HelloRequest>
, callOptions: CallOptions? = nil
) -> UnaryCall<Message<models_HelloRequest>, Message<models_HelloReply>> {
return self.makeUnaryCall(
path: "/models.Greeter/SayHello",
request: request,
callOptions: callOptions ?? self.defaultCallOptions,
interceptors: self.interceptors?.makeSayHelloInterceptors() ?? []
)
}
public func SayManyHellos(
_ request: Message<models_HelloRequest>
, callOptions: CallOptions? = nil,
handler: @escaping (Message<models_HelloReply>) -> Void
) -> ServerStreamingCall<Message<models_HelloRequest>, Message<models_HelloReply>> {
return self.makeServerStreamingCall(
path: "/models.Greeter/SayManyHellos",
request: request,
callOptions: callOptions ?? self.defaultCallOptions,
interceptors: self.interceptors?.makeSayManyHellosInterceptors() ?? [],
handler: handler
)
}
}
public protocol models_GreeterClientInterceptorFactoryProtocol {
/// - Returns: Interceptors to use when invoking 'SayHello'.
func makeSayHelloInterceptors() -> [ClientInterceptor<Message<models_HelloRequest>, Message<models_HelloReply>>]
/// - Returns: Interceptors to use when invoking 'SayManyHellos'.
func makeSayManyHellosInterceptors() -> [ClientInterceptor<Message<models_HelloRequest>, Message<models_HelloReply>>]
}
public final class models_GreeterServiceClient: models_GreeterClientProtocol {
public let channel: GRPCChannel
public var defaultCallOptions: CallOptions
public var interceptors: models_GreeterClientInterceptorFactoryProtocol?
public init(
channel: GRPCChannel,
defaultCallOptions: CallOptions = CallOptions(),
interceptors: models_GreeterClientInterceptorFactoryProtocol? = nil
) {
self.channel = channel
self.defaultCallOptions = defaultCallOptions
self.interceptors = interceptors
}
}
public protocol models_GreeterProvider: CallHandlerProvider {
var interceptors: models_GreeterServerInterceptorFactoryProtocol? { get }
func SayHello(request: Message<models_HelloRequest>, context: StatusOnlyCallContext) -> EventLoopFuture<Message<models_HelloReply>>
func SayManyHellos(request: Message<models_HelloRequest>, context: StreamingResponseCallContext<Message<models_HelloReply>>) -> EventLoopFuture<GRPCStatus>
}
public extension models_GreeterProvider {
var serviceName: Substring { return "models.Greeter" }
func handle(method name: Substring, context: CallHandlerContext) -> GRPCServerHandlerProtocol? {
switch name {
case "SayHello":
return UnaryServerHandler(
context: context,
requestDeserializer: GRPCPayloadDeserializer<Message<models_HelloRequest>>(),
responseSerializer: GRPCPayloadSerializer<Message<models_HelloReply>>(),
interceptors: self.interceptors?.makeSayHelloInterceptors() ?? [],
userFunction: self.SayHello(request:context:))
case "SayManyHellos":
return ServerStreamingServerHandler(
context: context,
requestDeserializer: GRPCPayloadDeserializer<Message<models_HelloRequest>>(),
responseSerializer: GRPCPayloadSerializer<Message<models_HelloReply>>(),
interceptors: self.interceptors?.makeSayManyHellosInterceptors() ?? [],
userFunction: self.SayManyHellos(request:context:))
default: return nil;
}
}
}
public protocol models_GreeterServerInterceptorFactoryProtocol {
/// - Returns: Interceptors to use when handling 'SayHello'.
/// Defaults to calling `self.makeInterceptors()`.
func makeSayHelloInterceptors() -> [ServerInterceptor<Message<models_HelloRequest>, Message<models_HelloReply>>]
/// - Returns: Interceptors to use when handling 'SayManyHellos'.
/// Defaults to calling `self.makeInterceptors()`.
func makeSayManyHellosInterceptors() -> [ServerInterceptor<Message<models_HelloRequest>, Message<models_HelloReply>>]
}
#endif

View File

@@ -0,0 +1,572 @@
// Generated GRPC code for FlatBuffers swift!
/// The following code is generated by the Flatbuffers library which might not be in sync with grpc-swift
/// in case of an issue please open github issue, though it would be maintained
// swiftlint:disable all
// swiftformat:disable all
#if !os(Windows) && compiler(>=6.0)
import FlatBuffers
import Foundation
import GRPCCore
import GRPCNIOTransportCore
/// Usage: instantiate models.GreeterServiceClient, then call methods of this protocol to make API calls.
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension FlatBuffersMessageSerializer: MessageSerializer {
public func serialize<Bytes>(_ message: Message) throws -> Bytes where Bytes : GRPCCore.GRPCContiguousBytes {
do {
return try self.serialize(message: message) { GRPCNIOTransportBytes($0) } as! Bytes
} catch let error {
throw RPCError(
code: .invalidArgument,
message: "Can't serialize message",
cause: error
)
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension FlatBuffersMessageDeserializer: MessageDeserializer {
public func deserialize<Bytes>(_ serializedMessageBytes: Bytes) throws -> Message where Bytes : GRPCCore.GRPCContiguousBytes {
do {
return try serializedMessageBytes.withUnsafeBytes {
try self.deserialize(pointer: $0)
}
} catch let error {
throw RPCError(
code: .invalidArgument,
message: "Can't Decode message of type \(Message.self)",
cause: error
)
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
public enum models_Greeter: Sendable {
public static let descriptor = GRPCCore.ServiceDescriptor(fullyQualifiedService: "models.Greeter")
public enum Method: Sendable {
public enum Get: Sendable {
public typealias Input = FlatBufferBuilder
public typealias Output = models_HelloResponse
public static let descriptor = GRPCCore.MethodDescriptor(
service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "models.Greeter"),
method: "Get"
)
}
public enum Collect: Sendable {
public typealias Input = FlatBufferBuilder
public typealias Output = models_HelloResponse
public static let descriptor = GRPCCore.MethodDescriptor(
service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "models.Greeter"),
method: "Collect"
)
}
public enum Expand: Sendable {
public typealias Input = FlatBufferBuilder
public typealias Output = models_HelloResponse
public static let descriptor = GRPCCore.MethodDescriptor(
service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "models.Greeter"),
method: "Expand"
)
}
public enum Update: Sendable {
public typealias Input = FlatBufferBuilder
public typealias Output = models_HelloResponse
public static let descriptor = GRPCCore.MethodDescriptor(
service: GRPCCore.ServiceDescriptor(fullyQualifiedService: "models.Greeter"),
method: "Update"
)
}
public static let descriptors: [GRPCCore.MethodDescriptor] = [
Get.descriptor,
Collect.descriptor,
Expand.descriptor,
Update.descriptor,
]
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension GRPCCore.ServiceDescriptor {
public static let models_Greeter = GRPCCore.ServiceDescriptor(fullyQualifiedService: "models.Greeter")
}
// MARK: models.Greeter Server
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter {
public protocol StreamingServiceProtocol: GRPCCore.RegistrableRPCService {
func Get(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>
func Collect(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>
func Expand(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>
func Update(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>
}
public protocol ServiceProtocol: models_Greeter.StreamingServiceProtocol {
func Get(
request: GRPCCore.ServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.ServerResponse<GRPCMessage<models_HelloResponse>>
func Collect(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.ServerResponse<GRPCMessage<models_HelloResponse>>
func Expand(
request: GRPCCore.ServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>
func Update(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>
}
public protocol SimpleServiceProtocol: models_Greeter.ServiceProtocol {
func Get(
request: GRPCMessage<models_HelloResponse>,
context: GRPCCore.ServerContext
) async throws -> GRPCMessage<models_HelloResponse>
func Collect(
request: GRPCCore.RPCAsyncSequence<GRPCMessage<models_HelloResponse>, any Swift.Error>,
context: GRPCCore.ServerContext
) async throws -> GRPCMessage<models_HelloResponse>
func Expand(
request: GRPCMessage<models_HelloResponse>,
response: GRPCCore.RPCWriter<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws
func Update(
request: GRPCCore.RPCAsyncSequence<GRPCMessage<models_HelloResponse>, any Swift.Error>,
response: GRPCCore.RPCWriter<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter.StreamingServiceProtocol {
public func registerMethods<Transport>(with router: inout GRPCCore.RPCRouter<Transport>) where Transport: GRPCCore.ServerTransport {
router.registerHandler(
forMethod: models_Greeter.Method.Get.descriptor,
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
handler: { request, context in
try await self.Get(
request: request,
context: context
)
}
)
router.registerHandler(
forMethod: models_Greeter.Method.Collect.descriptor,
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
handler: { request, context in
try await self.Collect(
request: request,
context: context
)
}
)
router.registerHandler(
forMethod: models_Greeter.Method.Expand.descriptor,
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
handler: { request, context in
try await self.Expand(
request: request,
context: context
)
}
)
router.registerHandler(
forMethod: models_Greeter.Method.Update.descriptor,
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
handler: { request, context in
try await self.Update(
request: request,
context: context
)
}
)
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter.ServiceProtocol {
public func Get(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>> {
let response = try await self.Get(
request: GRPCCore.ServerRequest(stream: request),
context: context
)
return GRPCCore.StreamingServerResponse(single: response)
}
public func Collect(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>> {
let response = try await self.Collect(
request: request,
context: context
)
return GRPCCore.StreamingServerResponse(single: response)
}
public func Expand(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>> {
let response = try await self.Expand(
request: GRPCCore.ServerRequest(stream: request),
context: context
)
return response
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter.SimpleServiceProtocol {
public func Get(
request: GRPCCore.ServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.ServerResponse<GRPCMessage<models_HelloResponse>> {
return GRPCCore.ServerResponse<GRPCMessage<models_HelloResponse>>(
message: try await self.Get(
request: request.message,
context: context
),
metadata: [:]
)
}
public func Collect(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.ServerResponse<GRPCMessage<models_HelloResponse>> {
return GRPCCore.ServerResponse<GRPCMessage<models_HelloResponse>>(
message: try await self.Collect(
request: request.messages,
context: context
),
metadata: [:]
)
}
public func Expand(
request: GRPCCore.ServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>> {
return GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>(
metadata: [:],
producer: { writer in
try await self.Expand(
request: request.message,
response: writer,
context: context
)
return [:]
}
)
}
public func Update(
request: GRPCCore.StreamingServerRequest<GRPCMessage<models_HelloResponse>>,
context: GRPCCore.ServerContext
) async throws -> GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>> {
return GRPCCore.StreamingServerResponse<GRPCMessage<models_HelloResponse>>(
metadata: [:],
producer: { writer in
try await self.Update(
request: request.messages,
response: writer,
context: context
)
return [:]
}
)
}
}
// MARK: models.Greeter Client
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter {
public protocol ClientProtocol: Sendable {
func Get<Result>(
request: GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable
func Collect<Result>(
request: GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable
func Expand<Result>(
request: GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable
func Update<Result>(
request: GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter {
public struct Client<Transport>: ClientProtocol where Transport: GRPCCore.ClientTransport {
private let client: GRPCCore.GRPCClient<Transport>
public init(wrapping client: GRPCCore.GRPCClient<Transport>) {
self.client = client
}
public func Get<Result>(
request: GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result = { response in try response.message }
) async throws -> Result where Result: Sendable {
try await self.client.unary(
request: request,
descriptor: models_Greeter.Method.Get.descriptor,
serializer: serializer,
deserializer: deserializer,
options: options,
onResponse: handleResponse
)
}
public func Collect<Result>(
request: GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result = { response in try response.message }
) async throws -> Result where Result: Sendable {
try await self.client.clientStreaming(
request: request,
descriptor: models_Greeter.Method.Collect.descriptor,
serializer: serializer,
deserializer: deserializer,
options: options,
onResponse: handleResponse
)
}
public func Expand<Result>(
request: GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable {
try await self.client.serverStreaming(
request: request,
descriptor: models_Greeter.Method.Expand.descriptor,
serializer: serializer,
deserializer: deserializer,
options: options,
onResponse: handleResponse
)
}
public func Update<Result>(
request: GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>,
serializer: some GRPCCore.MessageSerializer<GRPCMessage<models_HelloResponse>>,
deserializer: some GRPCCore.MessageDeserializer<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable {
try await self.client.bidirectionalStreaming(
request: request,
descriptor: models_Greeter.Method.Update.descriptor,
serializer: serializer,
deserializer: deserializer,
options: options,
onResponse: handleResponse
)
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter.ClientProtocol {
public func Get<Result>(
request: GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result = { response in try response.message }
) async throws -> Result where Result: Sendable {
try await self.Get(
request: request,
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
options: options,
onResponse: handleResponse
)
}
public func Collect<Result>(
request: GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result = { response in try response.message }
) async throws -> Result where Result: Sendable {
try await self.Collect(
request: request,
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
options: options,
onResponse: handleResponse
)
}
public func Expand<Result>(
request: GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable {
try await self.Expand(
request: request,
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
options: options,
onResponse: handleResponse
)
}
public func Update<Result>(
request: GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>,
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable {
try await self.Update(
request: request,
serializer: FlatBuffersMessageSerializer<GRPCMessage<models_HelloResponse>>(),
deserializer: FlatBuffersMessageDeserializer<GRPCMessage<models_HelloResponse>>(),
options: options,
onResponse: handleResponse
)
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
extension models_Greeter.ClientProtocol {
public func Get<Result>(
_ message: GRPCMessage<models_HelloResponse>,
metadata: GRPCCore.Metadata = [:],
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result = { try $0.message }
) async throws -> Result where Result: Sendable {
let request = GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>(
message: message,
metadata: metadata
)
return try await self.Get(
request: request,
options: options,
onResponse: handleResponse
)
}
public func Collect<Result>(
metadata: GRPCCore.Metadata = [:],
options: GRPCCore.CallOptions = .defaults,
requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter<GRPCMessage<models_HelloResponse>>) async throws -> Void,
onResponse handleResponse: @Sendable @escaping (GRPCCore.ClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result = { try $0.message }
) async throws -> Result where Result: Sendable {
let request = GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>(
metadata: metadata,
producer: producer
)
return try await self.Collect(
request: request,
options: options,
onResponse: handleResponse
)
}
public func Expand<Result>(
_ message: GRPCMessage<models_HelloResponse>,
metadata: GRPCCore.Metadata = [:],
options: GRPCCore.CallOptions = .defaults,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable {
let request = GRPCCore.ClientRequest<GRPCMessage<models_HelloResponse>>(
message: message,
metadata: metadata
)
return try await self.Expand(
request: request,
options: options,
onResponse: handleResponse
)
}
public func Update<Result>(
metadata: GRPCCore.Metadata = [:],
options: GRPCCore.CallOptions = .defaults,
requestProducer producer: @Sendable @escaping (GRPCCore.RPCWriter<GRPCMessage<models_HelloResponse>>) async throws -> Void,
onResponse handleResponse: @Sendable @escaping (GRPCCore.StreamingClientResponse<GRPCMessage<models_HelloResponse>>) async throws -> Result
) async throws -> Result where Result: Sendable {
let request = GRPCCore.StreamingClientRequest<GRPCMessage<models_HelloResponse>>(
metadata: metadata,
producer: producer
)
return try await self.Update(
request: request,
options: options,
onResponse: handleResponse
)
}
}
#endif

View File

@@ -8,7 +8,7 @@ import Common
import FlatBuffers
public struct models_HelloReply: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable {
public struct models_HelloResponse: FlatBufferVerifiableTable, FlatbuffersVectorInitializable {
static func validateVersion() { FlatBuffersVersion_25_12_19() }
public var __buffer: ByteBuffer! { return _accessor.bb }
@@ -17,45 +17,43 @@ public struct models_HelloReply: FlatBufferTable, FlatbuffersVectorInitializable
private init(_ t: Table) { _accessor = t }
public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
private enum VTOFFSET: VOffset {
case message = 4
var v: Int32 { Int32(self.rawValue) }
var p: VOffset { self.rawValue }
private struct VT {
static let message: VOffset = 4
}
public var message: String? { let o = _accessor.offset(VTOFFSET.message.v); return o == 0 ? nil : _accessor.string(at: o) }
public var messageSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.message.v) }
public static func startHelloReply(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
public static func add(message: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: message, at: VTOFFSET.message.p) }
public static func endHelloReply(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
public static func createHelloReply(
public var message: String? { let o = _accessor.offset(VT.message); return o == 0 ? nil : _accessor.string(at: o) }
public var messageSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.message) }
public static func startHelloResponse(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
public static func add(message: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: message, at: VT.message) }
public static func endHelloResponse(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
public static func createHelloResponse(
_ fbb: inout FlatBufferBuilder,
messageOffset message: Offset = Offset()
) -> Offset {
let __start = models_HelloReply.startHelloReply(&fbb)
models_HelloReply.add(message: message, &fbb)
return models_HelloReply.endHelloReply(&fbb, start: __start)
let __start = models_HelloResponse.startHelloResponse(&fbb)
models_HelloResponse.add(message: message, &fbb)
return models_HelloResponse.endHelloResponse(&fbb, start: __start)
}
public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.message.p, fieldName: "message", required: false, type: ForwardOffset<String>.self)
try _v.visit(field: VT.message, fieldName: "message", required: false, type: ForwardOffset<String>.self)
_v.finish()
}
}
extension models_HelloReply: Encodable {
extension models_HelloResponse: Encodable {
enum CodingKeys: String, CodingKey {
case message = "message"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(message, forKey: .message)
}
}
public struct models_HelloRequest: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable {
public struct models_HelloRequest: FlatBufferVerifiableTable, FlatbuffersVectorInitializable {
static func validateVersion() { FlatBuffersVersion_25_12_19() }
public var __buffer: ByteBuffer! { return _accessor.bb }
@@ -64,16 +62,14 @@ public struct models_HelloRequest: FlatBufferTable, FlatbuffersVectorInitializab
private init(_ t: Table) { _accessor = t }
public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
private enum VTOFFSET: VOffset {
case name = 4
var v: Int32 { Int32(self.rawValue) }
var p: VOffset { self.rawValue }
private struct VT {
static let name: VOffset = 4
}
public var name: String? { let o = _accessor.offset(VTOFFSET.name.v); return o == 0 ? nil : _accessor.string(at: o) }
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.name.v) }
public var name: String? { let o = _accessor.offset(VT.name); return o == 0 ? nil : _accessor.string(at: o) }
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.name) }
public static func startHelloRequest(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) }
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VTOFFSET.name.p) }
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VT.name) }
public static func endHelloRequest(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
public static func createHelloRequest(
_ fbb: inout FlatBufferBuilder,
@@ -86,16 +82,16 @@ public struct models_HelloRequest: FlatBufferTable, FlatbuffersVectorInitializab
public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: false, type: ForwardOffset<String>.self)
try _v.visit(field: VT.name, fieldName: "name", required: false, type: ForwardOffset<String>.self)
_v.finish()
}
}
extension models_HelloRequest: Encodable {
enum CodingKeys: String, CodingKey {
case name = "name"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(name, forKey: .name)

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import FlatBuffers
import GRPC
import Logging
import Model
import NIO
// Quieten the logs.
LoggingSystem.bootstrap {
var handler = StreamLogHandler.standardOutput(label: $0)
handler.logLevel = .critical
return handler
}
func greet(name: String, client greeter: models_GreeterServiceClient) {
// Form the request with the name, if one was provided.
var builder = FlatBufferBuilder()
let nameOff = builder.create(string: name)
let root = models_HelloRequest.createHelloRequest(
&builder,
nameOffset: nameOff)
builder.finish(offset: root)
// Make the RPC call to the server.
let sayHello =
greeter
.SayHello(Message<models_HelloRequest>(builder: &builder))
// wait() on the response to stop the program from exiting before the response is received.
do {
let response = try sayHello.response.wait()
print("Greeter SayHello received: \(response.object.message ?? "Unknown")")
} catch {
print("Greeter failed: \(error)")
}
let surname = builder.create(string: name)
let manyRoot = models_HelloRequest.createHelloRequest(
&builder,
nameOffset: surname)
builder.finish(offset: manyRoot)
let call = greeter.SayManyHellos(Message(builder: &builder)) { message in
print(
"Greeter SayManyHellos received: \(message.object.message ?? "Unknown")")
}
let status = try! call.status.recover { _ in .processingError }.wait()
if status.code != .ok {
print("RPC failed: \(status)")
}
}
func main(args: [String]) {
// arg0 (dropped) is the program name. We expect arg1 to be the port, and arg2 (optional) to be
// the name sent in the request.
let arg1 = args.dropFirst(1).first
let arg2 = args.dropFirst(2).first
switch (arg1.flatMap(Int.init), arg2) {
case (.none, _):
print("Usage: PORT [NAME]")
exit(1)
case (.some(let port), let name):
// Setup an `EventLoopGroup` for the connection to run on.
//
// See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
// Make sure the group is shutdown when we're done with it.
defer {
try! group.syncShutdownGracefully()
}
// Configure the channel, we're not using TLS so the connection is `insecure`.
let channel = ClientConnection.insecure(group: group)
.connect(host: "localhost", port: port)
// Close the connection when we're done with it.
defer {
try! channel.close().wait()
}
// Provide the connection to the generated client.
let greeter = models_GreeterServiceClient(channel: channel)
// Do the greeting.
greet(name: name ?? "FlatBuffers!", client: greeter)
}
}
main(args: CommandLine.arguments)

View File

@@ -1,97 +0,0 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import FlatBuffers
import GRPC
import Logging
import Model
import NIO
class Greeter: models_GreeterProvider {
var interceptors: models_GreeterServerInterceptorFactoryProtocol?
let greetings: [String]
init() {
greetings = ["Hi", "Hallo", "Ciao"]
}
func SayHello(
request: Message<models_HelloRequest>,
context: StatusOnlyCallContext)
-> EventLoopFuture<Message<models_HelloReply>>
{
let recipient = request.object.name ?? "Stranger"
var builder = FlatBufferBuilder()
let off = builder.create(string: "Hello \(recipient)")
let root = models_HelloReply.createHelloReply(&builder, messageOffset: off)
builder.finish(offset: root)
return context.eventLoop
.makeSucceededFuture(Message<models_HelloReply>(builder: &builder))
}
func SayManyHellos(
request: Message<models_HelloRequest>,
context: StreamingResponseCallContext<Message<models_HelloReply>>)
-> EventLoopFuture<GRPCStatus>
{
for name in greetings {
var builder = FlatBufferBuilder()
let off =
builder
.create(string: "\(name) \(request.object.name ?? "Unknown")")
let root = models_HelloReply.createHelloReply(
&builder,
messageOffset: off)
builder.finish(offset: root)
_ = context.sendResponse(Message<models_HelloReply>(builder: &builder))
}
return context.eventLoop.makeSucceededFuture(.ok)
}
}
// Quieten the logs.
LoggingSystem.bootstrap {
var handler = StreamLogHandler.standardOutput(label: $0)
handler.logLevel = .critical
return handler
}
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
defer {
try! group.syncShutdownGracefully()
}
// Create some configuration for the server:
let configuration = Server.Configuration(
target: .hostAndPort("localhost", 0),
eventLoopGroup: group,
serviceProviders: [Greeter()])
// Start the server and print its address once it has started.
let server = Server.start(configuration: configuration)
server.map {
$0.channel.localAddress
}.whenSuccess { address in
print("server started on port \(address!.port!)")
}
// Wait on the server's `onClose` future to stop the program from exiting.
_ = try server.flatMap {
$0.onClose
}.wait()

View File

@@ -172,6 +172,7 @@ class StubGenerator : public BaseGenerator {
<< " def __init__(self, channel: grpc.Channel) -> None: ...\n";
for (const RPCCall* method : service->calls.vec) {
imports->Import("typing");
std::string request = "bytes";
std::string response = "bytes";
@@ -183,14 +184,22 @@ class StubGenerator : public BaseGenerator {
imports->Import(ModuleFor(method->response), response);
}
ss << " def " << method->name << "(self, ";
ss << " def " << method->name << "(\n";
ss << " self,\n";
if (ClientStreaming(method)) {
imports->Import("typing");
ss << "request_iterator: typing.Iterator[" << request << "]";
ss << " request_iterator: typing.Iterator[" << request << "]\n";
} else {
ss << "request: " << request;
ss << " request: " << request << ",\n";
}
ss << ") -> ";
ss << " timeout: float | None = None,\n";
// https://github.com/python/typeshed/blob/ccf9411fb1f5bee2a8e3d278889de17a08f7bbe3/stubs/grpcio/grpc/__init__.pyi#L37
ss << " metadata: typing.Sequence[tuple[str, typing.Union[str, bytes]]] | None = None,\n";
ss << " credentials: grpc.CallCredentials | None = None,\n";
ss << " wait_for_ready: bool | None = None,\n";
ss << " compression: grpc.Compression | None = None\n";
ss << " ) -> ";
if (ServerStreaming(method)) {
imports->Import("typing");
ss << "typing.Iterator[" << response << "]";

File diff suppressed because it is too large Load Diff

View File

@@ -91,6 +91,14 @@ class Namer {
std::string keyword_prefix;
// Suffix used to escape keywords. It is usually "_".
std::string keyword_suffix;
// The casing used for keywords when escaping. For most languages, keywords
// are case sensitive. PHP is an instance where some keywords are case
// insensitive.
enum class KeywordsCasing {
CaseSensitive,
CaseInsensitive,
};
KeywordsCasing keywords_casing;
// Files.
@@ -204,8 +212,16 @@ class Namer {
return result;
}
virtual std::string NormalizeKeywordCase(const std::string& name) const {
if (config_.keywords_casing == Config::KeywordsCasing::CaseInsensitive) {
return ConvertCase(name, Case::kAllLower);
} else {
return name;
}
}
virtual std::string EscapeKeyword(const std::string& name) const {
if (keywords_.find(name) == keywords_.end()) {
if (keywords_.find(NormalizeKeywordCase(name)) == keywords_.end()) {
return name;
} else {
return config_.keyword_prefix + name + config_.keyword_suffix;

View File

@@ -26,6 +26,7 @@ static const Namer::Config kConfig = {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",
@@ -49,6 +50,7 @@ static const Namer::Config kStubConfig = {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",

View File

@@ -260,15 +260,15 @@ inline const char* flatbuffers_version_string() {
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator ~ (E lhs){\
return E(~T(lhs));\
}\
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator |= (E &lhs, E rhs){\
inline FLATBUFFERS_CONSTEXPR_CPP14 E operator |= (E &lhs, E rhs){\
lhs = lhs | rhs;\
return lhs;\
}\
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator &= (E &lhs, E rhs){\
inline FLATBUFFERS_CONSTEXPR_CPP14 E operator &= (E &lhs, E rhs){\
lhs = lhs & rhs;\
return lhs;\
}\
inline FLATBUFFERS_CONSTEXPR_CPP11 E operator ^= (E &lhs, E rhs){\
inline FLATBUFFERS_CONSTEXPR_CPP14 E operator ^= (E &lhs, E rhs){\
lhs = lhs ^ rhs;\
return lhs;\
}\

View File

@@ -1207,11 +1207,20 @@ class Builder FLATBUFFERS_FINAL_CLASS {
String(str);
}
size_t AlignedBlob(const void* data, size_t len, BitWidth alignment) {
// The requested alignment must not be smaller than the one required to
// store the length.
return CreateAlignedBlob(data, len, 0, FBT_BLOB,
std::max(alignment, WidthU(len)));
}
size_t AlignedBlob(const std::vector<uint8_t>& v, BitWidth alignment) {
return AlignedBlob(v.data(), v.size(), alignment);
}
size_t Blob(const void* data, size_t len) {
return CreateBlob(data, len, 0, FBT_BLOB);
}
size_t Blob(const std::vector<uint8_t>& v) {
return CreateBlob(v.data(), v.size(), 0, FBT_BLOB);
return Blob(v.data(), v.size());
}
void Blob(const char* key, const void* data, size_t len) {
@@ -1693,11 +1702,16 @@ class Builder FLATBUFFERS_FINAL_CLASS {
size_t CreateBlob(const void* data, size_t len, size_t trailing, Type type) {
auto bit_width = WidthU(len);
auto byte_width = Align(bit_width);
return CreateAlignedBlob(data, len, trailing, type, bit_width);
}
size_t CreateAlignedBlob(const void* data, size_t len, size_t trailing,
Type type, BitWidth alignment) {
auto byte_width = Align(alignment);
Write<uint64_t>(len, byte_width);
auto sloc = buf_.size();
WriteBytes(data, len + trailing);
stack_.push_back(Value(static_cast<uint64_t>(sloc), type, bit_width));
stack_.push_back(Value(static_cast<uint64_t>(sloc), type, alignment));
return sloc;
}
@@ -1962,7 +1976,7 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
bool VerifyKey(const uint8_t* p) {
FLEX_CHECK_VERIFIED(p, PackedType(BIT_WIDTH_8, FBT_KEY));
while (p < buf_ + size_)
if (*p++) return true;
if (!*p++) return true;
return false;
}

View File

@@ -223,7 +223,7 @@ struct Type {
uint16_t fixed_length; // only set if t == BASE_TYPE_ARRAY
};
// Represents a parsed scalar value, it's type, and field offset.
// Represents a parsed scalar value, its type, and field offset.
struct Value {
Value()
: constant("0"),
@@ -395,13 +395,20 @@ struct FieldDef : public Definition {
};
struct StructDef : public Definition {
enum class CycleStatus {
NotChecked,
InProgress,
Checked,
};
StructDef()
: fixed(false),
predecl(true),
sortbysize(true),
has_key(false),
minalign(1),
bytesize(0) {}
bytesize(0),
cycle_status{CycleStatus::NotChecked} {}
void PadLastField(size_t min_align) {
auto padding = PaddingBytes(bytesize, min_align);
@@ -423,6 +430,8 @@ struct StructDef : public Definition {
size_t minalign; // What the whole object needs to be aligned to.
size_t bytesize; // Size if fixed.
CycleStatus cycle_status; // used for determining if we have circular references
flatbuffers::unique_ptr<std::string> original_location;
std::vector<voffset_t> reserved_ids;
};
@@ -734,6 +743,7 @@ struct IDLOptions {
bool python_gen_numpy;
bool ts_omit_entrypoint;
bool ts_undefined_for_optionals;
ProtoIdGapAction proto_id_gap_action;
// Possible options for the more general generator below.
@@ -860,6 +870,7 @@ struct IDLOptions {
python_typing(false),
python_gen_numpy(true),
ts_omit_entrypoint(false),
ts_undefined_for_optionals(false),
proto_id_gap_action(ProtoIdGapAction::WARNING),
mini_reflect(IDLOptions::kNone),
require_explicit_ids(false),
@@ -1099,6 +1110,8 @@ class Parser : public ParserState {
// others includes.
std::vector<IncludedFile> GetIncludedFiles() const;
bool HasCircularStructDependency();
private:
class ParseDepthGuard;

View File

@@ -30,50 +30,52 @@ namespace flatbuffers {
// ------------------------- GETTERS -------------------------
inline bool IsScalar(reflection::BaseType t) {
constexpr bool IsScalar(reflection::BaseType t) {
return t >= reflection::UType && t <= reflection::Double;
}
inline bool IsInteger(reflection::BaseType t) {
constexpr bool IsInteger(reflection::BaseType t) {
return t >= reflection::UType && t <= reflection::ULong;
}
inline bool IsFloat(reflection::BaseType t) {
constexpr bool IsFloat(reflection::BaseType t) {
return t == reflection::Float || t == reflection::Double;
}
inline bool IsLong(reflection::BaseType t) {
constexpr bool IsLong(reflection::BaseType t) {
return t == reflection::Long || t == reflection::ULong;
}
// Size of a basic type, don't use with structs.
inline size_t GetTypeSize(reflection::BaseType base_type) {
// This needs to correspond to the BaseType enum.
static size_t sizes[] = {
0, // None
1, // UType
1, // Bool
1, // Byte
1, // UByte
2, // Short
2, // UShort
4, // Int
4, // UInt
8, // Long
8, // ULong
4, // Float
8, // Double
4, // String
4, // Vector
4, // Obj
4, // Union
0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds
// errors.
8, // Vector64
// This needs to correspond to the BaseType enum.
constexpr size_t kBaseTypeSize[] = {
0, // None
1, // UType
1, // Bool
1, // Byte
1, // UByte
2, // Short
2, // UShort
4, // Int
4, // UInt
8, // Long
8, // ULong
4, // Float
8, // Double
4, // String
4, // Vector
4, // Obj
4, // Union
0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds
// errors.
8, // Vector64
0 // MaxBaseType. This must be kept the last entry in this array.
};
static_assert(sizeof(sizes) / sizeof(size_t) == reflection::MaxBaseType + 1,
"Size of sizes[] array does not match the count of BaseType "
"enum values.");
return sizes[base_type];
0 // MaxBaseType. This must be kept the last entry in this array.
};
static_assert(sizeof(kBaseTypeSize) / sizeof(size_t) ==
reflection::MaxBaseType + 1,
"Size of sizes[] array does not match the count of BaseType "
"enum values.");
// Size of a basic type, don't use with structs.
constexpr size_t GetTypeSize(reflection::BaseType base_type) {
return kBaseTypeSize[base_type];
}
// Same as above, but now correctly returns the size of a struct if
@@ -420,7 +422,7 @@ pointer_inside_vector<T, U> piv(T* ptr, std::vector<U>& vec) {
return pointer_inside_vector<T, U>(ptr, vec);
}
inline const char* UnionTypeFieldSuffix() { return "_type"; }
constexpr const char* UnionTypeFieldSuffix() { return "_type"; }
// Helper to figure out the actual table type a union refers to.
inline const reflection::Object& GetUnionType(

View File

@@ -14,9 +14,12 @@
* limitations under the License.
*/
@file:Suppress("NOTHING_TO_INLINE")
@file:OptIn(ExperimentalNativeApi::class)
package com.google.flatbuffers.kotlin
import kotlin.experimental.ExperimentalNativeApi
/**
* This implementation assumes that of native macOSX64 the byte order of the implementation is
* Little Endian.

View File

@@ -296,25 +296,62 @@ function mt:Slot(slotnum)
self.currentVTable[slotnum + 1] = self:Offset()
end
local function finish(self, rootTable, sizePrefix)
local function finish(self, rootTable, sizePrefix, fileIdentifier)
UOffsetT:EnforceNumber(rootTable)
self:Prep(self.minalign, sizePrefix and 8 or 4)
self:PrependUOffsetTRelative(rootTable)
local hasFid = fileIdentifier ~= nil
if hasFid then
assert(#fileIdentifier == 4, "File identifier must be exactly 4 bytes")
end
local fid_byte_count = (hasFid and 4 or 0)
-- alignment:
-- root offset (4)
-- optional file id (4)
-- optional size prefix (4)
self:Prep(
self.minalign,
(sizePrefix and 4 or 0) +
4 +
fid_byte_count
)
-- root offset (points past file identifier if present)
self:PrependUOffsetTRelative(rootTable + fid_byte_count)
-- file identifier
if hasFid then
for i = 4, 1, -1 do
self:PrependByte(string.byte(fileIdentifier, i))
end
end
-- size prefix
if sizePrefix then
local size = self.bytes.size - self.head
Int32:EnforceNumber(size)
self:PrependInt32(size)
end
self.finished = true
return self.head
end
function mt:Finish(rootTable)
return finish(self, rootTable, false)
return finish(self, rootTable, false, nil)
end
function mt:FinishSizePrefixed(rootTable)
return finish(self, rootTable, true)
return finish(self, rootTable, true, nil)
end
function mt:FinishWithIdentifier(rootTable, fileIdentifier)
return finish(self, rootTable, false, fileIdentifier)
end
function mt:FinishSizePrefixedWithIdentifier(rootTable, fileIdentifier)
return finish(self, rootTable, true, fileIdentifier)
end
function mt:Prepend(flags, off)

View File

@@ -438,8 +438,7 @@ namespace Google.FlatBuffers
if (off > Offset)
throw new ArgumentException();
if (off != 0)
off = Offset - off + sizeof(int);
off = Offset - off + sizeof(int);
PutInt(off);
}

View File

@@ -65,11 +65,7 @@ namespace Google.FlatBuffers
// Create a .NET String from UTF-8 data stored inside the flatbuffer.
public string __string(int offset)
{
int stringOffset = bb.GetInt(offset);
if (stringOffset == 0)
return null;
offset += stringOffset;
offset += bb.GetInt(offset);
var len = bb.GetInt(offset);
var startPos = offset + sizeof(int);
return bb.GetStringUTF8(startPos, len);
@@ -150,7 +146,7 @@ namespace Google.FlatBuffers
var pos = this.__vector(o);
var len = this.__vector_len(o);
return bb.ToArray<T>(pos, len);
return bb.ToArray<T>(pos, len * ByteBuffer.SizeOf<T>());
}
// Initialize any Table-derived type to point to the union at the given offset.

44
pnpm-lock.yaml generated
View File

@@ -33,6 +33,12 @@ importers:
specifier: ^8.34.1
version: 8.34.1(eslint@9.29.0)(typescript@5.8.3)
tests/ts:
dependencies:
flatbuffers:
specifier: workspace:*
version: link:../..
packages:
'@esbuild/aix-ppc64@0.25.5':
@@ -343,8 +349,8 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
ajv@6.14.0:
resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
@@ -483,8 +489,8 @@ packages:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
flatted@3.3.1:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
flatted@3.4.2:
resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
@@ -571,11 +577,11 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@3.1.5:
resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
minimatch@9.0.9:
resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==}
engines: {node: '>=16 || 14 >=14.17'}
ms@2.1.3:
@@ -793,7 +799,7 @@ snapshots:
dependencies:
'@eslint/object-schema': 2.1.6
debug: 4.3.7
minimatch: 3.1.2
minimatch: 3.1.5
transitivePeerDependencies:
- supports-color
@@ -809,14 +815,14 @@ snapshots:
'@eslint/eslintrc@3.3.1':
dependencies:
ajv: 6.12.6
ajv: 6.14.0
debug: 4.3.7
espree: 10.4.0
globals: 14.0.0
ignore: 5.3.2
import-fresh: 3.3.0
js-yaml: 4.1.1
minimatch: 3.1.2
minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
@@ -932,7 +938,7 @@ snapshots:
debug: 4.3.7
fast-glob: 3.3.2
is-glob: 4.0.3
minimatch: 9.0.5
minimatch: 9.0.9
semver: 7.6.3
ts-api-utils: 2.1.0(typescript@5.8.3)
typescript: 5.8.3
@@ -961,7 +967,7 @@ snapshots:
acorn@8.15.0: {}
ajv@6.12.6:
ajv@6.14.0:
dependencies:
fast-deep-equal: 3.1.3
fast-json-stable-stringify: 2.1.0
@@ -1070,7 +1076,7 @@ snapshots:
'@humanwhocodes/retry': 0.4.3
'@types/estree': 1.0.8
'@types/json-schema': 7.0.15
ajv: 6.12.6
ajv: 6.14.0
chalk: 4.1.2
cross-spawn: 7.0.6
debug: 4.3.7
@@ -1089,7 +1095,7 @@ snapshots:
is-glob: 4.0.3
json-stable-stringify-without-jsonify: 1.0.1
lodash.merge: 4.6.2
minimatch: 3.1.2
minimatch: 3.1.5
natural-compare: 1.4.0
optionator: 0.9.4
transitivePeerDependencies:
@@ -1146,10 +1152,10 @@ snapshots:
flat-cache@4.0.1:
dependencies:
flatted: 3.3.1
flatted: 3.4.2
keyv: 4.5.4
flatted@3.3.1: {}
flatted@3.4.2: {}
glob-parent@5.1.2:
dependencies:
@@ -1218,11 +1224,11 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.1
minimatch@3.1.2:
minimatch@3.1.5:
dependencies:
brace-expansion: 1.1.12
minimatch@9.0.5:
minimatch@9.0.9:
dependencies:
brace-expansion: 2.0.2

2
pnpm-workspace.yaml Normal file
View File

@@ -0,0 +1,2 @@
packages:
- tests/ts

View File

@@ -422,7 +422,6 @@ class Builder(object):
off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
self.PlaceUOffsetT(off2)
## @cond FLATBUFFERS_INTERNAL
def StartVector(self, elemSize, numElems, alignment):
"""StartVector initializes bookkeeping for writing a new vector.
@@ -438,8 +437,6 @@ class Builder(object):
self.Prep(alignment, elemSize * numElems) # In case alignment > int.
return self.Offset()
## @endcond
def EndVector(self, numElems=None):
"""EndVector writes data necessary to finish vector construction."""
@@ -556,6 +553,21 @@ class Builder(object):
self.vectorNumElems = x.size
return self.EndVector()
def CreateVectorOfTables(self, offsets):
"""CreateVectorOfTables writes a vector of offsets such as tables or strings.
Args:
offsets: Iterable of offsets returned from previous builder operations.
Each element should be an integer compatible with UOffsetT.
"""
offsets = list(offsets)
self.StartVector(N.UOffsetTFlags.bytewidth, len(offsets),
N.UOffsetTFlags.bytewidth)
for off in reversed(offsets):
self.PrependUOffsetTRelative(off)
return self.EndVector()
## @cond FLATBUFFERS_INTERNAL
def assertNested(self):
"""Check that we are in the process of building an object."""

View File

@@ -155,6 +155,12 @@ def EnumStartValuesVector(builder, numElems):
def StartValuesVector(builder, numElems):
return EnumStartValuesVector(builder, numElems)
def EnumCreateValuesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateValuesVector(builder, data):
return EnumCreateValuesVector(builder, data)
def EnumAddIsUnion(builder, isUnion):
builder.PrependBoolSlot(2, isUnion, 0)
@@ -179,6 +185,12 @@ def EnumStartAttributesVector(builder, numElems):
def StartAttributesVector(builder, numElems):
return EnumStartAttributesVector(builder, numElems)
def EnumCreateAttributesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateAttributesVector(builder, data):
return EnumCreateAttributesVector(builder, data)
def EnumAddDocumentation(builder, documentation):
builder.PrependUOffsetTRelativeSlot(5, flatbuffers.number_types.UOffsetTFlags.py_type(documentation), 0)
@@ -191,6 +203,12 @@ def EnumStartDocumentationVector(builder, numElems):
def StartDocumentationVector(builder, numElems):
return EnumStartDocumentationVector(builder, numElems)
def EnumCreateDocumentationVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateDocumentationVector(builder, data):
return EnumCreateDocumentationVector(builder, data)
def EnumAddDeclarationFile(builder, declarationFile):
builder.PrependUOffsetTRelativeSlot(6, flatbuffers.number_types.UOffsetTFlags.py_type(declarationFile), 0)

View File

@@ -134,6 +134,12 @@ def EnumValStartDocumentationVector(builder, numElems):
def StartDocumentationVector(builder, numElems):
return EnumValStartDocumentationVector(builder, numElems)
def EnumValCreateDocumentationVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateDocumentationVector(builder, data):
return EnumValCreateDocumentationVector(builder, data)
def EnumValAddAttributes(builder, attributes):
builder.PrependUOffsetTRelativeSlot(5, flatbuffers.number_types.UOffsetTFlags.py_type(attributes), 0)
@@ -146,6 +152,12 @@ def EnumValStartAttributesVector(builder, numElems):
def StartAttributesVector(builder, numElems):
return EnumValStartAttributesVector(builder, numElems)
def EnumValCreateAttributesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateAttributesVector(builder, data):
return EnumValCreateAttributesVector(builder, data)
def EnumValEnd(builder):
return builder.EndObject()

View File

@@ -235,6 +235,12 @@ def FieldStartAttributesVector(builder, numElems):
def StartAttributesVector(builder, numElems):
return FieldStartAttributesVector(builder, numElems)
def FieldCreateAttributesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateAttributesVector(builder, data):
return FieldCreateAttributesVector(builder, data)
def FieldAddDocumentation(builder, documentation):
builder.PrependUOffsetTRelativeSlot(10, flatbuffers.number_types.UOffsetTFlags.py_type(documentation), 0)
@@ -247,6 +253,12 @@ def FieldStartDocumentationVector(builder, numElems):
def StartDocumentationVector(builder, numElems):
return FieldStartDocumentationVector(builder, numElems)
def FieldCreateDocumentationVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateDocumentationVector(builder, data):
return FieldCreateDocumentationVector(builder, data)
def FieldAddOptional(builder, optional):
builder.PrependBoolSlot(11, optional, 0)

View File

@@ -158,6 +158,12 @@ def ObjectStartFieldsVector(builder, numElems):
def StartFieldsVector(builder, numElems):
return ObjectStartFieldsVector(builder, numElems)
def ObjectCreateFieldsVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateFieldsVector(builder, data):
return ObjectCreateFieldsVector(builder, data)
def ObjectAddIsStruct(builder, isStruct):
builder.PrependBoolSlot(2, isStruct, 0)
@@ -188,6 +194,12 @@ def ObjectStartAttributesVector(builder, numElems):
def StartAttributesVector(builder, numElems):
return ObjectStartAttributesVector(builder, numElems)
def ObjectCreateAttributesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateAttributesVector(builder, data):
return ObjectCreateAttributesVector(builder, data)
def ObjectAddDocumentation(builder, documentation):
builder.PrependUOffsetTRelativeSlot(6, flatbuffers.number_types.UOffsetTFlags.py_type(documentation), 0)
@@ -200,6 +212,12 @@ def ObjectStartDocumentationVector(builder, numElems):
def StartDocumentationVector(builder, numElems):
return ObjectStartDocumentationVector(builder, numElems)
def ObjectCreateDocumentationVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateDocumentationVector(builder, data):
return ObjectCreateDocumentationVector(builder, data)
def ObjectAddDeclarationFile(builder, declarationFile):
builder.PrependUOffsetTRelativeSlot(7, flatbuffers.number_types.UOffsetTFlags.py_type(declarationFile), 0)

View File

@@ -138,6 +138,12 @@ def RPCCallStartAttributesVector(builder, numElems):
def StartAttributesVector(builder, numElems):
return RPCCallStartAttributesVector(builder, numElems)
def RPCCallCreateAttributesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateAttributesVector(builder, data):
return RPCCallCreateAttributesVector(builder, data)
def RPCCallAddDocumentation(builder, documentation):
builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(documentation), 0)
@@ -150,6 +156,12 @@ def RPCCallStartDocumentationVector(builder, numElems):
def StartDocumentationVector(builder, numElems):
return RPCCallStartDocumentationVector(builder, numElems)
def RPCCallCreateDocumentationVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateDocumentationVector(builder, data):
return RPCCallCreateDocumentationVector(builder, data)
def RPCCallEnd(builder):
return builder.EndObject()

View File

@@ -180,6 +180,12 @@ def SchemaStartObjectsVector(builder, numElems):
def StartObjectsVector(builder, numElems):
return SchemaStartObjectsVector(builder, numElems)
def SchemaCreateObjectsVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateObjectsVector(builder, data):
return SchemaCreateObjectsVector(builder, data)
def SchemaAddEnums(builder, enums):
builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(enums), 0)
@@ -192,6 +198,12 @@ def SchemaStartEnumsVector(builder, numElems):
def StartEnumsVector(builder, numElems):
return SchemaStartEnumsVector(builder, numElems)
def SchemaCreateEnumsVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateEnumsVector(builder, data):
return SchemaCreateEnumsVector(builder, data)
def SchemaAddFileIdent(builder, fileIdent):
builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(fileIdent), 0)
@@ -222,6 +234,12 @@ def SchemaStartServicesVector(builder, numElems):
def StartServicesVector(builder, numElems):
return SchemaStartServicesVector(builder, numElems)
def SchemaCreateServicesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateServicesVector(builder, data):
return SchemaCreateServicesVector(builder, data)
def SchemaAddAdvancedFeatures(builder, advancedFeatures):
builder.PrependUint64Slot(6, advancedFeatures, 0)
@@ -240,6 +258,12 @@ def SchemaStartFbsFilesVector(builder, numElems):
def StartFbsFilesVector(builder, numElems):
return SchemaStartFbsFilesVector(builder, numElems)
def SchemaCreateFbsFilesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateFbsFilesVector(builder, data):
return SchemaCreateFbsFilesVector(builder, data)
def SchemaEnd(builder):
return builder.EndObject()

View File

@@ -84,6 +84,12 @@ def SchemaFileStartIncludedFilenamesVector(builder, numElems):
def StartIncludedFilenamesVector(builder, numElems):
return SchemaFileStartIncludedFilenamesVector(builder, numElems)
def SchemaFileCreateIncludedFilenamesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateIncludedFilenamesVector(builder, data):
return SchemaFileCreateIncludedFilenamesVector(builder, data)
def SchemaFileEnd(builder):
return builder.EndObject()

View File

@@ -137,6 +137,12 @@ def ServiceStartCallsVector(builder, numElems):
def StartCallsVector(builder, numElems):
return ServiceStartCallsVector(builder, numElems)
def ServiceCreateCallsVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateCallsVector(builder, data):
return ServiceCreateCallsVector(builder, data)
def ServiceAddAttributes(builder, attributes):
builder.PrependUOffsetTRelativeSlot(2, flatbuffers.number_types.UOffsetTFlags.py_type(attributes), 0)
@@ -149,6 +155,12 @@ def ServiceStartAttributesVector(builder, numElems):
def StartAttributesVector(builder, numElems):
return ServiceStartAttributesVector(builder, numElems)
def ServiceCreateAttributesVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateAttributesVector(builder, data):
return ServiceCreateAttributesVector(builder, data)
def ServiceAddDocumentation(builder, documentation):
builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(documentation), 0)
@@ -161,6 +173,12 @@ def ServiceStartDocumentationVector(builder, numElems):
def StartDocumentationVector(builder, numElems):
return ServiceStartDocumentationVector(builder, numElems)
def ServiceCreateDocumentationVector(builder, data):
return builder.CreateVectorOfTables(data)
def CreateDocumentationVector(builder, data):
return ServiceCreateDocumentationVector(builder, data)
def ServiceAddDeclarationFile(builder, declarationFile):
builder.PrependUOffsetTRelativeSlot(4, flatbuffers.number_types.UOffsetTFlags.py_type(declarationFile), 0)

View File

@@ -1,6 +1,2 @@
[bdist_wheel]
universal=1
[metadata]
license_files =
../LICENSE
license_files = LICENSE

View File

@@ -12,35 +12,54 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from pathlib import Path
import shutil
from setuptools import setup
setup(
name='flatbuffers',
version='25.12.19',
license='Apache 2.0',
author='Derek Bailey',
author_email='derekbailey@google.com',
url='https://google.github.io/flatbuffers/',
long_description=(
'Python runtime library for use with the '
'`Flatbuffers <https://google.github.io/flatbuffers/>`_ '
'serialization format.'
),
packages=['flatbuffers'],
include_package_data=True,
requires=[],
description='The FlatBuffers serialization format for Python',
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries :: Python Modules',
],
project_urls={
'Documentation': 'https://google.github.io/flatbuffers/',
'Source': 'https://github.com/google/flatbuffers',
},
)
_THIS_DIR = Path(__file__).resolve().parent
_ROOT_LICENSE = _THIS_DIR.parent / 'LICENSE'
_LOCAL_LICENSE = _THIS_DIR / 'LICENSE'
def _stage_license_file():
if _LOCAL_LICENSE.exists() or not _ROOT_LICENSE.exists():
return False
shutil.copyfile(_ROOT_LICENSE, _LOCAL_LICENSE)
return True
_remove_staged_license = _stage_license_file()
try:
setup(
name='flatbuffers',
version='25.12.19',
license='Apache 2.0',
author='Derek Bailey',
author_email='derekbailey@google.com',
url='https://google.github.io/flatbuffers/',
long_description=(
'Python runtime library for use with the '
'`Flatbuffers <https://google.github.io/flatbuffers/>`_ '
'serialization format.'
),
packages=['flatbuffers'],
include_package_data=True,
requires=[],
description='The FlatBuffers serialization format for Python',
classifiers=[
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries :: Python Modules',
],
project_urls={
'Documentation': 'https://google.github.io/flatbuffers/',
'Source': 'https://github.com/google/flatbuffers',
},
)
finally:
if _remove_staged_license and _LOCAL_LICENSE.exists():
_LOCAL_LICENSE.unlink()

View File

@@ -24,6 +24,9 @@ use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Deref, DerefMut, Index, IndexMut, Sub, SubAssign};
use core::ptr::write_bytes;
#[cfg(feature = "std")]
use std::collections::HashMap;
use crate::endian_scalar::emplace_scalar;
use crate::primitives::*;
use crate::push::{Push, PushAlignment};
@@ -139,6 +142,9 @@ pub struct FlatBufferBuilder<'fbb, A: Allocator = DefaultAllocator> {
min_align: usize,
force_defaults: bool,
#[cfg(feature = "std")]
strings_pool: HashMap<String, WIPOffset<&'fbb str>>,
#[cfg(not(feature = "std"))]
strings_pool: Vec<WIPOffset<&'fbb str>>,
_phantom: PhantomData<&'fbb ()>,
@@ -160,6 +166,60 @@ impl<'fbb> FlatBufferBuilder<'fbb, DefaultAllocator> {
pub fn with_capacity(size: usize) -> Self {
Self::from_vec(vec![0; size])
}
/// Create a FlatBufferBuilder that is ready for writing, with a
/// ready-to-use capacity of the provided size and preallocated internal vecs.
///
/// The maximum valid value for `size` is `FLATBUFFERS_MAX_BUFFER_SIZE`.
///
/// # Arguments
///
/// * `size` - The initial capacity of the backing buffer in bytes.
/// * `field_locs_capacity` - Preallocated capacity for the field locations vec.
/// * `written_vtable_revpos_capacity` - Preallocated capacity for the written vtable reverse positions vec.
/// * `strings_pool_capacity` - Preallocated capacity for the shared strings pool vec.
pub fn with_internal_capacity(
size: usize,
field_locs_capacity: usize,
written_vtable_revpos_capacity: usize,
strings_pool_capacity: usize,
) -> Self {
Self::from_vec_with_internal_capacity(
vec![0; size],
field_locs_capacity,
written_vtable_revpos_capacity,
strings_pool_capacity,
)
}
/// Create a FlatBufferBuilder that is ready for writing, reusing
/// an existing vector and preallocated internal vecs.
///
/// # Arguments
///
/// * `buffer` - An existing `Vec<u8>` to reuse as the backing buffer.
/// * `field_locs_capacity` - Preallocated capacity for the field locations vec.
/// * `written_vtable_revpos_capacity` - Preallocated capacity for the written vtable reverse positions vec.
/// * `strings_pool_capacity` - Preallocated capacity for the shared strings pool vec.
pub fn from_vec_with_internal_capacity(
buffer: Vec<u8>,
field_locs_capacity: usize,
written_vtable_revpos_capacity: usize,
strings_pool_capacity: usize,
) -> Self {
// we need to check the size here because we create the backing buffer
// directly, bypassing the typical way of using grow_allocator:
assert!(
buffer.len() <= FLATBUFFERS_MAX_BUFFER_SIZE,
"cannot initialize buffer bigger than 2 gigabytes"
);
let allocator = DefaultAllocator::from_vec(buffer);
Self::new_in_with_internal_capacity(
allocator,
field_locs_capacity,
written_vtable_revpos_capacity,
strings_pool_capacity,
)
}
/// Create a FlatBufferBuilder that is ready for writing, reusing
/// an existing vector.
pub fn from_vec(buffer: Vec<u8>) -> Self {
@@ -197,12 +257,52 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
min_align: 0,
force_defaults: false,
#[cfg(feature = "std")]
strings_pool: HashMap::new(),
#[cfg(not(feature = "std"))]
strings_pool: Vec::new(),
_phantom: PhantomData,
}
}
/// Create a [`FlatBufferBuilder`] that is ready for writing with a custom [`Allocator`]
/// and preallocated internal vecs.
///
/// # Arguments
///
/// * `allocator` - A custom [`Allocator`] to use as the backing buffer.
/// * `field_locs_capacity` - Preallocated capacity for the field locations vec.
/// * `written_vtable_revpos_capacity` - Preallocated capacity for the written vtable reverse positions vec.
/// * `strings_pool_capacity` - Preallocated capacity for the shared strings pool vec.
pub fn new_in_with_internal_capacity(
allocator: A,
field_locs_capacity: usize,
written_vtable_revpos_capacity: usize,
strings_pool_capacity: usize,
) -> Self {
let head = ReverseIndex::end();
FlatBufferBuilder {
allocator,
head,
field_locs: Vec::with_capacity(field_locs_capacity),
written_vtable_revpos: Vec::with_capacity(written_vtable_revpos_capacity),
nested: false,
finished: false,
min_align: 0,
force_defaults: false,
#[cfg(feature = "std")]
strings_pool: HashMap::with_capacity(strings_pool_capacity),
#[cfg(not(feature = "std"))]
strings_pool: Vec::with_capacity(strings_pool_capacity),
_phantom: PhantomData,
}
}
/// Destroy the [`FlatBufferBuilder`], returning its [`Allocator`] and the index
/// into it that represents the start of valid data.
pub fn collapse_in(self) -> (A, usize) {
@@ -223,7 +323,9 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
/// new object.
pub fn reset(&mut self) {
// memset only the part of the buffer that could be dirty:
self.allocator[self.head.range_to_end()].iter_mut().for_each(|x| *x = 0);
self.allocator[self.head.range_to_end()]
.iter_mut()
.for_each(|x| *x = 0);
self.head = ReverseIndex::end();
self.written_vtable_revpos.clear();
@@ -235,22 +337,43 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
self.strings_pool.clear();
}
/// Push a Push'able value onto the front of the in-progress data.
///
/// This function uses traits to provide a unified API for writing
/// scalars, tables, vectors, and WIPOffsets.
/// Fallible version of [`push`](Self::push).
#[inline]
pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> {
pub fn try_push<P: Push>(&mut self, x: P) -> Result<WIPOffset<P::Output>, A::Error> {
let sz = P::size();
self.align(sz, P::alignment());
self.make_space(sz);
self.align(sz, P::alignment())?;
self.make_space(sz)?;
{
let (dst, rest) = self.allocator[self.head.range_to_end()].split_at_mut(sz);
// Safety:
// Called make_space above
unsafe { x.push(dst, rest.len()) };
}
WIPOffset::new(self.used_space() as UOffsetT)
Ok(WIPOffset::new(self.used_space() as UOffsetT))
}
/// Push a Push'able value onto the front of the in-progress data.
///
/// This function uses traits to provide a unified API for writing
/// scalars, tables, vectors, and WIPOffsets.
#[inline]
pub fn push<P: Push>(&mut self, x: P) -> WIPOffset<P::Output> {
self.try_push(x).expect("Flatbuffer allocation failure")
}
/// Fallible version of [`push_slot`](Self::push_slot).
#[inline]
pub fn try_push_slot<X: Push + PartialEq>(
&mut self,
slotoff: VOffsetT,
x: X,
default: X,
) -> Result<(), A::Error> {
self.assert_nested("push_slot");
if x != default || self.force_defaults {
self.try_push_slot_always(slotoff, x)?;
}
Ok(())
}
/// Push a Push'able value onto the front of the in-progress data, and
@@ -258,19 +381,29 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
/// the default, then this is a no-op.
#[inline]
pub fn push_slot<X: Push + PartialEq>(&mut self, slotoff: VOffsetT, x: X, default: X) {
self.assert_nested("push_slot");
if x != default || self.force_defaults {
self.push_slot_always(slotoff, x);
}
self.try_push_slot(slotoff, x, default)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`push_slot_always`](Self::push_slot_always).
#[inline]
pub fn try_push_slot_always<X: Push>(
&mut self,
slotoff: VOffsetT,
x: X,
) -> Result<(), A::Error> {
self.assert_nested("push_slot_always");
let off = self.try_push(x)?;
self.track_field(slotoff, off.value());
Ok(())
}
/// Push a Push'able value onto the front of the in-progress data, and
/// store a reference to it in the in-progress vtable.
#[inline]
pub fn push_slot_always<X: Push>(&mut self, slotoff: VOffsetT, x: X) {
self.assert_nested("push_slot_always");
let off = self.push(x);
self.track_field(slotoff, off.value());
self.try_push_slot_always(slotoff, x)
.expect("Flatbuffer allocation failure")
}
/// Retrieve the number of vtables that have been serialized into the
@@ -295,6 +428,22 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
WIPOffset::new(self.used_space() as UOffsetT)
}
/// Fallible version of [`end_table`](Self::end_table).
#[inline]
pub fn try_end_table(
&mut self,
off: WIPOffset<TableUnfinishedWIPOffset>,
) -> Result<WIPOffset<TableFinishedWIPOffset>, A::Error> {
self.assert_nested("end_table");
let o = self.write_vtable(off)?;
self.nested = false;
self.field_locs.clear();
Ok(WIPOffset::new(o.value()))
}
/// End a Table write.
///
/// Asserts that the builder is in a nested state.
@@ -303,14 +452,19 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
&mut self,
off: WIPOffset<TableUnfinishedWIPOffset>,
) -> WIPOffset<TableFinishedWIPOffset> {
self.assert_nested("end_table");
self.try_end_table(off)
.expect("Flatbuffer allocation failure")
}
let o = self.write_vtable(off);
self.nested = false;
self.field_locs.clear();
WIPOffset::new(o.value())
/// Fallible version of [`start_vector`](Self::start_vector).
#[inline]
pub fn try_start_vector<T: Push>(&mut self, num_items: usize) -> Result<(), A::Error> {
self.assert_not_nested(
"start_vector can not be called when a table or vector is under construction",
);
self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET))?;
self.nested = true;
Ok(())
}
/// Start a Vector write.
@@ -322,11 +476,20 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
/// function will want to use `push` to add values.
#[inline]
pub fn start_vector<T: Push>(&mut self, num_items: usize) {
self.assert_not_nested(
"start_vector can not be called when a table or vector is under construction",
);
self.nested = true;
self.align(num_items * T::size(), T::alignment().max_of(SIZE_UOFFSET));
self.try_start_vector::<T>(num_items)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`end_vector`](Self::end_vector).
#[inline]
pub fn try_end_vector<T: Push>(
&mut self,
num_elems: usize,
) -> Result<WIPOffset<Vector<'fbb, T>>, A::Error> {
self.assert_nested("end_vector");
let o = self.try_push::<UOffsetT>(num_elems as UOffsetT)?;
self.nested = false;
Ok(WIPOffset::new(o.value()))
}
/// End a Vector write.
@@ -337,14 +500,54 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
/// Asserts that the builder is in a nested state.
#[inline]
pub fn end_vector<T: Push>(&mut self, num_elems: usize) -> WIPOffset<Vector<'fbb, T>> {
self.assert_nested("end_vector");
self.nested = false;
let o = self.push::<UOffsetT>(num_elems as UOffsetT);
WIPOffset::new(o.value())
self.try_end_vector::<T>(num_elems)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`create_shared_string`](Self::create_shared_string).
///
/// Uses a HashMap to track previously written strings, providing O(1)
/// amortized lookup and insertion.
#[cfg(feature = "std")]
#[inline]
pub fn try_create_shared_string<'a: 'b, 'b>(
&'a mut self,
s: &'b str,
) -> Result<WIPOffset<&'fbb str>, A::Error> {
self.assert_not_nested(
"create_shared_string can not be called when a table or vector is under construction",
);
if let Some(&offset) = self.strings_pool.get(s) {
return Ok(offset);
}
let address = WIPOffset::new(self.try_create_byte_string(s.as_bytes())?.value());
self.strings_pool.insert(s.to_owned(), address);
Ok(address)
}
/// Create a utf8 string, and de-duplicate if already created.
///
/// Uses a HashMap to track previously written strings, providing O(1)
/// amortized lookup and insertion.
#[cfg(feature = "std")]
#[inline]
pub fn create_shared_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
self.try_create_shared_string(s)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`create_shared_string`](Self::create_shared_string).
///
/// Uses a sorted Vec with binary search to track previously written
/// strings when in `no_std` mode.
#[cfg(not(feature = "std"))]
#[inline]
pub fn try_create_shared_string<'a: 'b, 'b>(
&'a mut self,
s: &'b str,
) -> Result<WIPOffset<&'fbb str>, A::Error> {
self.assert_not_nested(
"create_shared_string can not be called when a table or vector is under construction",
);
@@ -355,68 +558,95 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
let found = self.strings_pool.binary_search_by(|offset| {
let ptr = offset.value() as usize;
// Gets The pointer to the size of the string
let str_memory = &buf[buf.len() - ptr..];
// Gets the size of the written string from buffer
let size =
u32::from_le_bytes([str_memory[0], str_memory[1], str_memory[2], str_memory[3]])
as usize;
// Size of the string size
let string_size: usize = 4;
// Fetches actual string bytes from index of string after string size
// to the size of string plus string size
let iter = str_memory[string_size..size + string_size].iter();
// Compares bytes of fetched string and current writable string
iter.cloned().cmp(s.bytes())
let size = u32::from_le_bytes([
str_memory[0],
str_memory[1],
str_memory[2],
str_memory[3],
]) as usize;
let stored = &str_memory[4..4 + size];
stored.cmp(s.as_bytes())
});
match found {
Ok(index) => self.strings_pool[index],
Ok(index) => Ok(self.strings_pool[index]),
Err(index) => {
let address = WIPOffset::new(self.create_byte_string(s.as_bytes()).value());
let address =
WIPOffset::new(self.try_create_byte_string(s.as_bytes())?.value());
self.strings_pool.insert(index, address);
address
Ok(address)
}
}
}
/// Create a utf8 string, and de-duplicate if already created.
///
/// Uses a sorted Vec with binary search to track previously written
/// strings when in `no_std` mode.
#[cfg(not(feature = "std"))]
#[inline]
pub fn create_shared_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
self.try_create_shared_string(s)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`create_string`](Self::create_string).
#[inline]
pub fn try_create_string<'a: 'b, 'b>(
&'a mut self,
s: &'b str,
) -> Result<WIPOffset<&'fbb str>, A::Error> {
self.assert_not_nested(
"create_string can not be called when a table or vector is under construction",
);
Ok(WIPOffset::new(
self.try_create_byte_string(s.as_bytes())?.value(),
))
}
/// Create a utf8 string.
///
/// The wire format represents this as a zero-terminated byte vector.
#[inline]
pub fn create_string<'a: 'b, 'b>(&'a mut self, s: &'b str) -> WIPOffset<&'fbb str> {
self.try_create_string(s)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`create_byte_string`](Self::create_byte_string).
#[inline]
pub fn try_create_byte_string(
&mut self,
data: &[u8],
) -> Result<WIPOffset<&'fbb [u8]>, A::Error> {
self.assert_not_nested(
"create_string can not be called when a table or vector is under construction",
"create_byte_string can not be called when a table or vector is under construction",
);
WIPOffset::new(self.create_byte_string(s.as_bytes()).value())
self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET))?;
self.try_push(0u8)?;
self.push_bytes_unprefixed(data)?;
self.try_push(data.len() as UOffsetT)?;
Ok(WIPOffset::new(self.used_space() as UOffsetT))
}
/// Create a zero-terminated byte vector.
#[inline]
pub fn create_byte_string(&mut self, data: &[u8]) -> WIPOffset<&'fbb [u8]> {
self.assert_not_nested(
"create_byte_string can not be called when a table or vector is under construction",
);
self.align(data.len() + 1, PushAlignment::new(SIZE_UOFFSET));
self.push(0u8);
self.push_bytes_unprefixed(data);
self.push(data.len() as UOffsetT);
WIPOffset::new(self.used_space() as UOffsetT)
self.try_create_byte_string(data)
.expect("Flatbuffer allocation failure")
}
/// Create a vector of Push-able objects.
///
/// Speed-sensitive users may wish to reduce memory usage by creating the
/// vector manually: use `start_vector`, `push`, and `end_vector`.
/// Fallible version of [`create_vector`](Self::create_vector).
#[inline]
pub fn create_vector<'a: 'b, 'b, T: Push + 'b>(
pub fn try_create_vector<'a: 'b, 'b, T: Push + 'b>(
&'a mut self,
items: &'b [T],
) -> WIPOffset<Vector<'fbb, T::Output>> {
) -> Result<WIPOffset<Vector<'fbb, T::Output>>, A::Error> {
let elem_size = T::size();
let slice_size = items.len() * elem_size;
self.align(slice_size, T::alignment().max_of(SIZE_UOFFSET));
self.ensure_capacity(slice_size + UOffsetT::size());
self.align(slice_size, T::alignment().max_of(SIZE_UOFFSET))?;
self.ensure_capacity(slice_size + UOffsetT::size())?;
self.head -= slice_size;
let mut written_len = self.head.distance_to_end();
@@ -430,7 +660,38 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
unsafe { item.push(out, written_len) };
}
WIPOffset::new(self.push::<UOffsetT>(items.len() as UOffsetT).value())
Ok(WIPOffset::new(
self.try_push::<UOffsetT>(items.len() as UOffsetT)?.value(),
))
}
/// Create a vector of Push-able objects.
///
/// Speed-sensitive users may wish to reduce memory usage by creating the
/// vector manually: use `start_vector`, `push`, and `end_vector`.
#[inline]
pub fn create_vector<'a: 'b, 'b, T: Push + 'b>(
&'a mut self,
items: &'b [T],
) -> WIPOffset<Vector<'fbb, T::Output>> {
self.try_create_vector(items)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`create_vector_from_iter`](Self::create_vector_from_iter).
#[inline]
pub fn try_create_vector_from_iter<T: Push>(
&mut self,
items: impl ExactSizeIterator<Item = T> + DoubleEndedIterator,
) -> Result<WIPOffset<Vector<'fbb, T::Output>>, A::Error> {
let elem_size = T::size();
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET))?;
let mut actual = 0;
for item in items.rev() {
self.try_push(item)?;
actual += 1;
}
Ok(WIPOffset::new(self.try_push::<UOffsetT>(actual)?.value()))
}
/// Create a vector of Push-able objects.
@@ -442,14 +703,8 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
&mut self,
items: impl ExactSizeIterator<Item = T> + DoubleEndedIterator,
) -> WIPOffset<Vector<'fbb, T::Output>> {
let elem_size = T::size();
self.align(items.len() * elem_size, T::alignment().max_of(SIZE_UOFFSET));
let mut actual = 0;
for item in items.rev() {
self.push(item);
actual += 1;
}
WIPOffset::new(self.push::<UOffsetT>(actual).value())
self.try_create_vector_from_iter(items)
.expect("Flatbuffer allocation failure")
}
/// Set whether default values are stored.
@@ -512,13 +767,34 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
assert!(o != 0, "missing required field {}", assert_msg_name);
}
/// Fallible version of [`finish_size_prefixed`](Self::finish_size_prefixed).
#[inline]
pub fn try_finish_size_prefixed<T>(
&mut self,
root: WIPOffset<T>,
file_identifier: Option<&str>,
) -> Result<(), A::Error> {
self.finish_with_opts(root, file_identifier, true)
}
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
/// identifier on to it, pushing a size prefix on to it, and marking the
/// internal state of the FlatBufferBuilder as `finished`. Afterwards,
/// users can call `finished_data` to get the resulting data.
#[inline]
pub fn finish_size_prefixed<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
self.finish_with_opts(root, file_identifier, true);
self.try_finish_size_prefixed(root, file_identifier)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`finish`](Self::finish).
#[inline]
pub fn try_finish<T>(
&mut self,
root: WIPOffset<T>,
file_identifier: Option<&str>,
) -> Result<(), A::Error> {
self.finish_with_opts(root, file_identifier, false)
}
/// Finalize the FlatBuffer by: aligning it, pushing an optional file
@@ -527,7 +803,14 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
/// `finished_data` to get the resulting data.
#[inline]
pub fn finish<T>(&mut self, root: WIPOffset<T>, file_identifier: Option<&str>) {
self.finish_with_opts(root, file_identifier, false);
self.try_finish(root, file_identifier)
.expect("Flatbuffer allocation failure")
}
/// Fallible version of [`finish_minimal`](Self::finish_minimal).
#[inline]
pub fn try_finish_minimal<T>(&mut self, root: WIPOffset<T>) -> Result<(), A::Error> {
self.finish_with_opts(root, None, false)
}
/// Finalize the FlatBuffer by: aligning it and marking the internal state
@@ -535,7 +818,8 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
/// `finished_data` to get the resulting data.
#[inline]
pub fn finish_minimal<T>(&mut self, root: WIPOffset<T>) {
self.finish_with_opts(root, None, false);
self.try_finish_minimal(root)
.expect("Flatbuffer allocation failure")
}
#[inline]
@@ -553,13 +837,13 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
fn write_vtable(
&mut self,
table_tail_revloc: WIPOffset<TableUnfinishedWIPOffset>,
) -> WIPOffset<VTableWIPOffset> {
) -> Result<WIPOffset<VTableWIPOffset>, A::Error> {
self.assert_nested("write_vtable");
// Write the vtable offset, which is the start of any Table.
// We fill its value later.
let object_revloc_to_vtable: WIPOffset<VTableWIPOffset> =
WIPOffset::new(self.push::<UOffsetT>(0xF0F0_F0F0).value());
WIPOffset::new(self.try_push::<UOffsetT>(0xF0F0_F0F0)?.value());
// Layout of the data this function will create when a new vtable is
// needed.
@@ -602,7 +886,7 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
// fill the WIP vtable with zeros:
let vtable_byte_len = get_vtable_byte_len(&self.field_locs);
self.make_space(vtable_byte_len);
self.make_space(vtable_byte_len)?;
// compute the length of the table (not vtable!) in bytes:
let table_object_size = object_revloc_to_vtable.value() - table_tail_revloc.value();
@@ -611,6 +895,8 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
// Write the VTable (we may delete it afterwards, if it is a duplicate):
let vt_start_pos = self.head;
let vt_end_pos = self.head + vtable_byte_len;
// Zero out the vtable space - make_space only reserves but doesn't initialize
self.allocator[vt_start_pos.range_to(vt_end_pos)].fill(0);
{
// write the vtable header:
let vtfw =
@@ -625,13 +911,15 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
}
}
let new_vt_bytes = &self.allocator[vt_start_pos.range_to(vt_end_pos)];
let found = self.written_vtable_revpos.binary_search_by(|old_vtable_revpos: &UOffsetT| {
let old_vtable_pos = self.allocator.len() - *old_vtable_revpos as usize;
// Safety:
// Already written vtables are valid by construction
let old_vtable = unsafe { VTable::init(&self.allocator, old_vtable_pos) };
new_vt_bytes.cmp(old_vtable.as_bytes())
});
let found = self
.written_vtable_revpos
.binary_search_by(|old_vtable_revpos: &UOffsetT| {
let old_vtable_pos = self.allocator.len() - *old_vtable_revpos as usize;
// Safety:
// Already written vtables are valid by construction
let old_vtable = unsafe { VTable::init(&self.allocator, old_vtable_pos) };
new_vt_bytes.cmp(old_vtable.as_bytes())
});
let final_vtable_revpos = match found {
Ok(i) => {
// The new vtable is a duplicate so clear it.
@@ -669,17 +957,18 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
self.field_locs.clear();
object_revloc_to_vtable
Ok(object_revloc_to_vtable)
}
// Only call this when you know it is safe to double the size of the buffer.
#[inline]
fn grow_allocator(&mut self) {
fn grow_allocator(&mut self) -> Result<(), A::Error> {
let starting_active_size = self.used_space();
self.allocator.grow_downwards().expect("Flatbuffer allocation failure");
self.allocator.grow_downwards()?;
let ending_active_size = self.used_space();
debug_assert_eq!(starting_active_size, ending_active_size);
Ok(())
}
// with or without a size prefix changes how we load the data, so finish*
@@ -689,7 +978,7 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
root: WIPOffset<T>,
file_identifier: Option<&str>,
size_prefixed: bool,
) {
) -> Result<(), A::Error> {
self.assert_not_finished("buffer cannot be finished when it is already finished");
self.assert_not_nested(
"buffer cannot be finished when a table or vector is under construction",
@@ -702,34 +991,40 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
// for the size prefix:
let b = if size_prefixed { SIZE_UOFFSET } else { 0 };
// for the file identifier (a string that is not zero-terminated):
let c = if file_identifier.is_some() { FILE_IDENTIFIER_LENGTH } else { 0 };
let c = if file_identifier.is_some() {
FILE_IDENTIFIER_LENGTH
} else {
0
};
a + b + c
};
{
let ma = PushAlignment::new(self.min_align);
self.align(to_align, ma);
self.align(to_align, ma)?;
}
if let Some(ident) = file_identifier {
debug_assert_eq!(ident.len(), FILE_IDENTIFIER_LENGTH);
self.push_bytes_unprefixed(ident.as_bytes());
self.push_bytes_unprefixed(ident.as_bytes())?;
}
self.push(root);
self.try_push(root)?;
if size_prefixed {
let sz = self.used_space() as UOffsetT;
self.push::<UOffsetT>(sz);
self.try_push::<UOffsetT>(sz)?;
}
self.finished = true;
Ok(())
}
#[inline]
fn align(&mut self, len: usize, alignment: PushAlignment) {
fn align(&mut self, len: usize, alignment: PushAlignment) -> Result<(), A::Error> {
self.track_min_align(alignment.value());
let s = self.used_space() as usize;
self.make_space(padding_bytes(s + len, alignment.value()));
self.make_space(padding_bytes(s + len, alignment.value()))?;
Ok(())
}
#[inline]
@@ -738,31 +1033,34 @@ impl<'fbb, A: Allocator> FlatBufferBuilder<'fbb, A> {
}
#[inline]
fn push_bytes_unprefixed(&mut self, x: &[u8]) -> UOffsetT {
let n = self.make_space(x.len());
fn push_bytes_unprefixed(&mut self, x: &[u8]) -> Result<UOffsetT, A::Error> {
let n = self.make_space(x.len())?;
self.allocator[n.range_to(n + x.len())].copy_from_slice(x);
n.to_forward_index(&self.allocator) as UOffsetT
Ok(n.to_forward_index(&self.allocator) as UOffsetT)
}
#[inline]
fn make_space(&mut self, want: usize) -> ReverseIndex {
self.ensure_capacity(want);
fn make_space(&mut self, want: usize) -> Result<ReverseIndex, A::Error> {
self.ensure_capacity(want)?;
self.head -= want;
self.head
Ok(self.head)
}
#[inline]
fn ensure_capacity(&mut self, want: usize) -> usize {
fn ensure_capacity(&mut self, want: usize) -> Result<usize, A::Error> {
if self.unused_ready_space() >= want {
return want;
return Ok(want);
}
assert!(want <= FLATBUFFERS_MAX_BUFFER_SIZE, "cannot grow buffer beyond 2 gigabytes");
assert!(
want <= FLATBUFFERS_MAX_BUFFER_SIZE,
"cannot grow buffer beyond 2 gigabytes"
);
while self.unused_ready_space() < want {
self.grow_allocator();
self.grow_allocator()?;
}
want
Ok(want)
}
#[inline]
fn unused_ready_space(&self) -> usize {
@@ -929,6 +1227,33 @@ impl<T> IndexMut<ReverseIndexRange> for [T] {
#[cfg(test)]
mod tests {
use super::*;
use core::sync::atomic::{AtomicUsize, Ordering};
use std::alloc::{GlobalAlloc, Layout, System};
static ALLOC_COUNT: AtomicUsize = AtomicUsize::new(0);
struct CountingAllocator;
unsafe impl GlobalAlloc for CountingAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
ALLOC_COUNT.fetch_add(1, Ordering::Relaxed);
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
}
#[global_allocator]
static GLOBAL: CountingAllocator = CountingAllocator;
fn reset_alloc_count() {
ALLOC_COUNT.store(0, Ordering::Relaxed);
}
fn alloc_count() -> usize {
ALLOC_COUNT.load(Ordering::Relaxed)
}
#[test]
fn reverse_index_test() {
@@ -938,4 +1263,150 @@ mod tests {
assert_eq!(&buf[idx.range_to(idx + 1)], &[4]);
assert_eq!(idx.to_forward_index(&buf), 4);
}
#[test]
fn with_internal_capacity_preallocates_vecs() {
let mut builder = FlatBufferBuilder::with_internal_capacity(64, 8, 16, 32);
assert!(builder.allocator.len() >= 64);
assert!(builder.field_locs.capacity() >= 8);
assert!(builder.written_vtable_revpos.capacity() >= 16);
assert!(builder.strings_pool.capacity() >= 32);
assert!(builder.field_locs.is_empty());
assert!(builder.written_vtable_revpos.is_empty());
assert!(builder.strings_pool.is_empty());
// Reset the allocation counter after builder construction
reset_alloc_count();
// Add a shared string and verify it lands in the pool
let s1 = builder.create_shared_string("hello");
assert_eq!(builder.strings_pool.len(), 1);
// Adding the same string again should reuse the pooled entry
let s2 = builder.create_shared_string("hello");
assert_eq!(builder.strings_pool.len(), 1);
assert_eq!(s1.value(), s2.value());
// A different string should add a new entry
let _s3 = builder.create_shared_string("world");
assert_eq!(builder.strings_pool.len(), 2);
// With sufficient preallocated capacity, no additional allocations
// should have occurred for the internal vecs during the operations above
let allocs = alloc_count();
assert_eq!(
allocs, 0,
"expected 0 allocations after builder construction, got {}",
allocs
);
}
/// A test allocator that fails after a specified number of grow operations.
struct FailingAllocator {
inner: DefaultAllocator,
grows_remaining: usize,
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct AllocationError;
impl core::fmt::Display for AllocationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "allocation failed")
}
}
impl FailingAllocator {
fn new(initial_size: usize, max_grows: usize) -> Self {
Self {
inner: DefaultAllocator::from_vec(vec![0u8; initial_size]),
grows_remaining: max_grows,
}
}
}
impl Deref for FailingAllocator {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for FailingAllocator {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
unsafe impl Allocator for FailingAllocator {
type Error = AllocationError;
fn grow_downwards(&mut self) -> Result<(), Self::Error> {
if self.grows_remaining == 0 {
return Err(AllocationError);
}
self.grows_remaining -= 1;
// DefaultAllocator returns Infallible, so unwrap is safe
self.inner.grow_downwards().unwrap();
Ok(())
}
fn len(&self) -> usize {
self.inner.len()
}
}
#[test]
fn try_push_propagates_allocation_error() {
let allocator = FailingAllocator::new(1, 0);
let mut builder = FlatBufferBuilder::new_in(allocator);
let result = builder.try_push::<u64>(0x1234567890ABCDEF);
assert!(result.is_err());
}
#[test]
fn try_create_string_propagates_allocation_error() {
let allocator = FailingAllocator::new(1, 0);
let mut builder = FlatBufferBuilder::new_in(allocator);
let result = builder.try_create_string("hello world");
assert!(result.is_err());
}
#[test]
fn try_create_vector_propagates_allocation_error() {
let allocator = FailingAllocator::new(1, 0);
let mut builder = FlatBufferBuilder::new_in(allocator);
let result = builder.try_create_vector(&[1u32, 2, 3, 4, 5]);
assert!(result.is_err());
}
#[test]
fn try_methods_succeed_with_sufficient_capacity() {
let allocator = FailingAllocator::new(1, 10);
let mut builder = FlatBufferBuilder::new_in(allocator);
let result = builder.try_create_string("hello");
assert!(result.is_ok());
let result = builder.try_create_vector(&[1u32, 2, 3]);
assert!(result.is_ok());
}
#[test]
fn try_finish_propagates_allocation_error() {
let allocator = FailingAllocator::new(1, 3);
let mut builder = FlatBufferBuilder::new_in(allocator);
let start = builder.start_table();
let table = builder
.try_end_table(start)
.expect("end_table should succeed with 3 grows");
let result = builder.try_finish_minimal(table);
assert!(result.is_err(), "finish should fail after grows exhausted");
}
}

View File

@@ -107,6 +107,20 @@ impl<'a, T: Follow<'a> + 'a> Vector<'a, T> {
key: K,
f: fn(&<T as Follow<'a>>::Inner, &K) -> Ordering,
) -> Option<T::Inner> {
self.lookup_index_by_key(key, f).map(|idx| self.get(idx))
}
/// Binary search by key, returning the index of the matching element.
///
/// This is similar to `lookup_by_key`, but returns the index of the found
/// element rather than the element itself. This is useful when you need
/// to reference elements by their position in the vector.
#[inline(always)]
pub fn lookup_index_by_key<K: Ord>(
&self,
key: K,
f: fn(&<T as Follow<'a>>::Inner, &K) -> Ordering,
) -> Option<usize> {
if self.is_empty() {
return None;
}
@@ -118,7 +132,7 @@ impl<'a, T: Follow<'a> + 'a> Vector<'a, T> {
let mid = (left + right) / 2;
let value = self.get(mid);
match f(&value, &key) {
Ordering::Equal => return Some(value),
Ordering::Equal => return Some(mid),
Ordering::Less => left = mid + 1,
Ordering::Greater => {
if mid == 0 {

View File

@@ -492,8 +492,8 @@ impl<'ver, 'opts, 'buf> TableVerifier<'ver, 'opts, 'buf> {
Ok(self)
}
_ => InvalidFlatbuffer::new_inconsistent_union(
key_field_name.into(),
val_field_name.into(),
key_field_name.into(),
),
}
}

View File

@@ -421,6 +421,9 @@ impl<'a> Serializer for MapKeySerializer<'a> {
type SerializeStruct = Impossible<(), Error>;
type SerializeStructVariant = Impossible<(), Error>;
fn is_human_readable(&self) -> bool {
self.0.is_human_readable()
}
fn serialize_bool(self, _value: bool) -> Result<(), Error> {
key_must_be_a_string()
}

View File

@@ -397,8 +397,8 @@ fn verify_union<'a, 'b, 'c>(
}
} else {
return InvalidFlatbuffer::new_inconsistent_union(
format!("{}_type", field.name()),
field.name().to_string(),
format!("{}_type", field.name()),
)?;
}

View File

@@ -643,7 +643,7 @@ inline ::flatbuffers::Offset<Monster> Monster::Pack(::flatbuffers::FlatBufferBui
auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
auto _inventory = _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0;
auto _color = _o->color;
auto _weapons = _o->weapons.size() ? _fbb.CreateVector<::flatbuffers::Offset<MyGame::Sample::Weapon>> (_o->weapons.size(), [](size_t i, _VectorArgs *__va) { return CreateWeapon(*__va->__fbb, __va->__o->weapons[i].get(), __va->__rehasher); }, &_va ) : 0;
auto _weapons = _o->weapons.size() ? _fbb.CreateVector<::flatbuffers::Offset<MyGame::Sample::Weapon>> (_o->weapons.size(), [](size_t i, _VectorArgs *__va) { return MyGame::Sample::CreateWeapon(*__va->__fbb, __va->__o->weapons[i].get(), __va->__rehasher); }, &_va ) : 0;
auto _equipped_type = _o->equipped.type;
auto _equipped = _o->equipped.Pack(_fbb);
auto _path = _o->path.size() ? _fbb.CreateVectorOfStructs(_o->path) : 0;

View File

@@ -113,12 +113,12 @@ public struct MyGame_Sample_Vec3: NativeStruct, FlatbuffersVectorInitializable,
}
extension MyGame_Sample_Vec3: Encodable {
enum CodingKeys: String, CodingKey {
case x = "x"
case y = "y"
case z = "z"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if x != 0.0 {
@@ -161,7 +161,7 @@ public struct MyGame_Sample_Vec3_Mutable: FlatBufferStruct, FlatbuffersVectorIni
}
}
public struct MyGame_Sample_Monster: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable, ObjectAPIPacker {
public struct MyGame_Sample_Monster: FlatBufferVerifiableTable, FlatbuffersVectorInitializable, ObjectAPIPacker {
static func validateVersion() { FlatBuffersVersion_25_12_19() }
public var __buffer: ByteBuffer! { return _accessor.bb }
@@ -170,51 +170,49 @@ public struct MyGame_Sample_Monster: FlatBufferTable, FlatbuffersVectorInitializ
private init(_ t: Table) { _accessor = t }
public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
private enum VTOFFSET: VOffset {
case pos = 4
case mana = 6
case hp = 8
case name = 10
case inventory = 14
case color = 16
case weapons = 18
case equippedType = 20
case equipped = 22
case path = 24
var v: Int32 { Int32(self.rawValue) }
var p: VOffset { self.rawValue }
private struct VT {
static let pos: VOffset = 4
static let mana: VOffset = 6
static let hp: VOffset = 8
static let name: VOffset = 10
static let inventory: VOffset = 14
static let color: VOffset = 16
static let weapons: VOffset = 18
static let equippedType: VOffset = 20
static let equipped: VOffset = 22
static let path: VOffset = 24
}
public var pos: MyGame_Sample_Vec3? { let o = _accessor.offset(VTOFFSET.pos.v); return o == 0 ? nil : _accessor.readBuffer(of: MyGame_Sample_Vec3.self, at: o) }
public var mutablePos: MyGame_Sample_Vec3_Mutable? { let o = _accessor.offset(VTOFFSET.pos.v); return o == 0 ? nil : MyGame_Sample_Vec3_Mutable(_accessor.bb, o: o + _accessor.position) }
public var mana: Int16 { let o = _accessor.offset(VTOFFSET.mana.v); return o == 0 ? 150 : _accessor.readBuffer(of: Int16.self, at: o) }
@discardableResult public func mutate(mana: Int16) -> Bool {let o = _accessor.offset(VTOFFSET.mana.v); return _accessor.mutate(mana, index: o) }
public var hp: Int16 { let o = _accessor.offset(VTOFFSET.hp.v); return o == 0 ? 100 : _accessor.readBuffer(of: Int16.self, at: o) }
@discardableResult public func mutate(hp: Int16) -> Bool {let o = _accessor.offset(VTOFFSET.hp.v); return _accessor.mutate(hp, index: o) }
public var name: String? { let o = _accessor.offset(VTOFFSET.name.v); return o == 0 ? nil : _accessor.string(at: o) }
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.name.v) }
public var inventory: FlatbufferVector<UInt8> { return _accessor.vector(at: VTOFFSET.inventory.v, byteSize: 1) }
public func mutate(inventory: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VTOFFSET.inventory.v); return _accessor.directMutate(inventory, index: _accessor.vector(at: o) + index * 1) }
public func withUnsafePointerToInventory<T>(_ body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.inventory.v, body: body) }
public var color: MyGame_Sample_Color { let o = _accessor.offset(VTOFFSET.color.v); return o == 0 ? .blue : MyGame_Sample_Color(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .blue }
@discardableResult public func mutate(color: MyGame_Sample_Color) -> Bool {let o = _accessor.offset(VTOFFSET.color.v); return _accessor.mutate(color.rawValue, index: o) }
public var weapons: FlatbufferVector<MyGame_Sample_Weapon> { return _accessor.vector(at: VTOFFSET.weapons.v, byteSize: 4) }
public var equippedType: MyGame_Sample_Equipment { let o = _accessor.offset(VTOFFSET.equippedType.v); return o == 0 ? .none_ : MyGame_Sample_Equipment(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ }
public func equipped<T: FlatbuffersInitializable>(type: T.Type) -> T? { let o = _accessor.offset(VTOFFSET.equipped.v); return o == 0 ? nil : _accessor.union(o) }
public var path: FlatbufferVector<MyGame_Sample_Vec3> { return _accessor.vector(at: VTOFFSET.path.v, byteSize: 12) }
public var mutablePath: FlatbufferVector<MyGame_Sample_Vec3_Mutable> { return _accessor.vector(at: VTOFFSET.path.v, byteSize: 12) }
public func withUnsafePointerToPath<T>(_ body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VTOFFSET.path.v, body: body) }
public var pos: MyGame_Sample_Vec3? { let o = _accessor.offset(VT.pos); return o == 0 ? nil : _accessor.readBuffer(of: MyGame_Sample_Vec3.self, at: o) }
public var mutablePos: MyGame_Sample_Vec3_Mutable? { let o = _accessor.offset(VT.pos); return o == 0 ? nil : MyGame_Sample_Vec3_Mutable(_accessor.bb, o: o + _accessor.position) }
public var mana: Int16 { let o = _accessor.offset(VT.mana); return o == 0 ? 150 : _accessor.readBuffer(of: Int16.self, at: o) }
@discardableResult public func mutate(mana: Int16) -> Bool {let o = _accessor.offset(VT.mana); return _accessor.mutate(mana, index: o) }
public var hp: Int16 { let o = _accessor.offset(VT.hp); return o == 0 ? 100 : _accessor.readBuffer(of: Int16.self, at: o) }
@discardableResult public func mutate(hp: Int16) -> Bool {let o = _accessor.offset(VT.hp); return _accessor.mutate(hp, index: o) }
public var name: String? { let o = _accessor.offset(VT.name); return o == 0 ? nil : _accessor.string(at: o) }
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.name) }
public var inventory: FlatbufferVector<UInt8> { return _accessor.vector(at: VT.inventory, byteSize: 1) }
public func mutate(inventory: UInt8, at index: Int32) -> Bool { let o = _accessor.offset(VT.inventory); return _accessor.directMutate(inventory, index: _accessor.vector(at: o) + index * 1) }
public func withUnsafePointerToInventory<T>(_ body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VT.inventory, body: body) }
public var color: MyGame_Sample_Color { let o = _accessor.offset(VT.color); return o == 0 ? .blue : MyGame_Sample_Color(rawValue: _accessor.readBuffer(of: Int8.self, at: o)) ?? .blue }
@discardableResult public func mutate(color: MyGame_Sample_Color) -> Bool {let o = _accessor.offset(VT.color); return _accessor.mutate(color.rawValue, index: o) }
public var weapons: FlatbufferVector<MyGame_Sample_Weapon> { return _accessor.vector(at: VT.weapons, byteSize: 4) }
public var equippedType: MyGame_Sample_Equipment { let o = _accessor.offset(VT.equippedType); return o == 0 ? .none_ : MyGame_Sample_Equipment(rawValue: _accessor.readBuffer(of: UInt8.self, at: o)) ?? .none_ }
public func equipped<T: FlatbuffersInitializable>(type: T.Type) -> T? { let o = _accessor.offset(VT.equipped); return o == 0 ? nil : _accessor.union(o) }
public var path: FlatbufferVector<MyGame_Sample_Vec3> { return _accessor.vector(at: VT.path, byteSize: 12) }
public var mutablePath: FlatbufferVector<MyGame_Sample_Vec3_Mutable> { return _accessor.vector(at: VT.path, byteSize: 12) }
public func withUnsafePointerToPath<T>(_ body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T? { return try _accessor.withUnsafePointerToSlice(at: VT.path, body: body) }
public static func startMonster(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 11) }
public static func add(pos: MyGame_Sample_Vec3?, _ fbb: inout FlatBufferBuilder) { guard let pos = pos else { return }; fbb.create(struct: pos, position: VTOFFSET.pos.p) }
public static func add(mana: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: mana, def: 150, at: VTOFFSET.mana.p) }
public static func add(hp: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: hp, def: 100, at: VTOFFSET.hp.p) }
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VTOFFSET.name.p) }
public static func addVectorOf(inventory: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: inventory, at: VTOFFSET.inventory.p) }
public static func add(color: MyGame_Sample_Color, _ fbb: inout FlatBufferBuilder) { fbb.add(element: color.rawValue, def: 2, at: VTOFFSET.color.p) }
public static func addVectorOf(weapons: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: weapons, at: VTOFFSET.weapons.p) }
public static func add(equippedType: MyGame_Sample_Equipment, _ fbb: inout FlatBufferBuilder) { fbb.add(element: equippedType.rawValue, def: 0, at: VTOFFSET.equippedType.p) }
public static func add(equipped: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: equipped, at: VTOFFSET.equipped.p) }
public static func addVectorOf(path: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: path, at: VTOFFSET.path.p) }
public static func add(pos: MyGame_Sample_Vec3?, _ fbb: inout FlatBufferBuilder) { guard let pos = pos else { return }; fbb.create(struct: pos, position: VT.pos) }
public static func add(mana: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: mana, def: 150, at: VT.mana) }
public static func add(hp: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: hp, def: 100, at: VT.hp) }
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VT.name) }
public static func addVectorOf(inventory: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: inventory, at: VT.inventory) }
public static func add(color: MyGame_Sample_Color, _ fbb: inout FlatBufferBuilder) { fbb.add(element: color.rawValue, def: 2, at: VT.color) }
public static func addVectorOf(weapons: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: weapons, at: VT.weapons) }
public static func add(equippedType: MyGame_Sample_Equipment, _ fbb: inout FlatBufferBuilder) { fbb.add(element: equippedType.rawValue, def: 0, at: VT.equippedType) }
public static func add(equipped: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: equipped, at: VT.equipped) }
public static func addVectorOf(path: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: path, at: VT.path) }
public static func startVectorOfPath(_ size: Int, in builder: inout FlatBufferBuilder) {
builder.startVector(size * MemoryLayout<MyGame_Sample_Vec3>.size, elementSize: MemoryLayout<MyGame_Sample_Vec3>.alignment)
}
@@ -293,14 +291,14 @@ public struct MyGame_Sample_Monster: FlatBufferTable, FlatbuffersVectorInitializ
public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.pos.p, fieldName: "pos", required: false, type: MyGame_Sample_Vec3.self)
try _v.visit(field: VTOFFSET.mana.p, fieldName: "mana", required: false, type: Int16.self)
try _v.visit(field: VTOFFSET.hp.p, fieldName: "hp", required: false, type: Int16.self)
try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: false, type: ForwardOffset<String>.self)
try _v.visit(field: VTOFFSET.inventory.p, fieldName: "inventory", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self)
try _v.visit(field: VTOFFSET.color.p, fieldName: "color", required: false, type: MyGame_Sample_Color.self)
try _v.visit(field: VTOFFSET.weapons.p, fieldName: "weapons", required: false, type: ForwardOffset<Vector<ForwardOffset<MyGame_Sample_Weapon>, MyGame_Sample_Weapon>>.self)
try _v.visit(unionKey: VTOFFSET.equippedType.p, unionField: VTOFFSET.equipped.p, unionKeyName: "equippedType", fieldName: "equipped", required: false, completion: { (verifier, key: MyGame_Sample_Equipment, pos) in
try _v.visit(field: VT.pos, fieldName: "pos", required: false, type: MyGame_Sample_Vec3.self)
try _v.visit(field: VT.mana, fieldName: "mana", required: false, type: Int16.self)
try _v.visit(field: VT.hp, fieldName: "hp", required: false, type: Int16.self)
try _v.visit(field: VT.name, fieldName: "name", required: false, type: ForwardOffset<String>.self)
try _v.visit(field: VT.inventory, fieldName: "inventory", required: false, type: ForwardOffset<Vector<UInt8, UInt8>>.self)
try _v.visit(field: VT.color, fieldName: "color", required: false, type: MyGame_Sample_Color.self)
try _v.visit(field: VT.weapons, fieldName: "weapons", required: false, type: ForwardOffset<Vector<ForwardOffset<MyGame_Sample_Weapon>, MyGame_Sample_Weapon>>.self)
try _v.visit(unionKey: VT.equippedType, unionField: VT.equipped, unionKeyName: "equippedType", fieldName: "equipped", required: false, completion: { (verifier, key: MyGame_Sample_Equipment, pos) in
switch key {
case .none_:
break // NOTE - SWIFT doesnt support none
@@ -308,13 +306,12 @@ public struct MyGame_Sample_Monster: FlatBufferTable, FlatbuffersVectorInitializ
try ForwardOffset<MyGame_Sample_Weapon>.verify(&verifier, at: pos, of: MyGame_Sample_Weapon.self)
}
})
try _v.visit(field: VTOFFSET.path.p, fieldName: "path", required: false, type: ForwardOffset<Vector<MyGame_Sample_Vec3, MyGame_Sample_Vec3>>.self)
try _v.visit(field: VT.path, fieldName: "path", required: false, type: ForwardOffset<Vector<MyGame_Sample_Vec3, MyGame_Sample_Vec3>>.self)
_v.finish()
}
}
extension MyGame_Sample_Monster: Encodable {
enum CodingKeys: String, CodingKey {
case pos = "pos"
case mana = "mana"
@@ -327,6 +324,7 @@ extension MyGame_Sample_Monster: Encodable {
case equipped = "equipped"
case path = "path"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(pos, forKey: .pos)
@@ -402,7 +400,7 @@ public class MyGame_Sample_MonsterT: NativeObject {
public func serialize() -> ByteBuffer { return serialize(type: MyGame_Sample_Monster.self) }
}
public struct MyGame_Sample_Weapon: FlatBufferTable, FlatbuffersVectorInitializable, Verifiable, ObjectAPIPacker {
public struct MyGame_Sample_Weapon: FlatBufferVerifiableTable, FlatbuffersVectorInitializable, ObjectAPIPacker {
static func validateVersion() { FlatBuffersVersion_25_12_19() }
public var __buffer: ByteBuffer! { return _accessor.bb }
@@ -411,20 +409,18 @@ public struct MyGame_Sample_Weapon: FlatBufferTable, FlatbuffersVectorInitializa
private init(_ t: Table) { _accessor = t }
public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) }
private enum VTOFFSET: VOffset {
case name = 4
case damage = 6
var v: Int32 { Int32(self.rawValue) }
var p: VOffset { self.rawValue }
private struct VT {
static let name: VOffset = 4
static let damage: VOffset = 6
}
public var name: String? { let o = _accessor.offset(VTOFFSET.name.v); return o == 0 ? nil : _accessor.string(at: o) }
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.name.v) }
public var damage: Int16 { let o = _accessor.offset(VTOFFSET.damage.v); return o == 0 ? 0 : _accessor.readBuffer(of: Int16.self, at: o) }
@discardableResult public func mutate(damage: Int16) -> Bool {let o = _accessor.offset(VTOFFSET.damage.v); return _accessor.mutate(damage, index: o) }
public var name: String? { let o = _accessor.offset(VT.name); return o == 0 ? nil : _accessor.string(at: o) }
public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VT.name) }
public var damage: Int16 { let o = _accessor.offset(VT.damage); return o == 0 ? 0 : _accessor.readBuffer(of: Int16.self, at: o) }
@discardableResult public func mutate(damage: Int16) -> Bool {let o = _accessor.offset(VT.damage); return _accessor.mutate(damage, index: o) }
public static func startWeapon(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 2) }
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VTOFFSET.name.p) }
public static func add(damage: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: damage, def: 0, at: VTOFFSET.damage.p) }
public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VT.name) }
public static func add(damage: Int16, _ fbb: inout FlatBufferBuilder) { fbb.add(element: damage, def: 0, at: VT.damage) }
public static func endWeapon(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end }
public static func createWeapon(
_ fbb: inout FlatBufferBuilder,
@@ -461,18 +457,18 @@ public struct MyGame_Sample_Weapon: FlatBufferTable, FlatbuffersVectorInitializa
public static func verify<T>(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable {
var _v = try verifier.visitTable(at: position)
try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: false, type: ForwardOffset<String>.self)
try _v.visit(field: VTOFFSET.damage.p, fieldName: "damage", required: false, type: Int16.self)
try _v.visit(field: VT.name, fieldName: "name", required: false, type: ForwardOffset<String>.self)
try _v.visit(field: VT.damage, fieldName: "damage", required: false, type: Int16.self)
_v.finish()
}
}
extension MyGame_Sample_Weapon: Encodable {
enum CodingKeys: String, CodingKey {
case name = "name"
case damage = "damage"
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encodeIfPresent(name, forKey: .name)

View File

@@ -1,18 +1,18 @@
// Automatically generated by the Flatbuffers compiler. Do not modify.
// @generated
pub mod my_game {
use super::*;
pub mod sample {
use super::*;
mod color_generated;
pub use self::color_generated::*;
mod equipment_generated;
pub use self::equipment_generated::*;
mod vec_3_generated;
pub use self::vec_3_generated::*;
mod monster_generated;
pub use self::monster_generated::*;
mod weapon_generated;
pub use self::weapon_generated::*;
} // sample
pub mod sample {
use super::*;
mod color_generated;
pub use self::color_generated::*;
mod equipment_generated;
pub use self::equipment_generated::*;
mod vec_3_generated;
pub use self::vec_3_generated::*;
mod monster_generated;
pub use self::monster_generated::*;
mod weapon_generated;
pub use self::weapon_generated::*;
} // sample
} // my_game

View File

@@ -2,64 +2,73 @@
// @generated
extern crate alloc;
use super::*;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_COLOR: i8 = 0;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_COLOR: i8 = 2;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_COLOR: [Color; 3] = [
Color::Red,
Color::Green,
Color::Blue,
Color::Red,
Color::Green,
Color::Blue,
];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct Color(pub i8);
#[allow(non_upper_case_globals)]
impl Color {
pub const Red: Self = Self(0);
pub const Green: Self = Self(1);
pub const Blue: Self = Self(2);
pub const Red: Self = Self(0);
pub const Green: Self = Self(1);
pub const Blue: Self = Self(2);
pub const ENUM_MIN: i8 = 0;
pub const ENUM_MAX: i8 = 2;
pub const ENUM_VALUES: &'static [Self] = &[
Self::Red,
Self::Green,
Self::Blue,
];
/// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> Option<&'static str> {
match self {
Self::Red => Some("Red"),
Self::Green => Some("Green"),
Self::Blue => Some("Blue"),
_ => None,
pub const ENUM_MIN: i8 = 0;
pub const ENUM_MAX: i8 = 2;
pub const ENUM_VALUES: &'static [Self] = &[
Self::Red,
Self::Green,
Self::Blue,
];
/// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> Option<&'static str> {
match self {
Self::Red => Some("Red"),
Self::Green => Some("Green"),
Self::Blue => Some("Blue"),
_ => None,
}
}
}
}
impl ::core::fmt::Debug for Color {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
}
}
}
}
impl<'a> ::flatbuffers::Follow<'a> for Color {
type Inner = Self;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = unsafe { ::flatbuffers::read_scalar_at::<i8>(buf, loc) };
Self(b)
}
type Inner = Self;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = unsafe { ::flatbuffers::read_scalar_at::<i8>(buf, loc) };
Self(b)
}
}
impl ::flatbuffers::Push for Color {
type Output = Color;
#[inline]
unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
unsafe { ::flatbuffers::emplace_scalar::<i8>(dst, self.0) };
@@ -67,26 +76,28 @@ impl ::flatbuffers::Push for Color {
}
impl ::flatbuffers::EndianScalar for Color {
type Scalar = i8;
#[inline]
fn to_little_endian(self) -> i8 {
self.0.to_le()
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(v: i8) -> Self {
let b = i8::from_le(v);
Self(b)
}
type Scalar = i8;
#[inline]
fn to_little_endian(self) -> i8 {
self.0.to_le()
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(v: i8) -> Self {
let b = i8::from_le(v);
Self(b)
}
}
impl<'a> ::flatbuffers::Verifiable for Color {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
i8::run_verifier(v, pos)
}
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
i8::run_verifier(v, pos)
}
}
impl ::flatbuffers::SimpleToVerifyInSlice for Color {}

View File

@@ -2,60 +2,69 @@
// @generated
extern crate alloc;
use super::*;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MIN_EQUIPMENT: u8 = 0;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
pub const ENUM_MAX_EQUIPMENT: u8 = 1;
#[deprecated(since = "2.0.0", note = "Use associated constants instead. This will no longer be generated in 2021.")]
#[allow(non_camel_case_types)]
pub const ENUM_VALUES_EQUIPMENT: [Equipment; 2] = [
Equipment::NONE,
Equipment::Weapon,
Equipment::NONE,
Equipment::Weapon,
];
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[repr(transparent)]
pub struct Equipment(pub u8);
#[allow(non_upper_case_globals)]
impl Equipment {
pub const NONE: Self = Self(0);
pub const Weapon: Self = Self(1);
pub const NONE: Self = Self(0);
pub const Weapon: Self = Self(1);
pub const ENUM_MIN: u8 = 0;
pub const ENUM_MAX: u8 = 1;
pub const ENUM_VALUES: &'static [Self] = &[
Self::NONE,
Self::Weapon,
];
/// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> Option<&'static str> {
match self {
Self::NONE => Some("NONE"),
Self::Weapon => Some("Weapon"),
_ => None,
pub const ENUM_MIN: u8 = 0;
pub const ENUM_MAX: u8 = 1;
pub const ENUM_VALUES: &'static [Self] = &[
Self::NONE,
Self::Weapon,
];
/// Returns the variant's name or "" if unknown.
pub fn variant_name(self) -> Option<&'static str> {
match self {
Self::NONE => Some("NONE"),
Self::Weapon => Some("Weapon"),
_ => None,
}
}
}
}
impl ::core::fmt::Debug for Equipment {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
if let Some(name) = self.variant_name() {
f.write_str(name)
} else {
f.write_fmt(format_args!("<UNKNOWN {:?}>", self.0))
}
}
}
}
impl<'a> ::flatbuffers::Follow<'a> for Equipment {
type Inner = Self;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = unsafe { ::flatbuffers::read_scalar_at::<u8>(buf, loc) };
Self(b)
}
type Inner = Self;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
let b = unsafe { ::flatbuffers::read_scalar_at::<u8>(buf, loc) };
Self(b)
}
}
impl ::flatbuffers::Push for Equipment {
type Output = Equipment;
#[inline]
unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
unsafe { ::flatbuffers::emplace_scalar::<u8>(dst, self.0) };
@@ -63,75 +72,85 @@ impl ::flatbuffers::Push for Equipment {
}
impl ::flatbuffers::EndianScalar for Equipment {
type Scalar = u8;
#[inline]
fn to_little_endian(self) -> u8 {
self.0.to_le()
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(v: u8) -> Self {
let b = u8::from_le(v);
Self(b)
}
type Scalar = u8;
#[inline]
fn to_little_endian(self) -> u8 {
self.0.to_le()
}
#[inline]
#[allow(clippy::wrong_self_convention)]
fn from_little_endian(v: u8) -> Self {
let b = u8::from_le(v);
Self(b)
}
}
impl<'a> ::flatbuffers::Verifiable for Equipment {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
u8::run_verifier(v, pos)
}
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
u8::run_verifier(v, pos)
}
}
impl ::flatbuffers::SimpleToVerifyInSlice for Equipment {}
pub struct EquipmentUnionTableOffset {}
#[allow(clippy::upper_case_acronyms)]
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub enum EquipmentT {
NONE,
Weapon(alloc::boxed::Box<WeaponT>),
NONE,
Weapon(alloc::boxed::Box<WeaponT>),
}
impl Default for EquipmentT {
fn default() -> Self {
Self::NONE
}
fn default() -> Self {
Self::NONE
}
}
impl EquipmentT {
pub fn equipment_type(&self) -> Equipment {
match self {
Self::NONE => Equipment::NONE,
Self::Weapon(_) => Equipment::Weapon,
pub fn equipment_type(&self) -> Equipment {
match self {
Self::NONE => Equipment::NONE,
Self::Weapon(_) => Equipment::Weapon,
}
}
}
pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>(&self, fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A>) -> Option<::flatbuffers::WIPOffset<::flatbuffers::UnionWIPOffset>> {
match self {
Self::NONE => None,
Self::Weapon(v) => Some(v.pack(fbb).as_union_value()),
pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>(&self, fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A>) -> Option<::flatbuffers::WIPOffset<::flatbuffers::UnionWIPOffset>> {
match self {
Self::NONE => None,
Self::Weapon(v) => Some(v.pack(fbb).as_union_value()),
}
}
}
/// If the union variant matches, return the owned WeaponT, setting the union to NONE.
pub fn take_weapon(&mut self) -> Option<alloc::boxed::Box<WeaponT>> {
if let Self::Weapon(_) = self {
let v = ::core::mem::replace(self, Self::NONE);
if let Self::Weapon(w) = v {
Some(w)
} else {
unreachable!()
}
} else {
None
/// If the union variant matches, return the owned WeaponT, setting the union to NONE.
pub fn take_weapon(&mut self) -> Option<alloc::boxed::Box<WeaponT>> {
if let Self::Weapon(_) = self {
let v = ::core::mem::replace(self, Self::NONE);
if let Self::Weapon(w) = v {
Some(w)
} else {
unreachable!()
}
} else {
None
}
}
/// If the union variant matches, return a reference to the WeaponT.
pub fn as_weapon(&self) -> Option<&WeaponT> {
if let Self::Weapon(v) = self { Some(v.as_ref()) } else { None }
}
/// If the union variant matches, return a mutable reference to the WeaponT.
pub fn as_weapon_mut(&mut self) -> Option<&mut WeaponT> {
if let Self::Weapon(v) = self { Some(v.as_mut()) } else { None }
}
}
/// If the union variant matches, return a reference to the WeaponT.
pub fn as_weapon(&self) -> Option<&WeaponT> {
if let Self::Weapon(v) = self { Some(v.as_ref()) } else { None }
}
/// If the union variant matches, return a mutable reference to the WeaponT.
pub fn as_weapon_mut(&mut self) -> Option<&mut WeaponT> {
if let Self::Weapon(v) = self { Some(v.as_mut()) } else { None }
}
}

View File

@@ -2,212 +2,225 @@
// @generated
extern crate alloc;
use super::*;
pub enum MonsterOffset {}
#[derive(Copy, Clone, PartialEq)]
pub enum MonsterOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct Monster<'a> {
pub _tab: ::flatbuffers::Table<'a>,
pub _tab: ::flatbuffers::Table<'a>,
}
impl<'a> ::flatbuffers::Follow<'a> for Monster<'a> {
type Inner = Monster<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
type Inner = Monster<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
}
impl<'a> Monster<'a> {
pub const VT_POS: ::flatbuffers::VOffsetT = 4;
pub const VT_MANA: ::flatbuffers::VOffsetT = 6;
pub const VT_HP: ::flatbuffers::VOffsetT = 8;
pub const VT_NAME: ::flatbuffers::VOffsetT = 10;
pub const VT_INVENTORY: ::flatbuffers::VOffsetT = 14;
pub const VT_COLOR: ::flatbuffers::VOffsetT = 16;
pub const VT_WEAPONS: ::flatbuffers::VOffsetT = 18;
pub const VT_EQUIPPED_TYPE: ::flatbuffers::VOffsetT = 20;
pub const VT_EQUIPPED: ::flatbuffers::VOffsetT = 22;
pub const VT_PATH: ::flatbuffers::VOffsetT = 24;
pub const VT_POS: ::flatbuffers::VOffsetT = 4;
pub const VT_MANA: ::flatbuffers::VOffsetT = 6;
pub const VT_HP: ::flatbuffers::VOffsetT = 8;
pub const VT_NAME: ::flatbuffers::VOffsetT = 10;
pub const VT_INVENTORY: ::flatbuffers::VOffsetT = 14;
pub const VT_COLOR: ::flatbuffers::VOffsetT = 16;
pub const VT_WEAPONS: ::flatbuffers::VOffsetT = 18;
pub const VT_EQUIPPED_TYPE: ::flatbuffers::VOffsetT = 20;
pub const VT_EQUIPPED: ::flatbuffers::VOffsetT = 22;
pub const VT_PATH: ::flatbuffers::VOffsetT = 24;
pub const fn get_fully_qualified_name() -> &'static str {
"MyGame.Sample.Monster"
}
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Monster { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args MonsterArgs<'args>
) -> ::flatbuffers::WIPOffset<Monster<'bldr>> {
let mut builder = MonsterBuilder::new(_fbb);
if let Some(x) = args.path { builder.add_path(x); }
if let Some(x) = args.equipped { builder.add_equipped(x); }
if let Some(x) = args.weapons { builder.add_weapons(x); }
if let Some(x) = args.inventory { builder.add_inventory(x); }
if let Some(x) = args.name { builder.add_name(x); }
if let Some(x) = args.pos { builder.add_pos(x); }
builder.add_hp(args.hp);
builder.add_mana(args.mana);
builder.add_equipped_type(args.equipped_type);
builder.add_color(args.color);
builder.finish()
}
pub fn unpack(&self) -> MonsterT {
let pos = self.pos().map(|x| {
x.unpack()
});
let mana = self.mana();
let hp = self.hp();
let name = self.name().map(|x| {
alloc::string::ToString::to_string(x)
});
let inventory = self.inventory().map(|x| {
x.into_iter().collect()
});
let color = self.color();
let weapons = self.weapons().map(|x| {
x.iter().map(|t| t.unpack()).collect()
});
let equipped = match self.equipped_type() {
Equipment::NONE => EquipmentT::NONE,
Equipment::Weapon => EquipmentT::Weapon(alloc::boxed::Box::new(
self.equipped_as_weapon()
.expect("Invalid union table, expected `Equipment::Weapon`.")
.unpack()
)),
_ => EquipmentT::NONE,
};
let path = self.path().map(|x| {
x.iter().map(|t| t.unpack()).collect()
});
MonsterT {
pos,
mana,
hp,
name,
inventory,
color,
weapons,
equipped,
path,
pub const fn get_fully_qualified_name() -> &'static str {
"MyGame.Sample.Monster"
}
}
#[inline]
pub fn pos(&self) -> Option<&'a Vec3> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<Vec3>(Monster::VT_POS, None)}
}
#[inline]
pub fn mana(&self) -> i16 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i16>(Monster::VT_MANA, Some(150)).unwrap()}
}
#[inline]
pub fn hp(&self) -> i16 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i16>(Monster::VT_HP, Some(100)).unwrap()}
}
#[inline]
pub fn name(&self) -> Option<&'a str> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<&str>>(Monster::VT_NAME, None)}
}
#[inline]
pub fn inventory(&self) -> Option<::flatbuffers::Vector<'a, u8>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, u8>>>(Monster::VT_INVENTORY, None)}
}
#[inline]
pub fn color(&self) -> Color {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<Color>(Monster::VT_COLOR, Some(Color::Blue)).unwrap()}
}
#[inline]
pub fn weapons(&self) -> Option<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Weapon<'a>>>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Weapon>>>>(Monster::VT_WEAPONS, None)}
}
#[inline]
pub fn equipped_type(&self) -> Equipment {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<Equipment>(Monster::VT_EQUIPPED_TYPE, Some(Equipment::NONE)).unwrap()}
}
#[inline]
pub fn equipped(&self) -> Option<::flatbuffers::Table<'a>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Table<'a>>>(Monster::VT_EQUIPPED, None)}
}
#[inline]
pub fn path(&self) -> Option<::flatbuffers::Vector<'a, Vec3>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, Vec3>>>(Monster::VT_PATH, None)}
}
#[inline]
#[allow(non_snake_case)]
pub fn equipped_as_weapon(&self) -> Option<Weapon<'a>> {
if self.equipped_type() == Equipment::Weapon {
self.equipped().map(|t| {
// Safety:
// Created from a valid Table for this object
// Which contains a valid union in this slot
unsafe { Weapon::init_from_table(t) }
})
} else {
None
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Monster { _tab: table }
}
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args MonsterArgs<'args>
) -> ::flatbuffers::WIPOffset<Monster<'bldr>> {
let mut builder = MonsterBuilder::new(_fbb);
if let Some(x) = args.path { builder.add_path(x); }
if let Some(x) = args.equipped { builder.add_equipped(x); }
if let Some(x) = args.weapons { builder.add_weapons(x); }
if let Some(x) = args.inventory { builder.add_inventory(x); }
if let Some(x) = args.name { builder.add_name(x); }
if let Some(x) = args.pos { builder.add_pos(x); }
builder.add_hp(args.hp);
builder.add_mana(args.mana);
builder.add_equipped_type(args.equipped_type);
builder.add_color(args.color);
builder.finish()
}
pub fn unpack(&self) -> MonsterT {
let pos = self.pos().map(|x| {
x.unpack()
});
let mana = self.mana();
let hp = self.hp();
let name = self.name().map(|x| {
alloc::string::ToString::to_string(x)
});
let inventory = self.inventory().map(|x| {
x.into_iter().collect()
});
let color = self.color();
let weapons = self.weapons().map(|x| {
x.iter().map(|t| t.unpack()).collect()
});
let equipped = match self.equipped_type() {
Equipment::NONE => EquipmentT::NONE,
Equipment::Weapon => EquipmentT::Weapon(alloc::boxed::Box::new(
self.equipped_as_weapon()
.expect("Invalid union table, expected `Equipment::Weapon`.")
.unpack()
)),
_ => EquipmentT::NONE,
};
let path = self.path().map(|x| {
x.iter().map(|t| t.unpack()).collect()
});
MonsterT {
pos,
mana,
hp,
name,
inventory,
color,
weapons,
equipped,
path,
}
}
#[inline]
pub fn pos(&self) -> Option<&'a Vec3> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<Vec3>(Monster::VT_POS, None)}
}
#[inline]
pub fn mana(&self) -> i16 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i16>(Monster::VT_MANA, Some(150)).unwrap()}
}
#[inline]
pub fn hp(&self) -> i16 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i16>(Monster::VT_HP, Some(100)).unwrap()}
}
#[inline]
pub fn name(&self) -> Option<&'a str> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<&str>>(Monster::VT_NAME, None)}
}
#[inline]
pub fn inventory(&self) -> Option<::flatbuffers::Vector<'a, u8>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, u8>>>(Monster::VT_INVENTORY, None)}
}
#[inline]
pub fn color(&self) -> Color {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<Color>(Monster::VT_COLOR, Some(Color::Blue)).unwrap()}
}
#[inline]
pub fn weapons(&self) -> Option<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Weapon<'a>>>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, ::flatbuffers::ForwardsUOffset<Weapon>>>>(Monster::VT_WEAPONS, None)}
}
#[inline]
pub fn equipped_type(&self) -> Equipment {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<Equipment>(Monster::VT_EQUIPPED_TYPE, Some(Equipment::NONE)).unwrap()}
}
#[inline]
pub fn equipped(&self) -> Option<::flatbuffers::Table<'a>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Table<'a>>>(Monster::VT_EQUIPPED, None)}
}
#[inline]
pub fn path(&self) -> Option<::flatbuffers::Vector<'a, Vec3>> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'a, Vec3>>>(Monster::VT_PATH, None)}
}
#[inline]
#[allow(non_snake_case)]
pub fn equipped_as_weapon(&self) -> Option<Weapon<'a>> {
if self.equipped_type() == Equipment::Weapon {
self.equipped().map(|t| {
// Safety:
// Created from a valid Table for this object
// Which contains a valid union in this slot
unsafe { Weapon::init_from_table(t) }
})
} else {
None
}
}
}
impl ::flatbuffers::Verifiable for Monster<'_> {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<Vec3>("pos", Self::VT_POS, false)?
.visit_field::<i16>("mana", Self::VT_MANA, false)?
.visit_field::<i16>("hp", Self::VT_HP, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<&str>>("name", Self::VT_NAME, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, u8>>>("inventory", Self::VT_INVENTORY, false)?
.visit_field::<Color>("color", Self::VT_COLOR, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, ::flatbuffers::ForwardsUOffset<Weapon>>>>("weapons", Self::VT_WEAPONS, false)?
.visit_union::<Equipment, _>("equipped_type", Self::VT_EQUIPPED_TYPE, "equipped", Self::VT_EQUIPPED, false, |key, v, pos| {
match key {
Equipment::Weapon => v.verify_union_variant::<::flatbuffers::ForwardsUOffset<Weapon>>("Equipment::Weapon", pos),
_ => Ok(()),
}
})?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, Vec3>>>("path", Self::VT_PATH, false)?
.finish();
Ok(())
}
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<Vec3>("pos", Self::VT_POS, false)?
.visit_field::<i16>("mana", Self::VT_MANA, false)?
.visit_field::<i16>("hp", Self::VT_HP, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<&str>>("name", Self::VT_NAME, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, u8>>>("inventory", Self::VT_INVENTORY, false)?
.visit_field::<Color>("color", Self::VT_COLOR, false)?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, ::flatbuffers::ForwardsUOffset<Weapon>>>>("weapons", Self::VT_WEAPONS, false)?
.visit_union::<Equipment, _>("equipped_type", Self::VT_EQUIPPED_TYPE, "equipped", Self::VT_EQUIPPED, false, |key, v, pos| {
match key {
Equipment::Weapon => v.verify_union_variant::<::flatbuffers::ForwardsUOffset<Weapon>>("Equipment::Weapon", pos),
_ => Ok(()),
}
})?
.visit_field::<::flatbuffers::ForwardsUOffset<::flatbuffers::Vector<'_, Vec3>>>("path", Self::VT_PATH, false)?
.finish();
Ok(())
}
}
pub struct MonsterArgs<'a> {
pub pos: Option<&'a Vec3>,
pub mana: i16,
@@ -220,246 +233,273 @@ pub struct MonsterArgs<'a> {
pub equipped: Option<::flatbuffers::WIPOffset<::flatbuffers::UnionWIPOffset>>,
pub path: Option<::flatbuffers::WIPOffset<::flatbuffers::Vector<'a, Vec3>>>,
}
impl<'a> Default for MonsterArgs<'a> {
#[inline]
fn default() -> Self {
MonsterArgs {
pos: None,
mana: 150,
hp: 100,
name: None,
inventory: None,
color: Color::Blue,
weapons: None,
equipped_type: Equipment::NONE,
equipped: None,
path: None,
#[inline]
fn default() -> Self {
MonsterArgs {
pos: None,
mana: 150,
hp: 100,
name: None,
inventory: None,
color: Color::Blue,
weapons: None,
equipped_type: Equipment::NONE,
equipped: None,
path: None,
}
}
}
}
pub struct MonsterBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> {
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> MonsterBuilder<'a, 'b, A> {
#[inline]
pub fn add_pos(&mut self, pos: &Vec3) {
self.fbb_.push_slot_always::<&Vec3>(Monster::VT_POS, pos);
}
#[inline]
pub fn add_mana(&mut self, mana: i16) {
self.fbb_.push_slot::<i16>(Monster::VT_MANA, mana, 150);
}
#[inline]
pub fn add_hp(&mut self, hp: i16) {
self.fbb_.push_slot::<i16>(Monster::VT_HP, hp, 100);
}
#[inline]
pub fn add_name(&mut self, name: ::flatbuffers::WIPOffset<&'b str>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_NAME, name);
}
#[inline]
pub fn add_inventory(&mut self, inventory: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , u8>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_INVENTORY, inventory);
}
#[inline]
pub fn add_color(&mut self, color: Color) {
self.fbb_.push_slot::<Color>(Monster::VT_COLOR, color, Color::Blue);
}
#[inline]
pub fn add_weapons(&mut self, weapons: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , ::flatbuffers::ForwardsUOffset<Weapon<'b >>>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_WEAPONS, weapons);
}
#[inline]
pub fn add_equipped_type(&mut self, equipped_type: Equipment) {
self.fbb_.push_slot::<Equipment>(Monster::VT_EQUIPPED_TYPE, equipped_type, Equipment::NONE);
}
#[inline]
pub fn add_equipped(&mut self, equipped: ::flatbuffers::WIPOffset<::flatbuffers::UnionWIPOffset>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_EQUIPPED, equipped);
}
#[inline]
pub fn add_path(&mut self, path: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , Vec3>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_PATH, path);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> MonsterBuilder<'a, 'b, A> {
let start = _fbb.start_table();
MonsterBuilder {
fbb_: _fbb,
start_: start,
#[inline]
pub fn add_pos(&mut self, pos: &Vec3) {
self.fbb_.push_slot_always::<&Vec3>(Monster::VT_POS, pos);
}
#[inline]
pub fn add_mana(&mut self, mana: i16) {
self.fbb_.push_slot::<i16>(Monster::VT_MANA, mana, 150);
}
#[inline]
pub fn add_hp(&mut self, hp: i16) {
self.fbb_.push_slot::<i16>(Monster::VT_HP, hp, 100);
}
#[inline]
pub fn add_name(&mut self, name: ::flatbuffers::WIPOffset<&'b str>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_NAME, name);
}
#[inline]
pub fn add_inventory(&mut self, inventory: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , u8>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_INVENTORY, inventory);
}
#[inline]
pub fn add_color(&mut self, color: Color) {
self.fbb_.push_slot::<Color>(Monster::VT_COLOR, color, Color::Blue);
}
#[inline]
pub fn add_weapons(&mut self, weapons: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , ::flatbuffers::ForwardsUOffset<Weapon<'b >>>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_WEAPONS, weapons);
}
#[inline]
pub fn add_equipped_type(&mut self, equipped_type: Equipment) {
self.fbb_.push_slot::<Equipment>(Monster::VT_EQUIPPED_TYPE, equipped_type, Equipment::NONE);
}
#[inline]
pub fn add_equipped(&mut self, equipped: ::flatbuffers::WIPOffset<::flatbuffers::UnionWIPOffset>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_EQUIPPED, equipped);
}
#[inline]
pub fn add_path(&mut self, path: ::flatbuffers::WIPOffset<::flatbuffers::Vector<'b , Vec3>>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Monster::VT_PATH, path);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> MonsterBuilder<'a, 'b, A> {
let start = _fbb.start_table();
MonsterBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Monster<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Monster<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
impl ::core::fmt::Debug for Monster<'_> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Monster");
ds.field("pos", &self.pos());
ds.field("mana", &self.mana());
ds.field("hp", &self.hp());
ds.field("name", &self.name());
ds.field("inventory", &self.inventory());
ds.field("color", &self.color());
ds.field("weapons", &self.weapons());
ds.field("equipped_type", &self.equipped_type());
match self.equipped_type() {
Equipment::Weapon => {
if let Some(x) = self.equipped_as_weapon() {
ds.field("equipped", &x)
} else {
ds.field("equipped", &"InvalidFlatbuffer: Union discriminant does not match value.")
}
},
_ => {
let x: Option<()> = None;
ds.field("equipped", &x)
},
};
ds.field("path", &self.path());
ds.finish()
}
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Monster");
ds.field("pos", &self.pos());
ds.field("mana", &self.mana());
ds.field("hp", &self.hp());
ds.field("name", &self.name());
ds.field("inventory", &self.inventory());
ds.field("color", &self.color());
ds.field("weapons", &self.weapons());
ds.field("equipped_type", &self.equipped_type());
match self.equipped_type() {
Equipment::Weapon => {
if let Some(x) = self.equipped_as_weapon() {
ds.field("equipped", &x)
} else {
ds.field("equipped", &"InvalidFlatbuffer: Union discriminant does not match value.")
}
},
_ => {
let x: Option<()> = None;
ds.field("equipped", &x)
},
};
ds.field("path", &self.path());
ds.finish()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct MonsterT {
pub pos: Option<Vec3T>,
pub mana: i16,
pub hp: i16,
pub name: Option<alloc::string::String>,
pub inventory: Option<alloc::vec::Vec<u8>>,
pub color: Color,
pub weapons: Option<alloc::vec::Vec<WeaponT>>,
pub equipped: EquipmentT,
pub path: Option<alloc::vec::Vec<Vec3T>>,
pub pos: Option<Vec3T>,
pub mana: i16,
pub hp: i16,
pub name: Option<alloc::string::String>,
pub inventory: Option<alloc::vec::Vec<u8>>,
pub color: Color,
pub weapons: Option<alloc::vec::Vec<WeaponT>>,
pub equipped: EquipmentT,
pub path: Option<alloc::vec::Vec<Vec3T>>,
}
impl Default for MonsterT {
fn default() -> Self {
Self {
pos: None,
mana: 150,
hp: 100,
name: None,
inventory: None,
color: Color::Blue,
weapons: None,
equipped: EquipmentT::NONE,
path: None,
fn default() -> Self {
Self {
pos: None,
mana: 150,
hp: 100,
name: None,
inventory: None,
color: Color::Blue,
weapons: None,
equipped: EquipmentT::NONE,
path: None,
}
}
}
}
impl MonsterT {
pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>(
&self,
_fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A>
) -> ::flatbuffers::WIPOffset<Monster<'b>> {
let pos_tmp = self.pos.as_ref().map(|x| x.pack());
let pos = pos_tmp.as_ref();
let mana = self.mana;
let hp = self.hp;
let name = self.name.as_ref().map(|x|{
_fbb.create_string(x)
});
let inventory = self.inventory.as_ref().map(|x|{
_fbb.create_vector(x)
});
let color = self.color;
let weapons = self.weapons.as_ref().map(|x|{
let w: alloc::vec::Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w)
});
let equipped_type = self.equipped.equipment_type();
let equipped = self.equipped.pack(_fbb);
let path = self.path.as_ref().map(|x|{
let w: alloc::vec::Vec<_> = x.iter().map(|t| t.pack()).collect();_fbb.create_vector(&w)
});
Monster::create(_fbb, &MonsterArgs{
pos,
mana,
hp,
name,
inventory,
color,
weapons,
equipped_type,
equipped,
path,
})
}
pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>(
&self,
_fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A>
) -> ::flatbuffers::WIPOffset<Monster<'b>> {
let pos_tmp = self.pos.as_ref().map(|x| x.pack());
let pos = pos_tmp.as_ref();
let mana = self.mana;
let hp = self.hp;
let name = self.name.as_ref().map(|x|{
_fbb.create_string(x)
});
let inventory = self.inventory.as_ref().map(|x|{
_fbb.create_vector(x)
});
let color = self.color;
let weapons = self.weapons.as_ref().map(|x|{
let w: alloc::vec::Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();_fbb.create_vector(&w)
});
let equipped_type = self.equipped.equipment_type();
let equipped = self.equipped.pack(_fbb);
let path = self.path.as_ref().map(|x|{
let w: alloc::vec::Vec<_> = x.iter().map(|t| t.pack()).collect();_fbb.create_vector(&w)
});
Monster::create(_fbb, &MonsterArgs{
pos,
mana,
hp,
name,
inventory,
color,
weapons,
equipped_type,
equipped,
path,
})
}
}
#[inline]
/// Verifies that a buffer of bytes contains a `Monster`
/// and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_monster_unchecked`.
pub fn root_as_monster(buf: &[u8]) -> Result<Monster<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root::<Monster>(buf)
}
#[inline]
pub fn root_as_monster(buf: &[u8]) -> Result<Monster<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root::<Monster>(buf)
}
/// Verifies that a buffer of bytes contains a size prefixed
/// `Monster` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `size_prefixed_root_as_monster_unchecked`.
pub fn size_prefixed_root_as_monster(buf: &[u8]) -> Result<Monster<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root::<Monster>(buf)
}
#[inline]
pub fn size_prefixed_root_as_monster(buf: &[u8]) -> Result<Monster<'_>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root::<Monster>(buf)
}
/// Verifies, with the given options, that a buffer of bytes
/// contains a `Monster` and returns it.
/// Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_monster_unchecked`.
pub fn root_as_monster_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Monster<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root_with_opts::<Monster<'b>>(opts, buf)
}
#[inline]
pub fn root_as_monster_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Monster<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::root_with_opts::<Monster<'b>>(opts, buf)
}
/// Verifies, with the given verifier options, that a buffer of
/// bytes contains a size prefixed `Monster` and returns
/// it. Note that verification is still experimental and may not
/// catch every error, or be maximally performant. For the
/// previous, unchecked, behavior use
/// `root_as_monster_unchecked`.
pub fn size_prefixed_root_as_monster_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Monster<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root_with_opts::<Monster<'b>>(opts, buf)
}
#[inline]
pub fn size_prefixed_root_as_monster_with_opts<'b, 'o>(
opts: &'o ::flatbuffers::VerifierOptions,
buf: &'b [u8],
) -> Result<Monster<'b>, ::flatbuffers::InvalidFlatbuffer> {
::flatbuffers::size_prefixed_root_with_opts::<Monster<'b>>(opts, buf)
}
/// Assumes, without verification, that a buffer of bytes contains a Monster and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid `Monster`.
pub unsafe fn root_as_monster_unchecked(buf: &[u8]) -> Monster<'_> {
unsafe { ::flatbuffers::root_unchecked::<Monster>(buf) }
}
#[inline]
pub unsafe fn root_as_monster_unchecked(buf: &[u8]) -> Monster<'_> {
unsafe { ::flatbuffers::root_unchecked::<Monster>(buf) }
}
/// Assumes, without verification, that a buffer of bytes contains a size prefixed Monster and returns it.
/// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `Monster`.
pub unsafe fn size_prefixed_root_as_monster_unchecked(buf: &[u8]) -> Monster<'_> {
unsafe { ::flatbuffers::size_prefixed_root_unchecked::<Monster>(buf) }
}
#[inline]
pub fn finish_monster_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(
fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
root: ::flatbuffers::WIPOffset<Monster<'a>>) {
fbb.finish(root, None);
pub unsafe fn size_prefixed_root_as_monster_unchecked(buf: &[u8]) -> Monster<'_> {
unsafe { ::flatbuffers::size_prefixed_root_unchecked::<Monster>(buf) }
}
#[inline]
pub fn finish_size_prefixed_monster_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>, root: ::flatbuffers::WIPOffset<Monster<'a>>) {
fbb.finish_size_prefixed(root, None);
pub fn finish_monster_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(
fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
root: ::flatbuffers::WIPOffset<Monster<'a>>
) {
fbb.finish(root, None);
}
#[inline]
pub fn finish_size_prefixed_monster_buffer<'a, 'b, A: ::flatbuffers::Allocator + 'a>(
fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
root: ::flatbuffers::WIPOffset<Monster<'a>>
) {
fbb.finish_size_prefixed(root, None);
}

View File

@@ -2,47 +2,57 @@
// @generated
extern crate alloc;
use super::*;
// struct Vec3, aligned to 4
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq)]
pub struct Vec3(pub [u8; 12]);
impl Default for Vec3 {
fn default() -> Self {
Self([0; 12])
}
impl Default for Vec3 {
fn default() -> Self {
Self([0; 12])
}
}
impl ::core::fmt::Debug for Vec3 {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
f.debug_struct("Vec3")
.field("x", &self.x())
.field("y", &self.y())
.field("z", &self.z())
.finish()
}
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
f.debug_struct("Vec3")
.field("x", &self.x())
.field("y", &self.y())
.field("z", &self.z())
.finish()
}
}
impl ::flatbuffers::SimpleToVerifyInSlice for Vec3 {}
impl<'a> ::flatbuffers::Follow<'a> for Vec3 {
type Inner = &'a Vec3;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe { <&'a Vec3>::follow(buf, loc) }
}
type Inner = &'a Vec3;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe { <&'a Vec3>::follow(buf, loc) }
}
}
impl<'a> ::flatbuffers::Follow<'a> for &'a Vec3 {
type Inner = &'a Vec3;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe { ::flatbuffers::follow_cast_ref::<Vec3>(buf, loc) }
}
type Inner = &'a Vec3;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
unsafe { ::flatbuffers::follow_cast_ref::<Vec3>(buf, loc) }
}
}
impl<'b> ::flatbuffers::Push for Vec3 {
type Output = Vec3;
#[inline]
unsafe fn push(&self, dst: &mut [u8], _written_len: usize) {
let src = unsafe { ::core::slice::from_raw_parts(self as *const Vec3 as *const u8, <Self as ::flatbuffers::Push>::size()) };
dst.copy_from_slice(src);
}
#[inline]
fn alignment() -> ::flatbuffers::PushAlignment {
::flatbuffers::PushAlignment::new(4)
@@ -50,141 +60,150 @@ impl<'b> ::flatbuffers::Push for Vec3 {
}
impl<'a> ::flatbuffers::Verifiable for Vec3 {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.in_buffer::<Self>(pos)
}
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.in_buffer::<Self>(pos)
}
}
impl<'a> Vec3 {
#[allow(clippy::too_many_arguments)]
pub fn new(
x: f32,
y: f32,
z: f32,
) -> Self {
let mut s = Self([0; 12]);
s.set_x(x);
s.set_y(y);
s.set_z(z);
s
}
pub const fn get_fully_qualified_name() -> &'static str {
"MyGame.Sample.Vec3"
}
pub fn x(&self) -> f32 {
let mut mem = ::core::mem::MaybeUninit::<<f32 as ::flatbuffers::EndianScalar>::Scalar>::uninit();
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
::flatbuffers::EndianScalar::from_little_endian(unsafe {
::core::ptr::copy_nonoverlapping(
self.0[0..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
}
pub fn set_x(&mut self, x: f32) {
let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
unsafe {
::core::ptr::copy_nonoverlapping(
&x_le as *const _ as *const u8,
self.0[0..].as_mut_ptr(),
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
#[allow(clippy::too_many_arguments)]
pub fn new(
x: f32,
y: f32,
z: f32,
) -> Self {
let mut s = Self([0; 12]);
s.set_x(x);
s.set_y(y);
s.set_z(z);
s
}
}
pub fn y(&self) -> f32 {
let mut mem = ::core::mem::MaybeUninit::<<f32 as ::flatbuffers::EndianScalar>::Scalar>::uninit();
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
::flatbuffers::EndianScalar::from_little_endian(unsafe {
::core::ptr::copy_nonoverlapping(
self.0[4..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
}
pub fn set_y(&mut self, x: f32) {
let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
unsafe {
::core::ptr::copy_nonoverlapping(
&x_le as *const _ as *const u8,
self.0[4..].as_mut_ptr(),
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
pub const fn get_fully_qualified_name() -> &'static str {
"MyGame.Sample.Vec3"
}
}
pub fn z(&self) -> f32 {
let mut mem = ::core::mem::MaybeUninit::<<f32 as ::flatbuffers::EndianScalar>::Scalar>::uninit();
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
::flatbuffers::EndianScalar::from_little_endian(unsafe {
::core::ptr::copy_nonoverlapping(
self.0[8..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
}
pub fn set_z(&mut self, x: f32) {
let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
unsafe {
::core::ptr::copy_nonoverlapping(
&x_le as *const _ as *const u8,
self.0[8..].as_mut_ptr(),
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
pub fn x(&self) -> f32 {
let mut mem = ::core::mem::MaybeUninit::<<f32 as ::flatbuffers::EndianScalar>::Scalar>::uninit();
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
::flatbuffers::EndianScalar::from_little_endian(unsafe {
::core::ptr::copy_nonoverlapping(
self.0[0..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
}
}
pub fn unpack(&self) -> Vec3T {
Vec3T {
x: self.x(),
y: self.y(),
z: self.z(),
pub fn set_x(&mut self, x: f32) {
let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
unsafe {
::core::ptr::copy_nonoverlapping(
&x_le as *const _ as *const u8,
self.0[0..].as_mut_ptr(),
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
}
}
pub fn y(&self) -> f32 {
let mut mem = ::core::mem::MaybeUninit::<<f32 as ::flatbuffers::EndianScalar>::Scalar>::uninit();
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
::flatbuffers::EndianScalar::from_little_endian(unsafe {
::core::ptr::copy_nonoverlapping(
self.0[4..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
}
pub fn set_y(&mut self, x: f32) {
let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
unsafe {
::core::ptr::copy_nonoverlapping(
&x_le as *const _ as *const u8,
self.0[4..].as_mut_ptr(),
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
}
}
pub fn z(&self) -> f32 {
let mut mem = ::core::mem::MaybeUninit::<<f32 as ::flatbuffers::EndianScalar>::Scalar>::uninit();
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
::flatbuffers::EndianScalar::from_little_endian(unsafe {
::core::ptr::copy_nonoverlapping(
self.0[8..].as_ptr(),
mem.as_mut_ptr() as *mut u8,
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
mem.assume_init()
})
}
pub fn set_z(&mut self, x: f32) {
let x_le = ::flatbuffers::EndianScalar::to_little_endian(x);
// Safety:
// Created from a valid Table for this object
// Which contains a valid value in this slot
unsafe {
::core::ptr::copy_nonoverlapping(
&x_le as *const _ as *const u8,
self.0[8..].as_mut_ptr(),
::core::mem::size_of::<<f32 as ::flatbuffers::EndianScalar>::Scalar>(),
);
}
}
pub fn unpack(&self) -> Vec3T {
Vec3T {
x: self.x(),
y: self.y(),
z: self.z(),
}
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
#[derive(Debug, Clone, PartialEq)]
pub struct Vec3T {
pub x: f32,
pub y: f32,
pub z: f32,
pub x: f32,
pub y: f32,
pub z: f32,
}
impl Vec3T {
pub fn pack(&self) -> Vec3 {
Vec3::new(
self.x,
self.y,
self.z,
)
}
impl Default for Vec3T {
fn default() -> Self {
Self {
x: 0.0,
y: 0.0,
z: 0.0,
}
}
}
impl Vec3T {
pub fn pack(&self) -> Vec3 {
Vec3::new(
self.x,
self.y,
self.z,
)
}
}

View File

@@ -2,159 +2,172 @@
// @generated
extern crate alloc;
use super::*;
pub enum WeaponOffset {}
#[derive(Copy, Clone, PartialEq)]
pub enum WeaponOffset {}
#[derive(Copy, Clone, PartialEq)]
pub struct Weapon<'a> {
pub _tab: ::flatbuffers::Table<'a>,
pub _tab: ::flatbuffers::Table<'a>,
}
impl<'a> ::flatbuffers::Follow<'a> for Weapon<'a> {
type Inner = Weapon<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
type Inner = Weapon<'a>;
#[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: unsafe { ::flatbuffers::Table::new(buf, loc) } }
}
}
impl<'a> Weapon<'a> {
pub const VT_NAME: ::flatbuffers::VOffsetT = 4;
pub const VT_DAMAGE: ::flatbuffers::VOffsetT = 6;
pub const VT_NAME: ::flatbuffers::VOffsetT = 4;
pub const VT_DAMAGE: ::flatbuffers::VOffsetT = 6;
pub const fn get_fully_qualified_name() -> &'static str {
"MyGame.Sample.Weapon"
}
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Weapon { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args WeaponArgs<'args>
) -> ::flatbuffers::WIPOffset<Weapon<'bldr>> {
let mut builder = WeaponBuilder::new(_fbb);
if let Some(x) = args.name { builder.add_name(x); }
builder.add_damage(args.damage);
builder.finish()
}
pub fn unpack(&self) -> WeaponT {
let name = self.name().map(|x| {
alloc::string::ToString::to_string(x)
});
let damage = self.damage();
WeaponT {
name,
damage,
pub const fn get_fully_qualified_name() -> &'static str {
"MyGame.Sample.Weapon"
}
}
#[inline]
pub fn name(&self) -> Option<&'a str> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<&str>>(Weapon::VT_NAME, None)}
}
#[inline]
pub fn damage(&self) -> i16 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i16>(Weapon::VT_DAMAGE, Some(0)).unwrap()}
}
#[inline]
pub unsafe fn init_from_table(table: ::flatbuffers::Table<'a>) -> Self {
Weapon { _tab: table }
}
#[allow(unused_mut)]
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: ::flatbuffers::Allocator + 'bldr>(
_fbb: &'mut_bldr mut ::flatbuffers::FlatBufferBuilder<'bldr, A>,
args: &'args WeaponArgs<'args>
) -> ::flatbuffers::WIPOffset<Weapon<'bldr>> {
let mut builder = WeaponBuilder::new(_fbb);
if let Some(x) = args.name { builder.add_name(x); }
builder.add_damage(args.damage);
builder.finish()
}
pub fn unpack(&self) -> WeaponT {
let name = self.name().map(|x| {
alloc::string::ToString::to_string(x)
});
let damage = self.damage();
WeaponT {
name,
damage,
}
}
#[inline]
pub fn name(&self) -> Option<&'a str> {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<::flatbuffers::ForwardsUOffset<&str>>(Weapon::VT_NAME, None)}
}
#[inline]
pub fn damage(&self) -> i16 {
// Safety:
// Created from valid Table for this object
// which contains a valid value in this slot
unsafe { self._tab.get::<i16>(Weapon::VT_DAMAGE, Some(0)).unwrap()}
}
}
impl ::flatbuffers::Verifiable for Weapon<'_> {
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<::flatbuffers::ForwardsUOffset<&str>>("name", Self::VT_NAME, false)?
.visit_field::<i16>("damage", Self::VT_DAMAGE, false)?
.finish();
Ok(())
}
#[inline]
fn run_verifier(
v: &mut ::flatbuffers::Verifier, pos: usize
) -> Result<(), ::flatbuffers::InvalidFlatbuffer> {
v.visit_table(pos)?
.visit_field::<::flatbuffers::ForwardsUOffset<&str>>("name", Self::VT_NAME, false)?
.visit_field::<i16>("damage", Self::VT_DAMAGE, false)?
.finish();
Ok(())
}
}
pub struct WeaponArgs<'a> {
pub name: Option<::flatbuffers::WIPOffset<&'a str>>,
pub damage: i16,
}
impl<'a> Default for WeaponArgs<'a> {
#[inline]
fn default() -> Self {
WeaponArgs {
name: None,
damage: 0,
#[inline]
fn default() -> Self {
WeaponArgs {
name: None,
damage: 0,
}
}
}
}
pub struct WeaponBuilder<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> {
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
fbb_: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>,
start_: ::flatbuffers::WIPOffset<::flatbuffers::TableUnfinishedWIPOffset>,
}
impl<'a: 'b, 'b, A: ::flatbuffers::Allocator + 'a> WeaponBuilder<'a, 'b, A> {
#[inline]
pub fn add_name(&mut self, name: ::flatbuffers::WIPOffset<&'b str>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Weapon::VT_NAME, name);
}
#[inline]
pub fn add_damage(&mut self, damage: i16) {
self.fbb_.push_slot::<i16>(Weapon::VT_DAMAGE, damage, 0);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> WeaponBuilder<'a, 'b, A> {
let start = _fbb.start_table();
WeaponBuilder {
fbb_: _fbb,
start_: start,
#[inline]
pub fn add_name(&mut self, name: ::flatbuffers::WIPOffset<&'b str>) {
self.fbb_.push_slot_always::<::flatbuffers::WIPOffset<_>>(Weapon::VT_NAME, name);
}
#[inline]
pub fn add_damage(&mut self, damage: i16) {
self.fbb_.push_slot::<i16>(Weapon::VT_DAMAGE, damage, 0);
}
#[inline]
pub fn new(_fbb: &'b mut ::flatbuffers::FlatBufferBuilder<'a, A>) -> WeaponBuilder<'a, 'b, A> {
let start = _fbb.start_table();
WeaponBuilder {
fbb_: _fbb,
start_: start,
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Weapon<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
#[inline]
pub fn finish(self) -> ::flatbuffers::WIPOffset<Weapon<'a>> {
let o = self.fbb_.end_table(self.start_);
::flatbuffers::WIPOffset::new(o.value())
}
}
impl ::core::fmt::Debug for Weapon<'_> {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Weapon");
ds.field("name", &self.name());
ds.field("damage", &self.damage());
ds.finish()
}
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
let mut ds = f.debug_struct("Weapon");
ds.field("name", &self.name());
ds.field("damage", &self.damage());
ds.finish()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq)]
pub struct WeaponT {
pub name: Option<alloc::string::String>,
pub damage: i16,
pub name: Option<alloc::string::String>,
pub damage: i16,
}
impl Default for WeaponT {
fn default() -> Self {
Self {
name: None,
damage: 0,
fn default() -> Self {
Self {
name: None,
damage: 0,
}
}
}
}
impl WeaponT {
pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>(
&self,
_fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A>
) -> ::flatbuffers::WIPOffset<Weapon<'b>> {
let name = self.name.as_ref().map(|x|{
_fbb.create_string(x)
});
let damage = self.damage;
Weapon::create(_fbb, &WeaponArgs{
name,
damage,
})
}
pub fn pack<'b, A: ::flatbuffers::Allocator + 'b>(
&self,
_fbb: &mut ::flatbuffers::FlatBufferBuilder<'b, A>
) -> ::flatbuffers::WIPOffset<Weapon<'b>> {
let name = self.name.as_ref().map(|x|{
_fbb.create_string(x)
});
let damage = self.damage;
Weapon::create(_fbb, &WeaponArgs{
name,
damage,
})
}
}

View File

@@ -33,11 +33,11 @@ result = subprocess.run(
if result.returncode != 0:
print(
"\n"
"ERROR: *********************************************************\n"
"ERROR: * The following differences were found after building. *\n"
"ERROR: * Perhaps there is a difference in the flags for the. *\n"
"ERROR: * CMakeLists.txt vs the script/generate_code.py script? *\n"
"ERROR: *********************************************************\n"
"ERROR: **********************************************************\n"
"ERROR: * The following differences were found after building. *\n"
"ERROR: * Perhaps there is a difference in the flags for the. *\n"
"ERROR: * CMakeLists.txt vs the scripts/generate_code.py script? *\n"
"ERROR: **********************************************************\n"
)
subprocess.run(["git", "diff", "--binary", "--exit-code"], cwd=root_path)
sys.exit(result.returncode)
@@ -55,11 +55,11 @@ result = subprocess.run(
if result.returncode != 0:
print(
"\n"
"ERROR: ********************************************************\n"
"ERROR: * The following differences were found after running *\n"
"ERROR: * the script/generate_code.py script. Maybe you forgot *\n"
"ERROR: * to run it after making changes in a generator? *\n"
"ERROR: ********************************************************\n"
"ERROR: *********************************************************\n"
"ERROR: * The following differences were found after running *\n"
"ERROR: * the scripts/generate_code.py script. Maybe you forgot *\n"
"ERROR: * to run it after making changes in a generator? *\n"
"ERROR: *********************************************************\n"
)
subprocess.run(["git", "diff", "--binary", "--exit-code"], cwd=root_path)
sys.exit(result.returncode)

View File

@@ -85,6 +85,11 @@ RUST_OPTS = BASE_OPTS + [
"--gen-name-strings",
"--rust-module-root-file",
]
RUST_STANDALONE_OPTS = BASE_OPTS + [
"--rust",
"--gen-all",
"--gen-name-strings",
]
RUST_SERIALIZE_OPTS = BASE_OPTS + [
"--rust",
"--gen-all",
@@ -240,6 +245,12 @@ flatc(
],
)
flatc(
BASE_OPTS + CPP_OPTS + ["--cpp-ptr-type", "naked"],
prefix="vector_table_naked_ptr",
schema="vector_table_naked_ptr.fbs",
)
flatc(
BASE_OPTS + CPP_OPTS + CS_OPTS + JAVA_OPTS + KOTLIN_OPTS + PHP_OPTS,
prefix="union_vector",
@@ -282,6 +293,12 @@ flatc(
schema="include_test/include_test1.fbs",
)
flatc(
RUST_STANDALONE_OPTS,
include="include_test",
schema="include_test/include_test1.fbs",
)
flatc(
RUST_OPTS,
prefix="include_test2",
@@ -289,6 +306,12 @@ flatc(
schema="include_test/sub/include_test2.fbs",
)
flatc(
RUST_STANDALONE_OPTS,
include="include_test",
schema="include_test/sub/include_test2.fbs",
)
flatc(
BINARY_OPTS + ["--bfbs-filenames", str(tests_path)],
include="include_test",
@@ -356,13 +379,7 @@ flatc(
)
flatc(
[
"--cpp",
"--gen-compare",
"--gen-mutable",
"--gen-object-api",
"--reflect-names",
],
["--cpp", "--gen-compare", "--gen-mutable", "--gen-object-api", "--reflect-names"],
schema="native_type_test.fbs",
)
@@ -377,6 +394,11 @@ flatc(
schema="native_inline_table_test.fbs",
)
flatc(
["--cpp", "--gen-compare", "--gen-mutable", "--gen-object-api", "--reflect-names"],
schema="cross_namespace_pack_test.fbs",
)
flatc(
RUST_OPTS,
prefix="arrays_test",
@@ -400,6 +422,11 @@ flatc(
schema="nested_union_test.fbs",
)
flatc(
["--python", "--gen-object-api"],
schema="union_name_test.fbs",
)
flatc(
NO_INCL_OPTS + CPP_OPTS,
schema="default_vectors_strings_test.fbs",
@@ -500,6 +527,13 @@ flatc(
cwd=swift_code_gen,
)
flatc(
SWIFT_OPTS_CODE_GEN + BASE_OPTS,
schema="empty_vtable.fbs",
cwd=swift_code_gen,
prefix="../../Tests/Flatbuffers/",
)
# Swift Wasm Tests
swift_Wasm_prefix = "swift/Wasm.tests/Tests/FlatBuffers.Test.Swift.WasmTests"
flatc(

View File

@@ -20,6 +20,7 @@ from util import flatc, root_path
grpc_examples_path = Path(root_path, "grpc/examples")
greeter_schema = str(Path(grpc_examples_path, "greeter.fbs"))
greeter_schema_v2 = str(Path(grpc_examples_path, "greeter_v2.fbs"))
COMMON_ARGS = [
"--grpc",
@@ -54,8 +55,8 @@ def GenerateGRPCExamples():
"--swift",
"--gen-json-emit",
],
schema=greeter_schema,
cwd=Path(grpc_examples_path, "swift/Greeter/Sources/Model"),
schema=greeter_schema_v2,
cwd=Path(grpc_examples_path, "swift/Greeter/Sources/Models"),
)
flatc(

View File

@@ -61,6 +61,7 @@ Namer::Config LuaDefaultConfig() {
/*object_suffix=*/"",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",
@@ -194,6 +195,13 @@ class LuaBfbsGenerator : public BaseBfbsGenerator {
code += "\n";
if (object == root_object) {
// emit file identifier if present
const auto ident = schema_->file_ident();
if (ident && ident->size() == 4) {
code += "local FileIdentifier = \"" + ident->str() + "\"\n";
code += "\n";
}
code += "function " + object_name + ".GetRootAs" + object_name +
"(buf, offset)\n";
code += " if type(buf) == \"string\" then\n";
@@ -454,6 +462,34 @@ class LuaBfbsGenerator : public BaseBfbsGenerator {
code += " return builder:EndObject()\n";
code += "end\n";
code += "\n";
if (object == root_object) {
code += "function " + object_name + ".Finish" + object_name +
"Buffer(builder, offset)\n";
// emit file identifier if present
const auto ident = schema_->file_ident();
if (ident && ident->size() == 4) {
code += " builder:FinishWithIdentifier(offset, FileIdentifier)\n";
} else {
code += " builder:Finish(offset)\n";
}
code += "end\n";
code += "\n";
// size prefixed option
code += "function " + object_name + ".FinishSizePrefixed" +
object_name + "Buffer(builder, offset)\n";
// emit file identifier if present
if (ident && ident->size() == 4) {
code +=
" builder:FinishSizePrefixedWithIdentifier(offset, "
"FileIdentifier)\n";
} else {
code += " builder:FinishSizePrefixed(offset)\n";
}
code += "end\n";
code += "\n";
}
}
EmitCodeBlock(code, object_name, ns, object->declaration_file()->str());

View File

@@ -70,6 +70,7 @@ Namer::Config NimDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",

View File

@@ -126,9 +126,7 @@ static BinarySection GenerateMissingSection(const uint64_t offset,
std::map<uint64_t, BinarySection> BinaryAnnotator::Annotate() {
if (bfbs_ != nullptr && bfbs_length_ != 0) {
flatbuffers::Verifier verifier(bfbs_, static_cast<size_t>(bfbs_length_));
if ((is_size_prefixed_ &&
!reflection::VerifySizePrefixedSchemaBuffer(verifier)) ||
!reflection::VerifySchemaBuffer(verifier)) {
if (!reflection::VerifySchemaBuffer(verifier)) {
return {};
}
}

View File

@@ -265,6 +265,9 @@ const static FlatCOption flatc_options[] = {
{"", "python-gen-numpy", "", "Whether to generate numpy helpers."},
{"", "ts-omit-entrypoint", "",
"Omit emission of namespace entrypoint file"},
{"", "ts-undefined-for-optionals", "",
"Whether to generate undefined values instead of null values for missing "
"optional keys"},
{"", "file-names-only", "",
"Print out generated file names without writing to the files"},
{"", "grpc-filename-suffix", "SUFFIX",
@@ -710,6 +713,8 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc,
opts.python_gen_numpy = false;
} else if (arg == "--ts-omit-entrypoint") {
opts.ts_omit_entrypoint = true;
} else if (arg == "--ts-undefined-for-optionals") {
opts.ts_undefined_for_optionals = true;
} else if (arg == "--annotate-sparse-vectors") {
options.annotate_include_vector_contents = false;
} else if (arg == "--annotate") {
@@ -922,6 +927,9 @@ std::unique_ptr<Parser> FlatCompiler::GenerateCode(const FlatCOptions& options,
auto err = parser->ConformTo(conform_parser);
if (!err.empty()) Error("schemas don\'t conform: " + err, false);
}
if (parser->HasCircularStructDependency()) {
Error("schema has circular struct dependencies: " + filename, false);
}
if (options.schema_binary || opts.binary_schema_gen_embed) {
parser->Serialize();
}

View File

@@ -2779,15 +2779,17 @@ class CppGenerator : public BaseGenerator {
get_call += ">(" + offset_str + ");";
code_ += get_call;
} else if (IsString(type) && field.value.constant != "0") {
// TODO: Add logic to always convert the string to a valid C++ string
// literal by handling string escapes.
std::string escaped;
flatbuffers::EscapeString(field.value.constant.c_str(),
field.value.constant.length(), &escaped,
true, false);
code_ += " auto* ptr = {{FIELD_VALUE}};";
code_ += " if (ptr) return ptr;";
code_ += " static const struct { uint32_t len; const char s[" +
NumToString(field.value.constant.length() + 1) +
"]; } bfbs_string = { " +
NumToString(field.value.constant.length()) + ", \"" +
field.value.constant + "\" };";
NumToString(field.value.constant.length()) + ", " +
escaped + " };";
code_ +=
" return reinterpret_cast<const ::flatbuffers::String "
" *>(&bfbs_string);";
@@ -3417,11 +3419,15 @@ class CppGenerator : public BaseGenerator {
code_.SetValue("CREATE_STRING", "CreateSharedString");
}
if (field->value.constant != "0") {
std::string escaped;
flatbuffers::EscapeString(field->value.constant.c_str(),
field->value.constant.length(), &escaped,
true, false);
code_ +=
" auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
"_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : "
"_fbb.{{CREATE_STRING}}(\"" +
field->value.constant + "\");";
"_fbb.{{CREATE_STRING}}(" +
escaped + ");";
} else {
code_ +=
" auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
@@ -3825,7 +3831,9 @@ class CppGenerator : public BaseGenerator {
code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
code += "(" + value + ".size(), ";
code += "[](size_t i, _VectorArgs *__va) { ";
code += "return Create" + vector_type.struct_def->name;
code += "return " +
WrapInNameSpace(vector_type.struct_def->defined_namespace,
"Create" + vector_type.struct_def->name);
code += "(*__va->__fbb, ";
if (field.native_inline) {
code += "&(__va->_" + value + "[i])";
@@ -3938,8 +3946,10 @@ class CppGenerator : public BaseGenerator {
}
} else {
// _o->field ? CreateT(_fbb, _o->field.get(), _rehasher);
const std::string& type = field.value.type.struct_def->name;
code += value + " ? Create" + type;
const auto& nested_struct = *field.value.type.struct_def;
code += value + " ? " +
WrapInNameSpace(nested_struct.defined_namespace,
"Create" + nested_struct.name);
code += "(_fbb, " + value;
if (!field.native_inline) code += GenPtrGet(field);
code += ", _rehasher) : 0";

View File

@@ -1243,6 +1243,58 @@ class CSharpGenerator : public BaseGenerator {
}
code += " }\n";
}
// Generate Length property and ByteBuffer accessor for arrays in structs.
if (IsArray(field.value.type) && struct_def.fixed &&
IsScalar(field.value.type.VectorType().base_type)) {
auto camel_name = Name(field);
if (camel_name == struct_def.name) { camel_name += "_"; }
// Generate Length constant
code += " public const int " + camel_name;
code += "Length = ";
code += NumToString(field.value.type.fixed_length);
code += ";\n";
// Generate GetBytes methods for scalar arrays (similar to vector pattern)
code += "#if ENABLE_SPAN_T\n";
code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) +
"> Get";
code += camel_name;
code += "Bytes() { return ";
// For byte arrays, we can return the span directly
if (field.value.type.VectorType().base_type == BASE_TYPE_UCHAR) {
code += "__p.bb.ToSpan(__p.bb_pos + ";
code += NumToString(field.value.offset);
code += ", ";
code += NumToString(field.value.type.fixed_length *
SizeOf(field.value.type.VectorType().base_type));
code += ")";
} else {
// For other types, we need to cast the byte span
code += "System.Runtime.InteropServices.MemoryMarshal.Cast<byte, " +
GenTypeBasic(field.value.type.VectorType()) + ">(__p.bb.ToSpan(__p.bb_pos + ";
code += NumToString(field.value.offset);
code += ", ";
code += NumToString(field.value.type.fixed_length *
SizeOf(field.value.type.VectorType().base_type));
code += "))";
}
code += "; }\n";
code += "#else\n";
code += " public ArraySegment<byte>? Get";
code += camel_name;
code += "Bytes() { return ";
code += "__p.bb.ToArraySegment(__p.bb_pos + ";
code += NumToString(field.value.offset);
code += ", ";
code += NumToString(field.value.type.fixed_length *
SizeOf(field.value.type.VectorType().base_type));
code += ");}\n";
code += "#endif\n";
}
// generate object accessors if is nested_flatbuffer
if (field.nested_flatbuffer) {
auto nested_type_name = NamespacedName(*field.nested_flatbuffer);

View File

@@ -48,6 +48,7 @@ static Namer::Config DartDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"$",
/*keyword_suffix=*/"",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",

View File

@@ -368,7 +368,17 @@ static std::string GenerateFBS(const Parser& parser,
if (field.value.type.base_type != BASE_TYPE_UTYPE) {
GenComment(field.doc_comment, &schema, nullptr, " ");
schema += " " + field.name + ":" + GenType(field.value.type);
if (field.value.constant != "0") schema += " = " + field.value.constant;
if (field.value.constant != "0") {
if (IsString(field.value.type)) {
std::string escaped;
flatbuffers::EscapeString(field.value.constant.c_str(),
field.value.constant.length(), &escaped,
true, false);
schema += " = " + escaped;
} else {
schema += " = " + field.value.constant;
}
}
std::vector<std::string> attributes;
if (field.IsRequired()) attributes.push_back("required");
if (field.key) attributes.push_back("key");

View File

@@ -75,6 +75,7 @@ static Namer::Config GoDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",

View File

@@ -46,6 +46,7 @@ static Namer::Config JavaDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",

View File

@@ -64,6 +64,7 @@ static Namer::Config KotlinDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",

View File

@@ -62,6 +62,7 @@ static Namer::Config KotlinDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"E",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kUpperCamel,
/*directories=*/Case::kLowerCamel,
/*output_path=*/"",

View File

@@ -593,6 +593,18 @@ class PythonStubGenerator {
"bytes) -> uoffset: ...\n";
}
}
stub << "def ";
if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
stub << "Create" << namer_.Method(*field)
<< "Vector(builder: flatbuffers.Builder, data: typing.Iterable["
"typing.Any]) -> uoffset: ...\n";
if (!parser_.opts.one_file &&
!parser_.opts.python_no_type_prefix_suffix) {
stub << "def Create" << namer_.Method(*field)
<< "Vector(builder: flatbuffers.Builder, data: "
"typing.Iterable[typing.Any]) -> uoffset: ...\n";
}
}
}
@@ -1467,6 +1479,59 @@ class PythonGenerator : public BaseGenerator {
}
}
void BuildVectorCreationHelper(const StructDef& struct_def,
const FieldDef& field, std::string* code_ptr,
ImportMap& imports) const {
auto& code = *code_ptr;
const auto vector_type = field.value.type.VectorType();
const bool is_struct_vector = IsStruct(vector_type);
const bool is_scalar_vector =
IsScalar(vector_type.base_type) || vector_type.enum_def != nullptr;
const std::string struct_type = namer_.Type(struct_def);
const std::string field_method = namer_.Method(field);
const std::string helper_name =
parser_.opts.python_no_type_prefix_suffix
? "Create" + field_method + "Vector"
: struct_type + "Create" + field_method + "Vector";
if (parser_.opts.python_typing) {
imports.insert(ImportMapEntry{"typing", "Iterable"});
code += "def " + helper_name +
"(builder: flatbuffers.Builder, data: Iterable[Any]) -> int:\n";
} else {
code += "def " + helper_name + "(builder, data):\n";
}
if (is_scalar_vector || is_struct_vector) {
auto alignment = InlineAlignment(vector_type);
auto elem_size = InlineSize(vector_type);
code += Indent + "data = list(data)\n";
code += Indent + "builder.StartVector(" + NumToString(elem_size) +
", len(data), " + NumToString(alignment) + ")\n";
code += Indent + "for item in reversed(data):\n";
if (is_struct_vector) {
code += Indent + Indent + "item.Pack(builder)\n";
} else {
code += Indent + Indent + "builder.Prepend" +
namer_.Method(GenTypeBasic(vector_type)) + "(item)\n";
}
code += Indent + "return builder.EndVector()\n\n";
} else {
code += Indent + "return builder.CreateVectorOfTables(data)\n\n";
}
if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
if (parser_.opts.python_typing) {
code += "def Create" + field_method +
"Vector(builder: flatbuffers.Builder, data: Iterable[Any]) "
"-> int:\n";
} else {
code += "def Create" + field_method + "Vector(builder, data):\n";
}
code += Indent + "return " + helper_name + "(builder, data)\n\n";
}
}
// Set the value of one of the members of a table's vector and fills in the
// elements from a bytearray. This is for simplifying the use of nested
// flatbuffers.
@@ -1617,8 +1682,8 @@ class PythonGenerator : public BaseGenerator {
}
// Generate table constructors, conditioned on its members' types.
void GenTableBuilders(const StructDef& struct_def,
std::string* code_ptr) const {
void GenTableBuilders(const StructDef& struct_def, std::string* code_ptr,
ImportMap& imports) const {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
@@ -1630,6 +1695,7 @@ class PythonGenerator : public BaseGenerator {
BuildFieldOfTable(struct_def, field, offset, code_ptr);
if (IsVector(field.value.type)) {
BuildVectorOfTable(struct_def, field, code_ptr);
BuildVectorCreationHelper(struct_def, field, code_ptr, imports);
BuildVectorOfTableFromBytes(struct_def, field, code_ptr);
}
}
@@ -1696,7 +1762,7 @@ class PythonGenerator : public BaseGenerator {
GenStructBuilder(struct_def, code_ptr);
} else {
// Creates a set of functions that allow table construction.
GenTableBuilders(struct_def, code_ptr);
GenTableBuilders(struct_def, code_ptr, imports);
}
}
@@ -2029,12 +2095,12 @@ class PythonGenerator : public BaseGenerator {
const auto field_method = namer_.Method(field);
const auto struct_var = namer_.Variable(struct_def);
const EnumDef& enum_def = *field.value.type.enum_def;
auto union_type = namer_.Type(enum_def);
auto union_fn = namer_.Function(enum_def);
if (parser_.opts.include_dependence_headers) {
union_type = namer_.NamespacedType(enum_def) + "." + union_type;
union_fn = namer_.NamespacedType(enum_def) + "." + union_fn;
}
code += GenIndents(2) + "self." + field_field + " = " + union_type +
code += GenIndents(2) + "self." + field_field + " = " + union_fn +
"Creator(" + "self." + field_field + "Type, " + struct_var + "." +
field_method + "())";
}
@@ -2405,7 +2471,7 @@ class PythonGenerator : public BaseGenerator {
} else {
GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
code_prefix += "(self." + field_field + "[i])";
code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@ static Namer::Config SwiftDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kKeep,
/*directories=*/Case::kKeep,
/*output_path=*/"",
@@ -163,15 +164,14 @@ class SwiftGenerator : public BaseGenerator {
bool generate() {
code_.Clear();
code_.SetValue("ACCESS", "_accessor");
code_.SetValue("TABLEOFFSET", "VTOFFSET");
code_.SetValue("TABLEOFFSET", "VT");
code_ += "// " + std::string(FlatBuffersGeneratedWarning());
code_ += "// swiftlint:disable all";
code_ += "// swiftformat:disable all\n";
if (parser_.opts.include_dependence_headers || parser_.opts.generate_all) {
code_.SetValue("IMPLEMENTONLY", parser_.opts.swift_implementation_only
? "@_implementationOnly "
: "");
code_.SetValue("IMPLEMENTONLY",
parser_.opts.swift_implementation_only ? "internal " : "");
code_ += "#if canImport(Common)";
code_ += "{{IMPLEMENTONLY}}import Common";
code_ += "#endif";
@@ -281,9 +281,16 @@ class SwiftGenerator : public BaseGenerator {
NumToString(field.value.type.VectorType().fixed_length);
code_.SetValue("FIXEDLENGTH", fixed_length);
const auto vector_base_type = IsStruct(field.value.type.VectorType())
? (type + "()")
: SwiftConstant(field);
std::string vector_base_type;
if (IsStruct(field.value.type.VectorType())) {
vector_base_type = type + "()";
} else if (IsBool(field.value.type.VectorType().base_type)) {
vector_base_type = "false";
} else if (IsFloat(field.value.type.VectorType().base_type)) {
vector_base_type = "0.0";
} else {
vector_base_type = SwiftConstant(field);
}
code_ += "private var _{{FIELDVAR}}: InlineArray<{{FIXEDLENGTH}}, " +
valueType + ">";
@@ -517,7 +524,7 @@ class SwiftGenerator : public BaseGenerator {
void GenTableAccessors(const StructDef& struct_def) {
// Generate field id constants.
if (struct_def.fields.vec.size() > 0) {
code_ += "private enum {{TABLEOFFSET}}: VOffset {";
code_ += "private struct {{TABLEOFFSET}} {";
Indent();
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
@@ -527,10 +534,8 @@ class SwiftGenerator : public BaseGenerator {
}
code_.SetValue("OFFSET_NAME", namer_.Variable(field));
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}";
code_ += "static let {{OFFSET_NAME}}: VOffset = {{OFFSET_VALUE}}";
}
code_ += "var v: Int32 { Int32(self.rawValue) }";
code_ += "var p: VOffset { self.rawValue }";
Outdent();
code_ += "}";
code_ += "";
@@ -543,13 +548,14 @@ class SwiftGenerator : public BaseGenerator {
code_.SetValue("SHORT_STRUCTNAME", namer_.Type(struct_def));
code_.SetValue("STRUCTNAME", namer_.NamespacedType(struct_def));
code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table");
code_.SetValue("PROTOCOL", struct_def.fixed ? "FlatBufferStruct"
: "FlatBufferVerifiableTable");
code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : "");
GenOSVersionChecks();
code_ +=
"{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: "
"FlatBuffer{{OBJECTTYPE}}, FlatbuffersVectorInitializable\\";
if (!struct_def.fixed) code_ += ", Verifiable\\";
"{{PROTOCOL}}, FlatbuffersVectorInitializable\\";
if (!struct_def.fixed && parser_.opts.generate_object_based_api)
code_ += ", ObjectAPIPacker\\";
code_ += " {\n";
@@ -619,7 +625,8 @@ class SwiftGenerator : public BaseGenerator {
if (should_generate_create) {
code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(";
Indent();
code_ += "_ fbb: inout FlatBufferBuilder,";
code_ += "_ fbb: inout FlatBufferBuilder\\";
if (create_func_header.empty() == false) code_ += ",";
for (auto it = create_func_header.begin(); it < create_func_header.end();
++it) {
code_ += *it + "\\";
@@ -698,7 +705,7 @@ class SwiftGenerator : public BaseGenerator {
code_ += field.IsOptional() ? (optional_enum + "\\")
: (is_enum + ", def: {{CONSTANT}}\\");
code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}) }";
const auto default_value =
IsEnum(field.value.type)
@@ -718,7 +725,7 @@ class SwiftGenerator : public BaseGenerator {
code_ +=
"{{VALUETYPE}}" + builder_string + "fbb.add(element: {{FIELDVAR}},\\";
code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},";
code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}) }";
create_func_header.push_back(
field_var + ": " + nullable_type + " = " +
(field.IsOptional() ? "nil" : default_value));
@@ -729,7 +736,7 @@ class SwiftGenerator : public BaseGenerator {
const auto create_struct =
"guard let {{FIELDVAR}} = {{FIELDVAR}} else { return };"
" fbb.create(struct: {{FIELDVAR}}, position: "
"{{TABLEOFFSET}}.{{OFFSET}}.p) }";
"{{TABLEOFFSET}}.{{OFFSET}}) }";
code_ += type + "?" + builder_string + create_struct;
/// Optional hard coded since structs are always optional
create_func_header.push_back(field_var + ": " + type +
@@ -746,8 +753,9 @@ class SwiftGenerator : public BaseGenerator {
(field.IsRequired() ? "" : " = Offset()"));
const auto reader_type =
IsStruct(field.value.type) && field.value.type.struct_def->fixed
? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }"
: "offset: {{FIELDVAR}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }";
? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}) }"
: "offset: {{FIELDVAR}}, at: {{TABLEOFFSET}}.{{OFFSET}}) "
"}";
code_ += "Offset" + builder_string + "fbb.add(" + reader_type;
const auto vectortype = field.value.type.VectorType();
@@ -851,7 +859,10 @@ class SwiftGenerator : public BaseGenerator {
break;
case BASE_TYPE_STRING: {
const auto default_string = "\"" + SwiftConstant(field) + "\"";
const auto sc = SwiftConstant(field);
std::string default_string;
flatbuffers::EscapeString(sc.c_str(), sc.length(), &default_string,
true, false);
code_.SetValue("VALUETYPE", GenType(field.value.type));
code_.SetValue("CONSTANT", field.IsDefault() ? default_string : "nil");
code_ += GenReaderMainBody(is_required) + GenOffset() +
@@ -859,7 +870,7 @@ class SwiftGenerator : public BaseGenerator {
code_ += "{{ACCESS_TYPE}} var {{FIELDVAR}}SegmentArray: [UInt8]" +
is_required +
" { return "
"{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }";
"{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}) }";
break;
}
case BASE_TYPE_ARRAY:
@@ -893,7 +904,7 @@ class SwiftGenerator : public BaseGenerator {
code_ +=
"{{ACCESS_TYPE}} var {{FIELDVAR}}: "
"FlatbufferVector<{{VALUETYPE}}> "
"{ return {{ACCESS}}.vector(at: {{TABLEOFFSET}}.{{OFFSET}}.v, "
"{ return {{ACCESS}}.vector(at: {{TABLEOFFSET}}.{{OFFSET}}, "
"byteSize: {{SIZE}}) }";
}
@@ -910,7 +921,7 @@ class SwiftGenerator : public BaseGenerator {
code_ +=
"{{ACCESS_TYPE}} var {{FIELDVAR}}: "
"FlatbufferVector<{{VALUETYPE}}_Mutable> "
"{ return {{ACCESS}}.vector(at: {{TABLEOFFSET}}.{{OFFSET}}.v, "
"{ return {{ACCESS}}.vector(at: {{TABLEOFFSET}}.{{OFFSET}}, "
"byteSize: {{SIZE}}) }";
GenUnsafeBufferPointer(field);
return;
@@ -919,7 +930,8 @@ class SwiftGenerator : public BaseGenerator {
if (vectortype.base_type == BASE_TYPE_UNION) {
code_ +=
"{{ACCESS_TYPE}} var {{FIELDVAR}}: UnionFlatbufferVector "
"{ return {{ACCESS}}.unionVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v, "
"{ return {{ACCESS}}.unionVector(at: "
"{{TABLEOFFSET}}.{{OFFSET}}, "
"byteSize: {{SIZE}}) }";
code_ +=
"{{ACCESS_TYPE}} func {{FIELDVAR}}<T: FlatbuffersInitializable>(at "
@@ -953,24 +965,21 @@ class SwiftGenerator : public BaseGenerator {
"{{ACCESS_TYPE}} func {{functionName}}<T>(_ body: "
"(UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T? { return "
"try "
"{{ACCESS}}.withUnsafePointerToSlice(at: {{TABLEOFFSET}}.{{OFFSET}}.v, "
"{{ACCESS}}.withUnsafePointerToSlice(at: "
"{{TABLEOFFSET}}.{{OFFSET}}, "
"body: body) }";
}
void GenerateCodingKeys(const StructDef& struct_def) {
code_ += "enum CodingKeys: String, CodingKey {";
Indent();
std::vector<std::string> GenerateCodingKeys(const StructDef& struct_def) {
std::vector<std::string> coding_keys;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
const auto& field = **it;
if (field.deprecated) continue;
code_.SetValue("RAWVALUENAME", field.name);
code_.SetValue("FIELDVAR", namer_.Variable(field));
code_ += "case {{FIELDVAR}} = \"{{RAWVALUENAME}}\"";
coding_keys.push_back("case " + namer_.Variable(field) + " = \"" +
field.name + "\"");
}
Outdent();
code_ += "}";
return coding_keys;
}
void GenerateEncoderUnionBody(const FieldDef& field) {
@@ -1092,14 +1101,31 @@ class SwiftGenerator : public BaseGenerator {
GenOSVersionChecks();
code_ += "extension {{STRUCTNAME}}: Encodable {";
Indent();
code_ += "";
if (struct_def.fields.vec.empty() == false) GenerateCodingKeys(struct_def);
auto coding_keys = GenerateCodingKeys(struct_def);
if (coding_keys.empty() == false) {
code_ += "enum CodingKeys: String, CodingKey {";
Indent();
for (auto it = coding_keys.begin(); it != coding_keys.end(); ++it) {
const auto& field = *it;
code_ += field;
}
Outdent();
code_ += "}";
code_ += "";
}
code_ += "{{ACCESS_TYPE}} func encode(to encoder: Encoder) throws {";
Indent();
if (struct_def.fields.vec.empty() == false) GenerateEncoderBody(struct_def);
Outdent();
if (coding_keys.empty() == false) {
Indent();
GenerateEncoderBody(struct_def);
Outdent();
}
code_ += "}";
Outdent();
code_ += "}";
code_ += "";
@@ -1129,7 +1155,7 @@ class SwiftGenerator : public BaseGenerator {
}
code_ +=
"try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}.p, fieldName: "
"try _v.visit(field: {{TABLEOFFSET}}.{{OFFSET}}, fieldName: "
"\"{{FIELDVAR}}\", required: {{ISREQUIRED}}, type: "
"{{VALUETYPE}}.self)";
}
@@ -1149,8 +1175,9 @@ class SwiftGenerator : public BaseGenerator {
code_.SetValue("VALUETYPE", namer_.NamespacedType(union_def));
code_.SetValue("FUNCTION_NAME", is_vector ? "visitUnionVector" : "visit");
code_ +=
"try _v.{{FUNCTION_NAME}}(unionKey: {{TABLEOFFSET}}.{{OFFSET}}Type.p, "
"unionField: {{TABLEOFFSET}}.{{OFFSET}}.p, unionKeyName: "
"try _v.{{FUNCTION_NAME}}(unionKey: "
"{{TABLEOFFSET}}.{{OFFSET}}Type, "
"unionField: {{TABLEOFFSET}}.{{OFFSET}}, unionKeyName: "
"\"{{FIELDVAR}}Type\", fieldName: \"{{FIELDVAR}}\", required: "
"{{ISREQUIRED}}, completion: { (verifier, key: {{VALUETYPE}}, pos) in";
Indent();
@@ -1625,15 +1652,23 @@ class SwiftGenerator : public BaseGenerator {
buffer_constructor.push_back(field_var + " = _t." + field_field);
if (field.IsRequired()) {
std::string default_value =
field.IsDefault() ? SwiftConstant(field) : "";
base_constructor.push_back(field_var + " = \"" + default_value +
"\"");
std::string default_value;
if (field.IsDefault()) {
const auto sc = SwiftConstant(field);
flatbuffers::EscapeString(sc.c_str(), sc.length(), &default_value,
true, false);
} else {
default_value = "\"\"";
}
base_constructor.push_back(field_var + " = " + default_value);
break;
}
if (field.IsDefault() && !field.IsRequired()) {
std::string value = field.IsDefault() ? SwiftConstant(field) : "nil";
base_constructor.push_back(field_var + " = \"" + value + "\"");
const auto sc = SwiftConstant(field);
std::string value;
flatbuffers::EscapeString(sc.c_str(), sc.length(), &value,
true, false);
base_constructor.push_back(field_var + " = " + value);
}
break;
}
@@ -1892,7 +1927,7 @@ class SwiftGenerator : public BaseGenerator {
}
std::string GenOffset() {
return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); ";
return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}); ";
}
std::string GenReaderMainBody(const std::string& optional = "") {
@@ -1962,7 +1997,7 @@ class SwiftGenerator : public BaseGenerator {
std::string GenType(const Type& type,
const bool should_consider_suffix = false) const {
return IsScalar(type.base_type) ? GenTypeBasic(type)
: IsArray(type) ? GenType(type.VectorType())
: IsArray(type) ? GenType(type.VectorType())
: GenTypePointer(type, should_consider_suffix);
}

View File

@@ -67,6 +67,7 @@ Namer::Config TypeScriptDefaultConfig() {
/*object_suffix=*/"T",
/*keyword_prefix=*/"",
/*keyword_suffix=*/"_",
/*keywords_casing=*/Namer::Config::KeywordsCasing::CaseSensitive,
/*filenames=*/Case::kDasher,
/*directories=*/Case::kDasher,
/*output_path=*/"",
@@ -86,6 +87,7 @@ std::set<std::string> TypescriptKeywords() {
"throw", "true", "try", "typeof", "var", "void",
"while", "with", "as", "implements", "interface", "let",
"package", "private", "protected", "public", "static", "yield",
"undefined" // Used with --ts-undefined-for-optionals
};
}
@@ -110,7 +112,9 @@ class TsGenerator : public BaseGenerator {
const std::string& file_name)
: BaseGenerator(parser, path, file_name, "", "_", "ts"),
namer_(WithFlagOptions(TypeScriptDefaultConfig(), parser.opts, path),
TypescriptKeywords()) {}
TypescriptKeywords()),
null_keyword_(parser_.opts.ts_undefined_for_optionals ? "undefined"
: "null") {}
bool generate() {
generateEnums();
@@ -214,6 +218,8 @@ class TsGenerator : public BaseGenerator {
std::map<std::string, NsDefinition> ns_defs_;
std::string null_keyword_;
// Generate code for all enums.
void generateEnums() {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
@@ -318,9 +324,10 @@ class TsGenerator : public BaseGenerator {
export_counter++;
}
if (export_counter > 0)
if (export_counter > 0) {
parser_.opts.file_saver->SaveFile(it.second.filepath.c_str(), code,
false);
}
}
}
@@ -467,7 +474,7 @@ class TsGenerator : public BaseGenerator {
std::string GenDefaultValue(const FieldDef& field, import_set& imports) {
if (field.IsScalarOptional()) {
return "null";
return null_keyword_;
}
const auto& value = field.value;
@@ -515,10 +522,23 @@ class TsGenerator : public BaseGenerator {
case BASE_TYPE_BOOL:
return value.constant == "0" ? "false" : "true";
case BASE_TYPE_STRING:
case BASE_TYPE_STRING: {
// NOTE: Strings without a default value are parsed as "0" by
// the parser, so therefore we have to treat "0" as a null-signifying
// value.
if (value.constant == "0" || value.constant == "null") {
return "null";
} else {
std::string escaped;
flatbuffers::EscapeString(value.constant.c_str(),
value.constant.length(), &escaped,
true, false);
return escaped;
}
}
case BASE_TYPE_UNION:
case BASE_TYPE_STRUCT: {
return "null";
return null_keyword_;
}
case BASE_TYPE_ARRAY:
@@ -554,16 +574,16 @@ class TsGenerator : public BaseGenerator {
} else {
name = AddImport(imports, owner, *type.struct_def).name;
}
return allowNull ? (name + "|null") : name;
return allowNull ? (name + "|" + null_keyword_) : name;
}
}
switch (type.base_type) {
case BASE_TYPE_BOOL:
return allowNull ? "boolean|null" : "boolean";
return allowNull ? ("boolean|" + null_keyword_) : "boolean";
case BASE_TYPE_LONG:
case BASE_TYPE_ULONG:
return allowNull ? "bigint|null" : "bigint";
return allowNull ? ("bigint|" + null_keyword_) : "bigint";
case BASE_TYPE_ARRAY: {
std::string name;
if (type.element == BASE_TYPE_LONG || type.element == BASE_TYPE_ULONG) {
@@ -578,16 +598,16 @@ class TsGenerator : public BaseGenerator {
}
}
return name + (allowNull ? "|null" : "");
return name + (allowNull ? ("|" + null_keyword_) : "");
}
default:
if (IsScalar(type.base_type)) {
if (type.enum_def) {
const auto enum_name =
AddImport(imports, owner, *type.enum_def).name;
return allowNull ? (enum_name + "|null") : enum_name;
return allowNull ? (enum_name + "|" + null_keyword_) : enum_name;
}
return allowNull ? "number|null" : "number";
return allowNull ? ("number|" + null_keyword_) : "number";
}
return "flatbuffers.Offset";
}
@@ -641,7 +661,8 @@ class TsGenerator : public BaseGenerator {
}
void GenStructArgs(import_set& imports, const StructDef& struct_def,
std::string* arguments, const std::string& nameprefix) {
const Definition& owner, std::string* arguments,
const std::string& nameprefix) {
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end(); ++it) {
auto& field = **it;
@@ -649,11 +670,11 @@ class TsGenerator : public BaseGenerator {
// Generate arguments for a struct inside a struct. To ensure names
// don't clash, and to make it obvious these arguments are constructing
// a nested struct, prefix the name with the field name.
GenStructArgs(imports, *field.value.type.struct_def, arguments,
GenStructArgs(imports, *field.value.type.struct_def, owner, arguments,
nameprefix + field.name + "_");
} else {
*arguments += ", " + nameprefix + field.name + ": " +
GenTypeName(imports, field, field.value.type, true,
GenTypeName(imports, owner, field.value.type, true,
field.IsOptional());
}
}
@@ -915,6 +936,48 @@ class TsGenerator : public BaseGenerator {
return symbols_expression;
}
std::vector<std::string> PathComponents(const std::string& path) const {
std::vector<std::string> components;
size_t start = 0;
while (start < path.size()) {
auto end = path.find(kPathSeparator, start);
if (end == std::string::npos) end = path.size();
if (end > start) {
components.emplace_back(path.substr(start, end - start));
}
if (end == path.size()) break;
start = end + 1;
}
return components;
}
std::string RelativeDirectory(const std::vector<std::string>& from,
const std::vector<std::string>& to) const {
size_t common = 0;
while (common < from.size() && common < to.size() &&
from[common] == to[common]) {
++common;
}
std::string rel;
const size_t ups = from.size() - common;
if (ups == 0) {
rel = ".";
} else {
for (size_t i = 0; i < ups; ++i) {
if (!rel.empty()) rel += kPathSeparator;
rel += "..";
}
}
for (size_t i = common; i < to.size(); ++i) {
if (!rel.empty()) rel += kPathSeparator;
rel += to[i];
}
return rel;
}
template <typename DefinitionT>
ImportDefinition AddImport(import_set& imports, const Definition& dependent,
const DefinitionT& dependency) {
@@ -942,26 +1005,32 @@ class TsGenerator : public BaseGenerator {
const std::string symbols_expression = GenSymbolExpression(
dependency, has_name_clash, import_name, name, object_name);
std::string bare_file_path;
std::string rel_file_path;
if (dependent.defined_namespace) {
const auto& dep_comps = dependent.defined_namespace->components;
for (size_t i = 0; i < dep_comps.size(); i++) {
rel_file_path += i == 0 ? ".." : (kPathSeparator + std::string(".."));
}
if (dep_comps.size() == 0) {
rel_file_path += ".";
}
} else {
rel_file_path += "..";
}
const Namespace* dependent_ns = dependent.defined_namespace
? dependent.defined_namespace
: parser_.empty_namespace_;
const Namespace* dependency_ns = dependency.defined_namespace
? dependency.defined_namespace
: parser_.empty_namespace_;
bare_file_path +=
kPathSeparator +
namer_.Directories(dependency.defined_namespace->components,
SkipDir::OutputPath) +
const std::string dependent_dirs =
namer_.Directories(*dependent_ns, SkipDir::OutputPath);
const std::string dependency_dirs =
namer_.Directories(*dependency_ns, SkipDir::OutputPath);
const auto dependent_components = PathComponents(dependent_dirs);
const auto dependency_components = PathComponents(dependency_dirs);
std::string rel_dir =
RelativeDirectory(dependent_components, dependency_components);
if (rel_dir.empty()) rel_dir = ".";
if (!rel_dir.empty()) rel_dir += kPathSeparator;
std::string rel_file_path =
rel_dir + namer_.File(dependency, SkipFile::SuffixAndExtension);
std::string bare_file_path =
kPathSeparator + dependency_dirs +
namer_.File(dependency, SkipFile::SuffixAndExtension);
rel_file_path += bare_file_path;
ImportDefinition import;
import.name = name;
@@ -1039,7 +1108,8 @@ class TsGenerator : public BaseGenerator {
const auto& enum_def = *union_type.enum_def;
const auto valid_union_type = GenUnionTypeTS(enum_def, imports);
const auto valid_union_type_with_null = valid_union_type + "|null";
const auto valid_union_type_with_null =
valid_union_type + "|" + null_keyword_;
auto ret = "\n\nexport function " + GenUnionConvFuncName(enum_def) +
"(\n type: " + GetTypeName(enum_def) +
@@ -1051,7 +1121,7 @@ class TsGenerator : public BaseGenerator {
const auto union_enum_loop = [&](const std::string& accessor_str) {
ret += " switch(" + enum_type + "[type]) {\n";
ret += " case 'NONE': return null; \n";
ret += " case 'NONE': return " + null_keyword_ + "; \n";
for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
++it) {
@@ -1075,7 +1145,7 @@ class TsGenerator : public BaseGenerator {
ret += "\n";
}
ret += " default: return null;\n";
ret += " default: return " + null_keyword_ + ";\n";
ret += " }\n";
};
@@ -1120,7 +1190,8 @@ class TsGenerator : public BaseGenerator {
ret += " const temp = " + conversion_function + "(this." +
namer_.Method(field_name, "Type") + "(), " +
field_binded_method + ");\n";
ret += " if(temp === null) { return null; }\n";
ret += " if(temp === " + null_keyword_ + ") { return " +
null_keyword_ + "; }\n";
ret += union_has_string
? " if(typeof temp === 'string') { return temp; }\n"
: "";
@@ -1140,12 +1211,12 @@ class TsGenerator : public BaseGenerator {
"++targetEnumIndex) {\n";
ret += " const targetEnum = this." +
namer_.Method(field_name, "Type") + "(targetEnumIndex);\n";
ret += " if(targetEnum === null || " + enum_type +
ret += " if(targetEnum === " + null_keyword_ + " || " + enum_type +
"[targetEnum!] === 'NONE') { "
"continue; }\n\n";
ret += " const temp = " + conversion_function + "(targetEnum, " +
field_binded_method + ", targetEnumIndex);\n";
ret += " if(temp === null) { continue; }\n";
ret += " if(temp === " + null_keyword_ + ") { continue; }\n";
ret += union_has_string ? " if(typeof temp === 'string') { "
"ret.push(temp); continue; }\n"
: "";
@@ -1162,11 +1233,12 @@ class TsGenerator : public BaseGenerator {
return "";
}
static std::string GenNullCheckConditional(
const std::string& nullCheckVar, const std::string& trueVal,
const std::string& falseVal = "null") {
return "(" + nullCheckVar + " !== null ? " + trueVal + " : " + falseVal +
")";
std::string GenNullCheckConditional(const std::string& nullCheckVar,
const std::string& trueVal,
const std::string& falseVal = "") {
std::string false_val = falseVal.empty() ? null_keyword_ : falseVal;
return "(" + nullCheckVar + " !== " + null_keyword_ + " ? " + trueVal +
" : " + false_val + ")";
}
std::string GenStructMemberValueTS(const StructDef& struct_def,
@@ -1275,10 +1347,9 @@ class TsGenerator : public BaseGenerator {
// Emit a scalar field
const auto is_string = IsString(field.value.type);
if (IsScalar(field.value.type.base_type) || is_string) {
const auto has_null_default = is_string || HasNullDefault(field);
field_type += GenTypeName(imports, field, field.value.type, false,
has_null_default);
field_type +=
GenTypeName(imports, field, field.value.type, false,
!HasDefaultValue(field) || HasNullDefault(field));
field_val = "this." + namer_.Method(field) + "()";
if (field.value.type.base_type != BASE_TYPE_STRING) {
@@ -1300,8 +1371,8 @@ class TsGenerator : public BaseGenerator {
const std::string field_accessor =
"this." + namer_.Method(field) + "()";
field_val = GenNullCheckConditional(field_accessor,
field_accessor + "!.unpack()");
field_val = GenNullCheckConditional(
field_accessor, field_accessor + "!.unpack()", null_keyword_);
auto packing = GenNullCheckConditional(
"this." + field_field,
"this." + field_field + "!.pack(builder)", "0");
@@ -1509,8 +1580,8 @@ class TsGenerator : public BaseGenerator {
break;
}
// length 0 vector is simply empty instead of null
field_type += is_vector ? "" : "|null";
// length 0 vector is simply empty instead of null/undefined.
field_type += is_vector ? "" : ("|" + null_keyword_);
}
if (!field_offset_decl.empty()) {
@@ -1539,7 +1610,7 @@ class TsGenerator : public BaseGenerator {
} else {
if (field.IsScalarOptional()) {
pack_func_create_call +=
" if (" + field_offset_val + " !== null)\n ";
" if (" + field_offset_val + " !== " + null_keyword_ + ")\n ";
}
pack_func_create_call += " " + struct_name + "." +
namer_.Method("add", field) + "(builder, " +
@@ -1624,12 +1695,14 @@ class TsGenerator : public BaseGenerator {
GenDocComment(struct_def.doc_comment, code_ptr);
code += "export class ";
code += object_name;
if (parser.opts.generate_object_based_api)
if (parser.opts.generate_object_based_api) {
code += " implements flatbuffers.IUnpackableObject<" + object_api_name +
"> {\n";
else
} else {
code += " {\n";
code += " bb: flatbuffers.ByteBuffer|null = null;\n";
}
code += " bb: flatbuffers.ByteBuffer|" + null_keyword_ + " = " +
null_keyword_ + ";\n";
code += " bb_pos = 0;\n";
// Generate the __init method that sets the field in a pre-existing
@@ -1670,21 +1743,22 @@ class TsGenerator : public BaseGenerator {
offset_prefix = " const offset = " + GenBBAccess() +
".__offset(this.bb_pos, " +
NumToString(field.value.offset) + ");\n";
offset_prefix += " return offset ? ";
offset_prefix += " return ";
}
// Emit a scalar field
const auto is_string = IsString(field.value.type);
if (IsScalar(field.value.type.base_type) || is_string) {
const auto has_null_default = is_string || HasNullDefault(field);
const auto has_null_default =
!field.IsRequired() && !HasDefaultValue(field);
GenDocComment(field.doc_comment, code_ptr);
std::string prefix = namer_.Method(field) + "(";
if (is_string) {
code += prefix + "):string|null\n";
code += prefix + "):" + (has_null_default ? "string|" + null_keyword_ : "string") + "\n";
code +=
prefix + "optionalEncoding:flatbuffers.Encoding" + "):" +
GenTypeName(imports, struct_def, field.value.type, false, true) +
GenTypeName(imports, struct_def, field.value.type, false, has_null_default) +
"\n";
code += prefix + "optionalEncoding?:any";
} else {
@@ -1713,9 +1787,16 @@ class TsGenerator : public BaseGenerator {
if (is_string) {
index += ", optionalEncoding";
}
code +=
offset_prefix + GenGetter(field.value.type, "(" + index + ")");
if (field.value.type.base_type != BASE_TYPE_ARRAY) {
if (field.IsRequired()) {
code +=
offset_prefix + GenGetter(field.value.type, "(" + index + ")");
;
} else {
code += offset_prefix + "offset ? " +
GenGetter(field.value.type, "(" + index + ")");
}
if (field.value.type.base_type != BASE_TYPE_ARRAY &&
!field.IsRequired()) {
code += " : " + GenDefaultValue(field, imports);
}
code += ";\n";
@@ -1731,7 +1812,8 @@ class TsGenerator : public BaseGenerator {
.name;
GenDocComment(field.doc_comment, code_ptr);
code += namer_.Method(field);
code += "(obj?:" + type + "):" + type + "|null {\n";
code +=
"(obj?:" + type + "):" + type + "|" + null_keyword_ + " {\n";
if (struct_def.fixed) {
code += " return (obj || " + GenerateNewExpression(type);
@@ -1739,12 +1821,12 @@ class TsGenerator : public BaseGenerator {
code +=
MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n";
} else {
code += offset_prefix + "(obj || " + GenerateNewExpression(type) +
").__init(";
code += offset_prefix + "offset ? (obj || " +
GenerateNewExpression(type) + ").__init(";
code += field.value.type.struct_def->fixed
? "this.bb_pos + offset"
: GenBBAccess() + ".__indirect(this.bb_pos + offset)";
code += ", " + GenBBAccess() + ") : null;\n";
code += ", " + GenBBAccess() + ") : " + null_keyword_ + ";\n";
}
break;
@@ -1797,7 +1879,7 @@ class TsGenerator : public BaseGenerator {
} else {
code += prefix;
}
code += "):" + vectortypename + "|null {\n";
code += "):" + vectortypename + "|" + null_keyword_ + " {\n";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += offset_prefix + "(obj || " +
@@ -1837,7 +1919,7 @@ class TsGenerator : public BaseGenerator {
code += " : 0";
}
} else {
code += ": null";
code += ": " + null_keyword_;
}
break;
}
@@ -1895,10 +1977,10 @@ class TsGenerator : public BaseGenerator {
} else {
code += prefix;
}
code += "):" + vectortypename + "|null {\n";
code += "):" + vectortypename + "|" + null_keyword_ + " {\n";
if (vectortype.base_type == BASE_TYPE_STRUCT) {
code += offset_prefix + "(obj || " +
code += offset_prefix + "offset ? (obj || " +
GenerateNewExpression(vectortypename);
code += ").__init(";
code += vectortype.struct_def->fixed
@@ -1911,7 +1993,8 @@ class TsGenerator : public BaseGenerator {
} else if (IsString(vectortype)) {
index += ", optionalEncoding";
}
code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
code += offset_prefix + "offset ? " +
GenGetter(vectortype, "(" + index + ")");
}
code += " : ";
if (field.value.type.element == BASE_TYPE_BOOL) {
@@ -1921,12 +2004,12 @@ class TsGenerator : public BaseGenerator {
code += "BigInt(0)";
} else if (IsScalar(field.value.type.element)) {
if (field.value.type.enum_def) {
code += "null";
code += null_keyword_;
} else {
code += "0";
}
} else {
code += "null";
code += null_keyword_;
}
code += ";\n";
break;
@@ -1939,13 +2022,13 @@ class TsGenerator : public BaseGenerator {
const auto& union_enum = *(field.value.type.enum_def);
const auto union_type = GenUnionGenericTypeTS(union_enum);
code += "<T extends flatbuffers.Table>(obj:" + union_type +
"):" + union_type +
"|null "
"):" + union_type + "|" + null_keyword_ +
" "
"{\n";
code += offset_prefix +
code += offset_prefix + "offset ? " +
GenGetter(field.value.type, "(obj, this.bb_pos + offset)") +
" : null;\n";
" : " + null_keyword_ + ";\n";
break;
}
default:
@@ -1996,7 +2079,7 @@ class TsGenerator : public BaseGenerator {
// Emit a length helper
GenDocComment(code_ptr);
code += namer_.Method(field, "Length");
code += "():number {\n" + offset_prefix;
code += "():number {\n" + offset_prefix + "offset ? ";
code +=
GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n}\n\n";
@@ -2007,14 +2090,30 @@ class TsGenerator : public BaseGenerator {
GenDocComment(code_ptr);
code += namer_.Method(field, "Array");
code +=
"():" + GenType(vectorType) + "Array|null {\n" + offset_prefix;
code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() +
".bytes().buffer, " + GenBBAccess() +
".bytes().byteOffset + " + GenBBAccess() +
".__vector(this.bb_pos + offset), " + GenBBAccess() +
".__vector_len(this.bb_pos + offset)) : null;\n}\n\n";
std::string return_type =
(field.IsRequired() || HasDefaultValue(field))
? "Array"
: ("Array|" + null_keyword_);
if (field.IsRequired()) {
code += "():" + GenType(vectorType) + return_type + " {\n" +
offset_prefix + "new " + GenType(vectorType) + "Array(" +
GenBBAccess() + ".bytes().buffer, " + GenBBAccess() +
".bytes().byteOffset + " + GenBBAccess() +
".__vector(this.bb_pos + offset), " + GenBBAccess() +
".__vector_len(this.bb_pos + offset));\n}\n\n";
} else {
std::string value = HasDefaultValue(field)
? "new " + GenType(vectorType) + "Array()"
: "null";
code += "():" + GenType(vectorType) + return_type + " {\n" +
offset_prefix + "offset ? new " + GenType(vectorType) +
"Array(" + GenBBAccess() + ".bytes().buffer, " +
GenBBAccess() + ".bytes().byteOffset + " + GenBBAccess() +
".__vector(this.bb_pos + offset), " + GenBBAccess() +
".__vector_len(this.bb_pos + offset)) : " + value +
";\n}\n\n";
}
}
}
}
@@ -2043,7 +2142,7 @@ class TsGenerator : public BaseGenerator {
// Emit a factory constructor
if (struct_def.fixed) {
std::string arguments;
GenStructArgs(imports, struct_def, &arguments, "");
GenStructArgs(imports, struct_def, struct_def, &arguments, "");
GenDocComment(code_ptr);
code += "static create" + GetPrefixedName(struct_def) +
@@ -2084,7 +2183,7 @@ class TsGenerator : public BaseGenerator {
if (!IsScalar(field.value.type.base_type)) {
code += "0";
} else if (HasNullDefault(field)) {
code += "null";
code += null_keyword_;
} else {
if (field.value.type.base_type == BASE_TYPE_BOOL) {
code += "+";
@@ -2201,7 +2300,7 @@ class TsGenerator : public BaseGenerator {
const auto arg_name = GetArgName(field);
if (field.IsScalarOptional()) {
code += " if (" + arg_name + " !== null)\n ";
code += " if (" + arg_name + " !== " + null_keyword_ + ")\n ";
}
code += " " + methodPrefix + "." + namer_.Method("add", field) + "(";
@@ -2241,10 +2340,38 @@ class TsGenerator : public BaseGenerator {
}
}
static bool HasNullDefault(const FieldDef& field) {
bool HasNullDefault(const FieldDef& field) {
return field.IsOptional() && field.value.constant == "null";
}
static bool HasDefaultValue(const FieldDef& field) {
switch (field.value.type.base_type) {
// These types can't have defaults
case BASE_TYPE_UNION:
case BASE_TYPE_STRUCT: {
return false;
}
// Arrays always have a default (empty array)
case BASE_TYPE_ARRAY:
return true;
// The only supported default for vectors is []
case BASE_TYPE_VECTOR:
return field.value.constant == "[]";
// Even strings are presumed to be null-default if the default value is
// "0", this is intended behavior.
case BASE_TYPE_STRING: {
return field.value.constant != "0" && field.value.constant != "null";
}
default: {
return field.value.constant != "null";
}
}
}
std::string GetArgType(import_set& imports, const Definition& owner,
const FieldDef& field, bool allowNull) {
return GenTypeName(imports, owner, field.value.type, true,

View File

@@ -2755,6 +2755,42 @@ std::vector<IncludedFile> Parser::GetIncludedFiles() const {
return {it->second.cbegin(), it->second.cend()};
}
bool Parser::HasCircularStructDependency() {
std::function<bool(StructDef*)> visit =
[&](StructDef* struct_def) {
// Only consider fixed structs and structs we have yet to check
if (!struct_def->fixed || struct_def->cycle_status == StructDef::CycleStatus::Checked) {
return false;
}
if (struct_def->cycle_status == StructDef::CycleStatus::InProgress) {
// cycle found
return true;
}
struct_def->cycle_status = StructDef::CycleStatus::InProgress;
for (const auto& field : struct_def->fields.vec) {
if (field->value.type.base_type == BASE_TYPE_STRUCT) {
if (visit(field->value.type.struct_def)) {
return true; // Cycle detected in recursion.
}
}
}
struct_def->cycle_status = StructDef::CycleStatus::Checked;
return false; // No cycle detected.
};
for (const auto& struct_def : structs_.vec) {
if (visit(struct_def)) {
return true; // Cycle detected.
}
}
return false; // No cycle detected.
}
bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions& opts) {
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
@@ -2773,7 +2809,8 @@ bool Parser::SupportsOptionalScalars() const {
bool Parser::SupportsDefaultVectorsAndStrings() const {
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim |
IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson;
IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson |
IDLOptions::kTs;
return !(opts.lang_to_generate & ~supported_langs);
}
@@ -3135,8 +3172,10 @@ CheckedError Parser::ParseProtoFields(StructDef* struct_def, bool isextend,
return Error("Protobuf has non positive number in reserved ids");
if (range) {
for (voffset_t id = from + 1; id <= attribute; id++)
struct_def->reserved_ids.push_back(id);
for (uint32_t id = static_cast<uint32_t>(from) + 1;
id <= static_cast<uint32_t>(attribute); id++) {
struct_def->reserved_ids.push_back(static_cast<voffset_t>(id));
}
range = false;
} else {
@@ -4093,7 +4132,15 @@ bool StructDef::Deserialize(Parser& parser, const reflection::Object* object) {
sortbysize = attributes.Lookup("original_order") == nullptr && !fixed;
const auto& of = *(object->fields());
auto indexes = std::vector<uoffset_t>(of.size());
for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i;
for (uoffset_t i = 0; i < of.size(); i++) {
uint16_t field_id = of.Get(i)->id();
if (field_id >= of.size()) {
parser.error_ = "Field ID " + std::to_string(field_id) +
" exceeds field count " + std::to_string(of.size());
return false;
}
indexes[field_id] = i;
}
size_t tmp_struct_size = 0;
for (size_t i = 0; i < indexes.size(); i++) {
auto field = of.Get(indexes[i]);

View File

@@ -389,7 +389,7 @@ void ForAllFields(const reflection::Object* object, bool reverse,
for (size_t i = 0; i < field_to_id_map.size(); ++i) {
func(object->fields()->Get(
field_to_id_map[reverse ? field_to_id_map.size() - i + 1 : i]));
field_to_id_map[reverse ? field_to_id_map.size() - (i + 1) : i]));
}
}
@@ -641,7 +641,10 @@ const uint8_t* AddFlatBuffer(std::vector<uint8_t>& flatbuf,
const uint8_t* newbuf, size_t newlen) {
// Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're
// going to chop off the root offset.
if (!newbuf || newlen < sizeof(uoffset_t)) return nullptr;
FLATBUFFERS_ASSERT(newlen >= sizeof(uoffset_t));
auto root = ReadScalar<uoffset_t>(newbuf);
if (root < sizeof(uoffset_t) || root >= newlen) return nullptr;
while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) ||
!(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) {
flatbuf.push_back(0);
@@ -649,7 +652,7 @@ const uint8_t* AddFlatBuffer(std::vector<uint8_t>& flatbuf,
auto insertion_point = static_cast<uoffset_t>(flatbuf.size());
// Insert the entire FlatBuffer minus the root pointer.
flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
auto root_offset = root - sizeof(uoffset_t);
return flatbuf.data() + insertion_point + root_offset;
}

View File

@@ -20,7 +20,7 @@ import Foundation
/// it allows users to write and read data directly from memory thus the use of its
/// functions should be used
@frozen
public struct ByteBuffer {
public struct ByteBuffer: @unchecked Sendable {
/// Storage is a container that would hold the memory pointer to solve the issue of
/// deallocating the memory that was held by (memory: UnsafeMutableRawPointer)
@@ -30,7 +30,7 @@ public struct ByteBuffer {
enum Blob {
#if !os(WASI)
case data(Data)
case bytes(ContiguousBytes)
case bytes(any ContiguousBytes)
#endif
case byteBuffer(_InternalByteBuffer)

View File

@@ -23,7 +23,7 @@ import Common
/// Enum is a protocol that all flatbuffers enums should conform to
/// Since it allows us to get the actual `ByteSize` and `Value` from
/// a swift enum.
public protocol Enum {
public protocol Enum: Sendable {
/// associatedtype that the type of the enum should conform to
associatedtype T: Scalar & Verifiable
/// Size of the current associatedtype in the enum

View File

@@ -45,7 +45,7 @@ public struct FlatBufferBuilder {
/// Dictonary that stores a map of all the strings that were written to the buffer
private var stringOffsetMap: [String: Offset] = [:]
/// A check to see if finish(::) was ever called to retreive data object
private var finished = false
private(set) var finished = false
/// A check to see if the buffer should serialize Default values
private var serializeDefaults: Bool
@@ -488,7 +488,7 @@ public struct FlatBufferBuilder {
///
/// - Parameter bytes: bytes to be written into the buffer
/// - Returns: ``Offset`` of the vector
mutating public func createVector(bytes: ContiguousBytes) -> Offset {
mutating public func createVector(bytes: any ContiguousBytes) -> Offset {
bytes.withUnsafeBytes {
startVector($0.count, elementSize: MemoryLayout<UInt8>.size)
_bb.push(bytes: $0)

View File

@@ -20,6 +20,8 @@ import Foundation
/// since now we will be serializing native structs into the buffer.
public protocol NativeStruct {}
public protocol FlatBufferVerifiableNativeStruct: NativeStruct, Verifiable {}
/// FlatbuffersInitializable is a protocol that allows any object to be
/// Initialized from a ByteBuffer
public protocol FlatbuffersInitializable {
@@ -35,6 +37,8 @@ public protocol FlatBufferTable: FlatbuffersInitializable,
var __buffer: ByteBuffer! { get }
}
public protocol FlatBufferVerifiableTable: FlatBufferTable, Verifiable {}
/// FlatbufferStruct structures all the Flatbuffers structs
public protocol FlatBufferStruct: FlatbuffersInitializable,
FlatbuffersVectorInitializable

View File

@@ -16,50 +16,52 @@
import Foundation
/// FlatBufferGRPCMessage protocol that should allow us to invoke
/// initializers directly from the GRPC generated code
public protocol FlatBufferGRPCMessage {
/// Size of readable bytes in the buffer
var size: Int { get }
init(byteBuffer: ByteBuffer)
@discardableResult
@inline(__always)
func withUnsafeReadableBytes<T>(
_ body: (UnsafeRawBufferPointer) throws
-> T) rethrows -> T
enum FlatbuffersGRPCError: Error {
case finishedNotCalledOnBuilder
}
/// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the
/// GRPC library
public struct Message<T: FlatBufferTable>: FlatBufferGRPCMessage {
internal var buffer: ByteBuffer
public protocol GRPCVerifiableMessage<Message> {
associatedtype Message
/// Returns the an object of type T that would be read from the buffer
public var object: T {
T.init(
buffer,
o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) &+
Int32(buffer.reader))
}
init(pointer: UnsafeRawBufferPointer)
init(byteBuffer: ByteBuffer)
func decode() throws -> Message
func withUnsafeReadableBytes<Data>(
_ body: (UnsafeRawBufferPointer) throws
-> Data) rethrows -> Data
}
public struct GRPCMessage<
Table: FlatBufferVerifiableTable
>: Sendable, GRPCVerifiableMessage {
public typealias Message = Table
private let buffer: ByteBuffer
public var size: Int { Int(buffer.size) }
/// Initializes the message with the type Flatbuffer.Bytebuffer that is transmitted over
/// GRPC
/// - Parameter byteBuffer: Flatbuffer ByteBuffer object
public init(pointer: UnsafeRawBufferPointer) {
buffer = ByteBuffer(
copyingMemoryBound: pointer.baseAddress!,
capacity: pointer.count)
}
public init(builder: inout FlatBufferBuilder) throws {
guard builder.finished else {
throw FlatbuffersGRPCError.finishedNotCalledOnBuilder
}
buffer = builder.sizedBuffer
}
public init(byteBuffer: ByteBuffer) {
buffer = byteBuffer
}
/// Initializes the message by copying the buffer to the message to be sent.
/// from the builder
/// - Parameter builder: FlatbufferBuilder that has the bytes created in
/// - Note: Use `builder.finish(offset)` before passing the builder without prefixing anything to it
public init(builder: inout FlatBufferBuilder) {
buffer = builder.sizedBuffer
builder.clear()
public func decode() throws -> Table {
var buf = buffer
return try getCheckedRoot(byteBuffer: &buf)
}
@discardableResult
@@ -73,3 +75,30 @@ public struct Message<T: FlatBufferTable>: FlatBufferGRPCMessage {
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
public struct FlatBuffersMessageSerializer<
Message: GRPCVerifiableMessage
>: Sendable {
public init() {}
public func serialize<Data>(
message: Message,
_ completion: (UnsafeRawBufferPointer) throws -> Data) throws -> Data
{
return try message.withUnsafeReadableBytes {
try completion($0)
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
public struct FlatBuffersMessageDeserializer<
Message: GRPCVerifiableMessage
>: Sendable {
public init() {}
public func deserialize(pointer: UnsafeRawBufferPointer) throws -> Message {
Message.init(pointer: pointer)
}
}

View File

@@ -49,7 +49,7 @@ public struct Table {
/// the vtable
/// - Parameter o: current offset
/// - Returns: offset of field within buffer
public func offset(_ o: Int32) -> Int32 {
public func offset(_ o: VOffset) -> Int32 {
let vtable = position &- bb.read(def: Int32.self, position: Int(position))
return o
< bb
@@ -57,7 +57,7 @@ public struct Table {
? Int32(
bb.read(
def: Int16.self,
position: Int(vtable &+ o))) : 0
position: Int(vtable &+ Int32(o)))) : 0
}
/// Gets the indirect offset of the current stored object
@@ -106,13 +106,13 @@ public struct Table {
/// This should only be used by `Scalars`
/// - Parameter off: Readable offset
/// - Returns: Returns a vector of type [T]
public func getVector<T>(at off: Int32) -> [T]? {
public func getVector<T>(at off: VOffset) -> [T]? {
let o = offset(off)
guard o != 0 else { return nil }
return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o)))
}
public func vector<T>(at off: Int32, byteSize: Int) -> FlatbufferVector<T> {
public func vector<T>(at off: VOffset, byteSize: Int) -> FlatbufferVector<T> {
let off = offset(off)
return FlatbufferVector(
bb: bb,
@@ -122,7 +122,7 @@ public struct Table {
}
public func unionVector(
at off: Int32,
at off: VOffset,
byteSize: Int) -> UnionFlatbufferVector
{
let off = offset(off)
@@ -146,7 +146,7 @@ public struct Table {
/// - Returns: Returns a pointer to the underlying data
@inline(__always)
public func withUnsafePointerToSlice<T>(
at off: Int32,
at off: VOffset,
body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T?
{
let o = offset(off)

View File

@@ -115,7 +115,7 @@ public struct TableVerifier {
unionKeyName: String,
fieldName: String,
required: Bool,
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
completion: (inout Verifier, T, Int) throws -> Void) throws
where T: UnionEnum
{
let keyPos = try dereference(key)

View File

@@ -68,7 +68,7 @@ public struct FlatbufferVector<
}
extension FlatbufferVector: Encodable where Element: Encodable {
public func encode(to encoder: Encoder) throws {
public func encode(to encoder: any Encoder) throws {
var container = encoder.unkeyedContainer()
for element in self {
try container.encode(element)

View File

@@ -49,8 +49,8 @@ public struct UnionFlatbufferVector {
public subscript(
position: Int,
Type: FlatbuffersVectorInitializable
.Type) -> FlatbuffersVectorInitializable
Type: any FlatbuffersVectorInitializable
.Type) -> any FlatbuffersVectorInitializable
{
guard position < count else {
fatalError(

View File

@@ -146,7 +146,7 @@ struct _InternalByteBuffer {
#if !os(WASI)
@inline(__always)
@usableFromInline
mutating func push(bytes: ContiguousBytes) {
mutating func push(bytes: any ContiguousBytes) {
bytes.withUnsafeBytes { ptr in
ensureSpace(size: ptr.count)
memcpy(

View File

@@ -30,7 +30,7 @@ public struct ByteBuffer {
enum Blob {
#if !os(WASI)
case data(Data)
case bytes(ContiguousBytes)
case bytes(any ContiguousBytes)
#endif
case byteBuffer(_InternalByteBuffer)

Some files were not shown because too many files have changed in this diff Show More