Compare commits

...

57 Commits

Author SHA1 Message Date
Derek Bailey
1872409707 FlatBuffers Version 25.9.23 (#8708) 2025-09-23 22:18:02 -07:00
dependabot[bot]
c427e1a65d Bump the npm_and_yarn group across 1 directory with 2 updates (#8704)
Bumps the npm_and_yarn group with 2 updates in the / directory: [@eslint/plugin-kit](https://github.com/eslint/rewrite/tree/HEAD/packages/plugin-kit) and [brace-expansion](https://github.com/juliangruber/brace-expansion).


Updates `@eslint/plugin-kit` from 0.3.2 to 0.3.5
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/packages/plugin-kit/CHANGELOG.md)
- [Commits](https://github.com/eslint/rewrite/commits/plugin-kit-v0.3.5/packages/plugin-kit)

Updates `brace-expansion` from 1.1.11 to 1.1.12
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12)

---
updated-dependencies:
- dependency-name: "@eslint/plugin-kit"
  dependency-version: 0.3.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: brace-expansion
  dependency-version: 1.1.12
  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>
Co-authored-by: Derek Bailey <derekbailey@google.com>
2025-09-23 21:54:56 -07:00
Derek Bailey
caf3b494db bulk code format fix (#8707) 2025-09-23 21:50:27 -07:00
Derek Bailey
0e047869da Use the Google Style for clang-format without exceptions (#8706)
This reduces the friction when merging from github and google repos by
using the exact same clang style guide.

MARKDOWN=true
2025-09-23 21:19:33 -07:00
mustiikhalil
881eaab706 Revert back to use the latest from the swiftly ci (#8702) 2025-09-21 21:47:05 -07:00
nurbo
48eccb83db fix(idl_gen_ts): bool to number conversion in mutable API (#8677)
Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
2025-09-11 08:36:15 -07:00
Peter Petrov
3c0511fa6a [C#] Added ToSizedArrayPadded(int padLeft, int padRight) to ByteBuffers to avoid unnecessary copying. (#8658)
* Added ToSizedArrayPadded(int padLeft, int padRight) + ToArrayPadded(pos, len, padLeft, padRight) to the byteBuffers.
This is for API completion and to avoid unnecessary copy when framing my packets. I needed this to create a flat buffer with space in front of it for header / metadata.

* Fix indentation

---------

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-09-09 11:38:15 -07:00
bigjt
82396fa0fe [C#] Improve Span<> utilization (#8588)
There are a couple instances where the ByteBuffer's Span property was accessed in a loop.
 + Extracted the use of the property outside of the loop to save a few cpu cycles.

Access to the allocator's internal buffer isn't exposed as a ReadOnlySpan<byte> from the ByteBuffer
or the FlatBufferBuilder.
 + Added a few convenience functions to access the buffer using a ReadOnlySpan<byte>.

There are a few cases where built in Span extensions can be used to run optimized code.
 + Added the use of Span.Fill() and ReadOnlySpan.SequenceCompareTo to replace existing loops.

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-08-28 16:06:18 -07:00
Curt Hagenlocher
a6b337f803 Add bounds checking to a method where it was missing (#8673)
Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-08-28 16:06:03 -07:00
TorsteinTenstadNorsonic
35230bd70c [C#] Fix union verifier (#8593)
* [C#] Add test verifying unions

* [C#] Fix verifying unions

---------

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-08-28 16:05:42 -07:00
Shashank
deb3d93454 gRPC callbackService support added (#8666)
* grpc callbackService support added

Signed-off-by: shankeleven <shashanksati11@gmail.com>

* tests: regenerate C++ gRPC golden with --grpc-callback-api (CallbackService & async_ reactor APIs); update formatting and method placement

---------

Signed-off-by: shankeleven <shashanksati11@gmail.com>
Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-08-28 15:49:27 -07:00
Felix
b87d04af8c Bugfix: grpc supress incorrect warning (#8669)
new_p is a local addr but is owned now by slice_
thus the life time does not end at the end of the function

Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-08-28 14:27:31 -07:00
Ville Vesilehto
1e6c851dba fix(go/grpc): avoid panic on short FlatBuffers input (#8684)
* fix(go/grpc): avoid panic on short FlatBuffers input

The gRPC codec read the root UOffsetT without checking input size. On
buffers shorter than SizeUOffsetT, GetUint32 touched data[3] and the
process panics.

Add a simple length check and validate the root offset stays within the
buffer. Return clear errors (insufficient data / invalid root offset)
instead of panicking.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>

* fix(go/grpc): avoid signed overflow in offset

Keep the bounds check in the unsigned domain (UOffsetT) to avoid
signedness pitfalls.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>

* chore: clarify comment regarding offset

A full FlatBuffer structure would be:

- uoffset_t: root table offset (4 bytes)
- soffset_t: vtable offset in root table (4 bytes)
- uint16_t: vtable size (2 bytes)
- uint16_t: table size (2 bytes)

In total 12 bytes. We are only validating the data length
before trying to read the uoffset_t, not the full structure.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>

---------

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
Co-authored-by: Derek Bailey <derekbailey@google.com>
2025-08-28 00:31:57 -07:00
mustiikhalil
6164edf558 Fixes swift windows CI (#8685)
Fixes ci failing to a missing component on the github actions side, and
this is enabled until its fixed from the swiftlylab side

Enables swift ci
2025-08-27 23:49:50 -07:00
Derek Bailey
ef1030ff0b Update build.yml - disable gradle CI failures
Both of this are failing and blocking other non-related PRs, disabling for now.
2025-08-27 23:22:12 -07:00
Derek Bailey
53c8c2ef16 Update build.yml - disable Test Swift Windows
This continually fails and the error message is cryptic enough that I don't know how to fix it without an expert.
2025-08-27 23:11:24 -07:00
Derek Bailey
f83525fe67 Update build.yml - update gradle actions
This follows the recommendation here: https://github.com/gradle/actions/blob/main/docs/setup-gradle.md#general-usage
2025-08-27 22:55:17 -07:00
Derek Bailey
b2cce474ba Update build.yml - use java-version 21
Our CI is broken and this is the error:

```
FAILURE: Build failed with an exception.

* What went wrong:
Gradle requires JVM 17 or later to run. Your build is currently configured to use JVM 11.
```

So updating our java-versions to the latest stable version which is 21 apparently.
2025-08-27 22:41:07 -07:00
Jason
067bfdbde9 Update ts codegen (#8421)
Makes the return type of `static getFullyQualifiedName()` be a string literal instead of just the string type

Update tests

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
2025-08-17 20:19:08 -07:00
Justin Davis
5218e29aa4 Fix: Actually call ValidateOptions (#8665)
* fix: actually call ValidateOptions

* convert error to warning in validateoptions
2025-08-12 15:30:35 -07:00
vzjc
957e09d684 CMakeLists: include(CheckSymbolExists) so check_symbol_exists() will work (#8580)
CMake 3.6 and earlier included this implicitly. Newer versions require
it to be explicit.

Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-08-11 23:11:14 -07:00
Chan Wang
af4b99a1d7 Add Rust reflection documentation (#8536)
* Add Rust reflection documentation

* Update rust.md
2025-08-08 10:18:17 -07:00
Isaiah Pettingill
b85b90e346 Fix typo in word JavaScript (#8530)
Noticed this on the site. I'm not sure if you have to change it anywhere else, but this looks like the only place the typo occurs
2025-08-08 10:16:52 -07:00
Nugine
ae3821233c docs: fix broken link in readme (#8656) 2025-08-06 22:06:44 -07:00
Felix
ff9cba2bff Doc fix verifier example code for cpp (#8664) 2025-08-06 13:53:44 -07:00
Felix
1759061908 Remove stray required in docs (#8663) 2025-08-06 13:52:57 -07:00
Sourya Kovvali
34af7fff70 Fix native_type non-native_inline fields, add tests (#8655)
* Fix native_type non-native_inline fields, add tests

* Format

* Add 'native_type_test' and 'native_inline_table_test' to generate_code.py

* Remove '--gen-compare' from native_type_test generation
2025-08-03 15:06:01 -07:00
mustiikhalil
518bf42df8 Fixes misaligned pointer by reading from the buffer instead of loading the memory separately (#8649) 2025-07-29 21:26:30 +00:00
mustiikhalil
575d616e60 [Swift] Moves capacity outside of Storage (#8650)
- Cleans up capacity usage within the lib and moves it outside of the Storage

-  Use overflow operators
2025-07-29 14:21:20 -07:00
Felix
f32a7dcbd2 Bugfix __eq__ for numpy data types (#8646)
* [Python] Sync PythonTest.sh flags with generate_code.py

* [Python] Update generated code to latest flatc version for tests

* [Python] Fix test support for numpy newer than 2.0.0

* [Python] Remove unused variable

* [Python] Fix __eq__ for numpy arrays

* [Python] Run clang-format over the entire file
2025-07-26 10:31:38 -07:00
Alex Băluț
860d645349 Support Rust edition 2024 (#8638)
* Developers intro how to contribute

* Fix Rust code generation for Rust edition 2024

The errors look like:

```
warning[E0133]: call to unsafe function `fbs::flatbuffers::emplace_scalar` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `fbs::flatbuffers::follow_cast_ref` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `fbs::flatbuffers::Follow::follow` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `fbs::flatbuffers::read_scalar_at` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `fbs::flatbuffers::root_unchecked` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `fbs::flatbuffers::size_prefixed_root_unchecked` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `fbs::flatbuffers::Table::<'a>::new` is unsafe and requires unsafe block
warning[E0133]: call to unsafe function `std::slice::from_raw_parts` is unsafe and requires unsafe block
```

* Update goldens

Ran `goldens/generate_goldens.py`

* Regenerate code files

Ran `scripts/generate_code.py`
2025-07-25 23:12:52 +00:00
Felix
06a53df0d3 Fix start page: Backwards and Forwards Compatibility (#8645) 2025-07-25 16:06:50 -07:00
Łukasz Kurowski
c526cb640b [Python] Enhance object API __init__ with typed keyword arguments (#8615)
This commit significantly improves the developer experience for the Python Object-Based API by overhauling the generated `__init__` method for `T`-suffixed classes.

Previously, `T` objects had to be instantiated with an empty constructor, and their fields had to be populated manually one by one. This was verbose and not idiomatic Python.

This change modifies the Python code generator (`GenInitialize`) to produce `__init__` methods that are:

1.  **Keyword-Argument-Friendly**: The constructor now accepts all table/struct fields as keyword arguments, allowing for concise, single-line object creation.

2.  **Fully Typed**: The signature of the `__init__` method is now annotated with Python type hints. This provides immediate benefits for static analysis tools (like Mypy) and IDEs, enabling better autocompletion and type checking.

3.  **Correctly Optional**: The generator now correctly wraps types in `Optional[...]` if their default value is `None`. This applies to strings, vectors, and other nullable fields, ensuring strict type safety.

The new approach remains **fully backward-compatible**, as all arguments have default values. Existing code that uses the empty constructor will continue to work without modification.

#### Example of a Generated `__init__`

**Before:**

```python
class KeyValueT(object):
    def __init__(self):
        self.key = None  # type: str
        self.value = None  # type: str
```

**After:**

```python
class KeyValueT(object):
    def __init__(self, key: Optional[str] = None, value: Optional[str] = None):
        self.key = key
        self.value = value
```

#### Example of User Code

**Before:**

```python
# Old, verbose way
kv = KeyValueT()
kv.key = "instrument"
kv.value = "EUR/USD"
```

**After:**

```python
# New, Pythonic way
kv = KeyValueT(key="instrument", value="EUR/USD")
```
2025-07-22 23:57:39 -07:00
mustiikhalil
ca73ff34b7 [Swift] Memory usage fix (#8643)
Allows a complete reset for the underlying memory of the
_InternalByteBuffers within FlatBuffers and FlexBuffers.
2025-07-18 09:37:58 -07:00
Rogério Lino
2e49b3ba60 docs: Fixing typo on PHP sample (#8566) 2025-07-17 19:42:14 +00:00
Felix
f830c47d68 [Python] Avoid double flatbuffers include in pyi files (#8626) 2025-07-17 12:37:19 -07:00
Emma
501810f4d1 Fix JavaScript typo in mkdocs.yml (#8515) 2025-07-17 17:53:12 +00:00
Felix
1047d7ec13 Fix Enum type definition (#8624)
Using the : syntax leads to non member attributes.

> If an attribute is defined in the class body with a type annotation
> but with no assigned value, a type checker should assume this is a non-member attribute

```
class Pet(Enum):
    genus: str  # Non-member attribute
    species: str  # Non-member attribute

    CAT = 1  # Member attribute
    DOG = 2  # Member attribute
```

https://typing.python.org/en/latest/spec/enums.html#defining-members
2025-07-16 12:22:45 -07:00
mustiikhalil
07c2eb5fe7 Moves away from @_exported import to add the import in the generated code (#8637) 2025-07-16 12:07:08 -07:00
Felix
c7b9dc83f5 [Python] Avoid include own type (#8625)
This prevents the include of the type defined in the pyi,
otherwise this leads to error message like this:
error: Name XYZ already defined (possibly by an import)  [no-redef]
2025-07-15 11:20:09 -07:00
Gio
4c9079e31b Update logo path (#8602) 2025-07-14 16:09:05 -07:00
Felix
64e5252b4e Fix typo in code comment (#8549) 2025-07-07 12:03:14 -07:00
Dylan Gallagher
00c30807ff Fixed typo in quick_start.md (#8592) 2025-07-07 12:02:40 -07:00
Felix
c15fe421ba Use correct default type for str (#8623)
* [Python] Use correct type for str with None

Otherwise mypy will correctly flag code like this

def __init__(self):
  self.fooBar = None  # type: Optional[str]

error: Incompatible types in assignment (expression has type "None", variable has type "str")

* [Python] Make list type optional as they can contain None
2025-07-04 23:47:36 +00:00
Felix
6b251aa1cf Bugfix/new decode flag (#8634)
* Add docs for new python-decode-obj-api-strings flag

* Fix generate_code by adding missing s to flag
2025-07-04 16:46:28 -07:00
mustiikhalil
6fe8afb3b6 [CI] Moves swift actions to use next (#8632)
* Moves to use swift-actions@next until final release is out

* Migrates to vapor that uses swiftly actions

* Trying to use windows 2022
2025-07-01 13:46:06 -07:00
Truman Mulholland
00eec2445b [TS] Fix relative paths for exports (#8517)
Fixes an issue where exports were using incorrect relative paths for
>=3 namespace levels. This is fixed by making the starting range of the
namespace components relative to the amount of components.

Co-authored-by: Björn Harrtell <bjornharrtell@users.noreply.github.com>
2025-07-01 08:38:02 -07:00
mustiikhalil
b8db3a9a6a Adds windows swift support (#8622)
Adding support for windows requires the code generations
to add a compiler statement to completely ignore GRPC code
generation on windows

Cleanup the project to use the main Package.swift to run tests
instead of having it separate and includes the imports for GRPC
within it.

Adds windows swift ci
2025-06-30 05:45:48 -07:00
Seth Raymond
75556437cc Decode bytes to strings in Python Object API (#8551) 2025-06-29 01:40:10 -07:00
Felix
31beb0fb2f Bugfix: grpc python code generation location and file suffix (#8359)
* clang-format

* [Python] Replace . with _ in grpc filename suffix

Having filenames with . like `file.fb.grcp`
is not great for Python. Since dots are used for namespaces.
Replacing all of them with _ eg suffix `foo.bar.baz` will become
`foo_bar_baz`.

Restoring the previous default `_fb` suffix.

* [Python] Use namespace in path

This fixes a regression introduced with:
fb9afbafc7
And generates the grpc file in the namespace folder again.

* Sync commandline docs with web docs
2025-06-24 22:52:40 -07:00
Aaron Barany
dfd92124aa Avoid outputting Python files for already generated types (#8500)
This may overwrite types that have already been generated and can create
unwanted empty files. Fixes #8490
2025-06-23 12:00:37 -07:00
Björn Harrtell
a2916d37e7 [TS] Upgrade deps (#8620) 2025-06-22 08:59:42 -07:00
mustiikhalil
5a95b7b6bc [Swift] Flexbuffers native swift port (#8577)
* Offical Swift port for FlexBuffers

This is the offical port for FlexBuffers within
swift, and it introcudes a Common Module where code
is shared between flatbuffers and flexbuffers.

Writing most supported values like maps, vectors,
nil and scalars into a flexbuffer buffer. And includes
tests to verify that its similar to cpp

* Reading a flexbuffer

Implementing reading from a flexbuffer, enabling
most of the buffers features, like most types, maps, vectors,
typedvectors, and fixedtypedvectors.

Currently, if an offset/object cant be read we default to a swift
nil instead of the default flexbuffers 'null' with all values.

* Fixes bazel breaking due to new project structure

Address warnings within the library

* Adds comment on why we added the code & properly enforce the amout of bytes needed
2025-06-22 08:36:38 +02:00
Björn Harrtell
595ac94a6a [TS] Enum value default null (#8619)
* [TS] Enum value default null

* Re-gen
2025-06-21 22:25:56 -07:00
Adam Oleksy
5822c1c8dd Fix dereference operator of VectorIterator to structures (#8425)
For Vector or Array of structures the dereference operator of an
iterator returns the pointer to the structure. However, IndirectHelper,
which is used in the implementation of this operator, is instantiated
in the way that the IndirectHelper::Read returns structure by value.

This is because, Vector and Array instantiate IndirectHelper with
const T*, but VectorIterator instantiates IndirectHelper with T. There
are three IndirectHelper template definition: first for T, second for
Offset<T> and the last one for const T*. Those have different
IndirectHelper:Read implementations and (more importantly) return type.
This is the reason of mismatch in VectorIterator::operator* between
return type declaration and what was exactly returned.

That is, for Array<T,...> where T is scalar the VectorIterator is
instantiated as VectorIterator<T, T>, dereference operator returns T
and its implementation uses IndirectHelper<T> which Read function
returns T.
When T is not scalar, then VectorIterator is instantiated as
VectorIterator<T, const T *>, dereference operator returns const T * and
its implementation uses IndirectHelper<T> which Read function returns T.

The fix is done as follows:
* implement type trait is_specialization_of_Offset and
 is_specialization_of_Offset64,
* change partial specialization of IndirectHelper with const T * that
 it is instantiated by T and enabled only if T is not scalar and not
 specialization of Offset or Offset64,
* remove type differentiation (due to scalar) from Array..

The above makes the IndirectHelper able to correctly instantiate itself
basing only on T. Thus, the instantiation in VectorIterator correctly
instantiate IndirectHelper::Read function, especially the return type.
2025-05-17 22:01:09 -07:00
Maurice Sotzny
609c72ca1a [C++] Fixes #8446 (#8447)
Fixes access to union members when generating code with options "--cpp-field-case-style upper" and "--gen-object-api"

Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
2025-04-14 08:54:10 -07:00
mustiikhalil
bd1b2d0baf [Swift] Adds new API to reduce memory copying within swift (#8484)
* Adds new API to reduce memory copying within swift

Adds new storage container _InternalByteBuffer which
will be holding the data that will be created within the swift
lib, however reading data will be redirected to ByteBuffer, which
should be able to handle all types of data that swift provide without
the need to copy the data itself. This is due to holding a reference to
the data.

Replaces assumingMemoryBinding with bindMemory which is safer

Adds function that provides access to a UnsafeBufferPointer for
scalars and NativeStructs within swift

Updates docs

Suppress compilation warnings by replacing var with let

Using overflow operators within swift to improve performance

Adds tests for GRPC message creation from a retained _InternalByteBuffer
2025-03-18 07:48:39 +01:00
1016 changed files with 55118 additions and 39680 deletions

View File

@@ -1,13 +1,5 @@
--- ---
Language: Cpp Language: Cpp
BasedOnStyle: Google BasedOnStyle: Google
DerivePointerAlignment: false
PointerAlignment: Right
IndentPPDirectives: AfterHash
Cpp11BracedListStyle: false
AlwaysBreakTemplateDeclarations: false
AllowShortCaseLabelsOnASingleLine: true
SpaceAfterTemplateKeyword: false
AllowShortBlocksOnASingleLine: true
... ...

View File

@@ -1,13 +0,0 @@
/* eslint-env node */
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: [
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
]
};

View File

@@ -129,7 +129,7 @@ jobs:
build-cpp-std: build-cpp-std:
name: Build Windows C++ name: Build Windows C++
runs-on: windows-2019 runs-on: windows-2022
strategy: strategy:
matrix: matrix:
std: [11, 14, 17, 20, 23] std: [11, 14, 17, 20, 23]
@@ -140,7 +140,7 @@ jobs:
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v1.1
- name: cmake - name: cmake
run: > run: >
cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release
-DFLATBUFFERS_STRICT_MODE=ON -DFLATBUFFERS_STRICT_MODE=ON
-DFLATBUFFERS_CPP_STD=${{ matrix.std }} -DFLATBUFFERS_CPP_STD=${{ matrix.std }}
-DFLATBUFFERS_BUILD_CPP17=${{ matrix.std >= 17 && 'On' || 'Off'}} -DFLATBUFFERS_BUILD_CPP17=${{ matrix.std >= 17 && 'On' || 'Off'}}
@@ -157,14 +157,14 @@ jobs:
contents: write contents: write
outputs: outputs:
digests: ${{ steps.hash.outputs.hashes }} digests: ${{ steps.hash.outputs.hashes }}
name: Build Windows 2019 name: Build Windows 2022
runs-on: windows-2019 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Add msbuild to PATH - name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v1.1
- name: cmake - name: cmake
run: cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON . run: cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON .
- name: build - name: build
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64 run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
- name: test - name: test
@@ -310,14 +310,17 @@ jobs:
build-android: build-android:
name: Build Android (on Linux) name: Build Android (on Linux)
if: false #disabled due to continual failure
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: set up Java - name: set up Java
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: temurin
java-version: '11' java-version: 17
- name: set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: set up flatc - name: set up flatc
run: | run: |
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON . cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF -DFLATBUFFERS_STRICT_MODE=ON .
@@ -344,13 +347,13 @@ jobs:
build-generator-windows: build-generator-windows:
name: Check Generated Code on Windows name: Check Generated Code on Windows
runs-on: windows-2019 runs-on: windows-2022
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Add msbuild to PATH - name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v1.1
- name: cmake - name: cmake
run: cmake -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON . run: cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DFLATBUFFERS_BUILD_CPP17=ON -DFLATBUFFERS_STRICT_MODE=ON .
- name: build - name: build
run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64 run: msbuild.exe FlatBuffers.sln /p:Configuration=Release /p:Platform=x64
- name: Generate - name: Generate
@@ -398,11 +401,13 @@ jobs:
# https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode # https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md#xcode
- name: Set up Xcode version - name: Set up Xcode version
run: sudo xcode-select -s /Applications/Xcode_14.3.app/Contents/Developer run: sudo xcode-select -s /Applications/Xcode_14.3.app/Contents/Developer
- uses: gradle/wrapper-validation-action@v1.0.5 - name: set up Java
- uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: temurin
java-version: '11' java-version: 17
- name: set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build flatc - name: Build flatc
run: | run: |
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF .
@@ -414,15 +419,18 @@ jobs:
build-kotlin-linux: build-kotlin-linux:
name: Build Kotlin Linux name: Build Kotlin Linux
if: false #disabled due to continual failure
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- uses: actions/setup-java@v3 - name: set up Java
uses: actions/setup-java@v4
with: with:
distribution: 'temurin' distribution: temurin
java-version: '11' java-version: 17
- uses: gradle/wrapper-validation-action@v1.0.5 - name: set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Build flatc - name: Build flatc
run: | run: |
cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF . cmake -DFLATBUFFERS_BUILD_TESTS=OFF -DFLATBUFFERS_BUILD_FLATLIB=OFF -DFLATBUFFERS_BUILD_FLATHASH=OFF .
@@ -492,27 +500,37 @@ jobs:
sh phpUnionVectorTest.sh sh phpUnionVectorTest.sh
build-swift: build-swift:
name: Build Swift name: Test Swift
strategy: strategy:
matrix: matrix:
swift: ["5.9", "5.10", "6.0"] swift: ["5.9", "5.10", "6.1"]
# Only 22.04 has swift at the moment https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md?plain=1#L30 # Only 22.04 has swift at the moment https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md?plain=1#L30
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: swift-actions/setup-swift@v2 - uses: vapor/swiftly-action@v0.2
with: with:
swift-version: ${{ matrix.swift }} toolchain: ${{ matrix.swift }}
- name: Get swift version - name: Get swift version
run: swift --version run: swift --version
- name: test - name: test
working-directory: tests/swift/tests
run: | run: |
swift build --build-tests swift build --build-tests
swift test swift test
build-swift-windows:
name: Test swift windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: SwiftyLab/setup-swift@latest
with:
swift-version: '6.1'
- run: swift build
- run: swift test
build-swift-wasm: build-swift-wasm:
name: Build Swift Wasm name: Test Swift Wasm
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
container: container:
image: ghcr.io/swiftwasm/carton:0.20.1 image: ghcr.io/swiftwasm/carton:0.20.1
@@ -534,14 +552,15 @@ jobs:
- name: flatc - name: flatc
# FIXME: make test script not rely on flatc # 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 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
- name: deps - name: deps
run: yarn run: pnpm i
- name: compile - name: compile
run: yarn compile run: pnpm compile
- name: test - name: test
working-directory: tests/ts working-directory: tests/ts
run: | run: |
yarn global add esbuild
python3 TypeScriptTest.py python3 TypeScriptTest.py
build-dart: build-dart:

View File

@@ -4,6 +4,13 @@ All major or breaking changes will be documented in this file, as well as any
new features that should be highlighted. Minor fixes or improvements are not new features that should be highlighted. Minor fixes or improvements are not
necessarily listed. necessarily listed.
## [25.9.23] (September 23 2025)(https://github.com/google/flatbuffers/releases/tag/v25.9.23)
* flatc: `--grpc-callback-api` flag generates C++ gRPC Callback API server `CallbackService` skeletons AND client native callback/async stubs (unary + all streaming reactor forms) (opt-in, non-breaking, issue #8596).
* Swift - Adds new API to reduce memory copying within swift (#8484)
* Rust - Support Rust edition 2024 (#8638)
# [:C++] - Use the Google Style for clang-format without exceptions (#8706)
## [25.2.10] (February 10 2025)(https://github.com/google/flatbuffers/releases/tag/v25.2.10) ## [25.2.10] (February 10 2025)(https://github.com/google/flatbuffers/releases/tag/v25.2.10)
* Removed the old documentation pages. The new one is live at https://flatbuffers.dev * Removed the old documentation pages. The new one is live at https://flatbuffers.dev

View File

@@ -1,6 +1,6 @@
set(VERSION_MAJOR 25) set(VERSION_MAJOR 25)
set(VERSION_MINOR 2) set(VERSION_MINOR 9)
set(VERSION_PATCH 10) set(VERSION_PATCH 23)
set(VERSION_COMMIT 0) set(VERSION_COMMIT 0)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git")

View File

@@ -112,6 +112,7 @@ endif()
add_definitions(-DFLATBUFFERS_LOCALE_INDEPENDENT=$<BOOL:${FLATBUFFERS_LOCALE_INDEPENDENT}>) add_definitions(-DFLATBUFFERS_LOCALE_INDEPENDENT=$<BOOL:${FLATBUFFERS_LOCALE_INDEPENDENT}>)
if(NOT WIN32) if(NOT WIN32)
include(CheckSymbolExists)
check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH) check_symbol_exists(realpath "stdlib.h" HAVE_REALPATH)
if(NOT HAVE_REALPATH) if(NOT HAVE_REALPATH)
add_definitions(-DFLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION) add_definitions(-DFLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION)
@@ -278,6 +279,8 @@ set(FlatBuffers_GRPCTest_SRCS
tests/test_builder.cpp tests/test_builder.cpp
grpc/tests/grpctest.cpp grpc/tests/grpctest.cpp
grpc/tests/message_builder_test.cpp grpc/tests/message_builder_test.cpp
grpc/tests/grpctest_callback_compile.cpp
grpc/tests/grpctest_callback_client_compile.cpp
) )
# TODO(dbaileychess): Figure out how this would now work. I posted a question on # TODO(dbaileychess): Figure out how this would now work. I posted a question on

View File

@@ -40,3 +40,26 @@ Some tips for good pull requests:
# The small print # The small print
Contributions made by corporations are covered by a different agreement than Contributions made by corporations are covered by a different agreement than
the one above, the Software Grant and Corporate Contributor License Agreement. the one above, the Software Grant and Corporate Contributor License Agreement.
# Code
TL/DR
See [how to build flatc](https://flatbuffers.dev/building/).
When making changes, build `flatc` and then re-generate the goldens files to see the effect of your changes:
```
$ cp build/flatc .
$ goldens/generate_goldens.py
```
Re-generate other code files to see the effects of the changes:
```
$ scripts/generate_code.py
```
Run tests with [TestAll.sh](tests/TestAll.sh) in [tests](tests), or directly any of the sub-scripts run by it.
[Format the code](Formatters.md) before submitting a PR.

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'FlatBuffers' s.name = 'FlatBuffers'
s.version = '25.2.10' s.version = '25.9.23'
s.summary = 'FlatBuffers: Memory Efficient Serialization Library' s.summary = 'FlatBuffers: Memory Efficient Serialization Library'
s.description = "FlatBuffers is a cross platform serialization library architected for s.description = "FlatBuffers is a cross platform serialization library architected for

View File

@@ -1,6 +1,6 @@
module( module(
name = "flatbuffers", name = "flatbuffers",
version = "25.2.10", version = "25.9.23",
compatibility_level = 1, compatibility_level = 1,
repo_name = "com_github_google_flatbuffers", repo_name = "com_github_google_flatbuffers",
) )
@@ -15,11 +15,11 @@ bazel_dep(
) )
bazel_dep( bazel_dep(
name = "aspect_rules_js", name = "aspect_rules_js",
version = "2.1.3", version = "2.3.8",
) )
bazel_dep( bazel_dep(
name = "aspect_rules_ts", name = "aspect_rules_ts",
version = "3.4.0", version = "3.6.0",
) )
bazel_dep( bazel_dep(
name = "grpc", name = "grpc",

View File

@@ -20,17 +20,61 @@ import PackageDescription
let package = Package( let package = Package(
name: "FlatBuffers", name: "FlatBuffers",
platforms: [ platforms: [
.iOS(.v11), .iOS(.v12),
.macOS(.v10_14), .macOS(.v10_14),
], ],
products: [ products: [
.library( .library(
name: "FlatBuffers", name: "FlatBuffers",
targets: ["FlatBuffers"]), targets: ["FlatBuffers"]),
.library(
name: "FlexBuffers",
targets: ["FlexBuffers"]),
], ],
dependencies: .dependencies,
targets: [ targets: [
.target( .target(
name: "FlatBuffers", name: "FlatBuffers",
dependencies: [], dependencies: ["Common"],
path: "swift/Sources"), path: "swift/Sources/FlatBuffers"),
.target(
name: "FlexBuffers",
dependencies: ["Common"],
path: "swift/Sources/FlexBuffers"),
.target(
name: "Common",
path: "swift/Sources/Common"),
.testTarget(
name: "FlatbuffersTests",
dependencies: .dependencies,
path: "tests/swift/Tests/Flatbuffers"),
.testTarget(
name: "FlexbuffersTests",
dependencies: ["FlexBuffers"],
path: "tests/swift/Tests/Flexbuffers"),
]) ])
extension Array where Element == Package.Dependency {
static var dependencies: [Package.Dependency] {
#if os(Windows)
[]
#else
// Test only Dependency
[.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.4.1")]
#endif
}
}
extension Array where Element == PackageDescription.Target.Dependency {
static var dependencies: [PackageDescription.Target.Dependency] {
#if os(Windows)
["FlatBuffers"]
#else
// Test only Dependency
[
.product(name: "GRPC", package: "grpc-swift"),
"FlatBuffers",
]
#endif
}
}

View File

@@ -1,4 +1,4 @@
![logo](http://google.github.io/flatbuffers/fpl_logo_small.png) FlatBuffers ![logo](https://flatbuffers.dev/assets/flatbuffers_logo.svg) FlatBuffers
=========== ===========
![Build status](https://github.com/google/flatbuffers/actions/workflows/build.yml/badge.svg?branch=master) ![Build status](https://github.com/google/flatbuffers/actions/workflows/build.yml/badge.svg?branch=master)

View File

@@ -1,6 +1,5 @@
// automatically generated by the FlatBuffers compiler, do not modify // automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_ANIMAL_COM_FBS_APP_H_ #ifndef FLATBUFFERS_GENERATED_ANIMAL_COM_FBS_APP_H_
#define FLATBUFFERS_GENERATED_ANIMAL_COM_FBS_APP_H_ #define FLATBUFFERS_GENERATED_ANIMAL_COM_FBS_APP_H_
@@ -33,17 +32,12 @@ struct Animal FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table {
const ::flatbuffers::String* sound() const { const ::flatbuffers::String* sound() const {
return GetPointer<const ::flatbuffers::String*>(VT_SOUND); return GetPointer<const ::flatbuffers::String*>(VT_SOUND);
} }
uint16_t weight() const { uint16_t weight() const { return GetField<uint16_t>(VT_WEIGHT, 0); }
return GetField<uint16_t>(VT_WEIGHT, 0);
}
bool Verify(::flatbuffers::Verifier& verifier) const { bool Verify(::flatbuffers::Verifier& verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) &&
VerifyOffset(verifier, VT_NAME) && verifier.VerifyString(name()) && VerifyOffset(verifier, VT_SOUND) &&
verifier.VerifyString(name()) &&
VerifyOffset(verifier, VT_SOUND) &&
verifier.VerifyString(sound()) && verifier.VerifyString(sound()) &&
VerifyField<uint16_t>(verifier, VT_WEIGHT, 2) && VerifyField<uint16_t>(verifier, VT_WEIGHT, 2) && verifier.EndTable();
verifier.EndTable();
} }
}; };
@@ -60,8 +54,7 @@ struct AnimalBuilder {
void add_weight(uint16_t weight) { void add_weight(uint16_t weight) {
fbb_.AddElement<uint16_t>(Animal::VT_WEIGHT, weight, 0); fbb_.AddElement<uint16_t>(Animal::VT_WEIGHT, weight, 0);
} }
explicit AnimalBuilder(::flatbuffers::FlatBufferBuilder &_fbb) explicit AnimalBuilder(::flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) {
: fbb_(_fbb) {
start_ = fbb_.StartTable(); start_ = fbb_.StartTable();
} }
::flatbuffers::Offset<Animal> Finish() { ::flatbuffers::Offset<Animal> Finish() {
@@ -84,17 +77,11 @@ inline ::flatbuffers::Offset<Animal> CreateAnimal(
} }
inline ::flatbuffers::Offset<Animal> CreateAnimalDirect( inline ::flatbuffers::Offset<Animal> CreateAnimalDirect(
::flatbuffers::FlatBufferBuilder &_fbb, ::flatbuffers::FlatBufferBuilder& _fbb, const char* name = nullptr,
const char *name = nullptr, const char* sound = nullptr, uint16_t weight = 0) {
const char *sound = nullptr,
uint16_t weight = 0) {
auto name__ = name ? _fbb.CreateString(name) : 0; auto name__ = name ? _fbb.CreateString(name) : 0;
auto sound__ = sound ? _fbb.CreateString(sound) : 0; auto sound__ = sound ? _fbb.CreateString(sound) : 0;
return com::fbs::app::CreateAnimal( return com::fbs::app::CreateAnimal(_fbb, name__, sound__, weight);
_fbb,
name__,
sound__,
weight);
} }
inline const com::fbs::app::Animal* GetAnimal(const void* buf) { inline const com::fbs::app::Animal* GetAnimal(const void* buf) {
@@ -105,13 +92,11 @@ inline const com::fbs::app::Animal *GetSizePrefixedAnimal(const void *buf) {
return ::flatbuffers::GetSizePrefixedRoot<com::fbs::app::Animal>(buf); return ::flatbuffers::GetSizePrefixedRoot<com::fbs::app::Animal>(buf);
} }
inline bool VerifyAnimalBuffer( inline bool VerifyAnimalBuffer(::flatbuffers::Verifier& verifier) {
::flatbuffers::Verifier &verifier) {
return verifier.VerifyBuffer<com::fbs::app::Animal>(nullptr); return verifier.VerifyBuffer<com::fbs::app::Animal>(nullptr);
} }
inline bool VerifySizePrefixedAnimalBuffer( inline bool VerifySizePrefixedAnimalBuffer(::flatbuffers::Verifier& verifier) {
::flatbuffers::Verifier &verifier) {
return verifier.VerifySizePrefixedBuffer<com::fbs::app::Animal>(nullptr); return verifier.VerifySizePrefixedBuffer<com::fbs::app::Animal>(nullptr);
} }

View File

@@ -1,9 +1,9 @@
package com.flatbuffers.app package com.flatbuffers.app
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.fbs.app.Animal import com.fbs.app.Animal
import com.google.flatbuffers.FlatBufferBuilder import com.google.flatbuffers.FlatBufferBuilder
import java.nio.ByteBuffer import java.nio.ByteBuffer
@@ -29,11 +29,12 @@ class MainActivity : AppCompatActivity() {
// Create a "Cow" Animal flatbuffers from Kotlin // Create a "Cow" Animal flatbuffers from Kotlin
private fun createAnimalFromKotlin(): Animal { private fun createAnimalFromKotlin(): Animal {
val fb = FlatBufferBuilder(100) val fb = FlatBufferBuilder(100)
val cowOffset = Animal.createAnimal( val cowOffset =
Animal.createAnimal(
builder = fb, builder = fb,
nameOffset = fb.createString("Cow"), nameOffset = fb.createString("Cow"),
soundOffset = fb.createString("Moo"), soundOffset = fb.createString("Moo"),
weight = 720u weight = 720u,
) )
fb.finish(cowOffset) fb.finish(cowOffset)
return Animal.getRootAsAnimal(fb.dataBuffer()) return Animal.getRootAsAnimal(fb.dataBuffer())

View File

@@ -2,21 +2,11 @@
package com.fbs.app package com.fbs.app
import com.google.flatbuffers.BaseVector
import com.google.flatbuffers.BooleanVector
import com.google.flatbuffers.ByteVector
import com.google.flatbuffers.Constants import com.google.flatbuffers.Constants
import com.google.flatbuffers.DoubleVector
import com.google.flatbuffers.FlatBufferBuilder import com.google.flatbuffers.FlatBufferBuilder
import com.google.flatbuffers.FloatVector
import com.google.flatbuffers.LongVector
import com.google.flatbuffers.StringVector
import com.google.flatbuffers.Struct
import com.google.flatbuffers.Table import com.google.flatbuffers.Table
import com.google.flatbuffers.UnionVector
import java.nio.ByteBuffer import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.ByteOrder
import kotlin.math.sign
@Suppress("unused") @Suppress("unused")
@kotlin.ExperimentalUnsignedTypes @kotlin.ExperimentalUnsignedTypes
@@ -25,10 +15,12 @@ class Animal : Table() {
fun __init(_i: Int, _bb: ByteBuffer) { fun __init(_i: Int, _bb: ByteBuffer) {
__reset(_i, _bb) __reset(_i, _bb)
} }
fun __assign(_i: Int, _bb: ByteBuffer): Animal { fun __assign(_i: Int, _bb: ByteBuffer): Animal {
__init(_i, _bb) __init(_i, _bb)
return this return this
} }
val name: String? val name: String?
get() { get() {
val o = __offset(4) val o = __offset(4)
@@ -38,8 +30,12 @@ class Animal : Table() {
null null
} }
} }
val nameAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(4, 1)
val nameAsByteBuffer: ByteBuffer
get() = __vector_as_bytebuffer(4, 1)
fun nameInByteBuffer(_bb: ByteBuffer): ByteBuffer = __vector_in_bytebuffer(_bb, 4, 1) fun nameInByteBuffer(_bb: ByteBuffer): ByteBuffer = __vector_in_bytebuffer(_bb, 4, 1)
val sound: String? val sound: String?
get() { get() {
val o = __offset(6) val o = __offset(6)
@@ -49,36 +45,58 @@ class Animal : Table() {
null null
} }
} }
val soundAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(6, 1)
val soundAsByteBuffer: ByteBuffer
get() = __vector_as_bytebuffer(6, 1)
fun soundInByteBuffer(_bb: ByteBuffer): ByteBuffer = __vector_in_bytebuffer(_bb, 6, 1) fun soundInByteBuffer(_bb: ByteBuffer): ByteBuffer = __vector_in_bytebuffer(_bb, 6, 1)
val weight: UShort val weight: UShort
get() { get() {
val o = __offset(8) val o = __offset(8)
return if (o != 0) bb.getShort(o + bb_pos).toUShort() else 0u return if (o != 0) bb.getShort(o + bb_pos).toUShort() else 0u
} }
companion object { companion object {
fun validateVersion() = Constants.FLATBUFFERS_25_2_10() fun validateVersion() = Constants.FLATBUFFERS_25_9_23()
fun getRootAsAnimal(_bb: ByteBuffer): Animal = getRootAsAnimal(_bb, Animal()) fun getRootAsAnimal(_bb: ByteBuffer): Animal = getRootAsAnimal(_bb, Animal())
fun getRootAsAnimal(_bb: ByteBuffer, obj: Animal): Animal { fun getRootAsAnimal(_bb: ByteBuffer, obj: Animal): Animal {
_bb.order(ByteOrder.LITTLE_ENDIAN) _bb.order(ByteOrder.LITTLE_ENDIAN)
return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)) return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb))
} }
fun createAnimal(builder: FlatBufferBuilder, nameOffset: Int, soundOffset: Int, weight: UShort) : Int {
fun createAnimal(
builder: FlatBufferBuilder,
nameOffset: Int,
soundOffset: Int,
weight: UShort,
): Int {
builder.startTable(3) builder.startTable(3)
addSound(builder, soundOffset) addSound(builder, soundOffset)
addName(builder, nameOffset) addName(builder, nameOffset)
addWeight(builder, weight) addWeight(builder, weight)
return endAnimal(builder) return endAnimal(builder)
} }
fun startAnimal(builder: FlatBufferBuilder) = builder.startTable(3) fun startAnimal(builder: FlatBufferBuilder) = builder.startTable(3)
fun addName(builder: FlatBufferBuilder, name: Int) = builder.addOffset(0, name, 0) fun addName(builder: FlatBufferBuilder, name: Int) = builder.addOffset(0, name, 0)
fun addSound(builder: FlatBufferBuilder, sound: Int) = builder.addOffset(1, sound, 0) fun addSound(builder: FlatBufferBuilder, sound: Int) = builder.addOffset(1, sound, 0)
fun addWeight(builder: FlatBufferBuilder, weight: UShort) = builder.addShort(2, weight.toShort(), 0)
fun addWeight(builder: FlatBufferBuilder, weight: UShort) =
builder.addShort(2, weight.toShort(), 0)
fun endAnimal(builder: FlatBufferBuilder): Int { fun endAnimal(builder: FlatBufferBuilder): Int {
val o = builder.endTable() val o = builder.endTable()
return o return o
} }
fun finishAnimalBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset) fun finishAnimalBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finish(offset)
fun finishSizePrefixedAnimalBuffer(builder: FlatBufferBuilder, offset: Int) = builder.finishSizePrefixed(offset)
fun finishSizePrefixedAnimalBuffer(builder: FlatBufferBuilder, offset: Int) =
builder.finishSizePrefixed(offset)
} }
} }

View File

@@ -1,6 +1,5 @@
// automatically generated by the FlatBuffers compiler, do not modify // automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_ #ifndef FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_
#define FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_ #define FLATBUFFERS_GENERATED_BENCH_BENCHMARKS_FLATBUFFERS_H_
@@ -34,21 +33,12 @@ enum Enum : int16_t {
}; };
inline const Enum (&EnumValuesEnum())[3] { inline const Enum (&EnumValuesEnum())[3] {
static const Enum values[] = { static const Enum values[] = {Enum_Apples, Enum_Pears, Enum_Bananas};
Enum_Apples,
Enum_Pears,
Enum_Bananas
};
return values; return values;
} }
inline const char* const* EnumNamesEnum() { inline const char* const* EnumNamesEnum() {
static const char * const names[4] = { static const char* const names[4] = {"Apples", "Pears", "Bananas", nullptr};
"Apples",
"Pears",
"Bananas",
nullptr
};
return names; return names;
} }
@@ -67,12 +57,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Foo FLATBUFFERS_FINAL_CLASS {
uint32_t length_; uint32_t length_;
public: public:
Foo() Foo() : id_(0), count_(0), prefix_(0), padding0__(0), length_(0) {
: id_(0),
count_(0),
prefix_(0),
padding0__(0),
length_(0) {
(void)padding0__; (void)padding0__;
} }
Foo(uint64_t _id, int16_t _count, int8_t _prefix, uint32_t _length) Foo(uint64_t _id, int16_t _count, int8_t _prefix, uint32_t _length)
@@ -83,18 +68,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Foo FLATBUFFERS_FINAL_CLASS {
length_(flatbuffers::EndianScalar(_length)) { length_(flatbuffers::EndianScalar(_length)) {
(void)padding0__; (void)padding0__;
} }
uint64_t id() const { uint64_t id() const { return flatbuffers::EndianScalar(id_); }
return flatbuffers::EndianScalar(id_); int16_t count() const { return flatbuffers::EndianScalar(count_); }
} int8_t prefix() const { return flatbuffers::EndianScalar(prefix_); }
int16_t count() const { uint32_t length() const { return flatbuffers::EndianScalar(length_); }
return flatbuffers::EndianScalar(count_);
}
int8_t prefix() const {
return flatbuffers::EndianScalar(prefix_);
}
uint32_t length() const {
return flatbuffers::EndianScalar(length_);
}
}; };
FLATBUFFERS_STRUCT_END(Foo, 16); FLATBUFFERS_STRUCT_END(Foo, 16);
@@ -104,20 +81,17 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Bar FLATBUFFERS_FINAL_CLASS {
int32_t time_; int32_t time_;
float ratio_; float ratio_;
uint16_t size_; uint16_t size_;
int16_t padding0__; int32_t padding1__; int16_t padding0__;
int32_t padding1__;
public: public:
Bar() Bar()
: parent_(), : parent_(), time_(0), ratio_(0), size_(0), padding0__(0), padding1__(0) {
time_(0),
ratio_(0),
size_(0),
padding0__(0),
padding1__(0) {
(void)padding0__; (void)padding0__;
(void)padding1__; (void)padding1__;
} }
Bar(const benchmarks_flatbuffers::Foo &_parent, int32_t _time, float _ratio, uint16_t _size) Bar(const benchmarks_flatbuffers::Foo& _parent, int32_t _time, float _ratio,
uint16_t _size)
: parent_(_parent), : parent_(_parent),
time_(flatbuffers::EndianScalar(_time)), time_(flatbuffers::EndianScalar(_time)),
ratio_(flatbuffers::EndianScalar(_ratio)), ratio_(flatbuffers::EndianScalar(_ratio)),
@@ -127,18 +101,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Bar FLATBUFFERS_FINAL_CLASS {
(void)padding0__; (void)padding0__;
(void)padding1__; (void)padding1__;
} }
const benchmarks_flatbuffers::Foo &parent() const { const benchmarks_flatbuffers::Foo& parent() const { return parent_; }
return parent_; int32_t time() const { return flatbuffers::EndianScalar(time_); }
} float ratio() const { return flatbuffers::EndianScalar(ratio_); }
int32_t time() const { uint16_t size() const { return flatbuffers::EndianScalar(size_); }
return flatbuffers::EndianScalar(time_);
}
float ratio() const {
return flatbuffers::EndianScalar(ratio_);
}
uint16_t size() const {
return flatbuffers::EndianScalar(size_);
}
}; };
FLATBUFFERS_STRUCT_END(Bar, 32); FLATBUFFERS_STRUCT_END(Bar, 32);
@@ -156,20 +122,14 @@ struct FooBar FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::String* name() const { const flatbuffers::String* name() const {
return GetPointer<const flatbuffers::String*>(VT_NAME); return GetPointer<const flatbuffers::String*>(VT_NAME);
} }
double rating() const { double rating() const { return GetField<double>(VT_RATING, 0.0); }
return GetField<double>(VT_RATING, 0.0); uint8_t postfix() const { return GetField<uint8_t>(VT_POSTFIX, 0); }
}
uint8_t postfix() const {
return GetField<uint8_t>(VT_POSTFIX, 0);
}
bool Verify(flatbuffers::Verifier& verifier) const { bool Verify(flatbuffers::Verifier& verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) &&
VerifyField<benchmarks_flatbuffers::Bar>(verifier, VT_SIBLING, 8) && VerifyField<benchmarks_flatbuffers::Bar>(verifier, VT_SIBLING, 8) &&
VerifyOffset(verifier, VT_NAME) && VerifyOffset(verifier, VT_NAME) && verifier.VerifyString(name()) &&
verifier.VerifyString(name()) &&
VerifyField<double>(verifier, VT_RATING, 8) && VerifyField<double>(verifier, VT_RATING, 8) &&
VerifyField<uint8_t>(verifier, VT_POSTFIX, 1) && VerifyField<uint8_t>(verifier, VT_POSTFIX, 1) && verifier.EndTable();
verifier.EndTable();
} }
}; };
@@ -189,8 +149,7 @@ struct FooBarBuilder {
void add_postfix(uint8_t postfix) { void add_postfix(uint8_t postfix) {
fbb_.AddElement<uint8_t>(FooBar::VT_POSTFIX, postfix, 0); fbb_.AddElement<uint8_t>(FooBar::VT_POSTFIX, postfix, 0);
} }
explicit FooBarBuilder(flatbuffers::FlatBufferBuilder &_fbb) explicit FooBarBuilder(flatbuffers::FlatBufferBuilder& _fbb) : fbb_(_fbb) {
: fbb_(_fbb) {
start_ = fbb_.StartTable(); start_ = fbb_.StartTable();
} }
flatbuffers::Offset<FooBar> Finish() { flatbuffers::Offset<FooBar> Finish() {
@@ -203,8 +162,7 @@ struct FooBarBuilder {
inline flatbuffers::Offset<FooBar> CreateFooBar( inline flatbuffers::Offset<FooBar> CreateFooBar(
flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::FlatBufferBuilder& _fbb,
const benchmarks_flatbuffers::Bar* sibling = nullptr, const benchmarks_flatbuffers::Bar* sibling = nullptr,
flatbuffers::Offset<flatbuffers::String> name = 0, flatbuffers::Offset<flatbuffers::String> name = 0, double rating = 0.0,
double rating = 0.0,
uint8_t postfix = 0) { uint8_t postfix = 0) {
FooBarBuilder builder_(_fbb); FooBarBuilder builder_(_fbb);
builder_.add_rating(rating); builder_.add_rating(rating);
@@ -217,15 +175,9 @@ inline flatbuffers::Offset<FooBar> CreateFooBar(
inline flatbuffers::Offset<FooBar> CreateFooBarDirect( inline flatbuffers::Offset<FooBar> CreateFooBarDirect(
flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::FlatBufferBuilder& _fbb,
const benchmarks_flatbuffers::Bar* sibling = nullptr, const benchmarks_flatbuffers::Bar* sibling = nullptr,
const char *name = nullptr, const char* name = nullptr, double rating = 0.0, uint8_t postfix = 0) {
double rating = 0.0,
uint8_t postfix = 0) {
auto name__ = name ? _fbb.CreateString(name) : 0; auto name__ = name ? _fbb.CreateString(name) : 0;
return benchmarks_flatbuffers::CreateFooBar( return benchmarks_flatbuffers::CreateFooBar(_fbb, sibling, name__, rating,
_fbb,
sibling,
name__,
rating,
postfix); postfix);
} }
@@ -237,28 +189,28 @@ struct FooBarContainer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_FRUIT = 8, VT_FRUIT = 8,
VT_LOCATION = 10 VT_LOCATION = 10
}; };
const flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>> *list() const { const flatbuffers::Vector<
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>> *>(VT_LIST); flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>*
} list() const {
bool initialized() const { return GetPointer<const flatbuffers::Vector<
return GetField<uint8_t>(VT_INITIALIZED, 0) != 0; flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>*>(VT_LIST);
} }
bool initialized() const { return GetField<uint8_t>(VT_INITIALIZED, 0) != 0; }
benchmarks_flatbuffers::Enum fruit() const { benchmarks_flatbuffers::Enum fruit() const {
return static_cast<benchmarks_flatbuffers::Enum>(GetField<int16_t>(VT_FRUIT, 0)); return static_cast<benchmarks_flatbuffers::Enum>(
GetField<int16_t>(VT_FRUIT, 0));
} }
const flatbuffers::String* location() const { const flatbuffers::String* location() const {
return GetPointer<const flatbuffers::String*>(VT_LOCATION); return GetPointer<const flatbuffers::String*>(VT_LOCATION);
} }
bool Verify(flatbuffers::Verifier& verifier) const { bool Verify(flatbuffers::Verifier& verifier) const {
return VerifyTableStart(verifier) && return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_LIST) &&
VerifyOffset(verifier, VT_LIST) &&
verifier.VerifyVector(list()) && verifier.VerifyVector(list()) &&
verifier.VerifyVectorOfTables(list()) && verifier.VerifyVectorOfTables(list()) &&
VerifyField<uint8_t>(verifier, VT_INITIALIZED, 1) && VerifyField<uint8_t>(verifier, VT_INITIALIZED, 1) &&
VerifyField<int16_t>(verifier, VT_FRUIT, 2) && VerifyField<int16_t>(verifier, VT_FRUIT, 2) &&
VerifyOffset(verifier, VT_LOCATION) && VerifyOffset(verifier, VT_LOCATION) &&
verifier.VerifyString(location()) && verifier.VerifyString(location()) && verifier.EndTable();
verifier.EndTable();
} }
}; };
@@ -266,14 +218,18 @@ struct FooBarContainerBuilder {
typedef FooBarContainer Table; typedef FooBarContainer Table;
flatbuffers::FlatBufferBuilder& fbb_; flatbuffers::FlatBufferBuilder& fbb_;
flatbuffers::uoffset_t start_; flatbuffers::uoffset_t start_;
void add_list(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>> list) { void add_list(flatbuffers::Offset<flatbuffers::Vector<
flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>>
list) {
fbb_.AddOffset(FooBarContainer::VT_LIST, list); fbb_.AddOffset(FooBarContainer::VT_LIST, list);
} }
void add_initialized(bool initialized) { void add_initialized(bool initialized) {
fbb_.AddElement<uint8_t>(FooBarContainer::VT_INITIALIZED, static_cast<uint8_t>(initialized), 0); fbb_.AddElement<uint8_t>(FooBarContainer::VT_INITIALIZED,
static_cast<uint8_t>(initialized), 0);
} }
void add_fruit(benchmarks_flatbuffers::Enum fruit) { void add_fruit(benchmarks_flatbuffers::Enum fruit) {
fbb_.AddElement<int16_t>(FooBarContainer::VT_FRUIT, static_cast<int16_t>(fruit), 0); fbb_.AddElement<int16_t>(FooBarContainer::VT_FRUIT,
static_cast<int16_t>(fruit), 0);
} }
void add_location(flatbuffers::Offset<flatbuffers::String> location) { void add_location(flatbuffers::Offset<flatbuffers::String> location) {
fbb_.AddOffset(FooBarContainer::VT_LOCATION, location); fbb_.AddOffset(FooBarContainer::VT_LOCATION, location);
@@ -291,7 +247,9 @@ struct FooBarContainerBuilder {
inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainer( inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainer(
flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::FlatBufferBuilder& _fbb,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>> list = 0, flatbuffers::Offset<flatbuffers::Vector<
flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>>
list = 0,
bool initialized = false, bool initialized = false,
benchmarks_flatbuffers::Enum fruit = benchmarks_flatbuffers::Enum_Apples, benchmarks_flatbuffers::Enum fruit = benchmarks_flatbuffers::Enum_Apples,
flatbuffers::Offset<flatbuffers::String> location = 0) { flatbuffers::Offset<flatbuffers::String> location = 0) {
@@ -305,36 +263,41 @@ inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainer(
inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainerDirect( inline flatbuffers::Offset<FooBarContainer> CreateFooBarContainerDirect(
flatbuffers::FlatBufferBuilder& _fbb, flatbuffers::FlatBufferBuilder& _fbb,
const std::vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>> *list = nullptr, const std::vector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>*
list = nullptr,
bool initialized = false, bool initialized = false,
benchmarks_flatbuffers::Enum fruit = benchmarks_flatbuffers::Enum_Apples, benchmarks_flatbuffers::Enum fruit = benchmarks_flatbuffers::Enum_Apples,
const char* location = nullptr) { const char* location = nullptr) {
auto list__ = list ? _fbb.CreateVector<flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>(*list) : 0; auto list__ =
list ? _fbb.CreateVector<
flatbuffers::Offset<benchmarks_flatbuffers::FooBar>>(*list)
: 0;
auto location__ = location ? _fbb.CreateString(location) : 0; auto location__ = location ? _fbb.CreateString(location) : 0;
return benchmarks_flatbuffers::CreateFooBarContainer( return benchmarks_flatbuffers::CreateFooBarContainer(
_fbb, _fbb, list__, initialized, fruit, location__);
list__,
initialized,
fruit,
location__);
} }
inline const benchmarks_flatbuffers::FooBarContainer *GetFooBarContainer(const void *buf) { inline const benchmarks_flatbuffers::FooBarContainer* GetFooBarContainer(
const void* buf) {
return flatbuffers::GetRoot<benchmarks_flatbuffers::FooBarContainer>(buf); return flatbuffers::GetRoot<benchmarks_flatbuffers::FooBarContainer>(buf);
} }
inline const benchmarks_flatbuffers::FooBarContainer *GetSizePrefixedFooBarContainer(const void *buf) { inline const benchmarks_flatbuffers::FooBarContainer*
return flatbuffers::GetSizePrefixedRoot<benchmarks_flatbuffers::FooBarContainer>(buf); GetSizePrefixedFooBarContainer(const void* buf) {
return flatbuffers::GetSizePrefixedRoot<
benchmarks_flatbuffers::FooBarContainer>(buf);
} }
inline bool VerifyFooBarContainerBuffer( inline bool VerifyFooBarContainerBuffer(flatbuffers::Verifier& verifier) {
flatbuffers::Verifier &verifier) { return verifier.VerifyBuffer<benchmarks_flatbuffers::FooBarContainer>(
return verifier.VerifyBuffer<benchmarks_flatbuffers::FooBarContainer>(nullptr); nullptr);
} }
inline bool VerifySizePrefixedFooBarContainerBuffer( inline bool VerifySizePrefixedFooBarContainerBuffer(
flatbuffers::Verifier& verifier) { flatbuffers::Verifier& verifier) {
return verifier.VerifySizePrefixedBuffer<benchmarks_flatbuffers::FooBarContainer>(nullptr); return verifier
.VerifySizePrefixedBuffer<benchmarks_flatbuffers::FooBarContainer>(
nullptr);
} }
inline void FinishFooBarContainerBuffer( inline void FinishFooBarContainerBuffer(

View File

@@ -15,8 +15,8 @@
*/ */
import Benchmark import Benchmark
import CoreFoundation
import FlatBuffers import FlatBuffers
import Foundation
@usableFromInline @usableFromInline
struct AA: NativeStruct { struct AA: NativeStruct {
@@ -29,6 +29,15 @@ struct AA: NativeStruct {
} }
let benchmarks = { let benchmarks = {
let oneGB: Int32 = 1_024_000_000
let data = {
var array = [8888.88, 8888.88]
var data = Data()
array.withUnsafeBytes { ptr in
data.append(contentsOf: ptr)
}
return data
}()
let ints: [Int] = Array(repeating: 42, count: 100) let ints: [Int] = Array(repeating: 42, count: 100)
let bytes: [UInt8] = Array(repeating: 42, count: 100) let bytes: [UInt8] = Array(repeating: 42, count: 100)
let str10 = (0...9).map { _ -> String in "x" }.joined() let str10 = (0...9).map { _ -> String in "x" }.joined()
@@ -73,12 +82,25 @@ let benchmarks = {
Benchmark("Allocating 1GB", configuration: singleConfiguration) { benchmark in Benchmark("Allocating 1GB", configuration: singleConfiguration) { benchmark in
for _ in benchmark.scaledIterations { for _ in benchmark.scaledIterations {
blackHole(FlatBufferBuilder(initialSize: 1_024_000_000)) blackHole(FlatBufferBuilder(initialSize: oneGB))
}
}
Benchmark(
"Allocating ByteBuffer 1GB",
configuration: singleConfiguration
) { benchmark in
let memory = UnsafeMutableRawPointer.allocate(
byteCount: 1_024_000_000,
alignment: 1)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
blackHole(ByteBuffer(assumingMemoryBound: memory, capacity: Int(oneGB)))
} }
} }
Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in
var fb = FlatBufferBuilder(initialSize: 1_024_000_000) var fb = FlatBufferBuilder(initialSize: oneGB)
benchmark.startMeasurement() benchmark.startMeasurement()
for _ in benchmark.scaledIterations { for _ in benchmark.scaledIterations {
blackHole(fb.clear()) blackHole(fb.clear())
@@ -143,8 +165,8 @@ let benchmarks = {
Benchmark( Benchmark(
"FlatBufferBuilder Add", "FlatBufferBuilder Add",
configuration: kiloConfiguration) configuration: kiloConfiguration
{ benchmark in ) { benchmark in
var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32) var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32)
benchmark.startMeasurement() benchmark.startMeasurement()
for _ in benchmark.scaledIterations { for _ in benchmark.scaledIterations {
@@ -158,6 +180,26 @@ let benchmarks = {
} }
} }
Benchmark(
"FlatBufferBuilder Start table",
configuration: kiloConfiguration
) { benchmark in
var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
let s = fb.startTable(with: 4)
blackHole(fb.endTable(at: s))
}
}
Benchmark("Struct") { benchmark in
var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
blackHole(fb.create(struct: array.first!))
}
}
Benchmark("Structs") { benchmark in Benchmark("Structs") { benchmark in
let rawSize = ((16 * 5) * benchmark.scaledIterations.count) / 1024 let rawSize = ((16 * 5) * benchmark.scaledIterations.count) / 1024
var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600)) var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600))
@@ -176,7 +218,7 @@ let benchmarks = {
let start = fb.startTable(with: 1) let start = fb.startTable(with: 1)
fb.add(offset: vector, at: 4) fb.add(offset: vector, at: 4)
let root = Offset(offset: fb.endTable(at: start)) let root = Offset(offset: fb.endTable(at: start))
fb.finish(offset: root) blackHole(fb.finish(offset: root))
} }
Benchmark("Vector of Offsets") { benchmark in Benchmark("Vector of Offsets") { benchmark in
@@ -198,4 +240,11 @@ let benchmarks = {
blackHole(fb.endTable(at: s)) blackHole(fb.endTable(at: s))
} }
} }
Benchmark("Reading Doubles") { benchmark in
let byteBuffer = ByteBuffer(data: data)
for _ in benchmark.scaledIterations {
blackHole(byteBuffer.read(def: Double.self, position: 0))
}
}
} }

View File

@@ -20,7 +20,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "benchmarks", name: "benchmarks",
platforms: [ platforms: [
.macOS(.v13), .macOS(.v13)
], ],
dependencies: [ dependencies: [
.package(path: "../.."), .package(path: "../.."),
@@ -37,6 +37,6 @@ let package = Package(
], ],
path: "Benchmarks/FlatbuffersBenchmarks", path: "Benchmarks/FlatbuffersBenchmarks",
plugins: [ plugins: [
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"), .plugin(name: "BenchmarkPlugin", package: "package-benchmark")
]), ])
]) ])

View File

@@ -6,10 +6,11 @@ import subprocess
from cpt.packager import ConanMultiPackager from cpt.packager import ConanMultiPackager
def get_branch(): def get_branch():
try: try:
for line in subprocess.check_output("git branch", shell=True).decode().splitlines(): for line in (
subprocess.check_output("git branch", shell=True).decode().splitlines()
):
line = line.strip() line = line.strip()
if line.startswith("*") and " (HEAD detached" not in line: if line.startswith("*") and " (HEAD detached" not in line:
return line.replace("*", "", 1).strip() return line.replace("*", "", 1).strip()
@@ -34,17 +35,25 @@ def get_reference(username):
if __name__ == "__main__": if __name__ == "__main__":
login_username = os.getenv("CONAN_LOGIN_USERNAME", "aardappel") login_username = os.getenv("CONAN_LOGIN_USERNAME", "aardappel")
username = os.getenv("CONAN_USERNAME", "google") username = os.getenv("CONAN_USERNAME", "google")
upload = os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/aardappel/flatbuffers") upload = os.getenv(
stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*") "CONAN_UPLOAD", "https://api.bintray.com/conan/aardappel/flatbuffers"
test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package")) )
stable_branch_pattern = os.getenv(
"CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*"
)
test_folder = os.getenv(
"CPT_TEST_FOLDER", os.path.join("conan", "test_package")
)
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True) upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
builder = ConanMultiPackager(reference=get_reference(username), builder = ConanMultiPackager(
reference=get_reference(username),
username=username, username=username,
login_username=login_username, login_username=login_username,
upload=upload, upload=upload,
stable_branch_pattern=stable_branch_pattern, stable_branch_pattern=stable_branch_pattern,
upload_only_when_stable=upload_only_when_stable, upload_only_when_stable=upload_only_when_stable,
test_folder=test_folder) test_folder=test_folder,
)
builder.add_common_builds(pure_c=False) builder.add_common_builds(pure_c=False)
builder.run() builder.run()

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from conans import ConanFile, CMake
import os import os
from conans import CMake, ConanFile
class TestPackageConan(ConanFile): class TestPackageConan(ConanFile):

View File

@@ -1,11 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Conan recipe package for Google FlatBuffers """Conan recipe package for Google FlatBuffers"""
"""
import os import os
import shutil import shutil
from conans import ConanFile, CMake, tools from conans import CMake, ConanFile, tools
class FlatbuffersConan(ConanFile): class FlatbuffersConan(ConanFile):
@@ -21,23 +20,27 @@ class FlatbuffersConan(ConanFile):
default_options = {"shared": False, "fPIC": True} default_options = {"shared": False, "fPIC": True}
generators = "cmake" generators = "cmake"
exports = "LICENSE" exports = "LICENSE"
exports_sources = ["CMake/*", "include/*", "src/*", "grpc/*", "CMakeLists.txt", "conan/CMakeLists.txt"] exports_sources = [
"CMake/*",
"include/*",
"src/*",
"grpc/*",
"CMakeLists.txt",
"conan/CMakeLists.txt",
]
def source(self): def source(self):
"""Wrap the original CMake file to call conan_basic_setup """Wrap the original CMake file to call conan_basic_setup"""
"""
shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt") shutil.move("CMakeLists.txt", "CMakeListsOriginal.txt")
shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt") shutil.move(os.path.join("conan", "CMakeLists.txt"), "CMakeLists.txt")
def config_options(self): def config_options(self):
"""Remove fPIC option on Windows platform """Remove fPIC option on Windows platform"""
"""
if self.settings.os == "Windows": if self.settings.os == "Windows":
self.options.remove("fPIC") self.options.remove("fPIC")
def configure_cmake(self): def configure_cmake(self):
"""Create CMake instance and execute configure step """Create CMake instance and execute configure step"""
"""
cmake = CMake(self) cmake = CMake(self)
cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False cmake.definitions["FLATBUFFERS_BUILD_TESTS"] = False
cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared cmake.definitions["FLATBUFFERS_BUILD_SHAREDLIB"] = self.options.shared
@@ -46,30 +49,35 @@ class FlatbuffersConan(ConanFile):
return cmake return cmake
def build(self): def build(self):
"""Configure, build and install FlatBuffers using CMake. """Configure, build and install FlatBuffers using CMake."""
"""
cmake = self.configure_cmake() cmake = self.configure_cmake()
cmake.build() cmake.build()
def package(self): def package(self):
"""Copy Flatbuffers' artifacts to package folder """Copy Flatbuffers' artifacts to package folder"""
"""
cmake = self.configure_cmake() cmake = self.configure_cmake()
cmake.install() cmake.install()
self.copy(pattern="LICENSE", dst="licenses") self.copy(pattern="LICENSE", dst="licenses")
self.copy(pattern="FindFlatBuffers.cmake", dst=os.path.join("lib", "cmake", "flatbuffers"), src="CMake") self.copy(
pattern="FindFlatBuffers.cmake",
dst=os.path.join("lib", "cmake", "flatbuffers"),
src="CMake",
)
self.copy(pattern="flathash*", dst="bin", src="bin") self.copy(pattern="flathash*", dst="bin", src="bin")
self.copy(pattern="flatc*", dst="bin", src="bin") self.copy(pattern="flatc*", dst="bin", src="bin")
if self.settings.os == "Windows" and self.options.shared: if self.settings.os == "Windows" and self.options.shared:
if self.settings.compiler == "Visual Studio": if self.settings.compiler == "Visual Studio":
shutil.move(os.path.join(self.package_folder, "lib", "%s.dll" % self.name), shutil.move(
os.path.join(self.package_folder, "bin", "%s.dll" % self.name)) os.path.join(self.package_folder, "lib", "%s.dll" % self.name),
os.path.join(self.package_folder, "bin", "%s.dll" % self.name),
)
elif self.settings.compiler == "gcc": elif self.settings.compiler == "gcc":
shutil.move(os.path.join(self.package_folder, "lib", "lib%s.dll" % self.name), shutil.move(
os.path.join(self.package_folder, "bin", "lib%s.dll" % self.name)) os.path.join(self.package_folder, "lib", "lib%s.dll" % self.name),
os.path.join(self.package_folder, "bin", "lib%s.dll" % self.name),
)
def package_info(self): def package_info(self):
"""Collect built libraries names and solve flatc path. """Collect built libraries names and solve flatc path."""
"""
self.cpp_info.libs = tools.collect_libs(self) self.cpp_info.libs = tools.collect_libs(self)
self.user_info.flatc = os.path.join(self.package_folder, "bin", "flatc") self.user_info.flatc = os.path.join(self.package_folder, "bin", "flatc")

View File

@@ -15,6 +15,7 @@
*/ */
import 'package:flat_buffers/flat_buffers.dart' as fb; import 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_my_game.sample_generated.dart' as my_game; import './monster_my_game.sample_generated.dart' as my_game;
// Example how to use FlatBuffers to create and read binary buffers. // Example how to use FlatBuffers to create and read binary buffers.
@@ -78,7 +79,8 @@ void builderTest() {
builder.finish(monsteroff); builder.finish(monsteroff);
if (verify(builder.buffer)) { if (verify(builder.buffer)) {
print( print(
"The FlatBuffer was successfully created with a builder and verified!"); "The FlatBuffer was successfully created with a builder and verified!",
);
} }
} }
@@ -94,7 +96,10 @@ void objectBuilderTest() {
name: 'Orc', name: 'Orc',
inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], inventory: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
color: my_game.Color.Red, color: my_game.Color.Red,
weapons: [my_game.WeaponObjectBuilder(name: 'Sword', damage: 3), axe], weapons: [
my_game.WeaponObjectBuilder(name: 'Sword', damage: 3),
axe,
],
equippedType: my_game.EquipmentTypeId.Weapon, equippedType: my_game.EquipmentTypeId.Weapon,
equipped: axe, equipped: axe,
); );
@@ -108,7 +113,8 @@ void objectBuilderTest() {
// Instead, we're going to access it right away (as if we just received it). // Instead, we're going to access it right away (as if we just received it).
if (verify(buffer)) { if (verify(buffer)) {
print( print(
"The FlatBuffer was successfully created with an object builder and verified!"); "The FlatBuffer was successfully created with an object builder and verified!",
);
} }
} }

View File

@@ -4,8 +4,8 @@
library my_game.sample; library my_game.sample;
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'package:flat_buffers/flat_buffers.dart' as fb;
class Color { class Color {
final int value; final int value;
@@ -29,10 +29,7 @@ class Color {
static const Color Red = Color._(0); static const Color Red = Color._(0);
static const Color Green = Color._(1); static const Color Green = Color._(1);
static const Color Blue = Color._(2); static const Color Blue = Color._(2);
static const Map<int, Color> values = { static const Map<int, Color> values = {0: Red, 1: Green, 2: Blue};
0: Red,
1: Green,
2: Blue};
static const fb.Reader<Color> reader = _ColorReader(); static const fb.Reader<Color> reader = _ColorReader();
@@ -60,7 +57,9 @@ class EquipmentTypeId {
factory EquipmentTypeId.fromValue(int value) { factory EquipmentTypeId.fromValue(int value) {
final result = values[value]; final result = values[value];
if (result == null) { if (result == null) {
throw StateError('Invalid value $value for bit flag enum EquipmentTypeId'); throw StateError(
'Invalid value $value for bit flag enum EquipmentTypeId',
);
} }
return result; return result;
} }
@@ -74,9 +73,7 @@ class EquipmentTypeId {
static const EquipmentTypeId NONE = EquipmentTypeId._(0); static const EquipmentTypeId NONE = EquipmentTypeId._(0);
static const EquipmentTypeId Weapon = EquipmentTypeId._(1); static const EquipmentTypeId Weapon = EquipmentTypeId._(1);
static const Map<int, EquipmentTypeId> values = { static const Map<int, EquipmentTypeId> values = {0: NONE, 1: Weapon};
0: NONE,
1: Weapon};
static const fb.Reader<EquipmentTypeId> reader = _EquipmentTypeIdReader(); static const fb.Reader<EquipmentTypeId> reader = _EquipmentTypeIdReader();
@@ -122,8 +119,7 @@ class _Vec3Reader extends fb.StructReader<Vec3> {
int get size => 12; int get size => 12;
@override @override
Vec3 createObject(fb.BufferContext bc, int offset) => Vec3 createObject(fb.BufferContext bc, int offset) => Vec3._(bc, offset);
Vec3._(bc, offset);
} }
class Vec3Builder { class Vec3Builder {
@@ -137,7 +133,6 @@ class Vec3Builder {
fbBuilder.putFloat32(x); fbBuilder.putFloat32(x);
return fbBuilder.offset; return fbBuilder.offset;
} }
} }
class Vec3ObjectBuilder extends fb.ObjectBuilder { class Vec3ObjectBuilder extends fb.ObjectBuilder {
@@ -145,11 +140,7 @@ class Vec3ObjectBuilder extends fb.ObjectBuilder {
final double _y; final double _y;
final double _z; final double _z;
Vec3ObjectBuilder({ Vec3ObjectBuilder({required double x, required double y, required double z})
required double x,
required double y,
required double z,
})
: _x = x, : _x = x,
_y = y, _y = y,
_z = z; _z = z;
@@ -171,6 +162,7 @@ class Vec3ObjectBuilder extends fb.ObjectBuilder {
return fbBuilder.buffer; return fbBuilder.buffer;
} }
} }
class Monster { class Monster {
Monster._(this._bc, this._bcOffset); Monster._(this._bc, this._bcOffset);
factory Monster(List<int> bytes) { factory Monster(List<int> bytes) {
@@ -186,18 +178,30 @@ class Monster {
Vec3? get pos => Vec3.reader.vTableGetNullable(_bc, _bcOffset, 4); Vec3? get pos => Vec3.reader.vTableGetNullable(_bc, _bcOffset, 4);
int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150); int get mana => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 150);
int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100); int get hp => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 8, 100);
String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 10); String? get name =>
List<int>? get inventory => const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 14); const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 10);
Color get color => Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2)); List<int>? get inventory =>
List<Weapon>? get weapons => const fb.ListReader<Weapon>(Weapon.reader).vTableGetNullable(_bc, _bcOffset, 18); const fb.Uint8ListReader().vTableGetNullable(_bc, _bcOffset, 14);
EquipmentTypeId? get equippedType => EquipmentTypeId._createOrNull(const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 20)); Color get color =>
Color.fromValue(const fb.Int8Reader().vTableGet(_bc, _bcOffset, 16, 2));
List<Weapon>? get weapons => const fb.ListReader<Weapon>(
Weapon.reader,
).vTableGetNullable(_bc, _bcOffset, 18);
EquipmentTypeId? get equippedType => EquipmentTypeId._createOrNull(
const fb.Uint8Reader().vTableGetNullable(_bc, _bcOffset, 20),
);
dynamic get equipped { dynamic get equipped {
switch (equippedType?.value) { switch (equippedType?.value) {
case 1: return Weapon.reader.vTableGetNullable(_bc, _bcOffset, 22); case 1:
default: return null; return Weapon.reader.vTableGetNullable(_bc, _bcOffset, 22);
default:
return null;
} }
} }
List<Vec3>? get path => const fb.ListReader<Vec3>(Vec3.reader).vTableGetNullable(_bc, _bcOffset, 24);
List<Vec3>? get path => const fb.ListReader<Vec3>(
Vec3.reader,
).vTableGetNullable(_bc, _bcOffset, 24);
@override @override
String toString() { String toString() {
@@ -226,38 +230,47 @@ class MonsterBuilder {
fbBuilder.addStruct(0, offset); fbBuilder.addStruct(0, offset);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addMana(int? mana) { int addMana(int? mana) {
fbBuilder.addInt16(1, mana); fbBuilder.addInt16(1, mana);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addHp(int? hp) { int addHp(int? hp) {
fbBuilder.addInt16(2, hp); fbBuilder.addInt16(2, hp);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addNameOffset(int? offset) { int addNameOffset(int? offset) {
fbBuilder.addOffset(3, offset); fbBuilder.addOffset(3, offset);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addInventoryOffset(int? offset) { int addInventoryOffset(int? offset) {
fbBuilder.addOffset(5, offset); fbBuilder.addOffset(5, offset);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addColor(Color? color) { int addColor(Color? color) {
fbBuilder.addInt8(6, color?.value); fbBuilder.addInt8(6, color?.value);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addWeaponsOffset(int? offset) { int addWeaponsOffset(int? offset) {
fbBuilder.addOffset(7, offset); fbBuilder.addOffset(7, offset);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addEquippedType(EquipmentTypeId? equippedType) { int addEquippedType(EquipmentTypeId? equippedType) {
fbBuilder.addUint8(8, equippedType?.value); fbBuilder.addUint8(8, equippedType?.value);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addEquippedOffset(int? offset) { int addEquippedOffset(int? offset) {
fbBuilder.addOffset(9, offset); fbBuilder.addOffset(9, offset);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addPathOffset(int? offset) { int addPathOffset(int? offset) {
fbBuilder.addOffset(10, offset); fbBuilder.addOffset(10, offset);
return fbBuilder.offset; return fbBuilder.offset;
@@ -291,8 +304,7 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
EquipmentTypeId? equippedType, EquipmentTypeId? equippedType,
dynamic equipped, dynamic equipped,
List<Vec3ObjectBuilder>? path, List<Vec3ObjectBuilder>? path,
}) }) : _pos = pos,
: _pos = pos,
_mana = mana, _mana = mana,
_hp = hp, _hp = hp,
_name = name, _name = name,
@@ -306,14 +318,20 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].
@override @override
int finish(fb.Builder fbBuilder) { int finish(fb.Builder fbBuilder) {
final int? nameOffset = _name == null ? null final int? nameOffset = _name == null
? null
: fbBuilder.writeString(_name!); : fbBuilder.writeString(_name!);
final int? inventoryOffset = _inventory == null ? null final int? inventoryOffset = _inventory == null
? null
: fbBuilder.writeListUint8(_inventory!); : fbBuilder.writeListUint8(_inventory!);
final int? weaponsOffset = _weapons == null ? null final int? weaponsOffset = _weapons == null
: fbBuilder.writeList(_weapons!.map((b) => b.getOrCreateOffset(fbBuilder)).toList()); ? null
: fbBuilder.writeList(
_weapons!.map((b) => b.getOrCreateOffset(fbBuilder)).toList(),
);
final int? equippedOffset = _equipped?.getOrCreateOffset(fbBuilder); final int? equippedOffset = _equipped?.getOrCreateOffset(fbBuilder);
final int? pathOffset = _path == null ? null final int? pathOffset = _path == null
? null
: fbBuilder.writeListOfStructs(_path!); : fbBuilder.writeListOfStructs(_path!);
fbBuilder.startTable(10); fbBuilder.startTable(10);
if (_pos != null) { if (_pos != null) {
@@ -339,6 +357,7 @@ class MonsterObjectBuilder extends fb.ObjectBuilder {
return fbBuilder.buffer; return fbBuilder.buffer;
} }
} }
class Weapon { class Weapon {
Weapon._(this._bc, this._bcOffset); Weapon._(this._bc, this._bcOffset);
factory Weapon(List<int> bytes) { factory Weapon(List<int> bytes) {
@@ -351,7 +370,8 @@ class Weapon {
final fb.BufferContext _bc; final fb.BufferContext _bc;
final int _bcOffset; final int _bcOffset;
String? get name => const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 4); String? get name =>
const fb.StringReader().vTableGetNullable(_bc, _bcOffset, 4);
int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 0); int get damage => const fb.Int16Reader().vTableGet(_bc, _bcOffset, 6, 0);
@override @override
@@ -364,8 +384,7 @@ class _WeaponReader extends fb.TableReader<Weapon> {
const _WeaponReader(); const _WeaponReader();
@override @override
Weapon createObject(fb.BufferContext bc, int offset) => Weapon createObject(fb.BufferContext bc, int offset) => Weapon._(bc, offset);
Weapon._(bc, offset);
} }
class WeaponBuilder { class WeaponBuilder {
@@ -381,6 +400,7 @@ class WeaponBuilder {
fbBuilder.addOffset(0, offset); fbBuilder.addOffset(0, offset);
return fbBuilder.offset; return fbBuilder.offset;
} }
int addDamage(int? damage) { int addDamage(int? damage) {
fbBuilder.addInt16(1, damage); fbBuilder.addInt16(1, damage);
return fbBuilder.offset; return fbBuilder.offset;
@@ -395,17 +415,15 @@ class WeaponObjectBuilder extends fb.ObjectBuilder {
final String? _name; final String? _name;
final int? _damage; final int? _damage;
WeaponObjectBuilder({ WeaponObjectBuilder({String? name, int? damage})
String? name,
int? damage,
})
: _name = name, : _name = name,
_damage = damage; _damage = damage;
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].
@override @override
int finish(fb.Builder fbBuilder) { int finish(fb.Builder fbBuilder) {
final int? nameOffset = _name == null ? null final int? nameOffset = _name == null
? null
: fbBuilder.writeString(_name!); : fbBuilder.writeString(_name!);
fbBuilder.startTable(2); fbBuilder.startTable(2);
fbBuilder.addOffset(0, nameOffset); fbBuilder.addOffset(0, nameOffset);

View File

@@ -27,10 +27,11 @@ class BufferContext {
ByteData get buffer => _buffer; ByteData get buffer => _buffer;
/// Create from a FlatBuffer represented by a list of bytes (uint8). /// Create from a FlatBuffer represented by a list of bytes (uint8).
factory BufferContext.fromBytes(List<int> byteList) => factory BufferContext.fromBytes(List<int> byteList) => BufferContext(
BufferContext(byteList is Uint8List byteList is Uint8List
? byteList.buffer.asByteData(byteList.offsetInBytes) ? byteList.buffer.asByteData(byteList.offsetInBytes)
: ByteData.view(Uint8List.fromList(byteList).buffer)); : ByteData.view(Uint8List.fromList(byteList).buffer),
);
/// Create from a FlatBuffer represented by ByteData. /// Create from a FlatBuffer represented by ByteData.
BufferContext(this._buffer); BufferContext(this._buffer);
@@ -350,8 +351,10 @@ class Builder {
Uint8List get buffer { Uint8List get buffer {
assert(_finished); assert(_finished);
final finishedSize = size(); final finishedSize = size();
return _buf.buffer return _buf.buffer.asUint8List(
.asUint8List(_buf.lengthInBytes - finishedSize, finishedSize); _buf.lengthInBytes - finishedSize,
finishedSize,
);
} }
/// Finish off the creation of the buffer. The given [offset] is used as the /// Finish off the creation of the buffer. The given [offset] is used as the
@@ -368,14 +371,18 @@ class Builder {
if (fileIdentifier != null) { if (fileIdentifier != null) {
for (var i = 0; i < 4; i++) { for (var i = 0; i < 4; i++) {
_setUint8AtTail( _setUint8AtTail(
finishedSize - _sizeofUint32 - i, fileIdentifier.codeUnitAt(i)); finishedSize - _sizeofUint32 - i,
fileIdentifier.codeUnitAt(i),
);
} }
} }
// zero out the added padding // zero out the added padding
for (var i = sizeBeforePadding + 1; for (
var i = sizeBeforePadding + 1;
i <= finishedSize - requiredBytes; i <= finishedSize - requiredBytes;
i++) { i++
) {
_setUint8AtTail(i, 0); _setUint8AtTail(i, 0);
} }
_finished = true; _finished = true;
@@ -687,8 +694,10 @@ class Builder {
int writeString(String value, {bool asciiOptimization = false}) { int writeString(String value, {bool asciiOptimization = false}) {
assert(!_inVTable); assert(!_inVTable);
if (_strings != null) { if (_strings != null) {
return _strings! return _strings!.putIfAbsent(
.putIfAbsent(value, () => _writeString(value, asciiOptimization)); value,
() => _writeString(value, asciiOptimization),
);
} else { } else {
return _writeString(value, asciiOptimization); return _writeString(value, asciiOptimization);
} }
@@ -1005,8 +1014,11 @@ class ListReader<E> extends Reader<List<E>> {
: List<E>.generate( : List<E>.generate(
bc.buffer.getUint32(listOffset, Endian.little), bc.buffer.getUint32(listOffset, Endian.little),
(int index) => _elementReader.read( (int index) => _elementReader.read(
bc, listOffset + size + _elementReader.size * index), bc,
growable: true); listOffset + size + _elementReader.size * index,
),
growable: true,
);
} }
} }
@@ -1454,7 +1466,11 @@ abstract class Allocator {
/// Params [inUseBack] and [inUseFront] indicate how much of [oldData] is /// Params [inUseBack] and [inUseFront] indicate how much of [oldData] is
/// actually in use at each end, and needs to be copied. /// actually in use at each end, and needs to be copied.
ByteData resize( ByteData resize(
ByteData oldData, int newSize, int inUseBack, int inUseFront) { ByteData oldData,
int newSize,
int inUseBack,
int inUseFront,
) {
final newData = allocate(newSize); final newData = allocate(newSize);
_copyDownward(oldData, newData, inUseBack, inUseFront); _copyDownward(oldData, newData, inUseBack, inUseFront);
deallocate(oldData); deallocate(oldData);
@@ -1465,17 +1481,25 @@ abstract class Allocator {
/// memory of size [inUseFront] and [inUseBack] will be copied from the front /// memory of size [inUseFront] and [inUseBack] will be copied from the front
/// and back of the old memory allocation. /// and back of the old memory allocation.
void _copyDownward( void _copyDownward(
ByteData oldData, ByteData newData, int inUseBack, int inUseFront) { ByteData oldData,
ByteData newData,
int inUseBack,
int inUseFront,
) {
if (inUseBack != 0) { if (inUseBack != 0) {
newData.buffer.asUint8List().setAll( newData.buffer.asUint8List().setAll(
newData.lengthInBytes - inUseBack, newData.lengthInBytes - inUseBack,
oldData.buffer.asUint8List().getRange( oldData.buffer.asUint8List().getRange(
oldData.lengthInBytes - inUseBack, oldData.lengthInBytes)); oldData.lengthInBytes - inUseBack,
oldData.lengthInBytes,
),
);
} }
if (inUseFront != 0) { if (inUseFront != 0) {
newData.buffer newData.buffer.asUint8List().setAll(
.asUint8List() 0,
.setAll(0, oldData.buffer.asUint8List().getRange(0, inUseFront)); oldData.buffer.asUint8List().getRange(0, inUseFront),
);
} }
} }
} }

View File

@@ -107,8 +107,11 @@ class Builder {
final newOffset = _newOffset(length + 1); final newOffset = _newOffset(length + 1);
_pushBuffer(utf8String); _pushBuffer(utf8String);
_offset = newOffset; _offset = newOffset;
final stackValue = final stackValue = _StackValue.withOffset(
_StackValue.withOffset(stringOffset, ValueType.String, bitWidth); stringOffset,
ValueType.String,
bitWidth,
);
_stack.add(stackValue); _stack.add(stackValue);
_stringCache[value] = stackValue; _stringCache[value] = stackValue;
} }
@@ -128,8 +131,11 @@ class Builder {
final newOffset = _newOffset(length + 1); final newOffset = _newOffset(length + 1);
_pushBuffer(utf8String); _pushBuffer(utf8String);
_offset = newOffset; _offset = newOffset;
final stackValue = final stackValue = _StackValue.withOffset(
_StackValue.withOffset(keyOffset, ValueType.Key, BitWidth.width8); keyOffset,
ValueType.Key,
BitWidth.width8,
);
_stack.add(stackValue); _stack.add(stackValue);
_keyCache[value] = stackValue; _keyCache[value] = stackValue;
} }
@@ -147,8 +153,11 @@ class Builder {
final newOffset = _newOffset(length); final newOffset = _newOffset(length);
_pushBuffer(value.asUint8List()); _pushBuffer(value.asUint8List());
_offset = newOffset; _offset = newOffset;
final stackValue = final stackValue = _StackValue.withOffset(
_StackValue.withOffset(blobOffset, ValueType.Blob, bitWidth); blobOffset,
ValueType.Blob,
bitWidth,
);
_stack.add(stackValue); _stack.add(stackValue);
} }
@@ -170,7 +179,10 @@ class Builder {
final valueOffset = _offset; final valueOffset = _offset;
_pushBuffer(stackValue.asU8List(stackValue.width)); _pushBuffer(stackValue.asU8List(stackValue.width));
final stackOffset = _StackValue.withOffset( final stackOffset = _StackValue.withOffset(
valueOffset, ValueType.IndirectInt, stackValue.width); valueOffset,
ValueType.IndirectInt,
stackValue.width,
);
_stack.add(stackOffset); _stack.add(stackOffset);
_offset = newOffset; _offset = newOffset;
if (cache) { if (cache) {
@@ -195,7 +207,10 @@ class Builder {
final valueOffset = _offset; final valueOffset = _offset;
_pushBuffer(stackValue.asU8List(stackValue.width)); _pushBuffer(stackValue.asU8List(stackValue.width));
final stackOffset = _StackValue.withOffset( final stackOffset = _StackValue.withOffset(
valueOffset, ValueType.IndirectFloat, stackValue.width); valueOffset,
ValueType.IndirectFloat,
stackValue.width,
);
_stack.add(stackOffset); _stack.add(stackOffset);
_offset = newOffset; _offset = newOffset;
if (cache) { if (cache) {
@@ -252,9 +267,10 @@ class Builder {
tmp._offset = _offset; tmp._offset = _offset;
tmp._stack = List.from(_stack); tmp._stack = List.from(_stack);
tmp._stackPointers = List.from(_stackPointers); tmp._stackPointers = List.from(_stackPointers);
tmp._buffer.buffer tmp._buffer.buffer.asUint8List().setAll(
.asUint8List() 0,
.setAll(0, _buffer.buffer.asUint8List(0, _offset)); _buffer.buffer.asUint8List(0, _offset),
);
for (var i = 0; i < tmp._stackPointers.length; i++) { for (var i = 0; i < tmp._stackPointers.length; i++) {
tmp.end(); tmp.end();
} }
@@ -271,7 +287,8 @@ class Builder {
if (_stackPointers.isNotEmpty && _stackPointers.last.isVector == false) { if (_stackPointers.isNotEmpty && _stackPointers.last.isVector == false) {
if (_stack.last.type != ValueType.Key) { if (_stack.last.type != ValueType.Key) {
throw StateError( throw StateError(
'Adding value to a map before adding a key is prohibited'); 'Adding value to a map before adding a key is prohibited',
);
} }
} }
} }
@@ -288,7 +305,8 @@ class Builder {
void _finish() { void _finish() {
if (_stack.length != 1) { if (_stack.length != 1) {
throw StateError( throw StateError(
'Stack has to be exactly 1, but is ${_stack.length}. You have to end all started vectors and maps, before calling [finish]'); 'Stack has to be exactly 1, but is ${_stack.length}. You have to end all started vectors and maps, before calling [finish]',
);
} }
final value = _stack[0]; final value = _stack[0];
final byteWidth = _align(value.elementWidth(_offset, 0)); final byteWidth = _align(value.elementWidth(_offset, 0));
@@ -298,8 +316,12 @@ class Builder {
_finished = true; _finished = true;
} }
_StackValue _createVector(int start, int vecLength, int step, _StackValue _createVector(
[_StackValue? keys]) { int start,
int vecLength,
int step, [
_StackValue? keys,
]) {
var bitWidth = BitWidthUtil.uwidth(vecLength); var bitWidth = BitWidthUtil.uwidth(vecLength);
var prefixElements = 1; var prefixElements = 1;
if (keys != null) { if (keys != null) {
@@ -326,7 +348,8 @@ class Builder {
} }
} }
final byteWidth = _align(bitWidth); final byteWidth = _align(bitWidth);
final fix = typed & ValueTypeUtils.isNumber(vectorType) && final fix =
typed & ValueTypeUtils.isNumber(vectorType) &&
vecLength >= 2 && vecLength >= 2 &&
vecLength <= 4; vecLength <= 4;
if (keys != null) { if (keys != null) {
@@ -349,8 +372,10 @@ class Builder {
return _StackValue.withOffset(vecOffset, ValueType.Map, bitWidth); return _StackValue.withOffset(vecOffset, ValueType.Map, bitWidth);
} }
if (typed) { if (typed) {
final vType = final vType = ValueTypeUtils.toTypedVector(
ValueTypeUtils.toTypedVector(vectorType, fix ? vecLength : 0); vectorType,
fix ? vecLength : 0,
);
return _StackValue.withOffset(vecOffset, vType, bitWidth); return _StackValue.withOffset(vecOffset, vType, bitWidth);
} }
return _StackValue.withOffset(vecOffset, ValueType.Vector, bitWidth); return _StackValue.withOffset(vecOffset, ValueType.Vector, bitWidth);
@@ -366,7 +391,8 @@ class Builder {
void _sortKeysAndEndMap(_StackPointer pointer) { void _sortKeysAndEndMap(_StackPointer pointer) {
if (((_stack.length - pointer.stackPosition) & 1) == 1) { if (((_stack.length - pointer.stackPosition) & 1) == 1) {
throw StateError( throw StateError(
'The stack needs to hold key value pairs (even number of elements). Check if you combined [addKey] with add... method calls properly.'); 'The stack needs to hold key value pairs (even number of elements). Check if you combined [addKey] with add... method calls properly.',
);
} }
var sorted = true; var sorted = true;
@@ -412,8 +438,12 @@ class Builder {
keysStackValue = _createVector(pointer.stackPosition, vecLength, 2); keysStackValue = _createVector(pointer.stackPosition, vecLength, 2);
_keyVectorCache[keysHash] = keysStackValue; _keyVectorCache[keysHash] = keysStackValue;
} }
final vec = final vec = _createVector(
_createVector(pointer.stackPosition + 1, vecLength, 2, keysStackValue); pointer.stackPosition + 1,
vecLength,
2,
keysStackValue,
);
_stack.removeRange(pointer.stackPosition, _stack.length); _stack.removeRange(pointer.stackPosition, _stack.length);
_stack.add(vec); _stack.add(vec);
} }
@@ -421,7 +451,8 @@ class Builder {
bool _shouldFlip(_StackValue v1, _StackValue v2) { bool _shouldFlip(_StackValue v1, _StackValue v2) {
if (v1.type != ValueType.Key || v2.type != ValueType.Key) { if (v1.type != ValueType.Key || v2.type != ValueType.Key) {
throw StateError( throw StateError(
'Stack values are not keys $v1 | $v2. Check if you combined [addKey] with add... method calls properly.'); 'Stack values are not keys $v1 | $v2. Check if you combined [addKey] with add... method calls properly.',
);
} }
late int c1, c2; late int c1, c2;
@@ -450,7 +481,8 @@ class Builder {
_writeUInt(relativeOffset, byteWidth); _writeUInt(relativeOffset, byteWidth);
} else { } else {
throw StateError( throw StateError(
'Unexpected size $byteWidth. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new'); 'Unexpected size $byteWidth. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new',
);
} }
} else { } else {
_pushBuffer(value.asU8List(BitWidthUtil.fromByteWidth(byteWidth))); _pushBuffer(value.asU8List(BitWidthUtil.fromByteWidth(byteWidth)));
@@ -523,9 +555,7 @@ class _StackValue {
final ValueType _type; final ValueType _type;
final BitWidth _width; final BitWidth _width;
_StackValue.withNull() _StackValue.withNull() : _type = ValueType.Null, _width = BitWidth.width8;
: _type = ValueType.Null,
_width = BitWidth.width8;
_StackValue.withInt(int value) _StackValue.withInt(int value)
: _type = ValueType.Int, : _type = ValueType.Int,
@@ -562,16 +592,16 @@ class _StackValue {
final offset = _offset!; final offset = _offset!;
for (var i = 0; i < 4; i++) { for (var i = 0; i < 4; i++) {
final width = 1 << i; final width = 1 << i;
final bitWidth = BitWidthUtil.uwidth(size + final bitWidth = BitWidthUtil.uwidth(
BitWidthUtil.paddingSize(size, width) + size + BitWidthUtil.paddingSize(size, width) + index * width - offset,
index * width - );
offset);
if (1 << bitWidth.index == width) { if (1 << bitWidth.index == width) {
return bitWidth; return bitWidth;
} }
} }
throw StateError( throw StateError(
'Element is of unknown. Size: $size at index: $index. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new'); 'Element is of unknown. Size: $size at index: $index. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new',
);
} }
List<int> asU8List(BitWidth width) { List<int> asU8List(BitWidth width) {
@@ -619,7 +649,8 @@ class _StackValue {
} }
throw StateError( throw StateError(
'Unexpected type: $_type. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new'); 'Unexpected type: $_type. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new',
);
} }
ValueType get type { ValueType get type {

View File

@@ -1,6 +1,7 @@
import 'dart:collection'; import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'types.dart'; import 'types.dart';
/// Main class to read a value out of a FlexBuffer. /// Main class to read a value out of a FlexBuffer.
@@ -16,9 +17,14 @@ class Reference {
int? _length; int? _length;
Reference._( Reference._(
this._buffer, this._offset, this._parentWidth, int packedType, this._path, this._buffer,
[int? byteWidth, ValueType? valueType]) this._offset,
: _byteWidth = byteWidth ?? 1 << (packedType & 3), this._parentWidth,
int packedType,
this._path, [
int? byteWidth,
ValueType? valueType,
]) : _byteWidth = byteWidth ?? 1 << (packedType & 3),
_valueType = valueType ?? ValueTypeUtils.fromInt(packedType >> 2); _valueType = valueType ?? ValueTypeUtils.fromInt(packedType >> 2);
/// Use this method to access the root value of a FlexBuffer. /// Use this method to access the root value of a FlexBuffer.
@@ -31,8 +37,13 @@ class Reference {
final byteWidth = byteData.getUint8(len - 1); final byteWidth = byteData.getUint8(len - 1);
final packedType = byteData.getUint8(len - 2); final packedType = byteData.getUint8(len - 2);
final offset = len - byteWidth - 2; final offset = len - byteWidth - 2;
return Reference._(ByteData.view(buffer), offset, return Reference._(
BitWidthUtil.fromByteWidth(byteWidth), packedType, "/"); ByteData.view(buffer),
offset,
BitWidthUtil.fromByteWidth(byteWidth),
packedType,
"/",
);
} }
/// Returns true if the underlying value is null. /// Returns true if the underlying value is null.
@@ -138,7 +149,8 @@ class Reference {
final index = key; final index = key;
if (index >= length || index < 0) { if (index >= length || index < 0) {
throw ArgumentError( throw ArgumentError(
'Key: [$key] is not applicable on: $_path of: $_valueType length: $length'); 'Key: [$key] is not applicable on: $_path of: $_valueType length: $length',
);
} }
final elementOffset = _indirect + index * _byteWidth; final elementOffset = _indirect + index * _byteWidth;
int packedType = 0; int packedType = 0;
@@ -160,7 +172,8 @@ class Reference {
packedType, packedType,
"$_path[$index]", "$_path[$index]",
byteWidth, byteWidth,
valueType); valueType,
);
} }
if (key is String && _valueType == ValueType.Map) { if (key is String && _valueType == ValueType.Map) {
final index = _keyIndex(key); final index = _keyIndex(key);
@@ -169,7 +182,8 @@ class Reference {
} }
} }
throw ArgumentError( throw ArgumentError(
'Key: [$key] is not applicable on: $_path of: $_valueType'); 'Key: [$key] is not applicable on: $_path of: $_valueType',
);
} }
/// Get an iterable if the underlying flexBuffer value is a vector. /// Get an iterable if the underlying flexBuffer value is a vector.
@@ -213,18 +227,24 @@ class Reference {
ValueTypeUtils.isAVector(_valueType) || ValueTypeUtils.isAVector(_valueType) ||
_valueType == ValueType.Map) { _valueType == ValueType.Map) {
_length = _readUInt( _length = _readUInt(
_indirect - _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth)); _indirect - _byteWidth,
BitWidthUtil.fromByteWidth(_byteWidth),
);
} else if (_valueType == ValueType.Null) { } else if (_valueType == ValueType.Null) {
_length = 0; _length = 0;
} else if (_valueType == ValueType.String) { } else if (_valueType == ValueType.String) {
final indirect = _indirect; final indirect = _indirect;
var sizeByteWidth = _byteWidth; var sizeByteWidth = _byteWidth;
var size = _readUInt(indirect - sizeByteWidth, var size = _readUInt(
BitWidthUtil.fromByteWidth(sizeByteWidth)); indirect - sizeByteWidth,
BitWidthUtil.fromByteWidth(sizeByteWidth),
);
while (_buffer.getInt8(indirect + size) != 0) { while (_buffer.getInt8(indirect + size) != 0) {
sizeByteWidth <<= 1; sizeByteWidth <<= 1;
size = _readUInt(indirect - sizeByteWidth, size = _readUInt(
BitWidthUtil.fromByteWidth(sizeByteWidth)); indirect - sizeByteWidth,
BitWidthUtil.fromByteWidth(sizeByteWidth),
);
} }
_length = size; _length = size;
} else if (_valueType == ValueType.Key) { } else if (_valueType == ValueType.Key) {
@@ -289,7 +309,8 @@ class Reference {
return result.toString(); return result.toString();
} }
throw UnsupportedError( throw UnsupportedError(
'Type: $_valueType is not supported for JSON conversion'); 'Type: $_valueType is not supported for JSON conversion',
);
} }
/// Computes the indirect offset of the value. /// Computes the indirect offset of the value.
@@ -354,10 +375,13 @@ class Reference {
int? _keyIndex(String key) { int? _keyIndex(String key) {
final input = utf8.encode(key); final input = utf8.encode(key);
final keysVectorOffset = _indirect - _byteWidth * 3; final keysVectorOffset = _indirect - _byteWidth * 3;
final indirectOffset = keysVectorOffset - final indirectOffset =
keysVectorOffset -
_readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth)); _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
final byteWidth = _readUInt( final byteWidth = _readUInt(
keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth)); keysVectorOffset + _byteWidth,
BitWidthUtil.fromByteWidth(_byteWidth),
);
var low = 0; var low = 0;
var high = length - 1; var high = length - 1;
while (low <= high) { while (low <= high) {
@@ -390,24 +414,37 @@ class Reference {
final indirect = _indirect; final indirect = _indirect;
final elementOffset = indirect + index * _byteWidth; final elementOffset = indirect + index * _byteWidth;
final packedType = _buffer.getUint8(indirect + length * _byteWidth + index); final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
return Reference._(_buffer, elementOffset, return Reference._(
BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/$key"); _buffer,
elementOffset,
BitWidthUtil.fromByteWidth(_byteWidth),
packedType,
"$_path/$key",
);
} }
Reference _valueForIndex(int index) { Reference _valueForIndex(int index) {
final indirect = _indirect; final indirect = _indirect;
final elementOffset = indirect + index * _byteWidth; final elementOffset = indirect + index * _byteWidth;
final packedType = _buffer.getUint8(indirect + length * _byteWidth + index); final packedType = _buffer.getUint8(indirect + length * _byteWidth + index);
return Reference._(_buffer, elementOffset, return Reference._(
BitWidthUtil.fromByteWidth(_byteWidth), packedType, "$_path/[$index]"); _buffer,
elementOffset,
BitWidthUtil.fromByteWidth(_byteWidth),
packedType,
"$_path/[$index]",
);
} }
String _keyForIndex(int index) { String _keyForIndex(int index) {
final keysVectorOffset = _indirect - _byteWidth * 3; final keysVectorOffset = _indirect - _byteWidth * 3;
final indirectOffset = keysVectorOffset - final indirectOffset =
keysVectorOffset -
_readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth)); _readUInt(keysVectorOffset, BitWidthUtil.fromByteWidth(_byteWidth));
final byteWidth = _readUInt( final byteWidth = _readUInt(
keysVectorOffset + _byteWidth, BitWidthUtil.fromByteWidth(_byteWidth)); keysVectorOffset + _byteWidth,
BitWidthUtil.fromByteWidth(_byteWidth),
);
final keyOffset = indirectOffset + index * byteWidth; final keyOffset = indirectOffset + index * byteWidth;
final keyIndirectOffset = final keyIndirectOffset =
keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth)); keyOffset - _readUInt(keyOffset, BitWidthUtil.fromByteWidth(byteWidth));

View File

@@ -86,7 +86,8 @@ enum ValueType {
VectorFloat, VectorFloat,
VectorKey, VectorKey,
@Deprecated( @Deprecated(
'VectorString is deprecated due to a flaw in the binary format (https://github.com/google/flatbuffers/issues/5627)') 'VectorString is deprecated due to a flaw in the binary format (https://github.com/google/flatbuffers/issues/5627)',
)
VectorString, VectorString,
VectorInt2, VectorInt2,
VectorUInt2, VectorUInt2,
@@ -99,7 +100,7 @@ enum ValueType {
VectorFloat4, VectorFloat4,
Blob, Blob,
Bool, Bool,
VectorBool VectorBool,
} }
class ValueTypeUtils { class ValueTypeUtils {
@@ -153,31 +154,37 @@ class ValueTypeUtils {
static ValueType toTypedVector(ValueType self, int length) { static ValueType toTypedVector(ValueType self, int length) {
if (length == 0) { if (length == 0) {
return ValueTypeUtils.fromInt( return ValueTypeUtils.fromInt(
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt)); toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt),
);
} }
if (length == 2) { if (length == 2) {
return ValueTypeUtils.fromInt( return ValueTypeUtils.fromInt(
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt2)); toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt2),
);
} }
if (length == 3) { if (length == 3) {
return ValueTypeUtils.fromInt( return ValueTypeUtils.fromInt(
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt3)); toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt3),
);
} }
if (length == 4) { if (length == 4) {
return ValueTypeUtils.fromInt( return ValueTypeUtils.fromInt(
toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt4)); toInt(self) - toInt(ValueType.Int) + toInt(ValueType.VectorInt4),
);
} }
throw Exception('unexpected length ' + length.toString()); throw Exception('unexpected length ' + length.toString());
} }
static ValueType typedVectorElementType(ValueType self) { static ValueType typedVectorElementType(ValueType self) {
return ValueTypeUtils.fromInt( return ValueTypeUtils.fromInt(
toInt(self) - toInt(ValueType.VectorInt) + toInt(ValueType.Int)); toInt(self) - toInt(ValueType.VectorInt) + toInt(ValueType.Int),
);
} }
static ValueType fixedTypedVectorElementType(ValueType self) { static ValueType fixedTypedVectorElementType(ValueType self) {
return ValueTypeUtils.fromInt( return ValueTypeUtils.fromInt(
(toInt(self) - toInt(ValueType.VectorInt2)) % 3 + toInt(ValueType.Int)); (toInt(self) - toInt(ValueType.VectorInt2)) % 3 + toInt(ValueType.Int),
);
} }
static int fixedTypedVectorElementSize(ValueType self) { static int fixedTypedVectorElementSize(ValueType self) {

View File

@@ -1,5 +1,5 @@
name: flat_buffers name: flat_buffers
version: 25.2.10 version: 25.9.23
description: FlatBuffers reading and writing library for Dart. Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team. description: FlatBuffers reading and writing library for Dart. Based on original work by Konstantin Scheglov and Paul Berry of the Dart SDK team.
homepage: https://github.com/google/flatbuffers homepage: https://github.com/google/flatbuffers
documentation: https://google.github.io/flatbuffers/index.html documentation: https://google.github.io/flatbuffers/index.html

View File

@@ -2,8 +2,8 @@
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names // ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'package:flat_buffers/flat_buffers.dart' as fb;
class Foo { class Foo {
Foo._(this._bc, this._bcOffset); Foo._(this._bc, this._bcOffset);
@@ -17,15 +17,15 @@ class Foo {
final fb.BufferContext _bc; final fb.BufferContext _bc;
final int _bcOffset; final int _bcOffset;
FooProperties? get myFoo => FooProperties.reader.vTableGetNullable(_bc, _bcOffset, 4); FooProperties? get myFoo =>
FooProperties.reader.vTableGetNullable(_bc, _bcOffset, 4);
@override @override
String toString() { String toString() {
return 'Foo{myFoo: ${myFoo}}'; return 'Foo{myFoo: ${myFoo}}';
} }
FooT unpack() => FooT( FooT unpack() => FooT(myFoo: myFoo?.unpack());
myFoo: myFoo?.unpack());
static int pack(fb.Builder fbBuilder, FooT? object) { static int pack(fb.Builder fbBuilder, FooT? object) {
if (object == null) return 0; if (object == null) return 0;
@@ -36,8 +36,7 @@ class Foo {
class FooT implements fb.Packable { class FooT implements fb.Packable {
FooPropertiesT? myFoo; FooPropertiesT? myFoo;
FooT({ FooT({this.myFoo});
this.myFoo});
@override @override
int pack(fb.Builder fbBuilder) { int pack(fb.Builder fbBuilder) {
@@ -58,8 +57,7 @@ class _FooReader extends fb.TableReader<Foo> {
const _FooReader(); const _FooReader();
@override @override
Foo createObject(fb.BufferContext bc, int offset) => Foo createObject(fb.BufferContext bc, int offset) => Foo._(bc, offset);
Foo._(bc, offset);
} }
class FooBuilder { class FooBuilder {
@@ -84,10 +82,7 @@ class FooBuilder {
class FooObjectBuilder extends fb.ObjectBuilder { class FooObjectBuilder extends fb.ObjectBuilder {
final FooPropertiesObjectBuilder? _myFoo; final FooPropertiesObjectBuilder? _myFoo;
FooObjectBuilder({ FooObjectBuilder({FooPropertiesObjectBuilder? myFoo}) : _myFoo = myFoo;
FooPropertiesObjectBuilder? myFoo,
})
: _myFoo = myFoo;
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].
@override @override
@@ -107,6 +102,7 @@ class FooObjectBuilder extends fb.ObjectBuilder {
return fbBuilder.buffer; return fbBuilder.buffer;
} }
} }
class FooProperties { class FooProperties {
FooProperties._(this._bc, this._bcOffset); FooProperties._(this._bc, this._bcOffset);
@@ -123,9 +119,7 @@ class FooProperties {
return 'FooProperties{a: ${a}, b: ${b}}'; return 'FooProperties{a: ${a}, b: ${b}}';
} }
FooPropertiesT unpack() => FooPropertiesT( FooPropertiesT unpack() => FooPropertiesT(a: a, b: b);
a: a,
b: b);
static int pack(fb.Builder fbBuilder, FooPropertiesT? object) { static int pack(fb.Builder fbBuilder, FooPropertiesT? object) {
if (object == null) return 0; if (object == null) return 0;
@@ -137,9 +131,7 @@ class FooPropertiesT implements fb.Packable {
bool a; bool a;
bool b; bool b;
FooPropertiesT({ FooPropertiesT({required this.a, required this.b});
required this.a,
required this.b});
@override @override
int pack(fb.Builder fbBuilder) { int pack(fb.Builder fbBuilder) {
@@ -175,17 +167,13 @@ class FooPropertiesBuilder {
fbBuilder.putBool(a); fbBuilder.putBool(a);
return fbBuilder.offset; return fbBuilder.offset;
} }
} }
class FooPropertiesObjectBuilder extends fb.ObjectBuilder { class FooPropertiesObjectBuilder extends fb.ObjectBuilder {
final bool _a; final bool _a;
final bool _b; final bool _b;
FooPropertiesObjectBuilder({ FooPropertiesObjectBuilder({required bool a, required bool b})
required bool a,
required bool b,
})
: _a = a, : _a = a,
_b = b; _b = b;

View File

@@ -2,8 +2,8 @@
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names // ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'package:flat_buffers/flat_buffers.dart' as fb;
enum OptionsEnum { enum OptionsEnum {
A(1), A(1),
@@ -15,10 +15,14 @@ enum OptionsEnum {
factory OptionsEnum.fromValue(int value) { factory OptionsEnum.fromValue(int value) {
switch (value) { switch (value) {
case 1: return OptionsEnum.A; case 1:
case 2: return OptionsEnum.B; return OptionsEnum.A;
case 3: return OptionsEnum.C; case 2:
default: throw StateError('Invalid value $value for bit flag enum'); return OptionsEnum.B;
case 3:
return OptionsEnum.C;
default:
throw StateError('Invalid value $value for bit flag enum');
} }
} }
@@ -53,7 +57,9 @@ class MyTable {
final fb.BufferContext _bc; final fb.BufferContext _bc;
final int _bcOffset; final int _bcOffset;
List<OptionsEnum>? get options => const fb.ListReader<OptionsEnum>(OptionsEnum.reader).vTableGetNullable(_bc, _bcOffset, 4); List<OptionsEnum>? get options => const fb.ListReader<OptionsEnum>(
OptionsEnum.reader,
).vTableGetNullable(_bc, _bcOffset, 4);
@override @override
String toString() { String toString() {
@@ -61,7 +67,11 @@ class MyTable {
} }
MyTableT unpack() => MyTableT( MyTableT unpack() => MyTableT(
options: const fb.ListReader<OptionsEnum>(OptionsEnum.reader, lazy: false).vTableGetNullable(_bc, _bcOffset, 4)); options: const fb.ListReader<OptionsEnum>(
OptionsEnum.reader,
lazy: false,
).vTableGetNullable(_bc, _bcOffset, 4),
);
static int pack(fb.Builder fbBuilder, MyTableT? object) { static int pack(fb.Builder fbBuilder, MyTableT? object) {
if (object == null) return 0; if (object == null) return 0;
@@ -72,12 +82,12 @@ class MyTable {
class MyTableT implements fb.Packable { class MyTableT implements fb.Packable {
List<OptionsEnum>? options; List<OptionsEnum>? options;
MyTableT({ MyTableT({this.options});
this.options});
@override @override
int pack(fb.Builder fbBuilder) { int pack(fb.Builder fbBuilder) {
final int? optionsOffset = options == null ? null final int? optionsOffset = options == null
? null
: fbBuilder.writeListUint32(options!.map((f) => f.value).toList()); : fbBuilder.writeListUint32(options!.map((f) => f.value).toList());
fbBuilder.startTable(1); fbBuilder.startTable(1);
fbBuilder.addOffset(0, optionsOffset); fbBuilder.addOffset(0, optionsOffset);
@@ -120,15 +130,13 @@ class MyTableBuilder {
class MyTableObjectBuilder extends fb.ObjectBuilder { class MyTableObjectBuilder extends fb.ObjectBuilder {
final List<OptionsEnum>? _options; final List<OptionsEnum>? _options;
MyTableObjectBuilder({ MyTableObjectBuilder({List<OptionsEnum>? options}) : _options = options;
List<OptionsEnum>? options,
})
: _options = options;
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].
@override @override
int finish(fb.Builder fbBuilder) { int finish(fb.Builder fbBuilder) {
final int? optionsOffset = _options == null ? null final int? optionsOffset = _options == null
? null
: fbBuilder.writeListUint32(_options!.map((f) => f.value).toList()); : fbBuilder.writeListUint32(_options!.map((f) => f.value).toList());
fbBuilder.startTable(1); fbBuilder.startTable(1);
fbBuilder.addOffset(0, optionsOffset); fbBuilder.addOffset(0, optionsOffset);

View File

@@ -1,16 +1,15 @@
import 'dart:typed_data';
import 'dart:io' as io; import 'dart:io' as io;
import 'dart:typed_data';
import 'package:path/path.dart' as path;
import 'package:flat_buffers/flat_buffers.dart'; import 'package:flat_buffers/flat_buffers.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart';
import './monster_test_my_game.example_generated.dart' as example;
import './monster_test_my_game.example2_generated.dart' as example2;
import 'enums_generated.dart' as example3;
import './bool_structs_generated.dart' as example4; import './bool_structs_generated.dart' as example4;
import './monster_test_my_game.example2_generated.dart' as example2;
import './monster_test_my_game.example_generated.dart' as example;
import 'enums_generated.dart' as example3;
main() { main() {
defineReflectiveSuite(() { defineReflectiveSuite(() {
@@ -29,11 +28,9 @@ int indexToField(int index) {
@reflectiveTest @reflectiveTest
class CheckOtherLangaugesData { class CheckOtherLangaugesData {
test_cppData() async { test_cppData() async {
List<int> data = await io.File(path.join( List<int> data = await io.File(
path.context.current, path.join(path.context.current, 'test', 'monsterdata_test.mon'),
'test', ).readAsBytes();
'monsterdata_test.mon',
)).readAsBytes();
example.Monster mon = example.Monster(data); example.Monster mon = example.Monster(data);
expect(mon.hp, 80); expect(mon.hp, 80);
expect(mon.mana, 150); expect(mon.mana, 150);
@@ -145,7 +142,8 @@ class CheckOtherLangaugesData {
'longEnumNormalDefault: LongEnum.LongOne, nanDefault: NaN, ' 'longEnumNormalDefault: LongEnum.LongOne, nanDefault: NaN, '
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: ' 'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: ' 'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
'-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}'); '-Infinity, negativeInfinityDefault: -Infinity, doubleInfDefault: Infinity}',
);
} }
} }
@@ -298,20 +296,72 @@ class BuilderTest {
expect(allocator.buffer(builder.size()), [2, 0, 0, 0, 0, 0, 0, 1]); expect(allocator.buffer(builder.size()), [2, 0, 0, 0, 0, 0, 0, 1]);
builder.putUint8(3); builder.putUint8(3);
expect( expect(allocator.buffer(builder.size()), [
allocator.buffer(builder.size()), [0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 0,
0,
0,
3,
2,
0,
0,
0,
0,
0,
0,
1,
]);
builder.putUint8(4); builder.putUint8(4);
expect( expect(allocator.buffer(builder.size()), [
allocator.buffer(builder.size()), [0, 0, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 0,
0,
4,
3,
2,
0,
0,
0,
0,
0,
0,
1,
]);
builder.putUint8(5); builder.putUint8(5);
expect( expect(allocator.buffer(builder.size()), [
allocator.buffer(builder.size()), [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 0,
5,
4,
3,
2,
0,
0,
0,
0,
0,
0,
1,
]);
builder.putUint32(6); builder.putUint32(6);
expect(allocator.buffer(builder.size()), expect(allocator.buffer(builder.size()), [
[6, 0, 0, 0, 0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 1]); 6,
0,
0,
0,
0,
5,
4,
3,
2,
0,
0,
0,
0,
0,
0,
1,
]);
} }
void test_table_default() { void test_table_default() {
@@ -331,14 +381,14 @@ class BuilderTest {
int objectOffset = buffer.derefObject(0); int objectOffset = buffer.derefObject(0);
// was not written, so uses the new default value // was not written, so uses the new default value
expect( expect(
const Int32Reader() const Int32Reader().vTableGet(buffer, objectOffset, indexToField(0), 15),
.vTableGet(buffer, objectOffset, indexToField(0), 15), 15,
15); );
// has the written value // has the written value
expect( expect(
const Int32Reader() const Int32Reader().vTableGet(buffer, objectOffset, indexToField(1), 15),
.vTableGet(buffer, objectOffset, indexToField(1), 15), 20,
20); );
} }
void test_table_format([Builder? builder]) { void test_table_format([Builder? builder]) {
@@ -370,7 +420,9 @@ class BuilderTest {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
int offset = byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little); int offset = byteData.getUint16(vTableLoc + 4 + 2 * i, Endian.little);
expect( expect(
byteData.getInt32(tableDataLoc + offset, Endian.little), 10 + 10 * i); byteData.getInt32(tableDataLoc + offset, Endian.little),
10 + 10 * i,
);
} }
} }
@@ -380,10 +432,14 @@ class BuilderTest {
List<int> byteList; List<int> byteList;
{ {
Builder builder = Builder(initialSize: 0); Builder builder = Builder(initialSize: 0);
int? latinStringOffset = int? latinStringOffset = builder.writeString(
builder.writeString(latinString, asciiOptimization: true); latinString,
int? unicodeStringOffset = asciiOptimization: true,
builder.writeString(unicodeString, asciiOptimization: true); );
int? unicodeStringOffset = builder.writeString(
unicodeString,
asciiOptimization: true,
);
builder.startTable(2); builder.startTable(2);
builder.addOffset(0, latinStringOffset); builder.addOffset(0, latinStringOffset);
builder.addOffset(1, unicodeStringOffset); builder.addOffset(1, unicodeStringOffset);
@@ -395,13 +451,19 @@ class BuilderTest {
BufferContext buf = BufferContext.fromBytes(byteList); BufferContext buf = BufferContext.fromBytes(byteList);
int objectOffset = buf.derefObject(0); int objectOffset = buf.derefObject(0);
expect( expect(
const StringReader() const StringReader().vTableGetNullable(
.vTableGetNullable(buf, objectOffset, indexToField(0)), buf,
latinString); objectOffset,
indexToField(0),
),
latinString,
);
expect( expect(
const StringReader(asciiOptimization: true) const StringReader(
.vTableGetNullable(buf, objectOffset, indexToField(1)), asciiOptimization: true,
unicodeString); ).vTableGetNullable(buf, objectOffset, indexToField(1)),
unicodeString,
);
} }
void test_table_types([Builder? builder]) { void test_table_types([Builder? builder]) {
@@ -425,33 +487,41 @@ class BuilderTest {
BufferContext buf = BufferContext.fromBytes(byteList); BufferContext buf = BufferContext.fromBytes(byteList);
int objectOffset = buf.derefObject(0); int objectOffset = buf.derefObject(0);
expect( expect(
const BoolReader() const BoolReader().vTableGetNullable(buf, objectOffset, indexToField(0)),
.vTableGetNullable(buf, objectOffset, indexToField(0)), true,
true); );
expect( expect(
const Int8Reader() const Int8Reader().vTableGetNullable(buf, objectOffset, indexToField(1)),
.vTableGetNullable(buf, objectOffset, indexToField(1)), 10,
10); );
expect( expect(
const Int32Reader() const Int32Reader().vTableGetNullable(buf, objectOffset, indexToField(2)),
.vTableGetNullable(buf, objectOffset, indexToField(2)), 20,
20); );
expect( expect(
const StringReader() const StringReader().vTableGetNullable(
.vTableGetNullable(buf, objectOffset, indexToField(3)), buf,
'12345'); objectOffset,
indexToField(3),
),
'12345',
);
expect( expect(
const Int32Reader() const Int32Reader().vTableGetNullable(buf, objectOffset, indexToField(4)),
.vTableGetNullable(buf, objectOffset, indexToField(4)), 40,
40); );
expect( expect(
const Uint32Reader() const Uint32Reader().vTableGetNullable(
.vTableGetNullable(buf, objectOffset, indexToField(5)), buf,
0x9ABCDEF0); objectOffset,
indexToField(5),
),
0x9ABCDEF0,
);
expect( expect(
const Uint8Reader() const Uint8Reader().vTableGetNullable(buf, objectOffset, indexToField(6)),
.vTableGetNullable(buf, objectOffset, indexToField(6)), 0x9A,
0x9A); );
} }
void test_writeList_of_Uint32() { void test_writeList_of_Uint32() {
@@ -596,8 +666,9 @@ class BuilderTest {
} }
// read and verify // read and verify
BufferContext buf = BufferContext.fromBytes(byteList); BufferContext buf = BufferContext.fromBytes(byteList);
List<TestPointImpl> items = List<TestPointImpl> items = const ListReader<TestPointImpl>(
const ListReader<TestPointImpl>(TestPointReader()).read(buf, 0); TestPointReader(),
).read(buf, 0);
expect(items, hasLength(2)); expect(items, hasLength(2));
expect(items[0].x, 10); expect(items[0].x, 10);
expect(items[0].y, 20); expect(items[0].y, 20);
@@ -627,8 +698,10 @@ class BuilderTest {
List<int> byteList; List<int> byteList;
{ {
builder ??= Builder(initialSize: 0); builder ??= Builder(initialSize: 0);
int listOffset = builder.writeList( int listOffset = builder.writeList([
[builder.writeString('12345'), builder.writeString('ABC')]); builder.writeString('12345'),
builder.writeString('ABC'),
]);
builder.startTable(1); builder.startTable(1);
builder.addOffset(0, listOffset); builder.addOffset(0, listOffset);
int offset = builder.endTable(); int offset = builder.endTable();
@@ -707,13 +780,14 @@ class BuilderTest {
test_table_format, test_table_format,
test_table_types, test_table_types,
test_writeList_ofObjects, test_writeList_ofObjects,
test_writeList_ofStrings_inObject test_writeList_ofStrings_inObject,
]; ];
// Execute all test cases in all permutations of their order. // Execute all test cases in all permutations of their order.
// To do that, we generate permutations of test case indexes. // To do that, we generate permutations of test case indexes.
final testCasesPermutations = final testCasesPermutations = _permutationsOf(
_permutationsOf(List.generate(testCases.length, (index) => index)); List.generate(testCases.length, (index) => index),
);
expect(testCasesPermutations.length, _factorial(testCases.length)); expect(testCasesPermutations.length, _factorial(testCases.length));
for (var indexes in testCasesPermutations) { for (var indexes in testCasesPermutations) {
@@ -788,7 +862,8 @@ class ObjectAPITest {
z: 3, z: 3,
test1: 4.0, test1: 4.0,
test2: example.Color.Red, test2: example.Color.Red,
test3: example.TestT(a: 1, b: 2)) test3: example.TestT(a: 1, b: 2),
)
..mana = 2 ..mana = 2
..name = 'Monstrous' ..name = 'Monstrous'
..inventory = [24, 42] ..inventory = [24, 42]
@@ -804,7 +879,7 @@ class ObjectAPITest {
..testf = 42.24 ..testf = 42.24
..testarrayofsortedstruct = [ ..testarrayofsortedstruct = [
example.AbilityT(id: 1, distance: 5), example.AbilityT(id: 1, distance: 5),
example.AbilityT(id: 3, distance: 7) example.AbilityT(id: 3, distance: 7),
] ]
..vectorOfLongs = [5, 6, 7] ..vectorOfLongs = [5, 6, 7]
..vectorOfDoubles = [8.9, 9.0, 10.1, 11.2] ..vectorOfDoubles = [8.9, 9.0, 10.1, 11.2]
@@ -867,8 +942,9 @@ class StringListWrapperImpl {
StringListWrapperImpl(this.bp, this.offset); StringListWrapperImpl(this.bp, this.offset);
List<String>? get items => const ListReader<String>(StringReader()) List<String>? get items => const ListReader<String>(
.vTableGetNullable(bp, offset, indexToField(0)); StringReader(),
).vTableGetNullable(bp, offset, indexToField(0));
} }
class StringListWrapperReader extends TableReader<StringListWrapperImpl> { class StringListWrapperReader extends TableReader<StringListWrapperImpl> {
@@ -906,10 +982,14 @@ class GeneratorTest {
expect(example.Color.values, same(example.Color.values)); expect(example.Color.values, same(example.Color.values));
expect(example.Race.values, same(example.Race.values)); expect(example.Race.values, same(example.Race.values));
expect(example.AnyTypeId.values, same(example.AnyTypeId.values)); expect(example.AnyTypeId.values, same(example.AnyTypeId.values));
expect(example.AnyUniqueAliasesTypeId.values, expect(
same(example.AnyUniqueAliasesTypeId.values)); example.AnyUniqueAliasesTypeId.values,
expect(example.AnyAmbiguousAliasesTypeId.values, same(example.AnyUniqueAliasesTypeId.values),
same(example.AnyAmbiguousAliasesTypeId.values)); );
expect(
example.AnyAmbiguousAliasesTypeId.values,
same(example.AnyAmbiguousAliasesTypeId.values),
);
} }
} }
@@ -917,11 +997,13 @@ class GeneratorTest {
@reflectiveTest @reflectiveTest
class ListOfEnumsTest { class ListOfEnumsTest {
void test_listOfEnums() async { void test_listOfEnums() async {
var mytable = example3.MyTableObjectBuilder(options: [ var mytable = example3.MyTableObjectBuilder(
options: [
example3.OptionsEnum.A, example3.OptionsEnum.A,
example3.OptionsEnum.B, example3.OptionsEnum.B,
example3.OptionsEnum.C example3.OptionsEnum.C,
]); ],
);
var bytes = mytable.toBytes(); var bytes = mytable.toBytes();
var mytable_read = example3.MyTable(bytes); var mytable_read = example3.MyTable(bytes);
expect(mytable_read.options![0].value, example3.OptionsEnum.A.value); expect(mytable_read.options![0].value, example3.OptionsEnum.A.value);
@@ -934,7 +1016,8 @@ class ListOfEnumsTest {
class BoolInStructTest { class BoolInStructTest {
void test_boolInStruct() async { void test_boolInStruct() async {
var mystruct = example4.FooObjectBuilder( var mystruct = example4.FooObjectBuilder(
myFoo: example4.FooPropertiesObjectBuilder(a: true, b: false)); myFoo: example4.FooPropertiesObjectBuilder(a: true, b: false),
);
var bytes = mystruct.toBytes(); var bytes = mystruct.toBytes();
var mystruct_read = example4.Foo(bytes); var mystruct_read = example4.Foo(bytes);
expect(mystruct_read.myFoo!.a, true); expect(mystruct_read.myFoo!.a, true);

View File

@@ -62,8 +62,23 @@ void main() {
{ {
var flx = Builder(); var flx = Builder();
flx.addString('hello 😱'); flx.addString('hello 😱');
expect(flx.finish(), expect(flx.finish(), [
[10, 104, 101, 108, 108, 111, 32, 240, 159, 152, 177, 0, 11, 20, 1]); 10,
104,
101,
108,
108,
111,
32,
240,
159,
152,
177,
0,
11,
20,
1,
]);
} }
}); });
@@ -117,7 +132,7 @@ void main() {
192, 192,
16, 16,
75, 75,
1 1,
]); ]);
} }
{ {
@@ -177,7 +192,7 @@ void main() {
7, 7,
3, 3,
60, 60,
1 1,
]); ]);
} }
{ {
@@ -215,7 +230,7 @@ void main() {
10, 10,
6, 6,
60, 60,
1 1,
]); ]);
} }
{ {
@@ -300,7 +315,7 @@ void main() {
104, 104,
45, 45,
43, 43,
1 1,
]); ]);
} }
}); });
@@ -322,8 +337,24 @@ void main() {
..addKey('') ..addKey('')
..addInt(45) ..addInt(45)
..end(); ..end();
expect( expect(flx.finish(), [
flx.finish(), [97, 0, 0, 2, 2, 5, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]); 97,
0,
0,
2,
2,
5,
2,
1,
2,
45,
12,
4,
4,
4,
36,
1,
]);
} }
{ {
var flx = Builder() var flx = Builder()
@@ -367,7 +398,7 @@ void main() {
36, 36,
4, 4,
40, 40,
1 1,
]); ]);
} }
}); });
@@ -381,21 +412,38 @@ void main() {
test('build from object', () { test('build from object', () {
expect( expect(
Builder.buildFromObject(Uint8List.fromList([1, 2, 3]).buffer) Builder.buildFromObject(
.asUint8List(), Uint8List.fromList([1, 2, 3]).buffer,
[3, 1, 2, 3, 3, 100, 1]); ).asUint8List(),
[3, 1, 2, 3, 3, 100, 1],
);
expect(Builder.buildFromObject(null).asUint8List(), [0, 0, 1]); expect(Builder.buildFromObject(null).asUint8List(), [0, 0, 1]);
expect(Builder.buildFromObject(true).asUint8List(), [1, 104, 1]); expect(Builder.buildFromObject(true).asUint8List(), [1, 104, 1]);
expect(Builder.buildFromObject(false).asUint8List(), [0, 104, 1]); expect(Builder.buildFromObject(false).asUint8List(), [0, 104, 1]);
expect(Builder.buildFromObject(25).asUint8List(), [25, 4, 1]); expect(Builder.buildFromObject(25).asUint8List(), [25, 4, 1]);
expect(Builder.buildFromObject(-250).asUint8List(), [6, 255, 5, 2]); expect(Builder.buildFromObject(-250).asUint8List(), [6, 255, 5, 2]);
expect(Builder.buildFromObject(-2.50).asUint8List(), [
0,
0,
32,
192,
14,
4,
]);
expect(Builder.buildFromObject('Maxim').asUint8List(), [
5,
77,
97,
120,
105,
109,
0,
6,
20,
1,
]);
expect( expect(
Builder.buildFromObject(-2.50).asUint8List(), [0, 0, 32, 192, 14, 4]); Builder.buildFromObject([1, 3.3, 'max', true, null, false]).asUint8List(),
expect(Builder.buildFromObject('Maxim').asUint8List(),
[5, 77, 97, 120, 105, 109, 0, 6, 20, 1]);
expect(
Builder.buildFromObject([1, 3.3, 'max', true, null, false])
.asUint8List(),
[ [
3, 3,
109, 109,
@@ -469,12 +517,13 @@ void main() {
104, 104,
54, 54,
43, 43,
1 1,
]); ],
);
expect( expect(
Builder.buildFromObject([ Builder.buildFromObject([
{'something': 12}, {'something': 12},
{'something': 45} {'something': 45},
]).asUint8List(), ]).asUint8List(),
[ [
115, 115,
@@ -506,8 +555,9 @@ void main() {
36, 36,
4, 4,
40, 40,
1 1,
]); ],
);
}); });
test('add double indirectly', () { test('add double indirectly', () {
@@ -543,7 +593,7 @@ void main() {
35, 35,
8, 8,
40, 40,
1 1,
]); ]);
}); });
@@ -580,7 +630,7 @@ void main() {
27, 27,
8, 8,
40, 40,
1 1,
]); ]);
}); });

View File

@@ -20,70 +20,76 @@ void main() {
expect(Reference.fromBuffer(b([1, 4, 5, 2])).intValue, 1025); expect(Reference.fromBuffer(b([1, 4, 5, 2])).intValue, 1025);
expect(Reference.fromBuffer(b([255, 251, 5, 2])).intValue, -1025); expect(Reference.fromBuffer(b([255, 251, 5, 2])).intValue, -1025);
expect(Reference.fromBuffer(b([1, 4, 9, 2])).intValue, 1025); expect(Reference.fromBuffer(b([1, 4, 9, 2])).intValue, 1025);
expect(Reference.fromBuffer(b([255, 255, 255, 127, 6, 4])).intValue, expect(
2147483647); Reference.fromBuffer(b([255, 255, 255, 127, 6, 4])).intValue,
2147483647,
);
expect(Reference.fromBuffer(b([0, 0, 0, 128, 6, 4])).intValue, -2147483648); expect(Reference.fromBuffer(b([0, 0, 0, 128, 6, 4])).intValue, -2147483648);
expect( expect(
Reference.fromBuffer(b([255, 255, 255, 255, 0, 0, 0, 0, 7, 8])) Reference.fromBuffer(b([255, 255, 255, 255, 0, 0, 0, 0, 7, 8])).intValue,
.intValue, 4294967295,
4294967295); );
expect( expect(
Reference.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 127, 7, 8])) Reference.fromBuffer(
.intValue, b([255, 255, 255, 255, 255, 255, 255, 127, 7, 8]),
9223372036854775807); ).intValue,
expect(Reference.fromBuffer(b([0, 0, 0, 0, 0, 0, 0, 128, 7, 8])).intValue, 9223372036854775807,
-9223372036854775808); );
expect(
Reference.fromBuffer(b([0, 0, 0, 0, 0, 0, 0, 128, 7, 8])).intValue,
-9223372036854775808,
);
// Dart does not really support UInt64 // Dart does not really support UInt64
// expect(FlxValue.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 255, 11, 8])).intValue, 18446744073709551615); // expect(FlxValue.fromBuffer(b([255, 255, 255, 255, 255, 255, 255, 255, 11, 8])).intValue, 18446744073709551615);
}); });
test('double value', () { test('double value', () {
expect(Reference.fromBuffer(b([0, 0, 128, 63, 14, 4])).doubleValue, 1.0); expect(Reference.fromBuffer(b([0, 0, 128, 63, 14, 4])).doubleValue, 1.0);
expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).doubleValue, 4.5); expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).doubleValue, 4.5);
expect(Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).doubleValue,
closeTo(.1, .001));
expect( expect(
Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8])) Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).doubleValue,
.doubleValue, closeTo(.1, .001),
.1); );
expect(
Reference.fromBuffer(
b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]),
).doubleValue,
.1,
);
}); });
test('num value', () { test('num value', () {
expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).numValue, 4.5); expect(Reference.fromBuffer(b([0, 0, 144, 64, 14, 4])).numValue, 4.5);
expect(Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).numValue,
closeTo(.1, .001));
expect( expect(
Reference.fromBuffer(b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8])) Reference.fromBuffer(b([205, 204, 204, 61, 14, 4])).numValue,
.numValue, closeTo(.1, .001),
.1); );
expect(
Reference.fromBuffer(
b([154, 153, 153, 153, 153, 153, 185, 63, 15, 8]),
).numValue,
.1,
);
expect(Reference.fromBuffer(b([255, 251, 5, 2])).numValue, -1025); expect(Reference.fromBuffer(b([255, 251, 5, 2])).numValue, -1025);
}); });
test('string value', () { test('string value', () {
expect( expect(
Reference.fromBuffer(b([5, 77, 97, 120, 105, 109, 0, 6, 20, 1])) Reference.fromBuffer(
.stringValue, b([5, 77, 97, 120, 105, 109, 0, 6, 20, 1]),
'Maxim'); ).stringValue,
'Maxim',
);
expect( expect(
Reference.fromBuffer(b([ Reference.fromBuffer(
10, b([10, 104, 101, 108, 108, 111, 32, 240, 159, 152, 177, 0, 11, 20, 1]),
104, ).stringValue,
101, 'hello 😱',
108, );
108,
111,
32,
240,
159,
152,
177,
0,
11,
20,
1
])).stringValue,
'hello 😱');
}); });
test('blob value', () { test('blob value', () {
expect( expect(Reference.fromBuffer(b([3, 1, 2, 3, 3, 100, 1])).blobValue, [
Reference.fromBuffer(b([3, 1, 2, 3, 3, 100, 1])).blobValue, [1, 2, 3]); 1,
2,
3,
]);
}); });
test('bool vector', () { test('bool vector', () {
var flx = Reference.fromBuffer(b([3, 1, 0, 1, 3, 144, 1])); var flx = Reference.fromBuffer(b([3, 1, 0, 1, 3, 144, 1]));
@@ -95,9 +101,12 @@ void main() {
testNumbers([3, 1, 2, 3, 3, 44, 1], [1, 2, 3]); testNumbers([3, 1, 2, 3, 3, 44, 1], [1, 2, 3]);
testNumbers([3, 255, 2, 3, 3, 44, 1], [-1, 2, 3]); testNumbers([3, 255, 2, 3, 3, 44, 1], [-1, 2, 3]);
testNumbers([3, 0, 1, 0, 43, 2, 3, 0, 6, 45, 1], [1, 555, 3]); testNumbers([3, 0, 1, 0, 43, 2, 3, 0, 6, 45, 1], [1, 555, 3]);
testNumbers([3, 0, 0, 0, 1, 0, 0, 0, 204, 216, 0, 0, 3, 0, 0, 0, 12, 46, 1], testNumbers(
[1, 55500, 3]); [3, 0, 0, 0, 1, 0, 0, 0, 204, 216, 0, 0, 3, 0, 0, 0, 12, 46, 1],
testNumbers([ [1, 55500, 3],
);
testNumbers(
[
3, 3,
0, 0,
0, 0,
@@ -132,16 +141,16 @@ void main() {
0, 0,
24, 24,
47, 47,
1
], [
1, 1,
55555555500, ],
3 [1, 55555555500, 3],
]); );
testNumbers( testNumbers(
[3, 0, 0, 0, 0, 0, 192, 63, 0, 0, 32, 64, 0, 0, 96, 64, 12, 54, 1], [3, 0, 0, 0, 0, 0, 192, 63, 0, 0, 32, 64, 0, 0, 96, 64, 12, 54, 1],
[1.5, 2.5, 3.5]); [1.5, 2.5, 3.5],
testNumbers([ );
testNumbers(
[
3, 3,
0, 0,
0, 0,
@@ -176,18 +185,17 @@ void main() {
64, 64,
24, 24,
55, 55,
1 1,
], [ ],
1.1, [1.1, 2.2, 3.3],
2.2, );
3.3
]);
}); });
test('number vector, fixed type', () { test('number vector, fixed type', () {
testNumbers([1, 2, 2, 64, 1], [1, 2]); testNumbers([1, 2, 2, 64, 1], [1, 2]);
testNumbers([255, 255, 0, 1, 4, 65, 1], [-1, 256]); testNumbers([255, 255, 0, 1, 4, 65, 1], [-1, 256]);
testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 8, 66, 1], [-45, 256000]); testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 8, 66, 1], [-45, 256000]);
testNumbers([ testNumbers(
[
211, 211,
255, 255,
255, 255,
@@ -206,18 +214,18 @@ void main() {
127, 127,
16, 16,
67, 67,
1 1,
], [ ],
-45, [-45, 9223372036854775807],
9223372036854775807 );
]);
testNumbers([1, 2, 2, 68, 1], [1, 2]); testNumbers([1, 2, 2, 68, 1], [1, 2]);
testNumbers([1, 0, 0, 1, 4, 69, 1], [1, 256]); testNumbers([1, 0, 0, 1, 4, 69, 1], [1, 256]);
testNumbers([45, 0, 0, 0, 0, 232, 3, 0, 8, 70, 1], [45, 256000]); testNumbers([45, 0, 0, 0, 0, 232, 3, 0, 8, 70, 1], [45, 256000]);
testNumbers([205, 204, 140, 63, 0, 0, 0, 192, 8, 74, 1], [1.1, -2]); testNumbers([205, 204, 140, 63, 0, 0, 0, 192, 8, 74, 1], [1.1, -2]);
testNumbers([ testNumbers(
[
154, 154,
153, 153,
153, 153,
@@ -236,16 +244,18 @@ void main() {
192, 192,
16, 16,
75, 75,
1 1,
], [ ],
1.1, [1.1, -256],
-256 );
]);
testNumbers([211, 255, 255, 255, 0, 232, 3, 0, 4, 0, 0, 0, 12, 78, 1], testNumbers(
[-45, 256000, 4]); [211, 255, 255, 255, 0, 232, 3, 0, 4, 0, 0, 0, 12, 78, 1],
[-45, 256000, 4],
);
testNumbers([ testNumbers(
[
211, 211,
255, 255,
255, 255,
@@ -280,15 +290,13 @@ void main() {
0, 0,
32, 32,
91, 91,
1 1,
], [ ],
-45, [-45, 9223372036854775807, 4, 9],
9223372036854775807, );
4,
9
]);
testNumbers([ testNumbers(
[
45, 45,
0, 0,
0, 0,
@@ -323,15 +331,13 @@ void main() {
0, 0,
32, 32,
95, 95,
1 1,
], [ ],
45, [45, 9223372036854775807, 4, 9],
9223372036854775807, );
4,
9
]);
testNumbers([ testNumbers(
[
154, 154,
153, 153,
153, 153,
@@ -358,14 +364,13 @@ void main() {
64, 64,
24, 24,
87, 87,
1 1,
], [ ],
1.1, [1.1, 256, 4],
256, );
4
]);
testNumbers([ testNumbers(
[
154, 154,
153, 153,
153, 153,
@@ -400,16 +405,14 @@ void main() {
64, 64,
32, 32,
99, 99,
1 1,
], [ ],
1.1, [1.1, 256, 4, 9],
256, );
4,
9
]);
}); });
test('string vector', () { test('string vector', () {
testStrings([ testStrings(
[
3, 3,
102, 102,
111, 111,
@@ -431,13 +434,12 @@ void main() {
7, 7,
3, 3,
60, 60,
1 1,
], [ ],
'foo', ['foo', 'bar', 'baz'],
'bar', );
'baz' testStrings(
]); [
testStrings([
3, 3,
102, 102,
111, 111,
@@ -462,18 +464,14 @@ void main() {
10, 10,
6, 6,
60, 60,
1 1,
], [ ],
'foo', ['foo', 'bar', 'baz', 'foo', 'bar', 'baz'],
'bar', );
'baz',
'foo',
'bar',
'baz'
]);
}); });
test('mixed vector', () { test('mixed vector', () {
var flx = Reference.fromBuffer(b([ var flx = Reference.fromBuffer(
b([
3, 3,
102, 102,
111, 111,
@@ -537,8 +535,9 @@ void main() {
104, 104,
45, 45,
43, 43,
1 1,
])); ]),
);
expect(flx.length, 5); expect(flx.length, 5);
expect(flx[0].stringValue, 'foo'); expect(flx[0].stringValue, 'foo');
expect(flx[1].numValue, 1); expect(flx[1].numValue, 1);
@@ -554,7 +553,8 @@ void main() {
}); });
test('two value map', () { test('two value map', () {
var flx = Reference.fromBuffer( var flx = Reference.fromBuffer(
b([0, 97, 0, 2, 4, 4, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1])); b([0, 97, 0, 2, 4, 4, 2, 1, 2, 45, 12, 4, 4, 4, 36, 1]),
);
expect(flx.length, 2); expect(flx.length, 2);
expect(flx['a'].numValue, 12); expect(flx['a'].numValue, 12);
expect(flx[''].numValue, 45); expect(flx[''].numValue, 45);
@@ -579,54 +579,89 @@ void main() {
expect( expect(
() => flx['address']['country'].stringValue, () => flx['address']['country'].stringValue,
throwsA(predicate((dynamic e) => throwsA(
predicate(
(dynamic e) =>
e is ArgumentError && e is ArgumentError &&
e.message == e.message ==
'Key: [country] is not applicable on: //address of: ValueType.Map'))); 'Key: [country] is not applicable on: //address of: ValueType.Map',
),
),
);
expect( expect(
() => flx['address']['countryCode'][0], () => flx['address']['countryCode'][0],
throwsA(predicate((dynamic e) => throwsA(
predicate(
(dynamic e) =>
e is ArgumentError && e is ArgumentError &&
e.message == e.message ==
'Key: [0] is not applicable on: //address/countryCode of: ValueType.String'))); 'Key: [0] is not applicable on: //address/countryCode of: ValueType.String',
),
),
);
expect( expect(
() => flx[1], () => flx[1],
throwsA(predicate((dynamic e) => throwsA(
predicate(
(dynamic e) =>
e is ArgumentError && e is ArgumentError &&
e.message == e.message == 'Key: [1] is not applicable on: / of: ValueType.Map',
'Key: [1] is not applicable on: / of: ValueType.Map'))); ),
),
);
expect( expect(
() => flx['flags'][4], () => flx['flags'][4],
throwsA(predicate((dynamic e) => throwsA(
predicate(
(dynamic e) =>
e is ArgumentError && e is ArgumentError &&
e.message == e.message ==
'Key: [4] is not applicable on: //flags of: ValueType.VectorBool length: 4'))); 'Key: [4] is not applicable on: //flags of: ValueType.VectorBool length: 4',
),
),
);
expect( expect(
() => flx['flags'][-1], () => flx['flags'][-1],
throwsA(predicate((dynamic e) => throwsA(
predicate(
(dynamic e) =>
e is ArgumentError && e is ArgumentError &&
e.message == e.message ==
'Key: [-1] is not applicable on: //flags of: ValueType.VectorBool length: 4'))); 'Key: [-1] is not applicable on: //flags of: ValueType.VectorBool length: 4',
),
),
);
}); });
test('complex map to json', () { test('complex map to json', () {
var flx = complexMap(); var flx = complexMap();
expect(flx.json, expect(
'{"address":{"city":"Bla","countryCode":"XX","zip":"12345"},"age":35,"flags":[true,false,true,true],"name":"Maxim","weight":72.5}'); flx.json,
'{"address":{"city":"Bla","countryCode":"XX","zip":"12345"},"age":35,"flags":[true,false,true,true],"name":"Maxim","weight":72.5}',
);
}); });
test('complex map iterators', () { test('complex map iterators', () {
var flx = complexMap(); var flx = complexMap();
expect(flx.mapKeyIterable.map((e) => e).toList(), expect(flx.mapKeyIterable.map((e) => e).toList(), [
['address', 'age', 'flags', 'name', 'weight']); 'address',
'age',
'flags',
'name',
'weight',
]);
expect(flx.mapValueIterable.map((e) => e.json).toList(), [ expect(flx.mapValueIterable.map((e) => e.json).toList(), [
flx['address'].json, flx['address'].json,
flx['age'].json, flx['age'].json,
flx['flags'].json, flx['flags'].json,
flx['name'].json, flx['name'].json,
flx['weight'].json flx['weight'].json,
]);
expect(flx['flags'].vectorIterable.map((e) => e.boolValue).toList(), [
true,
false,
true,
true,
]); ]);
expect(flx['flags'].vectorIterable.map((e) => e.boolValue).toList(),
[true, false, true, true]);
}); });
test('bug where offest were stored as int instead of uint', () { test('bug where offest were stored as int instead of uint', () {
@@ -790,11 +825,13 @@ void main() {
4, 4,
16, 16,
36, 36,
1 1,
]; ];
var flx = Reference.fromBuffer(b(data)); var flx = Reference.fromBuffer(b(data));
expect(flx.json, expect(
'{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}'); flx.json,
'{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}',
);
const object = { const object = {
"channels_in": 64, "channels_in": 64,
"dilation_height_factor": 1, "dilation_height_factor": 1,
@@ -803,13 +840,15 @@ void main() {
"pad_values": 1, "pad_values": 1,
"padding": 0, "padding": 0,
"stride_height": 1, "stride_height": 1,
"stride_width": 1 "stride_width": 1,
}; };
var data1 = Builder.buildFromObject(object).asUint8List(); var data1 = Builder.buildFromObject(object).asUint8List();
expect(data1.length, data.length); expect(data1.length, data.length);
var flx1 = Reference.fromBuffer(b(data1)); var flx1 = Reference.fromBuffer(b(data1));
expect(flx1.json, expect(
'{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}'); flx1.json,
'{"channels_in":64,"dilation_height_factor":1,"dilation_width_factor":1,"fused_activation_function":1,"pad_values":1,"padding":0,"stride_height":1,"stride_width":1}',
);
}); });
} }
@@ -846,7 +885,8 @@ Reference complexMap() {
// "countryCode": "XX", // "countryCode": "XX",
// } // }
// } // }
return Reference.fromBuffer(b([ return Reference.fromBuffer(
b([
97, 97,
100, 100,
100, 100,
@@ -986,6 +1026,7 @@ Reference complexMap() {
14, 14,
25, 25,
38, 38,
1 1,
])); ]),
);
} }

View File

@@ -48,116 +48,210 @@ void main() {
expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt), isFalse); expect(ValueTypeUtils.isFixedTypedVector(ValueType.VectorInt), isFalse);
}); });
test('to typed vector', () { test('to typed vector', () {
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 0), expect(
equals(ValueType.VectorInt)); ValueTypeUtils.toTypedVector(ValueType.Int, 0),
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 0), equals(ValueType.VectorInt),
equals(ValueType.VectorUInt)); );
expect(ValueTypeUtils.toTypedVector(ValueType.Bool, 0), expect(
equals(ValueType.VectorBool)); ValueTypeUtils.toTypedVector(ValueType.UInt, 0),
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 0), equals(ValueType.VectorUInt),
equals(ValueType.VectorFloat)); );
expect(ValueTypeUtils.toTypedVector(ValueType.Key, 0), expect(
equals(ValueType.VectorKey)); ValueTypeUtils.toTypedVector(ValueType.Bool, 0),
expect(ValueTypeUtils.toTypedVector(ValueType.String, 0), equals(ValueType.VectorBool),
equals(ValueType.VectorString)); );
expect(
ValueTypeUtils.toTypedVector(ValueType.Float, 0),
equals(ValueType.VectorFloat),
);
expect(
ValueTypeUtils.toTypedVector(ValueType.Key, 0),
equals(ValueType.VectorKey),
);
expect(
ValueTypeUtils.toTypedVector(ValueType.String, 0),
equals(ValueType.VectorString),
);
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 2), expect(
equals(ValueType.VectorInt2)); ValueTypeUtils.toTypedVector(ValueType.Int, 2),
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 2), equals(ValueType.VectorInt2),
equals(ValueType.VectorUInt2)); );
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 2), expect(
equals(ValueType.VectorFloat2)); ValueTypeUtils.toTypedVector(ValueType.UInt, 2),
equals(ValueType.VectorUInt2),
);
expect(
ValueTypeUtils.toTypedVector(ValueType.Float, 2),
equals(ValueType.VectorFloat2),
);
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 3), expect(
equals(ValueType.VectorInt3)); ValueTypeUtils.toTypedVector(ValueType.Int, 3),
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 3), equals(ValueType.VectorInt3),
equals(ValueType.VectorUInt3)); );
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 3), expect(
equals(ValueType.VectorFloat3)); ValueTypeUtils.toTypedVector(ValueType.UInt, 3),
equals(ValueType.VectorUInt3),
);
expect(
ValueTypeUtils.toTypedVector(ValueType.Float, 3),
equals(ValueType.VectorFloat3),
);
expect(ValueTypeUtils.toTypedVector(ValueType.Int, 4), expect(
equals(ValueType.VectorInt4)); ValueTypeUtils.toTypedVector(ValueType.Int, 4),
expect(ValueTypeUtils.toTypedVector(ValueType.UInt, 4), equals(ValueType.VectorInt4),
equals(ValueType.VectorUInt4)); );
expect(ValueTypeUtils.toTypedVector(ValueType.Float, 4), expect(
equals(ValueType.VectorFloat4)); ValueTypeUtils.toTypedVector(ValueType.UInt, 4),
equals(ValueType.VectorUInt4),
);
expect(
ValueTypeUtils.toTypedVector(ValueType.Float, 4),
equals(ValueType.VectorFloat4),
);
}); });
test('typed vector element type', () { test('typed vector element type', () {
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorInt), expect(
equals(ValueType.Int)); ValueTypeUtils.typedVectorElementType(ValueType.VectorInt),
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorUInt), equals(ValueType.Int),
equals(ValueType.UInt)); );
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorFloat), expect(
equals(ValueType.Float)); ValueTypeUtils.typedVectorElementType(ValueType.VectorUInt),
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorString), equals(ValueType.UInt),
equals(ValueType.String)); );
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorKey), expect(
equals(ValueType.Key)); ValueTypeUtils.typedVectorElementType(ValueType.VectorFloat),
expect(ValueTypeUtils.typedVectorElementType(ValueType.VectorBool), equals(ValueType.Float),
equals(ValueType.Bool)); );
expect(
ValueTypeUtils.typedVectorElementType(ValueType.VectorString),
equals(ValueType.String),
);
expect(
ValueTypeUtils.typedVectorElementType(ValueType.VectorKey),
equals(ValueType.Key),
);
expect(
ValueTypeUtils.typedVectorElementType(ValueType.VectorBool),
equals(ValueType.Bool),
);
}); });
test('fixed typed vector element type', () { test('fixed typed vector element type', () {
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt2), expect(
equals(ValueType.Int)); ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt2),
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt3), equals(ValueType.Int),
equals(ValueType.Int)); );
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt4), expect(
equals(ValueType.Int)); ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt3),
equals(ValueType.Int),
);
expect(
ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorInt4),
equals(ValueType.Int),
);
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt2), expect(
equals(ValueType.UInt)); ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt2),
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt3), equals(ValueType.UInt),
equals(ValueType.UInt)); );
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt4), expect(
equals(ValueType.UInt)); ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt3),
equals(ValueType.UInt),
);
expect(
ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorUInt4),
equals(ValueType.UInt),
);
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat2), expect(
equals(ValueType.Float)); ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat2),
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat3), equals(ValueType.Float),
equals(ValueType.Float)); );
expect(ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat4), expect(
equals(ValueType.Float)); ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat3),
equals(ValueType.Float),
);
expect(
ValueTypeUtils.fixedTypedVectorElementType(ValueType.VectorFloat4),
equals(ValueType.Float),
);
}); });
test('fixed typed vector element size', () { test('fixed typed vector element size', () {
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt2), expect(
equals(2)); ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt2),
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt3), equals(2),
equals(3)); );
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt4), expect(
equals(4)); ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt3),
equals(3),
);
expect(
ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorInt4),
equals(4),
);
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt2), expect(
equals(2)); ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt2),
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt3), equals(2),
equals(3)); );
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt4), expect(
equals(4)); ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt3),
equals(3),
);
expect(
ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorUInt4),
equals(4),
);
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat2), expect(
equals(2)); ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat2),
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat3), equals(2),
equals(3)); );
expect(ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat4), expect(
equals(4)); ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat3),
equals(3),
);
expect(
ValueTypeUtils.fixedTypedVectorElementSize(ValueType.VectorFloat4),
equals(4),
);
}); });
test('packed type', () { test('packed type', () {
expect( expect(
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width8), equals(0)); ValueTypeUtils.packedType(ValueType.Null, BitWidth.width8),
equals(0),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width16), equals(1)); ValueTypeUtils.packedType(ValueType.Null, BitWidth.width16),
equals(1),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width32), equals(2)); ValueTypeUtils.packedType(ValueType.Null, BitWidth.width32),
equals(2),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Null, BitWidth.width64), equals(3)); ValueTypeUtils.packedType(ValueType.Null, BitWidth.width64),
equals(3),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width8), equals(4)); ValueTypeUtils.packedType(ValueType.Int, BitWidth.width8),
equals(4),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width16), equals(5)); ValueTypeUtils.packedType(ValueType.Int, BitWidth.width16),
equals(5),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width32), equals(6)); ValueTypeUtils.packedType(ValueType.Int, BitWidth.width32),
equals(6),
);
expect( expect(
ValueTypeUtils.packedType(ValueType.Int, BitWidth.width64), equals(7)); ValueTypeUtils.packedType(ValueType.Int, BitWidth.width64),
equals(7),
);
}); });
test('bit width', () { test('bit width', () {
expect(BitWidthUtil.width(0), BitWidth.width8); expect(BitWidthUtil.width(0), BitWidth.width8);

View File

@@ -2,10 +2,11 @@
// ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names // ignore_for_file: unused_import, unused_field, unused_element, unused_local_variable, constant_identifier_names
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb; import 'package:flat_buffers/flat_buffers.dart' as fb;
import './include_test2_my_game.other_name_space_generated.dart'
import './include_test2_my_game.other_name_space_generated.dart' as my_game_other_name_space; as my_game_other_name_space;
class TableA { class TableA {
TableA._(this._bc, this._bcOffset); TableA._(this._bc, this._bcOffset);
@@ -19,15 +20,17 @@ class TableA {
final fb.BufferContext _bc; final fb.BufferContext _bc;
final int _bcOffset; final int _bcOffset;
my_game_other_name_space.TableB? get b => my_game_other_name_space.TableB.reader.vTableGetNullable(_bc, _bcOffset, 4); my_game_other_name_space.TableB? get b => my_game_other_name_space
.TableB
.reader
.vTableGetNullable(_bc, _bcOffset, 4);
@override @override
String toString() { String toString() {
return 'TableA{b: ${b}}'; return 'TableA{b: ${b}}';
} }
TableAT unpack() => TableAT( TableAT unpack() => TableAT(b: b?.unpack());
b: b?.unpack());
static int pack(fb.Builder fbBuilder, TableAT? object) { static int pack(fb.Builder fbBuilder, TableAT? object) {
if (object == null) return 0; if (object == null) return 0;
@@ -38,8 +41,7 @@ class TableA {
class TableAT implements fb.Packable { class TableAT implements fb.Packable {
my_game_other_name_space.TableBT? b; my_game_other_name_space.TableBT? b;
TableAT({ TableAT({this.b});
this.b});
@override @override
int pack(fb.Builder fbBuilder) { int pack(fb.Builder fbBuilder) {
@@ -59,8 +61,7 @@ class _TableAReader extends fb.TableReader<TableA> {
const _TableAReader(); const _TableAReader();
@override @override
TableA createObject(fb.BufferContext bc, int offset) => TableA createObject(fb.BufferContext bc, int offset) => TableA._(bc, offset);
TableA._(bc, offset);
} }
class TableABuilder { class TableABuilder {
@@ -85,9 +86,7 @@ class TableABuilder {
class TableAObjectBuilder extends fb.ObjectBuilder { class TableAObjectBuilder extends fb.ObjectBuilder {
final my_game_other_name_space.TableBObjectBuilder? _b; final my_game_other_name_space.TableBObjectBuilder? _b;
TableAObjectBuilder({ TableAObjectBuilder({my_game_other_name_space.TableBObjectBuilder? b})
my_game_other_name_space.TableBObjectBuilder? b,
})
: _b = b; : _b = b;
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].

View File

@@ -4,8 +4,8 @@
library my_game.other_name_space; library my_game.other_name_space;
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'package:flat_buffers/flat_buffers.dart' as fb;
import './include_test1_generated.dart'; import './include_test1_generated.dart';
@@ -17,8 +17,10 @@ enum FromInclude {
factory FromInclude.fromValue(int value) { factory FromInclude.fromValue(int value) {
switch (value) { switch (value) {
case 0: return FromInclude.IncludeVal; case 0:
default: throw StateError('Invalid value $value for bit flag enum'); return FromInclude.IncludeVal;
default:
throw StateError('Invalid value $value for bit flag enum');
} }
} }
@@ -56,8 +58,7 @@ class Unused {
return 'Unused{a: ${a}}'; return 'Unused{a: ${a}}';
} }
UnusedT unpack() => UnusedT( UnusedT unpack() => UnusedT(a: a);
a: a);
static int pack(fb.Builder fbBuilder, UnusedT? object) { static int pack(fb.Builder fbBuilder, UnusedT? object) {
if (object == null) return 0; if (object == null) return 0;
@@ -68,8 +69,7 @@ class Unused {
class UnusedT implements fb.Packable { class UnusedT implements fb.Packable {
int a; int a;
UnusedT({ UnusedT({required this.a});
required this.a});
@override @override
int pack(fb.Builder fbBuilder) { int pack(fb.Builder fbBuilder) {
@@ -90,8 +90,7 @@ class _UnusedReader extends fb.StructReader<Unused> {
int get size => 4; int get size => 4;
@override @override
Unused createObject(fb.BufferContext bc, int offset) => Unused createObject(fb.BufferContext bc, int offset) => Unused._(bc, offset);
Unused._(bc, offset);
} }
class UnusedBuilder { class UnusedBuilder {
@@ -103,16 +102,12 @@ class UnusedBuilder {
fbBuilder.putInt32(a); fbBuilder.putInt32(a);
return fbBuilder.offset; return fbBuilder.offset;
} }
} }
class UnusedObjectBuilder extends fb.ObjectBuilder { class UnusedObjectBuilder extends fb.ObjectBuilder {
final int _a; final int _a;
UnusedObjectBuilder({ UnusedObjectBuilder({required int a}) : _a = a;
required int a,
})
: _a = a;
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].
@override @override
@@ -129,6 +124,7 @@ class UnusedObjectBuilder extends fb.ObjectBuilder {
return fbBuilder.buffer; return fbBuilder.buffer;
} }
} }
class TableB { class TableB {
TableB._(this._bc, this._bcOffset); TableB._(this._bc, this._bcOffset);
factory TableB(List<int> bytes) { factory TableB(List<int> bytes) {
@@ -148,8 +144,7 @@ class TableB {
return 'TableB{a: ${a}}'; return 'TableB{a: ${a}}';
} }
TableBT unpack() => TableBT( TableBT unpack() => TableBT(a: a?.unpack());
a: a?.unpack());
static int pack(fb.Builder fbBuilder, TableBT? object) { static int pack(fb.Builder fbBuilder, TableBT? object) {
if (object == null) return 0; if (object == null) return 0;
@@ -160,8 +155,7 @@ class TableB {
class TableBT implements fb.Packable { class TableBT implements fb.Packable {
TableAT? a; TableAT? a;
TableBT({ TableBT({this.a});
this.a});
@override @override
int pack(fb.Builder fbBuilder) { int pack(fb.Builder fbBuilder) {
@@ -181,8 +175,7 @@ class _TableBReader extends fb.TableReader<TableB> {
const _TableBReader(); const _TableBReader();
@override @override
TableB createObject(fb.BufferContext bc, int offset) => TableB createObject(fb.BufferContext bc, int offset) => TableB._(bc, offset);
TableB._(bc, offset);
} }
class TableBBuilder { class TableBBuilder {
@@ -207,10 +200,7 @@ class TableBBuilder {
class TableBObjectBuilder extends fb.ObjectBuilder { class TableBObjectBuilder extends fb.ObjectBuilder {
final TableAObjectBuilder? _a; final TableAObjectBuilder? _a;
TableBObjectBuilder({ TableBObjectBuilder({TableAObjectBuilder? a}) : _a = a;
TableAObjectBuilder? a,
})
: _a = a;
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].
@override @override

View File

@@ -4,12 +4,12 @@
library my_game.example2; library my_game.example2;
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb; import 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_test_my_game_generated.dart' as my_game;
import './monster_test_my_game.example_generated.dart' as my_game_example;
import './include_test1_generated.dart'; import './include_test1_generated.dart';
import './monster_test_my_game.example_generated.dart' as my_game_example;
import './monster_test_my_game_generated.dart' as my_game;
class Monster { class Monster {
Monster._(this._bc, this._bcOffset); Monster._(this._bc, this._bcOffset);
@@ -23,7 +23,6 @@ class Monster {
final fb.BufferContext _bc; final fb.BufferContext _bc;
final int _bcOffset; final int _bcOffset;
@override @override
String toString() { String toString() {
return 'Monster{}'; return 'Monster{}';
@@ -59,7 +58,6 @@ class _MonsterReader extends fb.TableReader<Monster> {
} }
class MonsterObjectBuilder extends fb.ObjectBuilder { class MonsterObjectBuilder extends fb.ObjectBuilder {
MonsterObjectBuilder(); MonsterObjectBuilder();
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].

File diff suppressed because it is too large Load Diff

View File

@@ -4,12 +4,12 @@
library my_game; library my_game;
import 'dart:typed_data' show Uint8List; import 'dart:typed_data' show Uint8List;
import 'package:flat_buffers/flat_buffers.dart' as fb; import 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_test_my_game.example_generated.dart' as my_game_example;
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
import './include_test1_generated.dart'; import './include_test1_generated.dart';
import './monster_test_my_game.example2_generated.dart' as my_game_example2;
import './monster_test_my_game.example_generated.dart' as my_game_example;
class InParentNamespace { class InParentNamespace {
InParentNamespace._(this._bc, this._bcOffset); InParentNamespace._(this._bc, this._bcOffset);
@@ -23,7 +23,6 @@ class InParentNamespace {
final fb.BufferContext _bc; final fb.BufferContext _bc;
final int _bcOffset; final int _bcOffset;
@override @override
String toString() { String toString() {
return 'InParentNamespace{}'; return 'InParentNamespace{}';
@@ -59,7 +58,6 @@ class _InParentNamespaceReader extends fb.TableReader<InParentNamespace> {
} }
class InParentNamespaceObjectBuilder extends fb.ObjectBuilder { class InParentNamespaceObjectBuilder extends fb.ObjectBuilder {
InParentNamespaceObjectBuilder(); InParentNamespaceObjectBuilder();
/// Finish building, and store into the [fbBuilder]. /// Finish building, and store into the [fbBuilder].

View File

@@ -6,7 +6,7 @@ https://flatbuffers.dev.
## Local Building ## Local Building
The documentation can be built and served locally during development, see [https//flatbuffers.dev/contributing/#local-development] for full details. The documentation can be built and served locally during development, see <https://flatbuffers.dev/contributing/#local-development> for full details.
__tl;dr__ __tl;dr__

View File

@@ -139,7 +139,7 @@ nav:
- Dart: "languages/dart.md" - Dart: "languages/dart.md"
- Go: "languages/go.md" - Go: "languages/go.md"
- Java: "languages/java.md" - Java: "languages/java.md"
- JavasScript: "languages/javascript.md" - JavaScript: "languages/javascript.md"
- Kotlin: "languages/kotlin.md" - Kotlin: "languages/kotlin.md"
- Lobster: "languages/lobster.md" - Lobster: "languages/lobster.md"
- Lua: "languages/lua.md" - Lua: "languages/lua.md"

View File

@@ -131,7 +131,7 @@ list of `FILES...`.
- `--gen-mutable` : Generate additional non-const accessors for mutating - `--gen-mutable` : Generate additional non-const accessors for mutating
FlatBuffers in-place. FlatBuffers in-place.
- `--gen-onefile` : Generate single output file for C#, Go, and Python. - `--gen-onefile` : Generate a single output file for C#, Go, Java, Kotlin and Python.
- `--gen-name-strings` : Generate type name functions for C++. - `--gen-name-strings` : Generate type name functions for C++.
@@ -259,6 +259,8 @@ list of `FILES...`.
- `--python-typing` : Generate Python type annotations - `--python-typing` : Generate Python type annotations
- `--python-decode-obj-api-strings` : Decode bytes automaticaly with utf-8
Additional gRPC options: Additional gRPC options:
- `--grpc-filename-suffix`: `[C++]` An optional suffix for the generated - `--grpc-filename-suffix`: `[C++]` An optional suffix for the generated

View File

@@ -21,15 +21,15 @@ It is available as Open Source on
- :material-memory:{ .lg .middle } **Memory Efficiency and Speed** - :material-memory:{ .lg .middle } **Memory Efficiency and Speed**
--- ---
The only memory needed to access your data is that of the buffer. No heap is The only memory needed to access your data is that of the buffer.
required. No heap is required.
- :material-compare-horizontal:{ .lg .middle } **Backwards and Forwards - :material-compare-horizontal:{ .lg .middle } **Backwards and Forwards
Compatibility** Compatibility**
--- ---
The only memory needed to access your data is that of the buffer. No heap is FlatBuffers enables the schema to evolve over time while still maintaining
required. forwards and backwards compatibility with old flatbuffers.
- :material-scale-off:{ .lg .middle } **Small Footprint** - :material-scale-off:{ .lg .middle } **Small Footprint**

View File

@@ -419,7 +419,8 @@ Each root type will have a verification function generated for it,
e.g. for `Monster`, you can call: e.g. for `Monster`, you can call:
```cpp ```cpp
bool ok = VerifyMonsterBuffer(Verifier(buf, len)); Verifier verifier(buf, len);
bool ok = VerifyMonsterBuffer(verifier);
``` ```
if `ok` is true, the buffer is safe to read. if `ok` is true, the buffer is safe to read.

View File

@@ -48,7 +48,7 @@ function). Then you can read a FlatBuffer binary file, which you
pass the contents of to the `GetRootAsMonster` function: pass the contents of to the `GetRootAsMonster` function:
~~~{.php} ~~~{.php}
// It is recommended that your use PSR autoload when using FlatBuffers in PHP. // It is recommended that you use PSR autoload when using FlatBuffers in PHP.
// Here is an example: // Here is an example:
function __autoload($class_name) { function __autoload($class_name) {
// The last segment of the class name matches the file name. // The last segment of the class name matches the file name.
@@ -69,7 +69,7 @@ pass the contents of to the `GetRootAsMonster` function:
// Read the contents of the FlatBuffer binary file. // Read the contents of the FlatBuffer binary file.
$filename = "monster.dat"; $filename = "monster.dat";
$handle = fopen($filename, "rb"); $handle = fopen($filename, "rb");
$contents = $fread($handle, filesize($filename)); $contents = fread($handle, filesize($filename));
fclose($handle); fclose($handle);
// Pass the contents to `GetRootAsMonster`. // Pass the contents to `GetRootAsMonster`.

View File

@@ -177,6 +177,34 @@ functions require a mutable (aka exclusive) reference which can only be created
when no other references to the `FlatBufferBuilder` exist, and may not be copied when no other references to the `FlatBufferBuilder` exist, and may not be copied
within the same thread, let alone to a second thread. within the same thread, let alone to a second thread.
## Reflection (& Resizing)
There is experimental support for reflection in FlatBuffers, allowing you to
read and write data even if you don't know the exact format of a buffer, and
even allows you to change sizes of strings in-place.
The way this works is very elegant; there is actually a FlatBuffer schema that
describes schemas (\!) which you can find in `reflection/reflection.fbs`.
The compiler, `flatc`, can write out any schemas it has just parsed as a binary
FlatBuffer, corresponding to this meta-schema.
Loading in one of these binary schemas at runtime allows you to traverse any
FlatBuffer data that corresponds to it without knowing the exact format. You
can query what fields are present, and then read/write them after.
For convenient field manipulation, you can use the crate
`flatbuffers-reflection` which includes both the generated code from the meta
schema, as well as a lot of helper functions.
And example of usage, for the time being, can be found in
`tests/rust_reflection_test/src/lib.rs`. Two sets of APIs are provided:
- [Unsafe getters/setters](https://docs.rs/flatbuffers-reflection/latest/flatbuffers_reflection/#functions),
which you can use when you are processing trusted data (either from a source you know, or has been verified)
- 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
## Useful tools created by others ## Useful tools created by others
* [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler * [flatc-rust](https://github.com/frol/flatc-rust) - FlatBuffers compiler

View File

@@ -57,7 +57,7 @@ a data object from the server, which you can pass into the `GetRootAsMonster` fu
let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon") let url = URL(fileURLWithPath: path, isDirectory: true).appendingPathComponent("monsterdata_test").appendingPathExtension("mon")
guard let data = try? Data(contentsOf: url) else { return } guard let data = try? Data(contentsOf: url) else { return }
let monster = Monster.getRootAsMonster(bb: ByteBuffer(data: data)) let monster: Monster = try! getCheckedRoot(byteBuffer: &byteBuffer)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now you can access values like this: Now you can access values like this:

View File

@@ -30,7 +30,7 @@ See the [Tutorial](tutorial.md) for a more in depth guide.
code: code:
```sh ```sh
./flatc --cpp --rust mosnter.fbs ./flatc --cpp --rust monster.fbs
``` ```
Which generates `monster_generated.h` and `monster_generated.rs` files. Which generates `monster_generated.h` and `monster_generated.rs` files.

View File

@@ -2011,6 +2011,8 @@ like so:
let buf = builder.sizedByteArray let buf = builder.sizedByteArray
// or you can use to get an object of type Data // or you can use to get an object of type Data
let bufData = ByteBuffer(data: builder.data) let bufData = ByteBuffer(data: builder.data)
// or
let buf = builder.sizedBuffer
``` ```
=== "TypeScript" === "TypeScript"

10
eslint.config.mjs Normal file
View File

@@ -0,0 +1,10 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
export default [
{files: ["**/*.{js,mjs,cjs,ts}"]},
{languageOptions: { globals: {...globals.browser, ...globals.node} }},
pluginJs.configs.recommended,
...tseslint.configs.recommended,
];

View File

@@ -104,13 +104,16 @@ func (b *Builder) StartObject(numfields int) {
// logically-equal vtables will be deduplicated. // logically-equal vtables will be deduplicated.
// //
// A vtable has the following format: // A vtable has the following format:
//
// <VOffsetT: size of the vtable in bytes, including this value> // <VOffsetT: size of the vtable in bytes, including this value>
// <VOffsetT: size of the object in bytes, including the vtable offset> // <VOffsetT: size of the object in bytes, including the vtable offset>
// <VOffsetT: offset for a field> * N, where N is the number of fields in // <VOffsetT: offset for a field> * N, where N is the number of fields in
// the schema for this type. Includes deprecated fields. // the schema for this type. Includes deprecated fields.
//
// Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide. // Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide.
// //
// An object has the following format: // An object has the following format:
//
// <SOffsetT: offset to this object's vtable (may be negative)> // <SOffsetT: offset to this object's vtable (may be negative)>
// <byte: data>+ // <byte: data>+
func (b *Builder) WriteVtable() (n UOffsetT) { func (b *Builder) WriteVtable() (n UOffsetT) {
@@ -296,6 +299,7 @@ func (b *Builder) PrependUOffsetT(off UOffsetT) {
// StartVector initializes bookkeeping for writing a new vector. // StartVector initializes bookkeeping for writing a new vector.
// //
// A vector has the following format: // A vector has the following format:
//
// <UOffsetT: number of elements in this vector> // <UOffsetT: number of elements in this vector>
// <T: data>+, where T is the type of elements of this vector. // <T: data>+, where T is the type of elements of this vector.
func (b *Builder) StartVector(elemSize, numElems, alignment int) UOffsetT { func (b *Builder) StartVector(elemSize, numElems, alignment int) UOffsetT {

View File

@@ -1,7 +1,17 @@
package flatbuffers package flatbuffers
import "errors"
var (
// Codec implements gRPC-go Codec which is used to encode and decode messages. // Codec implements gRPC-go Codec which is used to encode and decode messages.
var Codec = "flatbuffers" Codec = "flatbuffers"
// ErrInsufficientData is returned when the data is too short to read the root UOffsetT.
ErrInsufficientData = errors.New("insufficient data")
// ErrInvalidRootOffset is returned when the root UOffsetT is out of bounds.
ErrInvalidRootOffset = errors.New("invalid root offset")
)
// FlatbuffersCodec defines the interface gRPC uses to encode and decode messages. Note // FlatbuffersCodec defines the interface gRPC uses to encode and decode messages. Note
// that implementations of this interface must be thread safe; a Codec's // that implementations of this interface must be thread safe; a Codec's
@@ -15,7 +25,21 @@ func (FlatbuffersCodec) Marshal(v interface{}) ([]byte, error) {
// Unmarshal parses the wire format into v. // Unmarshal parses the wire format into v.
func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error { func (FlatbuffersCodec) Unmarshal(data []byte, v interface{}) error {
v.(flatbuffersInit).Init(data, GetUOffsetT(data)) // Need at least 4 bytes to read the root table offset (UOffsetT).
// Vtable soffset_t and metadata are read later during field access.
if len(data) < SizeUOffsetT {
return ErrInsufficientData
}
off := GetUOffsetT(data)
// The root UOffsetT must be within the data buffer
// Compare in the unsigned domain to avoid signedness pitfalls
if off > UOffsetT(len(data)-SizeUOffsetT) {
return ErrInvalidRootOffset
}
v.(flatbuffersInit).Init(data, off)
return nil return nil
} }

View File

@@ -3,8 +3,8 @@
This directory is a repository for the generated files of `flatc`. This directory is a repository for the generated files of `flatc`.
We check in the generated code so we can see, during a PR review, how the We check in the generated code so we can see, during a PR review, how the
changes affect the generated output. Its also useful as a reference to point too changes affect the generated output. It's also useful as a reference to show
as how things work across various languages. how things work across various languages.
These files are **NOT** intended to be depended on by any code, such as tests or These files are **NOT** intended to be depended on by any code, such as tests or
or compiled examples. or compiled examples.

View File

@@ -9,8 +9,8 @@
// Ensure the included flatbuffers.h is the same version as when this file was // Ensure the included flatbuffers.h is the same version as when this file was
// generated, otherwise it may not be compatible. // generated, otherwise it may not be compatible.
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 && static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
FLATBUFFERS_VERSION_MINOR == 2 && FLATBUFFERS_VERSION_MINOR == 9 &&
FLATBUFFERS_VERSION_REVISION == 10, FLATBUFFERS_VERSION_REVISION == 23,
"Non-compatible flatbuffers version included"); "Non-compatible flatbuffers version included");
namespace flatbuffers { namespace flatbuffers {

View File

@@ -13,7 +13,7 @@ public struct Galaxy : IFlatbufferObject
{ {
private Table __p; private Table __p;
public ByteBuffer ByteBuffer { get { return __p.bb; } } public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_9_23(); }
public static Galaxy GetRootAsGalaxy(ByteBuffer _bb) { return GetRootAsGalaxy(_bb, new Galaxy()); } public static Galaxy GetRootAsGalaxy(ByteBuffer _bb) { return GetRootAsGalaxy(_bb, new Galaxy()); }
public static Galaxy GetRootAsGalaxy(ByteBuffer _bb, Galaxy obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } public static Galaxy GetRootAsGalaxy(ByteBuffer _bb, Galaxy obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); } public void __init(int _i, ByteBuffer _bb) { __p = new Table(_i, _bb); }

View File

@@ -13,7 +13,7 @@ public struct Universe : IFlatbufferObject
{ {
private Table __p; private Table __p;
public ByteBuffer ByteBuffer { get { return __p.bb; } } public ByteBuffer ByteBuffer { get { return __p.bb; } }
public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_2_10(); } public static void ValidateVersion() { FlatBufferConstants.FLATBUFFERS_25_9_23(); }
public static Universe GetRootAsUniverse(ByteBuffer _bb) { return GetRootAsUniverse(_bb, new Universe()); } public static Universe GetRootAsUniverse(ByteBuffer _bb) { return GetRootAsUniverse(_bb, new Universe()); }
public static Universe GetRootAsUniverse(ByteBuffer _bb, Universe obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); } public static Universe GetRootAsUniverse(ByteBuffer _bb, Universe obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public static bool VerifyUniverse(ByteBuffer _bb) {Google.FlatBuffers.Verifier verifier = new Google.FlatBuffers.Verifier(_bb); return verifier.VerifyBuffer("", false, UniverseVerify.Verify); } public static bool VerifyUniverse(ByteBuffer _bb) {Google.FlatBuffers.Verifier verifier = new Google.FlatBuffers.Verifier(_bb); return verifier.VerifyBuffer("", false, UniverseVerify.Verify); }

View File

@@ -1,5 +1,5 @@
import sys
from pathlib import Path from pathlib import Path
import sys
# Get the path where this script is located so we can invoke the script from # Get the path where this script is located so we can invoke the script from
# any directory and have the paths work correctly. # any directory and have the paths work correctly.

View File

@@ -21,7 +21,7 @@ import java.nio.ByteOrder;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class Galaxy extends Table { public final class Galaxy extends Table {
public static void ValidateVersion() { Constants.FLATBUFFERS_25_2_10(); } public static void ValidateVersion() { Constants.FLATBUFFERS_25_9_23(); }
public static Galaxy getRootAsGalaxy(ByteBuffer _bb) { return getRootAsGalaxy(_bb, new Galaxy()); } public static Galaxy getRootAsGalaxy(ByteBuffer _bb) { return getRootAsGalaxy(_bb, new Galaxy()); }
public static Galaxy getRootAsGalaxy(ByteBuffer _bb, Galaxy obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } public static Galaxy getRootAsGalaxy(ByteBuffer _bb, Galaxy obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }

View File

@@ -21,7 +21,7 @@ import java.nio.ByteOrder;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class Universe extends Table { public final class Universe extends Table {
public static void ValidateVersion() { Constants.FLATBUFFERS_25_2_10(); } public static void ValidateVersion() { Constants.FLATBUFFERS_25_9_23(); }
public static Universe getRootAsUniverse(ByteBuffer _bb) { return getRootAsUniverse(_bb, new Universe()); } public static Universe getRootAsUniverse(ByteBuffer _bb) { return getRootAsUniverse(_bb, new Universe()); }
public static Universe getRootAsUniverse(ByteBuffer _bb, Universe obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } public static Universe getRootAsUniverse(ByteBuffer _bb, Universe obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); } public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }

View File

@@ -34,7 +34,7 @@ class Galaxy : Table() {
return if(o != 0) bb.getLong(o + bb_pos) else 0L return if(o != 0) bb.getLong(o + bb_pos) else 0L
} }
companion object { companion object {
fun validateVersion() = Constants.FLATBUFFERS_25_2_10() fun validateVersion() = Constants.FLATBUFFERS_25_9_23()
fun getRootAsGalaxy(_bb: ByteBuffer): Galaxy = getRootAsGalaxy(_bb, Galaxy()) fun getRootAsGalaxy(_bb: ByteBuffer): Galaxy = getRootAsGalaxy(_bb, Galaxy())
fun getRootAsGalaxy(_bb: ByteBuffer, obj: Galaxy): Galaxy { fun getRootAsGalaxy(_bb: ByteBuffer, obj: Galaxy): Galaxy {
_bb.order(ByteOrder.LITTLE_ENDIAN) _bb.order(ByteOrder.LITTLE_ENDIAN)

View File

@@ -47,7 +47,7 @@ class Universe : Table() {
val o = __offset(6); return if (o != 0) __vector_len(o) else 0 val o = __offset(6); return if (o != 0) __vector_len(o) else 0
} }
companion object { companion object {
fun validateVersion() = Constants.FLATBUFFERS_25_2_10() fun validateVersion() = Constants.FLATBUFFERS_25_9_23()
fun getRootAsUniverse(_bb: ByteBuffer): Universe = getRootAsUniverse(_bb, Universe()) fun getRootAsUniverse(_bb: ByteBuffer): Universe = getRootAsUniverse(_bb, Universe())
fun getRootAsUniverse(_bb: ByteBuffer, obj: Universe): Universe { fun getRootAsUniverse(_bb: ByteBuffer, obj: Universe): Universe {
_bb.order(ByteOrder.LITTLE_ENDIAN) _bb.order(ByteOrder.LITTLE_ENDIAN)

View File

@@ -37,7 +37,7 @@ impl<'a> flatbuffers::Follow<'a> for Galaxy<'a> {
type Inner = Galaxy<'a>; type Inner = Galaxy<'a>;
#[inline] #[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table::new(buf, loc) } Self { _tab: unsafe { flatbuffers::Table::new(buf, loc) } }
} }
} }
@@ -134,7 +134,7 @@ impl<'a> flatbuffers::Follow<'a> for Universe<'a> {
type Inner = Universe<'a>; type Inner = Universe<'a>;
#[inline] #[inline]
unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
Self { _tab: flatbuffers::Table::new(buf, loc) } Self { _tab: unsafe { flatbuffers::Table::new(buf, loc) } }
} }
} }
@@ -288,14 +288,14 @@ pub fn size_prefixed_root_as_universe_with_opts<'b, 'o>(
/// # Safety /// # Safety
/// Callers must trust the given bytes do indeed contain a valid `Universe`. /// Callers must trust the given bytes do indeed contain a valid `Universe`.
pub unsafe fn root_as_universe_unchecked(buf: &[u8]) -> Universe { pub unsafe fn root_as_universe_unchecked(buf: &[u8]) -> Universe {
flatbuffers::root_unchecked::<Universe>(buf) unsafe { flatbuffers::root_unchecked::<Universe>(buf) }
} }
#[inline] #[inline]
/// Assumes, without verification, that a buffer of bytes contains a size prefixed Universe and returns it. /// Assumes, without verification, that a buffer of bytes contains a size prefixed Universe and returns it.
/// # Safety /// # Safety
/// Callers must trust the given bytes do indeed contain a valid size prefixed `Universe`. /// 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 { pub unsafe fn size_prefixed_root_as_universe_unchecked(buf: &[u8]) -> Universe {
flatbuffers::size_prefixed_root_unchecked::<Universe>(buf) unsafe { flatbuffers::size_prefixed_root_unchecked::<Universe>(buf) }
} }
#[inline] #[inline]
pub fn finish_universe_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>( pub fn finish_universe_buffer<'a, 'b, A: flatbuffers::Allocator + 'a>(

View File

@@ -2,11 +2,15 @@
// swiftlint:disable all // swiftlint:disable all
// swiftformat:disable all // swiftformat:disable all
#if canImport(Common)
import Common
#endif
import FlatBuffers import FlatBuffers
public struct flatbuffers_goldens_Galaxy: FlatBufferObject, Verifiable { public struct flatbuffers_goldens_Galaxy: FlatBufferObject, Verifiable {
static func validateVersion() { FlatBuffersVersion_25_2_10() } static func validateVersion() { FlatBuffersVersion_25_9_23() }
public var __buffer: ByteBuffer! { return _accessor.bb } public var __buffer: ByteBuffer! { return _accessor.bb }
private var _accessor: Table private var _accessor: Table
@@ -41,7 +45,7 @@ public struct flatbuffers_goldens_Galaxy: FlatBufferObject, Verifiable {
public struct flatbuffers_goldens_Universe: FlatBufferObject, Verifiable { public struct flatbuffers_goldens_Universe: FlatBufferObject, Verifiable {
static func validateVersion() { FlatBuffersVersion_25_2_10() } static func validateVersion() { FlatBuffersVersion_25_9_23() }
public var __buffer: ByteBuffer! { return _accessor.bb } public var __buffer: ByteBuffer! { return _accessor.bb }
private var _accessor: Table private var _accessor: Table

View File

@@ -1,5 +1,4 @@
GRPC implementation and test GRPC implementation and test
============================
NOTE: files in `src/` are shared with the GRPC project, and maintained there NOTE: files in `src/` are shared with the GRPC project, and maintained there
(any changes should be submitted to GRPC instead). These files are copied (any changes should be submitted to GRPC instead). These files are copied
@@ -40,3 +39,63 @@ For Bazel users:
```shell ```shell
$bazel test tests/... $bazel test tests/...
``` ```
## C++ Callback API Generation
FlatBuffers gRPC C++ code generation now optionally supports the modern gRPC Callback API.
To enable generation of a `CallbackService` skeleton alongside the existing `Service` and async mixins, invoke `flatc` with both `--grpc` and `--grpc-callback-api`:
```shell
flatc --cpp --grpc --grpc-callback-api your_service.fbs
```
This adds (guarded by `#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)`) a class:
```cpp
class YourService::CallbackService : public ::grpc::Service { /* reactor virtuals */ };
```
Each RPC shape maps to the appropriate reactor return type:
- Unary -> `::grpc::ServerUnaryReactor*` Method(...)
- Client streaming -> `::grpc::ServerReadReactor<Request>*`
- Server streaming -> `::grpc::ServerWriteReactor<Response>*`
- Bidi streaming -> `::grpc::ServerBidiReactor<Request, Response>*`
Default generated implementations return `nullptr`; override in your derived class and return a reactor instance you manage (see gRPC docs for lifecycle patterns).
If your gRPC library predates the stable callback API macro, the code inside the guard will be skipped (no breaking changes). Ensure you build against a recent gRPC (1.38+; verify current minimum in grpc repo) to use this feature.
### Client Callback Stubs
When `--grpc-callback-api` is supplied, the generated C++ client stub gains native callback / reactor based async methods in addition to the existing synchronous / generic async flavors, guarded by the same macro. For each RPC named `Foo`:
Unary:
```
void async_Foo(::grpc::ClientContext*, const Request&, Response*, std::function<void(::grpc::Status)>);
void async_Foo(::grpc::ClientContext*, const Request&, Response*, ::grpc::ClientUnaryReactor*);
```
Client streaming:
```
::grpc::ClientWriteReactor<Request>* async_Foo(::grpc::ClientContext*, Response*, ::grpc::ClientWriteReactor<Request>*);
```
Server streaming:
```
::grpc::ClientReadReactor<Response>* async_Foo(::grpc::ClientContext*, const Request&, ::grpc::ClientReadReactor<Response>*);
```
Bidirectional streaming:
```
::grpc::ClientBidiReactor<Request, Response>* async_Foo(::grpc::ClientContext*, ::grpc::ClientBidiReactor<Request, Response>*);
```
These map directly onto the native gRPC callback API factories (e.g. `CallbackUnaryCall`, `ClientCallbackWriterFactory::Create`, etc.) and do not spawn threads. Override the appropriate reactor callbacks per gRPC's documentation to drive I/O.
If your build uses an older gRPC lacking the non-experimental macro, these symbols will not be emitted, preserving backwards compatibility.

View File

@@ -1,31 +1,36 @@
import sys
import argparse import argparse
import sys
import grpc import grpc
sys.path.insert(0, '../../../../../flatbuffers/python') sys.path.insert(0, "../../../../../flatbuffers/python")
import flatbuffers import flatbuffers
from models import HelloReply, HelloRequest, greeter_grpc_fb from models import HelloReply, HelloRequest, greeter_grpc_fb
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("port", help="server port to connect to", default=3000) parser.add_argument("port", help="server port to connect to", default=3000)
parser.add_argument("name", help="name to be sent to server", default="flatbuffers") parser.add_argument(
"name", help="name to be sent to server", default="flatbuffers"
)
def say_hello(stub, hello_request): def say_hello(stub, hello_request):
reply = stub.SayHello(hello_request) reply = stub.SayHello(hello_request)
r = HelloReply.HelloReply.GetRootAs(reply) r = HelloReply.HelloReply.GetRootAs(reply)
print(r.Message()) print(r.Message())
def say_many_hellos(stub, hello_request): def say_many_hellos(stub, hello_request):
greetings = stub.SayManyHellos(hello_request) greetings = stub.SayManyHellos(hello_request)
for greeting in greetings: for greeting in greetings:
r = HelloReply.HelloReply.GetRootAs(greeting) r = HelloReply.HelloReply.GetRootAs(greeting)
print(r.Message()) print(r.Message())
def main(): def main():
args = parser.parse_args() args = parser.parse_args()
with grpc.insecure_channel('localhost:' + args.port) as channel: with grpc.insecure_channel("localhost:" + args.port) as channel:
builder = flatbuffers.Builder() builder = flatbuffers.Builder()
ind = builder.CreateString(args.name) ind = builder.CreateString(args.name)
HelloRequest.HelloRequestStart(builder) HelloRequest.HelloRequestStart(builder)
@@ -37,4 +42,5 @@ def main():
say_hello(stub, output) say_hello(stub, output)
say_many_hellos(stub, output) say_many_hellos(stub, output)
main() main()

View File

@@ -2,30 +2,29 @@
import flatbuffers import flatbuffers
import grpc import grpc
from models.HelloReply import HelloReply from models.HelloReply import HelloReply
from models.HelloRequest import HelloRequest from models.HelloRequest import HelloRequest
class GreeterStub(object): class GreeterStub(object):
'''Interface exported by the server.''' """Interface exported by the server."""
def __init__(self, channel): def __init__(self, channel):
'''Constructor. """Constructor.
Args: Args:
channel: A grpc.Channel. channel: A grpc.Channel.
''' """
self.SayHello = channel.unary_unary( self.SayHello = channel.unary_unary(method='/models.Greeter/SayHello')
method='/models.Greeter/SayHello')
self.SayManyHellos = channel.unary_stream( self.SayManyHellos = channel.unary_stream(
method='/models.Greeter/SayManyHellos') method='/models.Greeter/SayManyHellos'
)
class GreeterServicer(object): class GreeterServicer(object):
'''Interface exported by the server.''' """Interface exported by the server."""
def SayHello(self, request, context): def SayHello(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -40,15 +39,14 @@ class GreeterServicer(object):
def add_GreeterServicer_to_server(servicer, server): def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = { rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler( 'SayHello': grpc.unary_unary_rpc_method_handler(servicer.SayHello),
servicer.SayHello),
'SayManyHellos': grpc.unary_stream_rpc_method_handler( 'SayManyHellos': grpc.unary_stream_rpc_method_handler(
servicer.SayManyHellos), servicer.SayManyHellos
),
} }
generic_handler = grpc.method_handlers_generic_handler( generic_handler = grpc.method_handlers_generic_handler(
'models.Greeter', rpc_method_handlers) 'models.Greeter', rpc_method_handlers
)
server.add_generic_rpc_handlers((generic_handler,)) server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -1,52 +1,54 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! # Generated by the gRPC FlatBuffers compiler. DO NOT EDIT!
import flatbuffers
import grpc import grpc
from models.HelloReply import HelloReply
from models.HelloRequest import HelloRequest
class GreeterStub(object): class GreeterStub(object):
""" Interface exported by the server. """ '''Interface exported by the server.'''
def __init__(self, channel): def __init__(self, channel):
""" Constructor. '''Constructor.
Args: Args:
channel: A grpc.Channel. channel: A grpc.Channel.
""" '''
self.SayHello = channel.unary_unary( self.SayHello = channel.unary_unary(
"/models.Greeter/SayHello" method='/models.Greeter/SayHello')
)
self.SayManyHellos = channel.unary_stream( self.SayManyHellos = channel.unary_stream(
"/models.Greeter/SayManyHellos" method='/models.Greeter/SayManyHellos')
)
class GreeterServicer(object): class GreeterServicer(object):
""" Interface exported by the server. """ '''Interface exported by the server.'''
def SayHello(self, request, context): def SayHello(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!') context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!') raise NotImplementedError('Method not implemented!')
def SayManyHellos(self, request, context): def SayManyHellos(self, request, context):
context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!') context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!') raise NotImplementedError('Method not implemented!')
def add_GreeterServicer_to_server(servicer, server): def add_GreeterServicer_to_server(servicer, server):
rpc_method_handlers = { rpc_method_handlers = {
'SayHello': grpc.unary_unary_rpc_method_handler( 'SayHello': grpc.unary_unary_rpc_method_handler(
servicer.SayHello servicer.SayHello),
),
'SayManyHellos': grpc.unary_stream_rpc_method_handler( 'SayManyHellos': grpc.unary_stream_rpc_method_handler(
servicer.SayManyHellos servicer.SayManyHellos),
),
} }
generic_handler = grpc.method_handlers_generic_handler( generic_handler = grpc.method_handlers_generic_handler(
'models.Greeter', rpc_method_handlers) 'models.Greeter', rpc_method_handlers)
server.add_generic_rpc_handlers((generic_handler,)) server.add_generic_rpc_handlers((generic_handler,))

View File

@@ -1,9 +1,9 @@
import argparse
from concurrent import futures from concurrent import futures
import sys import sys
import argparse
import grpc import grpc
sys.path.insert(0, '../../../../../flatbuffers/python') sys.path.insert(0, "../../../../../flatbuffers/python")
import flatbuffers import flatbuffers
from models import HelloReply, HelloRequest, greeter_grpc_fb from models import HelloReply, HelloRequest, greeter_grpc_fb
@@ -11,6 +11,7 @@ from models import HelloReply, HelloRequest, greeter_grpc_fb
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("port", help="server on port", default=3000) parser.add_argument("port", help="server on port", default=3000)
def build_reply(message): def build_reply(message):
builder = flatbuffers.Builder() builder = flatbuffers.Builder()
ind = builder.CreateString(message) ind = builder.CreateString(message)
@@ -20,6 +21,7 @@ def build_reply(message):
builder.Finish(root) builder.Finish(root)
return bytes(builder.Output()) return bytes(builder.Output())
class GreeterServicer(greeter_grpc_fb.GreeterServicer): class GreeterServicer(greeter_grpc_fb.GreeterServicer):
def __init__(self): def __init__(self):
@@ -30,7 +32,7 @@ class GreeterServicer(greeter_grpc_fb.GreeterServicer):
reply = "Unknown" reply = "Unknown"
if r.Name(): if r.Name():
reply = r.Name() reply = r.Name()
return build_reply("welcome " + reply.decode('UTF-8')) return build_reply("welcome " + reply.decode("UTF-8"))
def SayManyHellos(self, request, context): def SayManyHellos(self, request, context):
r = HelloRequest.HelloRequest().GetRootAs(request, 0) r = HelloRequest.HelloRequest().GetRootAs(request, 0)
@@ -40,18 +42,17 @@ class GreeterServicer(greeter_grpc_fb.GreeterServicer):
for greeting in self.greetings: for greeting in self.greetings:
print(type(reply)) print(type(reply))
yield build_reply(greeting + " " + reply.decode('UTF-8')) yield build_reply(greeting + " " + reply.decode("UTF-8"))
def serve(): def serve():
args = parser.parse_args() args = parser.parse_args()
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
greeter_grpc_fb.add_GreeterServicer_to_server( greeter_grpc_fb.add_GreeterServicer_to_server(GreeterServicer(), server)
GreeterServicer(), server server.add_insecure_port("[::]:" + args.port)
)
server.add_insecure_port('[::]:' + args.port)
server.start() server.start()
server.wait_for_termination() server.wait_for_termination()
if __name__ == '__main__':
if __name__ == "__main__":
serve() serve()

View File

@@ -20,7 +20,7 @@ import PackageDescription
let package = Package( let package = Package(
name: "Greeter", name: "Greeter",
platforms: [ platforms: [
.iOS(.v11), .iOS(.v12),
.macOS(.v10_14), .macOS(.v10_14),
], ],
dependencies: [ dependencies: [

View File

@@ -5,6 +5,7 @@
// swiftlint:disable all // swiftlint:disable all
// swiftformat:disable all // swiftformat:disable all
#if !os(Windows)
import Foundation import Foundation
import GRPC import GRPC
import NIO import NIO
@@ -17,8 +18,7 @@ public extension GRPCFlatBufPayload {
self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes)) self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes))
} }
func serialize(into buffer: inout NIO.ByteBuffer) throws { func serialize(into buffer: inout NIO.ByteBuffer) throws {
let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: Int(self.size)) withUnsafeReadableBytes { buffer.writeBytes($0) }
buffer.writeBytes(buf)
} }
} }
extension Message: GRPCFlatBufPayload {} extension Message: GRPCFlatBufPayload {}
@@ -143,3 +143,5 @@ public protocol models_GreeterServerInterceptorFactoryProtocol {
func makeSayManyHellosInterceptors() -> [ServerInterceptor<Message<models_HelloRequest>, Message<models_HelloReply>>] func makeSayManyHellosInterceptors() -> [ServerInterceptor<Message<models_HelloRequest>, Message<models_HelloReply>>]
} }
#endif

View File

@@ -2,11 +2,15 @@
// swiftlint:disable all // swiftlint:disable all
// swiftformat:disable all // swiftformat:disable all
#if canImport(Common)
import Common
#endif
import FlatBuffers import FlatBuffers
public struct models_HelloReply: FlatBufferObject, Verifiable { public struct models_HelloReply: FlatBufferObject, Verifiable {
static func validateVersion() { FlatBuffersVersion_25_2_10() } static func validateVersion() { FlatBuffersVersion_25_9_23() }
public var __buffer: ByteBuffer! { return _accessor.bb } public var __buffer: ByteBuffer! { return _accessor.bb }
private var _accessor: Table private var _accessor: Table
@@ -53,7 +57,7 @@ extension models_HelloReply: Encodable {
public struct models_HelloRequest: FlatBufferObject, Verifiable { public struct models_HelloRequest: FlatBufferObject, Verifiable {
static func validateVersion() { FlatBuffersVersion_25_2_10() } static func validateVersion() { FlatBuffersVersion_25_9_23() }
public var __buffer: ByteBuffer! { return _accessor.bb } public var __buffer: ByteBuffer! { return _accessor.bb }
private var _accessor: Table private var _accessor: Table

View File

@@ -37,7 +37,8 @@ func greet(name: String, client greeter: models_GreeterServiceClient) {
builder.finish(offset: root) builder.finish(offset: root)
// Make the RPC call to the server. // Make the RPC call to the server.
let sayHello = greeter let sayHello =
greeter
.SayHello(Message<models_HelloRequest>(builder: &builder)) .SayHello(Message<models_HelloRequest>(builder: &builder))
// wait() on the response to stop the program from exiting before the response is received. // wait() on the response to stop the program from exiting before the response is received.
@@ -76,7 +77,7 @@ func main(args: [String]) {
print("Usage: PORT [NAME]") print("Usage: PORT [NAME]")
exit(1) exit(1)
case let (.some(port), name): case (.some(let port), let name):
// Setup an `EventLoopGroup` for the connection to run on. // Setup an `EventLoopGroup` for the connection to run on.
// //
// See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups // See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups

View File

@@ -32,7 +32,8 @@ class Greeter: models_GreeterProvider {
func SayHello( func SayHello(
request: Message<models_HelloRequest>, request: Message<models_HelloRequest>,
context: StatusOnlyCallContext) context: StatusOnlyCallContext
)
-> EventLoopFuture<Message<models_HelloReply>> -> EventLoopFuture<Message<models_HelloReply>>
{ {
let recipient = request.object.name ?? "Stranger" let recipient = request.object.name ?? "Stranger"
@@ -47,12 +48,14 @@ class Greeter: models_GreeterProvider {
func SayManyHellos( func SayManyHellos(
request: Message<models_HelloRequest>, request: Message<models_HelloRequest>,
context: StreamingResponseCallContext<Message<models_HelloReply>>) context: StreamingResponseCallContext<Message<models_HelloReply>>
)
-> EventLoopFuture<GRPCStatus> -> EventLoopFuture<GRPCStatus>
{ {
for name in greetings { for name in greetings {
var builder = FlatBufferBuilder() var builder = FlatBufferBuilder()
let off = builder let off =
builder
.create(string: "\(name) \(request.object.name ?? "Unknown")") .create(string: "\(name) \(request.object.name ?? "Unknown")")
let root = models_HelloReply.createHelloReply( let root = models_HelloReply.createHelloReply(
&builder, &builder,

View File

@@ -1,16 +1,21 @@
import * as grpc from '@grpc/grpc-js'; import * as grpc from '@grpc/grpc-js';
import * as flatbuffers from 'flatbuffers'; import * as flatbuffers from 'flatbuffers';
import {GreeterClient} from './greeter_grpc';
import {HelloReply} from './models/hello-reply'; import {HelloReply} from './models/hello-reply';
import {HelloRequest} from './models/hello-request'; import {HelloRequest} from './models/hello-request';
import { GreeterClient } from './greeter_grpc';
async function main(PORT: Number, name: string) { async function main(PORT: Number, name: string) {
const client = new GreeterClient(`localhost:${PORT}`, grpc.credentials.createInsecure()); const client = new GreeterClient(
`localhost:${PORT}`,
grpc.credentials.createInsecure(),
);
const builder = new flatbuffers.Builder(); const builder = new flatbuffers.Builder();
const offset = builder.createString(name); const offset = builder.createString(name);
const root = HelloRequest.createHelloRequest(builder, offset); const root = HelloRequest.createHelloRequest(builder, offset);
builder.finish(root); builder.finish(root);
const buffer = HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(builder.asUint8Array())); const buffer = HelloRequest.getRootAsHelloRequest(
new flatbuffers.ByteBuffer(builder.asUint8Array()),
);
client.SayHello(buffer, (err, response) => { client.SayHello(buffer, (err, response) => {
console.log(response.message()); console.log(response.message());
@@ -23,12 +28,12 @@ async function main(PORT: Number, name: string) {
}); });
} }
const args = process.argv.slice(2) const args = process.argv.slice(2);
const PORT = Number(args[0]); const PORT = Number(args[0]);
const name: string = args[1] ?? "flatbuffers"; const name: string = args[1] ?? 'flatbuffers';
if (PORT) { if (PORT) {
main(PORT, name); main(PORT, name);
} else { } else {
throw new Error("Requires a valid port number.") throw new Error('Requires a valid port number.');
} }

View File

@@ -1,31 +1,45 @@
import * as grpc from '@grpc/grpc-js'; import * as grpc from '@grpc/grpc-js';
import * as flatbuffers from 'flatbuffers'; import * as flatbuffers from 'flatbuffers';
import {GreeterService, IGreeterServer} from './greeter_grpc';
import {HelloReply} from './models/hello-reply'; import {HelloReply} from './models/hello-reply';
import {HelloRequest} from './models/hello-request'; import {HelloRequest} from './models/hello-request';
import { IGreeterServer, GreeterService } from './greeter_grpc';
const greeter: IGreeterServer = { const greeter: IGreeterServer = {
SayHello(call: grpc.ServerUnaryCall<HelloRequest, HelloReply>, callback: grpc.sendUnaryData<HelloReply>): void { SayHello(
call: grpc.ServerUnaryCall<HelloRequest, HelloReply>,
callback: grpc.sendUnaryData<HelloReply>,
): void {
console.log(`SayHello ${call.request.name()}`); console.log(`SayHello ${call.request.name()}`);
const builder = new flatbuffers.Builder(); const builder = new flatbuffers.Builder();
const offset = builder.createString(`welcome ${call.request.name()}`); const offset = builder.createString(`welcome ${call.request.name()}`);
const root = HelloReply.createHelloReply(builder, offset); const root = HelloReply.createHelloReply(builder, offset);
builder.finish(root); builder.finish(root);
callback(null, HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array()))); callback(
null,
HelloReply.getRootAsHelloReply(
new flatbuffers.ByteBuffer(builder.asUint8Array()),
),
);
}, },
async SayManyHellos(call: grpc.ServerWritableStream<HelloRequest, HelloReply>): Promise<void> { async SayManyHellos(
call: grpc.ServerWritableStream<HelloRequest, HelloReply>,
): Promise<void> {
const name = call.request.name(); const name = call.request.name();
console.log(`${call.request.name()} saying hi in different langagues`); console.log(`${call.request.name()} saying hi in different langagues`);
['Hi', 'Hallo', 'Ciao'].forEach(element => { ['Hi', 'Hallo', 'Ciao'].forEach((element) => {
const builder = new flatbuffers.Builder(); const builder = new flatbuffers.Builder();
const offset = builder.createString(`${element} ${name}`); const offset = builder.createString(`${element} ${name}`);
const root = HelloReply.createHelloReply(builder, offset); const root = HelloReply.createHelloReply(builder, offset);
builder.finish(root); builder.finish(root);
call.write(HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array()))) call.write(
HelloReply.getRootAsHelloReply(
new flatbuffers.ByteBuffer(builder.asUint8Array()),
),
);
}); });
call.end(); call.end();
} },
} };
function serve(): void { function serve(): void {
const PORT = 3000; const PORT = 3000;
@@ -42,7 +56,7 @@ function serve(): void {
console.log(`Server bound on port: ${port}`); console.log(`Server bound on port: ${port}`);
server.start(); server.start();
} }
} },
); );
} }

View File

@@ -19,16 +19,15 @@ import com.google.flatbuffers.Table;
import io.grpc.Drainable; import io.grpc.Drainable;
import io.grpc.KnownLength; import io.grpc.KnownLength;
import io.grpc.MethodDescriptor; import io.grpc.MethodDescriptor;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import javax.annotation.Nullable;
public class FlatbuffersUtils { public class FlatbuffersUtils {
abstract public static class FBExtactor <T extends Table> { public abstract static class FBExtactor<T extends Table> {
T extract(InputStream stream) throws IOException { T extract(InputStream stream) throws IOException {
if (stream instanceof KnownLength) { if (stream instanceof KnownLength) {
int size = stream.available(); int size = stream.available();
@@ -36,11 +35,13 @@ public class FlatbuffersUtils {
stream.read(buffer.array()); stream.read(buffer.array());
return extract(buffer); return extract(buffer);
} else } else
throw new RuntimeException("The class " + stream.getClass().getCanonicalName() + " does not extend from KnownLength "); throw new RuntimeException(
"The class "
+ stream.getClass().getCanonicalName()
+ " does not extend from KnownLength ");
} }
public abstract T extract(ByteBuffer buffer); public abstract T extract(ByteBuffer buffer);
} }
static class FBInputStream extends InputStream implements Drainable, KnownLength { static class FBInputStream extends InputStream implements Drainable, KnownLength {
@@ -81,18 +82,17 @@ public class FlatbuffersUtils {
makeStreamIfNotAlready(); makeStreamIfNotAlready();
return inputStream.read(b, off, len); return inputStream.read(b, off, len);
} }
} else } else return inputStream.read(b, off, len);
return inputStream.read(b, off, len);
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
return inputStream == null ? size : inputStream.available(); return inputStream == null ? size : inputStream.available();
} }
} }
public static <T extends Table> MethodDescriptor.Marshaller<T> marshaller(final Class<T> clazz, final FBExtactor<T> extractor) { public static <T extends Table> MethodDescriptor.Marshaller<T> marshaller(
final Class<T> clazz, final FBExtactor<T> extractor) {
return new MethodDescriptor.ReflectableMarshaller<T>() { return new MethodDescriptor.ReflectableMarshaller<T>() {
@Override @Override
public Class<T> getMessageClass() { public Class<T> getMessageClass() {

View File

@@ -40,7 +40,9 @@ static grpc::string FilenameIdentifier(const grpc::string &filename) {
} }
template <class T, size_t N> template <class T, size_t N>
static T *array_end(T (&array)[N]) { return array + N; } static T* array_end(T (&array)[N]) {
return array + N;
}
static void PrintIncludes(grpc_generator::Printer* printer, static void PrintIncludes(grpc_generator::Printer* printer,
const std::vector<grpc::string>& headers, const std::vector<grpc::string>& headers,
@@ -53,13 +55,26 @@ static void PrintIncludes(grpc_generator::Printer *printer,
auto& s = params.grpc_search_path; auto& s = params.grpc_search_path;
if (!s.empty()) { if (!s.empty()) {
vars["l"] += s; vars["l"] += s;
if (s[s.size() - 1] != '/') { vars["l"] += '/'; } if (s[s.size() - 1] != '/') {
vars["l"] += '/';
}
} }
for (auto i = headers.begin(); i != headers.end(); i++) { for (auto i = headers.begin(); i != headers.end(); i++) {
vars["h"] = *i; vars["h"] = *i;
printer->Print(vars, "#include $l$$h$$r$\n"); printer->Print(vars, "#include $l$$h$$r$\n");
} }
if (params.generate_callback_api) {
// Callback API headers (guarded later by feature macro in emitted code).
static const char* cb_headers[] = {
"grpcpp/impl/codegen/callback_common.h",
"grpcpp/impl/codegen/server_callback_handlers.h",
"grpcpp/support/client_callback.h"};
for (auto& h : cb_headers) {
vars["h"] = h;
printer->Print(vars, "#include $l$$h$$r$\n");
}
}
} }
} // namespace } // namespace
@@ -113,8 +128,7 @@ grpc::string GetHeaderIncludes(grpc_generator::File *file,
"grpcpp/impl/codegen/service_type.h", "grpcpp/impl/codegen/service_type.h",
"grpcpp/impl/codegen/status.h", "grpcpp/impl/codegen/status.h",
"grpcpp/impl/codegen/stub_options.h", "grpcpp/impl/codegen/stub_options.h",
"grpcpp/impl/codegen/sync_stream.h" "grpcpp/impl/codegen/sync_stream.h"};
};
std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
PrintIncludes(printer.get(), headers, params); PrintIncludes(printer.get(), headers, params);
printer->Print(vars, "\n"); printer->Print(vars, "\n");
@@ -138,7 +152,6 @@ grpc::string GetHeaderIncludes(grpc_generator::File *file,
return output; return output;
} }
namespace { namespace {
static void PrintHeaderClientMethodInterfaces( static void PrintHeaderClientMethodInterfaces(
@@ -355,8 +368,6 @@ static void PrintHeaderClientMethodInterfaces(
} }
} }
static void PrintHeaderClientMethod(grpc_generator::Printer* printer, static void PrintHeaderClientMethod(grpc_generator::Printer* printer,
const grpc_generator::Method* method, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars, std::map<grpc::string, grpc::string>* vars,
@@ -377,6 +388,22 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
*vars, *vars,
"::grpc::Status $Method$(::grpc::ClientContext* context, " "::grpc::Status $Method$(::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response) override;\n"); "const $Request$& request, $Response$* response) override;\n");
if ((*vars)["generate_callback_api"] == "1") {
// Native gRPC callback unary wrappers (function callback & reactor
// variants).
printer->Print(*vars,
"// Callback unary (function form). Request/response "
"must outlive callback.\n");
printer->Print(*vars,
"void async_$Method$(::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response, "
"std::function<void(::grpc::Status)> on_done);\n");
printer->Print(*vars, "// Callback unary (reactor form).\n");
printer->Print(*vars,
"void async_$Method$(::grpc::ClientContext* context, "
"const $Request$& request, $Response$* response, "
"::grpc::ClientUnaryReactor* reactor);\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -407,6 +434,13 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
"($Method$Raw(context, response));\n"); "($Method$Raw(context, response));\n");
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(*vars, "// Client streaming callback reactor entry.\n");
printer->Print(
*vars,
"void async_$Method$(::grpc::ClientContext* context, $Response$* "
"response, ::grpc::ClientWriteReactor< $Request$ >* reactor);\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -440,6 +474,13 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
"($Method$Raw(context, request));\n"); "($Method$Raw(context, request));\n");
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(*vars, "// Server streaming callback reactor entry.\n");
printer->Print(*vars,
"void async_$Method$(::grpc::ClientContext* context, "
"const $Request$& request, ::grpc::ClientReadReactor< "
"$Response$ >* reactor);\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -472,6 +513,14 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
"$Method$Raw(context));\n"); "$Method$Raw(context));\n");
printer->Outdent(); printer->Outdent();
printer->Print("}\n"); printer->Print("}\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(*vars,
"// Bidirectional streaming callback reactor entry.\n");
printer->Print(
*vars,
"void async_$Method$(::grpc::ClientContext* context, "
"::grpc::ClientBidiReactor< $Request$, $Response$ >* reactor);\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -506,6 +555,10 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
"const $Request$& request, " "const $Request$& request, "
"::grpc::CompletionQueue* cq) override;\n"); "::grpc::CompletionQueue* cq) override;\n");
} }
if ((*vars)["generate_callback_api"] == "1") {
// Native callback unary forms declared earlier (no private sync helper
// needed).
}
} else if (ClientOnlyStreaming(method)) { } else if (ClientOnlyStreaming(method)) {
printer->Print(*vars, printer->Print(*vars,
"::grpc::ClientWriter< $Request$>* $Method$Raw(" "::grpc::ClientWriter< $Request$>* $Method$Raw("
@@ -560,16 +613,16 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
} }
} }
static void PrintHeaderClientMethodData(grpc_generator::Printer *printer, static void PrintHeaderClientMethodData(
const grpc_generator::Method *method, grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) { std::map<grpc::string, grpc::string>* vars) {
(*vars)["Method"] = method->name(); (*vars)["Method"] = method->name();
printer->Print(*vars, printer->Print(*vars,
"const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n"); "const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n");
} }
static void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, static void PrintHeaderServerMethodSync(
const grpc_generator::Method *method, grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) { std::map<grpc::string, grpc::string>* vars) {
(*vars)["Method"] = method->name(); (*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name(); (*vars)["Request"] = method->input_type_name();
@@ -602,8 +655,8 @@ static void PrintHeaderServerMethodSync(grpc_generator::Printer *printer,
printer->Print(method->GetTrailingComments("//").c_str()); printer->Print(method->GetTrailingComments("//").c_str());
} }
static void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer, static void PrintHeaderServerMethodAsync(
const grpc_generator::Method *method, grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) { std::map<grpc::string, grpc::string>* vars) {
(*vars)["Method"] = method->name(); (*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name(); (*vars)["Request"] = method->input_type_name();
@@ -930,6 +983,10 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
false); false);
} }
printer->Outdent(); printer->Outdent();
// Forward declaration of nested CallbackService if callback API enabled.
if ((*vars)["generate_callback_api"] == "1") {
printer->Print("class CallbackService;\n");
}
printer->Print("};\n"); printer->Print("};\n");
printer->Print( printer->Print(
"class Stub final : public StubInterface" "class Stub final : public StubInterface"
@@ -986,7 +1043,9 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
printer->Print(*vars, "WithAsyncMethod_$method_name$<"); printer->Print(*vars, "WithAsyncMethod_$method_name$<");
} }
printer->Print("Service"); printer->Print("Service");
for (int i = 0; i < service->method_count(); ++i) { printer->Print(" >"); } for (int i = 0; i < service->method_count(); ++i) {
printer->Print(" >");
}
printer->Print(" AsyncService;\n"); printer->Print(" AsyncService;\n");
// Server side - Generic // Server side - Generic
@@ -1011,7 +1070,9 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
} }
printer->Print("Service"); printer->Print("Service");
for (int i = 0; i < service->method_count(); ++i) { for (int i = 0; i < service->method_count(); ++i) {
if (service->method(i)->NoStreaming()) { printer->Print(" >"); } if (service->method(i)->NoStreaming()) {
printer->Print(" >");
}
} }
printer->Print(" StreamedUnaryService;\n"); printer->Print(" StreamedUnaryService;\n");
@@ -1033,7 +1094,9 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
printer->Print("Service"); printer->Print("Service");
for (int i = 0; i < service->method_count(); ++i) { for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i); auto method = service->method(i);
if (ServerOnlyStreaming(method.get())) { printer->Print(" >"); } if (ServerOnlyStreaming(method.get())) {
printer->Print(" >");
}
} }
printer->Print(" SplitStreamedService;\n"); printer->Print(" SplitStreamedService;\n");
@@ -1062,6 +1125,48 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
printer->Outdent(); printer->Outdent();
printer->Print("};\n"); printer->Print("};\n");
printer->Print(service->GetTrailingComments("//").c_str()); printer->Print(service->GetTrailingComments("//").c_str());
// Optional CallbackService (modern async API)
if ((*vars)["generate_callback_api"] == "1") {
(*vars)["Service"] = service->name();
printer->Print("\n#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)\n");
printer->Print(*vars,
"class $Service$::CallbackService : public ::grpc::Service "
"{\n public:\n CallbackService();\n virtual "
"~CallbackService();\n");
printer->Indent();
for (int i = 0; i < service->method_count(); ++i) {
auto m = service->method(i);
(*vars)["Method"] = m->name();
(*vars)["Request"] = m->input_type_name();
(*vars)["Response"] = m->output_type_name();
if (m->NoStreaming()) {
printer->Print(*vars,
"virtual ::grpc::ServerUnaryReactor* "
"$Method$(::grpc::CallbackServerContext* context, const "
"$Request$* request, $Response$* response);\n");
} else if (ClientOnlyStreaming(m.get())) {
printer->Print(*vars,
"virtual ::grpc::ServerReadReactor<$Request$>* "
"$Method$(::grpc::CallbackServerContext* context, "
"$Response$* response);\n");
} else if (ServerOnlyStreaming(m.get())) {
printer->Print(*vars,
"virtual ::grpc::ServerWriteReactor<$Response$>* "
"$Method$(::grpc::CallbackServerContext* context, const "
"$Request$* request);\n");
} else if (m->BidiStreaming()) {
printer->Print(
*vars,
"virtual ::grpc::ServerBidiReactor<$Request$, $Response$>* "
"$Method$(::grpc::CallbackServerContext* context);\n");
}
}
printer->Outdent();
printer->Print(
"};\n#else\n// Callback API requested but not available in this gRPC "
"version.\n#endif // GRPC_CALLBACK_API_NONEXPERIMENTAL\n");
}
} }
} // namespace } // namespace
@@ -1076,7 +1181,9 @@ grpc::string GetHeaderServices(grpc_generator::File *file,
// Package string is empty or ends with a dot. It is used to fully qualify // Package string is empty or ends with a dot. It is used to fully qualify
// method names. // method names.
vars["Package"] = file->package(); vars["Package"] = file->package();
if (!file->package().empty()) { vars["Package"].append("."); } if (!file->package().empty()) {
vars["Package"].append(".");
}
if (!params.services_namespace.empty()) { if (!params.services_namespace.empty()) {
vars["services_namespace"] = params.services_namespace; vars["services_namespace"] = params.services_namespace;
@@ -1084,9 +1191,14 @@ grpc::string GetHeaderServices(grpc_generator::File *file,
} }
for (int i = 0; i < file->service_count(); ++i) { for (int i = 0; i < file->service_count(); ++i) {
vars["generate_callback_api"] = params.generate_callback_api ? "1" : "0";
PrintHeaderService(printer.get(), file->service(i).get(), &vars); PrintHeaderService(printer.get(), file->service(i).get(), &vars);
printer->Print("\n"); printer->Print("\n");
} }
if (params.generate_callback_api) {
printer->Print("// FlatBuffers: Callback API code generated.\n");
printer->Print("#define FLATBUFFERS_GENERATED_GRPC_CALLBACK_API 1\n\n");
}
if (!params.services_namespace.empty()) { if (!params.services_namespace.empty()) {
printer->Print(vars, "} // namespace $services_namespace$\n\n"); printer->Print(vars, "} // namespace $services_namespace$\n\n");
@@ -1139,7 +1251,8 @@ grpc::string GetSourcePrologue(grpc_generator::File *file,
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
printer->Print(vars, printer->Print(vars,
"// If you make any local change, they will be lost.\n"); "// FlatBuffers modified generator: native gRPC callback "
"client API enabled when --grpc-callback-api.\n");
printer->Print(vars, "// source: $filename$\n\n"); printer->Print(vars, "// source: $filename$\n\n");
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
@@ -1165,8 +1278,7 @@ grpc::string GetSourceIncludes(grpc_generator::File *file,
"grpcpp/impl/codegen/method_handler.h", "grpcpp/impl/codegen/method_handler.h",
"grpcpp/impl/codegen/rpc_service_method.h", "grpcpp/impl/codegen/rpc_service_method.h",
"grpcpp/impl/codegen/service_type.h", "grpcpp/impl/codegen/service_type.h",
"grpcpp/impl/codegen/sync_stream.h" "grpcpp/impl/codegen/sync_stream.h"};
};
std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
PrintIncludes(printer.get(), headers, params); PrintIncludes(printer.get(), headers, params);
@@ -1184,11 +1296,10 @@ grpc::string GetSourceIncludes(grpc_generator::File *file,
return output; return output;
} }
namespace { namespace {
static void PrintSourceClientMethod(grpc_generator::Printer *printer, static void PrintSourceClientMethod(
const grpc_generator::Method *method, grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) { std::map<grpc::string, grpc::string>* vars) {
(*vars)["Method"] = method->name(); (*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name(); (*vars)["Request"] = method->input_type_name();
@@ -1209,6 +1320,28 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
" return ::grpc::internal::BlockingUnaryCall" " return ::grpc::internal::BlockingUnaryCall"
"(channel_.get(), rpcmethod_$Method$_, " "(channel_.get(), rpcmethod_$Method$_, "
"context, request, response);\n}\n\n"); "context, request, response);\n}\n\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(
*vars,
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
"context, const $Request$& request, $Response$* response, "
"std::function<void(::grpc::Status)> on_done) {\n");
printer->Print(*vars,
" ::grpc::internal::CallbackUnaryCall(channel_.get(), "
"rpcmethod_$Method$_, context, &request, response, "
"std::move(on_done));\n}\n\n");
printer->Print(
*vars,
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
"context, const $Request$& request, $Response$* response, "
"::grpc::ClientUnaryReactor* reactor) {\n");
printer->Print(
*vars,
" "
"::grpc::internal::ClientCallbackUnaryFactory::Create(channel_.get(),"
" rpcmethod_$Method$_, context, &request, response, "
"reactor);\n}\n\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -1241,6 +1374,17 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
"rpcmethod_$Method$_, " "rpcmethod_$Method$_, "
"context, response);\n" "context, response);\n"
"}\n\n"); "}\n\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(
*vars,
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
"context, $Response$* response, ::grpc::ClientWriteReactor< "
"$Request$ >* reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackWriterFactory< "
"$Request$ >::Create(channel_.get(), rpcmethod_$Method$_, "
"context, response, reactor);\n}\n\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -1274,6 +1418,18 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
"rpcmethod_$Method$_, " "rpcmethod_$Method$_, "
"context, request);\n" "context, request);\n"
"}\n\n"); "}\n\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(
*vars,
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
"context, const $Request$& request, ::grpc::ClientReadReactor< "
"$Response$ >* reactor) {\n");
printer->Print(
*vars,
" ::grpc::internal::ClientCallbackReaderFactory< "
"$Response$ >::Create(channel_.get(), "
"rpcmethod_$Method$_, context, &request, reactor);\n}\n\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -1307,6 +1463,17 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
"rpcmethod_$Method$_, " "rpcmethod_$Method$_, "
"context);\n" "context);\n"
"}\n\n"); "}\n\n");
if ((*vars)["generate_callback_api"] == "1") {
printer->Print(
*vars,
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
"context, ::grpc::ClientBidiReactor< $Request$, $Response$ >* "
"reactor) {\n");
printer->Print(*vars,
" ::grpc::internal::ClientCallbackReaderWriterFactory< "
"$Request$, $Response$ >::Create(channel_.get(), "
"rpcmethod_$Method$_, context, reactor);\n}\n\n");
}
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
i++) { i++) {
auto& async_prefix = async_prefixes[i]; auto& async_prefix = async_prefixes[i];
@@ -1331,8 +1498,8 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
} }
} }
static void PrintSourceServerMethod(grpc_generator::Printer *printer, static void PrintSourceServerMethod(
const grpc_generator::Method *method, grpc_generator::Printer* printer, const grpc_generator::Method* method,
std::map<grpc::string, grpc::string>* vars) { std::map<grpc::string, grpc::string>* vars) {
(*vars)["Method"] = method->name(); (*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name(); (*vars)["Request"] = method->input_type_name();
@@ -1495,6 +1662,114 @@ static void PrintSourceService(grpc_generator::Printer *printer,
(*vars)["Idx"] = as_string(i); (*vars)["Idx"] = as_string(i);
PrintSourceServerMethod(printer, service->method(i).get(), vars); PrintSourceServerMethod(printer, service->method(i).get(), vars);
} }
// CallbackService implementation (if enabled)
if ((*vars)["generate_callback_api"] == "1") {
(*vars)["Service"] = service->name();
printer->Print("#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)\n");
printer->Print(*vars,
"$ns$$Service$::CallbackService::CallbackService() {\n");
printer->Indent();
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
(*vars)["Idx"] = as_string(i);
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
if (method->NoStreaming()) {
printer->Print(
*vars,
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
" $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::internal::RpcMethod::NORMAL_RPC,\n"
" new ::grpc::internal::CallbackUnaryHandler<$Request$, "
"$Response$>(\n"
" [this](::grpc::CallbackServerContext* ctx, const $Request$* "
"req, $Response$* resp) {\n"
" return this->$Method$(ctx, req, resp);\n"
" })));\n");
} else if (ClientOnlyStreaming(method.get())) {
printer->Print(*vars,
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
" $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n"
" new "
"::grpc::internal::CallbackClientStreamingHandler<$"
"Request$, $Response$>(\n"
" [this](::grpc::CallbackServerContext* ctx, "
"$Response$* resp) {\n"
" return this->$Method$(ctx, resp);\n"
" })));\n");
} else if (ServerOnlyStreaming(method.get())) {
printer->Print(*vars,
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
" $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::internal::RpcMethod::SERVER_STREAMING,\n"
" new "
"::grpc::internal::CallbackServerStreamingHandler<$"
"Request$, $Response$>(\n"
" [this](::grpc::CallbackServerContext* ctx, const "
"$Request$* req) {\n"
" return this->$Method$(ctx, req);\n"
" })));\n");
} else if (method->BidiStreaming()) {
printer->Print(
*vars,
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
" $prefix$$Service$_method_names[$Idx$],\n"
" ::grpc::internal::RpcMethod::BIDI_STREAMING,\n"
" new ::grpc::internal::CallbackBidiHandler<$Request$, "
"$Response$>(\n"
" [this](::grpc::CallbackServerContext* ctx) {\n"
" return this->$Method$(ctx);\n"
" })));\n");
}
}
printer->Outdent();
printer->Print("}\n\n");
printer->Print(*vars,
"$ns$$Service$::CallbackService::~CallbackService() {}\n\n");
// Default method bodies returning UNIMPLEMENTED reactors.
for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i);
(*vars)["Method"] = method->name();
(*vars)["Request"] = method->input_type_name();
(*vars)["Response"] = method->output_type_name();
if (method->NoStreaming()) {
printer->Print(*vars,
"::grpc::ServerUnaryReactor* "
"$ns$$Service$::CallbackService::$Method$(::grpc::"
"CallbackServerContext* /*context*/, const $Request$* "
"/*request*/, $Response$* /*response*/) {\n"
" return nullptr; // user must override\n"
"}\n\n");
} else if (ClientOnlyStreaming(method.get())) {
printer->Print(
*vars,
"::grpc::ServerReadReactor<$Request$>* "
"$ns$$Service$::CallbackService::$Method$(::grpc::"
"CallbackServerContext* /*context*/, $Response$* /*response*/) {\n"
" return nullptr; // user must override\n"
"}\n\n");
} else if (ServerOnlyStreaming(method.get())) {
printer->Print(*vars,
"::grpc::ServerWriteReactor<$Response$>* "
"$ns$$Service$::CallbackService::$Method$(::grpc::"
"CallbackServerContext* /*context*/, const $Request$* "
"/*request*/) {\n"
" return nullptr; // user must override\n"
"}\n\n");
} else if (method->BidiStreaming()) {
printer->Print(*vars,
"::grpc::ServerBidiReactor<$Request$, $Response$>* "
"$ns$$Service$::CallbackService::$Method$(::grpc::"
"CallbackServerContext* /*context*/) {\n"
" return nullptr; // user must override\n"
"}\n\n");
}
}
printer->Print("#endif // GRPC_CALLBACK_API_NONEXPERIMENTAL\n");
}
} }
} // namespace } // namespace
@@ -1509,7 +1784,9 @@ grpc::string GetSourceServices(grpc_generator::File *file,
// Package string is empty or ends with a dot. It is used to fully qualify // Package string is empty or ends with a dot. It is used to fully qualify
// method names. // method names.
vars["Package"] = file->package(); vars["Package"] = file->package();
if (!file->package().empty()) { vars["Package"].append("."); } if (!file->package().empty()) {
vars["Package"].append(".");
}
if (!params.services_namespace.empty()) { if (!params.services_namespace.empty()) {
vars["ns"] = params.services_namespace + "::"; vars["ns"] = params.services_namespace + "::";
vars["prefix"] = params.services_namespace; vars["prefix"] = params.services_namespace;
@@ -1519,6 +1796,7 @@ grpc::string GetSourceServices(grpc_generator::File *file,
} }
for (int i = 0; i < file->service_count(); ++i) { for (int i = 0; i < file->service_count(); ++i) {
vars["generate_callback_api"] = params.generate_callback_api ? "1" : "0";
PrintSourceService(printer.get(), file->service(i).get(), &vars); PrintSourceService(printer.get(), file->service(i).get(), &vars);
printer->Print("\n"); printer->Print("\n");
} }
@@ -1601,7 +1879,6 @@ grpc::string GetMockIncludes(grpc_generator::File *file,
return output; return output;
} }
namespace { namespace {
static void PrintMockClientMethods(grpc_generator::Printer* printer, static void PrintMockClientMethods(grpc_generator::Printer* printer,
@@ -1615,8 +1892,7 @@ static void PrintMockClientMethods(grpc_generator::Printer *printer,
grpc::string prefix; grpc::string prefix;
grpc::string method_params; // extra arguments to method grpc::string method_params; // extra arguments to method
int extra_method_param_count; int extra_method_param_count;
} async_prefixes[] = { { "Async", ", void* tag", 1 }, } async_prefixes[] = {{"Async", ", void* tag", 1}, {"PrepareAsync", "", 0}};
{ "PrepareAsync", "", 0 } };
if (method->NoStreaming()) { if (method->NoStreaming()) {
printer->Print( printer->Print(
@@ -1724,7 +2000,9 @@ grpc::string GetMockServices(grpc_generator::File *file,
// Package string is empty or ends with a dot. It is used to fully qualify // Package string is empty or ends with a dot. It is used to fully qualify
// method names. // method names.
vars["Package"] = file->package(); vars["Package"] = file->package();
if (!file->package().empty()) { vars["Package"].append("."); } if (!file->package().empty()) {
vars["Package"].append(".");
}
if (!params.services_namespace.empty()) { if (!params.services_namespace.empty()) {
vars["services_namespace"] = params.services_namespace; vars["services_namespace"] = params.services_namespace;

View File

@@ -37,6 +37,8 @@ struct Parameters {
std::string message_header_extension; std::string message_header_extension;
// Default: ".grpc.fb.h" // Default: ".grpc.fb.h"
std::string service_header_extension; std::string service_header_extension;
// Generate modern callback-based async API service code (CallbackService)
bool generate_callback_api = false;
}; };
// Return the prologue of the generated header file. // Return the prologue of the generated header file.

View File

@@ -4,7 +4,8 @@
#include <map> #include <map>
#include <sstream> #include <sstream>
template<class T> grpc::string as_string(T x) { template <class T>
grpc::string as_string(T x) {
std::ostringstream out; std::ostringstream out;
out << x; out << x;
return out.str(); return out.str();
@@ -67,8 +68,8 @@ static void GenerateImports(grpc_generator::File *file,
} }
// Generates Server method signature source // Generates Server method signature source
static void GenerateServerMethodSignature(const grpc_generator::Method *method, static void GenerateServerMethodSignature(
grpc_generator::Printer *printer, const grpc_generator::Method* method, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string> vars) { std::map<grpc::string, grpc::string> vars) {
vars["Method"] = exportName(method->name()); vars["Method"] = exportName(method->name());
vars["Request"] = method->get_input_type_name(); vars["Request"] = method->get_input_type_name();
@@ -160,8 +161,12 @@ static void GenerateServerMethod(const grpc_generator::Method *method,
printer->Print(vars, "type $Service$_$Method$Server interface {\n"); printer->Print(vars, "type $Service$_$Method$Server interface {\n");
printer->Indent(); printer->Indent();
if (genSend) { printer->Print(vars, "Send(*$Response$) error\n"); } if (genSend) {
if (genRecv) { printer->Print(vars, "Recv() (*$Request$, error)\n"); } printer->Print(vars, "Send(*$Response$) error\n");
}
if (genRecv) {
printer->Print(vars, "Recv() (*$Request$, error)\n");
}
if (genSendAndClose) { if (genSendAndClose) {
printer->Print(vars, "SendAndClose(*$Response$) error\n"); printer->Print(vars, "SendAndClose(*$Response$) error\n");
} }
@@ -205,8 +210,8 @@ static void GenerateServerMethod(const grpc_generator::Method *method,
} }
// Generates Client method signature source // Generates Client method signature source
static void GenerateClientMethodSignature(const grpc_generator::Method *method, static void GenerateClientMethodSignature(
grpc_generator::Printer *printer, const grpc_generator::Method* method, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string> vars) { std::map<grpc::string, grpc::string> vars) {
vars["Method"] = exportName(method->name()); vars["Method"] = exportName(method->name());
vars["Request"] = vars["Request"] =
@@ -277,8 +282,12 @@ static void GenerateClientMethod(const grpc_generator::Method *method,
// Stream interface // Stream interface
printer->Print(vars, "type $Service$_$Method$Client interface {\n"); printer->Print(vars, "type $Service$_$Method$Client interface {\n");
printer->Indent(); printer->Indent();
if (genSend) { printer->Print(vars, "Send(*$Request$) error\n"); } if (genSend) {
if (genRecv) { printer->Print(vars, "Recv() (*$Response$, error)\n"); } printer->Print(vars, "Send(*$Request$) error\n");
}
if (genRecv) {
printer->Print(vars, "Recv() (*$Response$, error)\n");
}
if (genCloseAndRecv) { if (genCloseAndRecv) {
printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n"); printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n");
} }

View File

@@ -136,8 +136,7 @@ static void GrpcSplitStringToIteratorUsing(const string &full,
++p; ++p;
} else { } else {
const char* start = p; const char* start = p;
while (++p != end && *p != c) while (++p != end && *p != c);
;
*result++ = string(start, p - start); *result++ = string(start, p - start);
} }
} }
@@ -218,7 +217,9 @@ static string GrpcEscapeJavadoc(const string &input) {
// Java interprets Unicode escape sequences anywhere! // Java interprets Unicode escape sequences anywhere!
result.append("&#92;"); result.append("&#92;");
break; break;
default: result.push_back(c); break; default:
result.push_back(c);
break;
} }
prev = c; prev = c;
@@ -238,7 +239,9 @@ static std::vector<string> GrpcGetDocLines(const string &comments) {
string escapedComments = GrpcEscapeJavadoc(comments); string escapedComments = GrpcEscapeJavadoc(comments);
std::vector<string> lines = GrpcSplit(escapedComments, "\n"); std::vector<string> lines = GrpcSplit(escapedComments, "\n");
while (!lines.empty() && lines.back().empty()) { lines.pop_back(); } while (!lines.empty() && lines.back().empty()) {
lines.pop_back();
}
return lines; return lines;
} }
return std::vector<string>(); return std::vector<string>();
@@ -254,7 +257,9 @@ static void GrpcWriteDocCommentBody(Printer *printer, VARS &vars,
const std::vector<string>& lines, const std::vector<string>& lines,
bool surroundWithPreTag) { bool surroundWithPreTag) {
if (!lines.empty()) { if (!lines.empty()) {
if (surroundWithPreTag) { printer->Print(" * <pre>\n"); } if (surroundWithPreTag) {
printer->Print(" * <pre>\n");
}
for (size_t i = 0; i < lines.size(); i++) { for (size_t i = 0; i < lines.size(); i++) {
// Most lines should start with a space. Watch out for lines that start // Most lines should start with a space. Watch out for lines that start
@@ -268,7 +273,9 @@ static void GrpcWriteDocCommentBody(Printer *printer, VARS &vars,
} }
} }
if (surroundWithPreTag) { printer->Print(" * </pre>\n"); } if (surroundWithPreTag) {
printer->Print(" * </pre>\n");
}
} }
} }
@@ -493,7 +500,9 @@ static void PrintStub(Printer *p, VARS &vars, const ServiceDescriptor *service,
vars["client_name"] = client_name; vars["client_name"] = client_name;
// Class head // Class head
if (!interface) { GrpcWriteServiceDocComment(p, vars, service); } if (!interface) {
GrpcWriteServiceDocComment(p, vars, service);
}
if (impl_base) { if (impl_base) {
p->Print(vars, p->Print(vars,
"public static abstract class $abstract_name$ implements " "public static abstract class $abstract_name$ implements "
@@ -555,7 +564,9 @@ static void PrintStub(Printer *p, VARS &vars, const ServiceDescriptor *service,
p->Print("\n"); p->Print("\n");
// TODO(nmittler): Replace with WriteMethodDocComment once included by the // TODO(nmittler): Replace with WriteMethodDocComment once included by the
// protobuf distro. // protobuf distro.
if (!interface) { GrpcWriteMethodDocComment(p, vars, &*method); } if (!interface) {
GrpcWriteMethodDocComment(p, vars, &*method);
}
p->Print("public "); p->Print("public ");
switch (call_type) { switch (call_type) {
case BLOCKING_CALL: case BLOCKING_CALL:
@@ -620,7 +631,8 @@ static void PrintStub(Printer *p, VARS &vars, const ServiceDescriptor *service,
"responseObserver);\n"); "responseObserver);\n");
} }
break; break;
default: break; default:
break;
} }
} else if (!interface) { } else if (!interface) {
switch (call_type) { switch (call_type) {
@@ -746,7 +758,9 @@ static void PrintMethodHandlerClass(Printer *p, VARS &vars,
for (int i = 0; i < service->method_count(); ++i) { for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i); auto method = service->method(i);
if (method->ClientStreaming() || method->BidiStreaming()) { continue; } if (method->ClientStreaming() || method->BidiStreaming()) {
continue;
}
vars["method_id_name"] = MethodIdFieldName(&*method); vars["method_id_name"] = MethodIdFieldName(&*method);
vars["lower_method_name"] = LowerMethodName(&*method); vars["lower_method_name"] = LowerMethodName(&*method);
vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); vars["input_type"] = JavaClassName(vars, method->get_input_type_name());
@@ -778,7 +792,9 @@ static void PrintMethodHandlerClass(Printer *p, VARS &vars,
for (int i = 0; i < service->method_count(); ++i) { for (int i = 0; i < service->method_count(); ++i) {
auto method = service->method(i); auto method = service->method(i);
if (!(method->ClientStreaming() || method->BidiStreaming())) { continue; } if (!(method->ClientStreaming() || method->BidiStreaming())) {
continue;
}
vars["method_id_name"] = MethodIdFieldName(&*method); vars["method_id_name"] = MethodIdFieldName(&*method);
vars["lower_method_name"] = LowerMethodName(&*method); vars["lower_method_name"] = LowerMethodName(&*method);
vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); vars["input_type"] = JavaClassName(vars, method->get_input_type_name());

View File

@@ -18,6 +18,7 @@
#define NET_GRPC_COMPILER_JAVA_GENERATOR_H_ #define NET_GRPC_COMPILER_JAVA_GENERATOR_H_
#include <stdlib.h> // for abort() #include <stdlib.h> // for abort()
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <string> #include <string>
@@ -39,8 +40,8 @@ class LogHelper {
LogHelper(std::ostream* os) : os_(os) {} LogHelper(std::ostream* os) : os_(os) {}
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(push) #pragma warning(push)
#pragma warning( \ #pragma warning(disable \
disable : 4722) // the flow of control terminates in a destructor : 4722) // the flow of control terminates in a destructor
// (needed to compile ~LogHelper where destructor emits abort intentionally - // (needed to compile ~LogHelper where destructor emits abort intentionally -
// inherited from grpc/java code generator). // inherited from grpc/java code generator).
#endif #endif

View File

@@ -37,12 +37,14 @@ namespace grpc {
namespace { namespace {
bool ClientStreaming(const RPCCall* method) { bool ClientStreaming(const RPCCall* method) {
const Value* val = method->attributes.Lookup("streaming"); const Value* val = method->attributes.Lookup("streaming");
return val != nullptr && (val->constant == "client" || val->constant == "bidi"); return val != nullptr &&
(val->constant == "client" || val->constant == "bidi");
} }
bool ServerStreaming(const RPCCall* method) { bool ServerStreaming(const RPCCall* method) {
const Value* val = method->attributes.Lookup("streaming"); const Value* val = method->attributes.Lookup("streaming");
return val != nullptr && (val->constant == "server" || val->constant == "bidi"); return val != nullptr &&
(val->constant == "server" || val->constant == "bidi");
} }
void FormatImports(std::stringstream& ss, const Imports& imports) { void FormatImports(std::stringstream& ss, const Imports& imports) {
@@ -105,7 +107,8 @@ class BaseGenerator {
const std::string& path, const Version& version) const std::string& path, const Version& version)
: parser_{parser}, : parser_{parser},
namer_{WithFlagOptions(config, parser.opts, path), Keywords(version)}, namer_{WithFlagOptions(config, parser.opts, path), Keywords(version)},
version_{version} {} version_{version},
path_(path) {}
protected: protected:
std::string ModuleForFile(const std::string& file) const { std::string ModuleForFile(const std::string& file) const {
@@ -121,9 +124,29 @@ class BaseGenerator {
return namer_.NamespacedType(*def); return namer_.NamespacedType(*def);
} }
std::string NamespaceDir(const Parser& parser, const std::string& path,
const Namespace& ns, const bool dasherize) {
EnsureDirExists(path);
if (parser.opts.one_file) return path;
std::string namespace_dir = path; // Either empty or ends in separator.
auto& namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
namespace_dir +=
!dasherize ? *it : ConvertCase(*it, Case::kDasher, Case::kUpperCamel);
namespace_dir += kPathSeparator;
EnsureDirExists(namespace_dir);
}
return namespace_dir;
}
std::string NamespaceDir(const Namespace& ns, const bool dasherize) {
return NamespaceDir(parser_, path_, ns, dasherize);
}
const Parser& parser_; const Parser& parser_;
const IdlNamer namer_; const IdlNamer namer_;
const Version version_; const Version version_;
const std::string& path_;
}; };
class StubGenerator : public BaseGenerator { class StubGenerator : public BaseGenerator {
@@ -135,14 +158,18 @@ class StubGenerator : public BaseGenerator {
bool Generate() { bool Generate() {
Imports imports; Imports imports;
std::stringstream stub; std::stringstream stub;
std::string ns_name{};
for (const ServiceDef* service : parser_.services_.vec) { for (const ServiceDef* service : parser_.services_.vec) {
Generate(stub, service, &imports); Generate(stub, service, &imports);
ns_name = NamespaceDir(*service->defined_namespace, false);
} }
std::string sanitized_suffix{parser_.opts.grpc_filename_suffix};
std::replace(sanitized_suffix.begin(), sanitized_suffix.end(), '.', '_');
std::string filename = std::string filename =
namer_.config_.output_path + ns_name + kPathSeparator +
StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" + StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" +
parser_.opts.grpc_filename_suffix + namer_.config_.filename_extension; sanitized_suffix + namer_.config_.filename_extension;
return SaveStub(filename, imports, stub.str()); return SaveStub(filename, imports, stub.str());
} }
@@ -247,16 +274,20 @@ class ServiceGenerator : public BaseGenerator {
<< '\n'; << '\n';
} }
std::string ns_name{};
for (const ServiceDef* service : parser_.services_.vec) { for (const ServiceDef* service : parser_.services_.vec) {
GenerateStub(ss, service, &imports); GenerateStub(ss, service, &imports);
GenerateServicer(ss, service, &imports); GenerateServicer(ss, service, &imports);
GenerateRegister(ss, service, &imports); GenerateRegister(ss, service, &imports);
ns_name = NamespaceDir(*service->defined_namespace, false);
} }
std::string sanitized_suffix{parser_.opts.grpc_filename_suffix};
std::replace(sanitized_suffix.begin(), sanitized_suffix.end(), '.', '_');
std::string filename = std::string filename =
namer_.config_.output_path + ns_name + kPathSeparator +
StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" + StripPath(StripExtension(parser_.file_being_parsed_)) + "_grpc" +
parser_.opts.grpc_filename_suffix + namer_.config_.filename_extension; sanitized_suffix + namer_.config_.filename_extension;
return SaveService(filename, imports, ss.str()); return SaveService(filename, imports, ss.str());
} }

View File

@@ -20,12 +20,13 @@
* please open an issue in the flatbuffers repository. This file should always * please open an issue in the flatbuffers repository. This file should always
* be maintained according to the Swift-grpc repository * be maintained according to the Swift-grpc repository
*/ */
#include "src/compiler/swift_generator.h"
#include <map> #include <map>
#include <sstream> #include <sstream>
#include "flatbuffers/util.h" #include "flatbuffers/util.h"
#include "src/compiler/schema_interface.h" #include "src/compiler/schema_interface.h"
#include "src/compiler/swift_generator.h"
namespace grpc_swift_generator { namespace grpc_swift_generator {
namespace { namespace {
@@ -45,8 +46,8 @@ static grpc::string GenerateMessage(const std::vector<std::string> &components,
// MARK: - Client // MARK: - Client
static void GenerateClientFuncName(const grpc_generator::Method *method, static void GenerateClientFuncName(
grpc_generator::Printer *printer, const grpc_generator::Method* method, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* dictonary) { std::map<grpc::string, grpc::string>* dictonary) {
auto vars = *dictonary; auto vars = *dictonary;
if (method->NoStreaming()) { if (method->NoStreaming()) {
@@ -83,8 +84,8 @@ static void GenerateClientFuncName(const grpc_generator::Method *method,
" ) -> BidirectionalStreamingCall<$Input$, $Output$>"); " ) -> BidirectionalStreamingCall<$Input$, $Output$>");
} }
static void GenerateClientFuncBody(const grpc_generator::Method *method, static void GenerateClientFuncBody(
grpc_generator::Printer *printer, const grpc_generator::Method* method, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* dictonary) { std::map<grpc::string, grpc::string>* dictonary) {
auto vars = *dictonary; auto vars = *dictonary;
vars["Interceptor"] = vars["Interceptor"] =
@@ -380,7 +381,9 @@ grpc::string Generate(grpc_generator::File *file,
grpc::string output; grpc::string output;
std::map<grpc::string, grpc::string> vars; std::map<grpc::string, grpc::string> vars;
vars["PATH"] = file->package(); vars["PATH"] = file->package();
if (!file->package().empty()) { vars["PATH"].append("."); } if (!file->package().empty()) {
vars["PATH"].append(".");
}
vars["ServiceQualifiedName"] = vars["ServiceQualifiedName"] =
WrapInNameSpace(service->namespace_parts(), service->name()); WrapInNameSpace(service->namespace_parts(), service->name());
vars["ServiceName"] = service->name(); vars["ServiceName"] = service->name();
@@ -394,6 +397,8 @@ grpc::string Generate(grpc_generator::File *file,
GenerateClientClass(&*printer, &vars); GenerateClientClass(&*printer, &vars);
printer->Print("\n"); printer->Print("\n");
GenerateServerProtocol(service, &*printer, &vars); GenerateServerProtocol(service, &*printer, &vars);
printer->Print("\n");
printer->Print("#endif\n");
return output; return output;
} }
@@ -409,6 +414,7 @@ grpc::string GenerateHeader() {
code += "// swiftlint:disable all\n"; code += "// swiftlint:disable all\n";
code += "// swiftformat:disable all\n"; code += "// swiftformat:disable all\n";
code += "\n"; code += "\n";
code += "#if !os(Windows)\n";
code += "import Foundation\n"; code += "import Foundation\n";
code += "import GRPC\n"; code += "import GRPC\n";
code += "import NIO\n"; code += "import NIO\n";
@@ -428,10 +434,7 @@ grpc::string GenerateHeader() {
code += " }\n"; code += " }\n";
code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n"; code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n";
code += code += " withUnsafeReadableBytes { buffer.writeBytes($0) }\n";
" let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: "
"Int(self.size))\n";
code += " buffer.writeBytes(buf)\n";
code += " }\n"; code += " }\n";
code += "}\n"; code += "}\n";
code += "extension Message: GRPCFlatBufPayload {}\n"; code += "extension Message: GRPCFlatBufPayload {}\n";

View File

@@ -117,7 +117,8 @@ static void GetStreamType(grpc_generator::Printer *printer,
printer->Print(vars, "responseStream: $ServerStreaming$,\n"); printer->Print(vars, "responseStream: $ServerStreaming$,\n");
} }
static void GenerateSerializeMethod(grpc_generator::Printer *printer, static void GenerateSerializeMethod(
grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* dictonary) { std::map<grpc::string, grpc::string>* dictonary) {
auto vars = *dictonary; auto vars = *dictonary;
printer->Print(vars, "function serialize_$Type$(buffer_args) {\n"); printer->Print(vars, "function serialize_$Type$(buffer_args) {\n");
@@ -223,7 +224,9 @@ grpc::string Generate(grpc_generator::File *file,
vars["PATH"] = file->package(); vars["PATH"] = file->package();
if (!file->package().empty()) { vars["PATH"].append("."); } if (!file->package().empty()) {
vars["PATH"].append(".");
}
vars["ServiceName"] = service->name(); vars["ServiceName"] = service->name();
vars["FBSFile"] = service->name() + "_fbs"; vars["FBSFile"] = service->name() + "_fbs";
@@ -258,8 +261,8 @@ static void FillInterface(grpc_generator::Printer *printer,
printer->Print("}\n"); printer->Print("}\n");
} }
static void GenerateInterfaces(const grpc_generator::Service *service, static void GenerateInterfaces(
grpc_generator::Printer *printer, const grpc_generator::Service* service, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* dictonary) { std::map<grpc::string, grpc::string>* dictonary) {
auto vars = *dictonary; auto vars = *dictonary;
for (auto it = 0; it < service->method_count(); it++) { for (auto it = 0; it < service->method_count(); it++) {
@@ -324,8 +327,8 @@ static void GenerateExportedInterface(
printer->Print("}\n"); printer->Print("}\n");
} }
static void GenerateMainInterface(const grpc_generator::Service *service, static void GenerateMainInterface(
grpc_generator::Printer *printer, const grpc_generator::Service* service, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* dictonary) { std::map<grpc::string, grpc::string>* dictonary) {
auto vars = *dictonary; auto vars = *dictonary;
printer->Print( printer->Print(
@@ -351,7 +354,9 @@ static void GenerateMainInterface(const grpc_generator::Service *service,
static grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; } static grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; }
static grpc::string GenerateOptions() { return "options: Partial<grpc.CallOptions>"; } static grpc::string GenerateOptions() {
return "options: Partial<grpc.CallOptions>";
}
static void GenerateUnaryClientInterface( static void GenerateUnaryClientInterface(
grpc_generator::Printer* printer, grpc_generator::Printer* printer,
@@ -413,8 +418,8 @@ static void GenerateDepluxStreamInterface(
.c_str()); .c_str());
} }
static void GenerateClientInterface(const grpc_generator::Service *service, static void GenerateClientInterface(
grpc_generator::Printer *printer, const grpc_generator::Service* service, grpc_generator::Printer* printer,
std::map<grpc::string, grpc::string>* dictonary) { std::map<grpc::string, grpc::string>* dictonary) {
auto vars = *dictonary; auto vars = *dictonary;
printer->Print(vars, "export interface I$ServiceName$Client {\n"); printer->Print(vars, "export interface I$ServiceName$Client {\n");
@@ -494,7 +499,6 @@ static void GenerateClientClassInterface(
} }
} // namespace } // namespace
grpc::string GenerateInterface(grpc_generator::File* file, grpc::string GenerateInterface(grpc_generator::File* file,
const grpc_generator::Service* service, const grpc_generator::Service* service,
const grpc::string& filename) { const grpc::string& filename) {
@@ -505,7 +509,9 @@ grpc::string GenerateInterface(grpc_generator::File *file,
vars["PATH"] = file->package(); vars["PATH"] = file->package();
if (!file->package().empty()) { vars["PATH"].append("."); } if (!file->package().empty()) {
vars["PATH"].append(".");
}
vars["ServiceName"] = service->name(); vars["ServiceName"] = service->name();
vars["FBSFile"] = service->name() + "_fbs"; vars["FBSFile"] = service->name() + "_fbs";

View File

@@ -17,3 +17,27 @@ cc_test(
"@com_github_grpc_grpc//:grpc++", "@com_github_grpc_grpc//:grpc++",
], ],
) )
cc_test(
name = "grpc_callback_compile_test",
srcs = ["grpctest_callback_compile.cpp"],
copts = ["-Itests"],
linkstatic = 1,
deps = [
"//tests:monster_test_cc_fbs",
"//tests:monster_test_grpc",
"@com_github_grpc_grpc//:grpc++",
],
)
cc_test(
name = "grpc_callback_client_compile_test",
srcs = ["grpctest_callback_client_compile.cpp"],
copts = ["-Itests"],
linkstatic = 1,
deps = [
"//tests:monster_test_cc_fbs",
"//tests:monster_test_grpc",
"@com_github_grpc_grpc//:grpc++",
],
)

View File

@@ -1,10 +1,11 @@
import java.nio.ByteBuffer;
import MyGame.Example.Monster; import MyGame.Example.Monster;
import MyGame.Example.Stat; import MyGame.Example.Stat;
import com.google.flatbuffers.FlatBufferBuilder; import com.google.flatbuffers.FlatBufferBuilder;
import java.nio.ByteBuffer;
class GameFactory { class GameFactory {
public static Monster createMonster(String monsterName, short nestedMonsterHp, short nestedMonsterMana) { public static Monster createMonster(
String monsterName, short nestedMonsterHp, short nestedMonsterMana) {
FlatBufferBuilder builder = new FlatBufferBuilder(); FlatBufferBuilder builder = new FlatBufferBuilder();
int name_offset = builder.createString(monsterName); int name_offset = builder.createString(monsterName);
@@ -38,5 +39,4 @@ class GameFactory {
Stat stat = Stat.getRootAsStat(builder.dataBuffer()); Stat stat = Stat.getRootAsStat(builder.dataBuffer());
return stat; return stat;
} }
} }

View File

@@ -17,27 +17,20 @@
import MyGame.Example.Monster; import MyGame.Example.Monster;
import MyGame.Example.MonsterStorageGrpc; import MyGame.Example.MonsterStorageGrpc;
import MyGame.Example.Stat; import MyGame.Example.Stat;
import com.google.flatbuffers.FlatBufferBuilder;
import io.grpc.ManagedChannel; import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder; import io.grpc.ManagedChannelBuilder;
import io.grpc.Server; import io.grpc.Server;
import io.grpc.ServerBuilder; import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Assert; import org.junit.Assert;
import java.io.IOException; /** Demonstrates basic client-server interaction using grpc-java over netty. */
import java.lang.InterruptedException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CountDownLatch;
/**
* Demonstrates basic client-server interaction using grpc-java over netty.
*/
public class JavaGrpcTest { public class JavaGrpcTest {
static final String BIG_MONSTER_NAME = "Cyberdemon"; static final String BIG_MONSTER_NAME = "Cyberdemon";
static final short nestedMonsterHp = 600; static final short nestedMonsterHp = 600;
@@ -82,7 +75,8 @@ public class JavaGrpcTest {
return computeMinMax(responseObserver, true); return computeMinMax(responseObserver, true);
} }
private StreamObserver<Monster> computeMinMax(final StreamObserver<Stat> responseObserver, final boolean includeMin) { private StreamObserver<Monster> computeMinMax(
final StreamObserver<Stat> responseObserver, final boolean includeMin) {
final AtomicInteger maxHp = new AtomicInteger(Integer.MIN_VALUE); final AtomicInteger maxHp = new AtomicInteger(Integer.MIN_VALUE);
final AtomicReference<String> maxHpMonsterName = new AtomicReference<String>(); final AtomicReference<String> maxHpMonsterName = new AtomicReference<String>();
final AtomicInteger maxHpCount = new AtomicInteger(); final AtomicInteger maxHpCount = new AtomicInteger();
@@ -98,8 +92,7 @@ public class JavaGrpcTest {
maxHp.set(monster.hp()); maxHp.set(monster.hp());
maxHpMonsterName.set(monster.name()); maxHpMonsterName.set(monster.name());
maxHpCount.set(1); maxHpCount.set(1);
} } else if (monster.hp() == maxHp.get()) {
else if (monster.hp() == maxHp.get()) {
// Count how many times we saw a monster of current max hit points. // Count how many times we saw a monster of current max hit points.
maxHpCount.getAndIncrement(); maxHpCount.getAndIncrement();
} }
@@ -109,27 +102,31 @@ public class JavaGrpcTest {
minHp.set(monster.hp()); minHp.set(monster.hp());
minHpMonsterName.set(monster.name()); minHpMonsterName.set(monster.name());
minHpCount.set(1); minHpCount.set(1);
} } else if (monster.hp() == minHp.get()) {
else if (monster.hp() == minHp.get()) {
// Count how many times we saw a monster of current min hit points. // Count how many times we saw a monster of current min hit points.
minHpCount.getAndIncrement(); minHpCount.getAndIncrement();
} }
} }
public void onCompleted() { public void onCompleted() {
Stat maxHpStat = GameFactory.createStat(maxHpMonsterName.get(), maxHp.get(), maxHpCount.get()); Stat maxHpStat =
GameFactory.createStat(maxHpMonsterName.get(), maxHp.get(), maxHpCount.get());
// Send max hit points first. // Send max hit points first.
responseObserver.onNext(maxHpStat); responseObserver.onNext(maxHpStat);
if (includeMin) { if (includeMin) {
// Send min hit points. // Send min hit points.
Stat minHpStat = GameFactory.createStat(minHpMonsterName.get(), minHp.get(), minHpCount.get()); Stat minHpStat =
GameFactory.createStat(minHpMonsterName.get(), minHp.get(), minHpCount.get());
responseObserver.onNext(minHpStat); responseObserver.onNext(minHpStat);
} }
responseObserver.onCompleted(); responseObserver.onCompleted();
} }
public void onError(Throwable t) { public void onError(Throwable t) {
// Not expected // Not expected
Assert.fail(); Assert.fail();
}; }
;
}; };
} }
} }
@@ -138,7 +135,8 @@ public class JavaGrpcTest {
public static void startServer() throws IOException { public static void startServer() throws IOException {
server = ServerBuilder.forPort(0).addService(new MyService()).build().start(); server = ServerBuilder.forPort(0).addService(new MyService()).build().start();
int port = server.getPort(); int port = server.getPort();
channel = ManagedChannelBuilder.forAddress("localhost", port) channel =
ManagedChannelBuilder.forAddress("localhost", port)
// Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
// needing certificates. // needing certificates.
.usePlaintext() .usePlaintext()
@@ -150,7 +148,8 @@ public class JavaGrpcTest {
@org.junit.Test @org.junit.Test
public void testUnary() throws IOException { public void testUnary() throws IOException {
Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana); Monster monsterRequest =
GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
Stat stat = blockingStub.store(monsterRequest); Stat stat = blockingStub.store(monsterRequest);
Assert.assertEquals(stat.id(), "Hello " + BIG_MONSTER_NAME); Assert.assertEquals(stat.id(), "Hello " + BIG_MONSTER_NAME);
System.out.println("Received stat response from service: " + stat.id()); System.out.println("Received stat response from service: " + stat.id());
@@ -158,7 +157,8 @@ public class JavaGrpcTest {
@org.junit.Test @org.junit.Test
public void testServerStreaming() throws IOException { public void testServerStreaming() throws IOException {
Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana); Monster monsterRequest =
GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana);
Stat stat = blockingStub.store(monsterRequest); Stat stat = blockingStub.store(monsterRequest);
Iterator<Monster> iterator = blockingStub.retrieve(stat); Iterator<Monster> iterator = blockingStub.retrieve(stat);
int counter = 0; int counter = 0;
@@ -176,11 +176,14 @@ public class JavaGrpcTest {
final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>(); final AtomicReference<Stat> maxHitStat = new AtomicReference<Stat>();
final CountDownLatch streamAlive = new CountDownLatch(1); final CountDownLatch streamAlive = new CountDownLatch(1);
StreamObserver<Stat> statObserver = new StreamObserver<Stat>() { StreamObserver<Stat> statObserver =
new StreamObserver<Stat>() {
public void onCompleted() { public void onCompleted() {
streamAlive.countDown(); streamAlive.countDown();
} }
public void onError(Throwable ex) {} public void onError(Throwable ex) {}
public void onNext(Stat stat) { public void onNext(Stat stat) {
maxHitStat.set(stat); maxHitStat.set(stat);
} }
@@ -188,7 +191,9 @@ public class JavaGrpcTest {
StreamObserver<Monster> monsterStream = asyncStub.getMaxHitPoint(statObserver); StreamObserver<Monster> monsterStream = asyncStub.getMaxHitPoint(statObserver);
short count = 10; short count = 10;
for (short i = 0; i < count; ++i) { for (short i = 0; i < count; ++i) {
Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana); Monster monster =
GameFactory.createMonster(
BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
monsterStream.onNext(monster); monsterStream.onNext(monster);
} }
monsterStream.onCompleted(); monsterStream.onCompleted();
@@ -205,17 +210,19 @@ public class JavaGrpcTest {
final AtomicReference<Stat> minHitStat = new AtomicReference<Stat>(); final AtomicReference<Stat> minHitStat = new AtomicReference<Stat>();
final CountDownLatch streamAlive = new CountDownLatch(1); final CountDownLatch streamAlive = new CountDownLatch(1);
StreamObserver<Stat> statObserver = new StreamObserver<Stat>() { StreamObserver<Stat> statObserver =
new StreamObserver<Stat>() {
public void onCompleted() { public void onCompleted() {
streamAlive.countDown(); streamAlive.countDown();
} }
public void onError(Throwable ex) {} public void onError(Throwable ex) {}
public void onNext(Stat stat) { public void onNext(Stat stat) {
// We expect the server to send the max stat first and then the min stat. // We expect the server to send the max stat first and then the min stat.
if (maxHitStat.get() == null) { if (maxHitStat.get() == null) {
maxHitStat.set(stat); maxHitStat.set(stat);
} } else {
else {
minHitStat.set(stat); minHitStat.set(stat);
} }
} }
@@ -223,12 +230,15 @@ public class JavaGrpcTest {
StreamObserver<Monster> monsterStream = asyncStub.getMinMaxHitPoints(statObserver); StreamObserver<Monster> monsterStream = asyncStub.getMinMaxHitPoints(statObserver);
short count = 10; short count = 10;
for (short i = 0; i < count; ++i) { for (short i = 0; i < count; ++i) {
Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana); Monster monster =
GameFactory.createMonster(
BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana);
monsterStream.onNext(monster); monsterStream.onNext(monster);
} }
monsterStream.onCompleted(); monsterStream.onCompleted();
// Wait a little bit for the server to send the stats of the monster with the max and min hit-points. // Wait a little bit for the server to send the stats of the monster with the max and min
// hit-points.
streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS); streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS);
Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1)); Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1));

View File

@@ -98,7 +98,8 @@ void RunServer() {
server_instance->Wait(); server_instance->Wait();
} }
template<class Builder> void StoreRPC(MonsterStorage::Stub *stub) { template <class Builder>
void StoreRPC(MonsterStorage::Stub* stub) {
Builder fbb; Builder fbb;
grpc::ClientContext context; grpc::ClientContext context;
// Build a request with the name set. // Build a request with the name set.
@@ -119,7 +120,8 @@ template<class Builder> void StoreRPC(MonsterStorage::Stub *stub) {
} }
} }
template<class Builder> void RetrieveRPC(MonsterStorage::Stub *stub) { template <class Builder>
void RetrieveRPC(MonsterStorage::Stub* stub) {
Builder fbb; Builder fbb;
grpc::ClientContext context; grpc::ClientContext context;
fbb.Clear(); fbb.Clear();

View File

@@ -1,13 +1,13 @@
from __future__ import print_function from __future__ import print_function
from concurrent import futures
import os import os
import sys import sys
import grpc
import flatbuffers import flatbuffers
import grpc
from concurrent import futures sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", "tests"))
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'tests'))
import MyGame.Example.Monster as Monster import MyGame.Example.Monster as Monster
import MyGame.Example.Stat as Stat import MyGame.Example.Stat as Stat
import MyGame.Example.Vec3 as Vec3 import MyGame.Example.Vec3 as Vec3
@@ -103,7 +103,7 @@ def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
monster_grpc_fb.add_MonsterStorageServicer_to_server(MonsterStorage(), server) monster_grpc_fb.add_MonsterStorageServicer_to_server(MonsterStorage(), server)
server.add_insecure_port('[::]:50051') server.add_insecure_port("[::]:50051")
server.start() server.start()
@@ -112,7 +112,7 @@ def serve():
def run(): def run():
channel = grpc.insecure_channel('127.0.0.1:50051') channel = grpc.insecure_channel("127.0.0.1:50051")
stub = monster_grpc_fb.MonsterStorageStub(channel) stub = monster_grpc_fb.MonsterStorageStub(channel)
b = flatbuffers.Builder(0) b = flatbuffers.Builder(0)
@@ -142,7 +142,9 @@ def run():
Monster.MonsterAddHp(b, test_hp) Monster.MonsterAddHp(b, test_hp)
Monster.MonsterAddName(b, name1) Monster.MonsterAddName(b, name1)
Monster.MonsterAddColor(b, test_color) Monster.MonsterAddColor(b, test_color)
pos = Vec3.CreateVec3(b, test_X, test_Y, test_Z, test_test1, test_color, test_a, test_b) pos = Vec3.CreateVec3(
b, test_X, test_Y, test_Z, test_test1, test_color, test_a, test_b
)
Monster.MonsterAddPos(b, pos) Monster.MonsterAddPos(b, pos)
Monster.MonsterAddInventory(b, inv) Monster.MonsterAddInventory(b, inv)
Monster.MonsterAddTestType(b, test_testtype) Monster.MonsterAddTestType(b, test_testtype)
@@ -170,5 +172,5 @@ def run():
count = count + 1 count = count + 1
if __name__ == '__main__': if __name__ == "__main__":
serve() serve()

View File

@@ -0,0 +1,60 @@
// Verifies that the generated gRPC callback client stub methods are present.
// This is a compile-time only test: it never performs an actual RPC.
// It supplements grpctest_callback_compile.cpp (server side) by checking
// client-side async_ / reactor entry points.
#include <type_traits>
#include "monster_test.grpc.fb.h"
#if defined(FLATBUFFERS_GENERATED_GRPC_CALLBACK_API) && \
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
using Stub = MyGame::Example::MonsterStorage::Stub;
using namespace MyGame::Example; // NOLINT
// Unary async overloads
static_assert(std::is_member_function_pointer<
decltype(static_cast<void (Stub::*)(
::grpc::ClientContext*,
const flatbuffers::grpc::Message<Monster>&,
flatbuffers::grpc::Message<Stat>*,
std::function<void(::grpc::Status)>)>(
&Stub::async_Store))>::value,
"Function-form unary async_Store missing");
static_assert(
std::is_member_function_pointer<
decltype(static_cast<void (Stub::*)(
::grpc::ClientContext*,
const flatbuffers::grpc::Message<Monster>&,
flatbuffers::grpc::Message<Stat>*,
::grpc::ClientUnaryReactor*)>(&Stub::async_Store))>::value,
"Reactor-form unary async_Store missing");
// Streaming reactor entry points
static_assert(
std::is_member_function_pointer<
decltype(static_cast<void (Stub::*)(
::grpc::ClientContext*,
const flatbuffers::grpc::Message<Stat>&,
::grpc::ClientReadReactor<flatbuffers::grpc::Message<
Monster> >*)>(&Stub::async_Retrieve))>::value,
"Server streaming reactor async_Retrieve missing");
static_assert(
std::is_member_function_pointer<
decltype(static_cast<void (Stub::*)(
::grpc::ClientContext*, flatbuffers::grpc::Message<Stat>*,
::grpc::ClientWriteReactor<flatbuffers::grpc::Message<
Monster> >*)>(&Stub::async_GetMaxHitPoint))>::value,
"Client streaming reactor async_GetMaxHitPoint missing");
static_assert(std::is_member_function_pointer<
decltype(static_cast<void (Stub::*)(
::grpc::ClientContext*,
::grpc::ClientBidiReactor<
flatbuffers::grpc::Message<Monster>,
flatbuffers::grpc::Message<Stat> >*)>(
&Stub::async_GetMinMaxHitPoints))>::value,
"Bidi streaming reactor async_GetMinMaxHitPoints missing");
#endif // FLATBUFFERS_GENERATED_GRPC_CALLBACK_API &&
// GRPC_CALLBACK_API_NONEXPERIMENTAL
int main() { return 0; }

View File

@@ -0,0 +1,22 @@
#include "monster_test.grpc.fb.h"
// This test only verifies that the generated CallbackService compiles when the
// callback API is available. It does not run any RPCs.
#if defined(FLATBUFFERS_GENERATED_GRPC_CALLBACK_API) && \
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
class CallbackServiceImpl
: public MyGame::Example::MonsterStorage::CallbackService {
public:
// For brevity we don't override methods; user code will provide reactors.
};
#endif
int main() {
#if defined(FLATBUFFERS_GENERATED_GRPC_CALLBACK_API) && \
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
CallbackServiceImpl svc;
(void)svc; // suppress unused
#endif
return 0;
}

View File

@@ -45,7 +45,9 @@ template<class SrcBuilder>
struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> { struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
static void builder_reusable_after_release_message_test( static void builder_reusable_after_release_message_test(
TestSelector selector) { TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) { return; } if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) {
return;
}
flatbuffers::grpc::MessageBuilder mb; flatbuffers::grpc::MessageBuilder mb;
std::vector<flatbuffers::grpc::Message<Monster>> buffers; std::vector<flatbuffers::grpc::Message<Monster>> buffers;
@@ -58,7 +60,9 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
} }
static void builder_reusable_after_release_test(TestSelector selector) { static void builder_reusable_after_release_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; } if (!selector.count(REUSABLE_AFTER_RELEASE)) {
return;
}
// FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in // FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in
// SliceAllocator::allocate in the second iteration. // SliceAllocator::allocate in the second iteration.
@@ -74,7 +78,9 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
} }
static void builder_reusable_after_releaseraw_test(TestSelector selector) { static void builder_reusable_after_releaseraw_test(TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; } if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) {
return;
}
flatbuffers::grpc::MessageBuilder mb; flatbuffers::grpc::MessageBuilder mb;
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
@@ -89,7 +95,9 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
static void builder_reusable_after_release_and_move_assign_test( static void builder_reusable_after_release_and_move_assign_test(
TestSelector selector) { TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; } if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) {
return;
}
// FIXME: Release-move_assign loop fails assert(p == // FIXME: Release-move_assign loop fails assert(p ==
// GRPC_SLICE_START_PTR(slice_)) in DetachedBuffer destructor after all the // GRPC_SLICE_START_PTR(slice_)) in DetachedBuffer destructor after all the
@@ -137,7 +145,9 @@ struct BuilderReuseTests<flatbuffers::grpc::MessageBuilder, SrcBuilder> {
static void builder_reusable_after_releaseraw_and_move_assign_test( static void builder_reusable_after_releaseraw_and_move_assign_test(
TestSelector selector) { TestSelector selector) {
if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; } if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) {
return;
}
flatbuffers::grpc::MessageBuilder dst; flatbuffers::grpc::MessageBuilder dst;
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
@@ -358,8 +368,7 @@ void message_builder_tests() {
REUSABLE_AFTER_RELEASE_RAW, REUSABLE_AFTER_RELEASE_MESSAGE, REUSABLE_AFTER_RELEASE_RAW, REUSABLE_AFTER_RELEASE_MESSAGE,
REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN, REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN,
REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN};
};
BuilderReuseTests<MessageBuilder, MessageBuilder>::run_tests( BuilderReuseTests<MessageBuilder, MessageBuilder>::run_tests(
TestSelector(tests, tests + 6)); TestSelector(tests, tests + 6));

View File

@@ -104,10 +104,10 @@ class IdlNamer : public Namer {
return "VT_" + ConvertCase(EscapeKeyword(field.name), Case::kAllUpper); return "VT_" + ConvertCase(EscapeKeyword(field.name), Case::kAllUpper);
} }
std::string LegacyRustUnionTypeOffsetName(const FieldDef& field) const { std::string LegacyRustUnionTypeOffsetName(const FieldDef& field) const {
return "VT_" + ConvertCase(EscapeKeyword(field.name + "_type"), Case::kAllUpper); return "VT_" +
ConvertCase(EscapeKeyword(field.name + "_type"), Case::kAllUpper);
} }
std::string LegacySwiftVariant(const EnumVal& ev) const { std::string LegacySwiftVariant(const EnumVal& ev) const {
auto name = ev.name; auto name = ev.name;
if (isupper(name.front())) { if (isupper(name.front())) {
@@ -155,7 +155,9 @@ class IdlNamer : public Namer {
std::string NamespacedString(const struct Namespace* ns, std::string NamespacedString(const struct Namespace* ns,
const std::string& str) const { const std::string& str) const {
std::string ret; std::string ret;
if (ns != nullptr) { ret += Namespace(ns->components); } if (ns != nullptr) {
ret += Namespace(ns->components);
}
if (!ret.empty()) ret += config_.namespace_seperator; if (!ret.empty()) ret += config_.namespace_seperator;
return ret + str; return ret + str;
} }

View File

@@ -110,12 +110,12 @@ class Namer {
virtual ~Namer() {} virtual ~Namer() {}
template<typename T> std::string Method(const T &s) const { template <typename T>
std::string Method(const T& s) const {
return Method(s.name); return Method(s.name);
} }
virtual std::string Method(const std::string &pre, virtual std::string Method(const std::string& pre, const std::string& mid,
const std::string &mid,
const std::string& suf) const { const std::string& suf) const {
return Format(pre + "_" + mid + "_" + suf, config_.methods); return Format(pre + "_" + mid + "_" + suf, config_.methods);
} }

View File

@@ -59,5 +59,21 @@ const python::Import &python::Imports::Import(const std::string &module,
imports.push_back(std::move(import)); imports.push_back(std::move(import));
return imports.back(); return imports.back();
} }
const python::Import& python::Imports::Export(const std::string& module) {
python::Import import;
import.module = module;
exports.push_back(std::move(import));
return exports.back();
}
const python::Import& python::Imports::Export(const std::string& module,
const std::string& name) {
python::Import import;
import.module = module;
import.name = name;
exports.push_back(std::move(import));
return exports.back();
}
} // namespace python } // namespace python
} // namespace flatbuffers } // namespace flatbuffers

View File

@@ -85,7 +85,12 @@ struct Imports {
const python::Import& Import(const std::string& module, const python::Import& Import(const std::string& module,
const std::string& name); const std::string& name);
const python::Import& Export(const std::string& module);
const python::Import& Export(const std::string& module,
const std::string& name);
std::vector<python::Import> imports; std::vector<python::Import> imports;
std::vector<python::Import> exports;
}; };
} // namespace python } // namespace python
} // namespace flatbuffers } // namespace flatbuffers

View File

@@ -27,17 +27,15 @@
namespace flatbuffers { namespace flatbuffers {
// This is used as a helper type for accessing arrays. // This is used as a helper type for accessing arrays.
template<typename T, uint16_t length> class Array { template <typename T, uint16_t length>
class Array {
// Array<T> can carry only POD data types (scalars or structs). // Array<T> can carry only POD data types (scalars or structs).
typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value> typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
scalar_tag; scalar_tag;
typedef
typename flatbuffers::conditional<scalar_tag::value, T, const T *>::type
IndirectHelperType;
public: public:
typedef uint16_t size_type; typedef uint16_t size_type;
typedef typename IndirectHelper<IndirectHelperType>::return_type return_type; typedef typename IndirectHelper<T>::return_type return_type;
typedef VectorConstIterator<T, return_type, uoffset_t> const_iterator; typedef VectorConstIterator<T, return_type, uoffset_t> const_iterator;
typedef VectorReverseIterator<const_iterator> const_reverse_iterator; typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
@@ -50,7 +48,7 @@ template<typename T, uint16_t length> class Array {
return_type Get(uoffset_t i) const { return_type Get(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size()); FLATBUFFERS_ASSERT(i < size());
return IndirectHelper<IndirectHelperType>::Read(Data(), i); return IndirectHelper<T>::Read(Data(), i);
} }
return_type operator[](uoffset_t i) const { return Get(i); } return_type operator[](uoffset_t i) const { return Get(i); }
@@ -58,7 +56,8 @@ template<typename T, uint16_t length> class Array {
// If this is a Vector of enums, T will be its storage type, not the enum // If this is a Vector of enums, T will be its storage type, not the enum
// type. This function makes it convenient to retrieve value with enum // type. This function makes it convenient to retrieve value with enum
// type E. // type E.
template<typename E> E GetEnum(uoffset_t i) const { template <typename E>
E GetEnum(uoffset_t i) const {
return static_cast<E>(Get(i)); return static_cast<E>(Get(i));
} }
@@ -134,7 +133,9 @@ template<typename T, uint16_t length> class Array {
// Copy data from flatbuffers::span with endian conversion. // Copy data from flatbuffers::span with endian conversion.
void CopyFromSpanImpl(flatbuffers::false_type, void CopyFromSpanImpl(flatbuffers::false_type,
flatbuffers::span<const T, length> src) { flatbuffers::span<const T, length> src) {
for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); } for (size_type k = 0; k < length; k++) {
Mutate(k, src[k]);
}
} }
// This class is only used to access pre-existing data. Don't ever // This class is only used to access pre-existing data. Don't ever

View File

@@ -140,8 +140,8 @@
#endif // !defined(FLATBUFFERS_LITTLEENDIAN) #endif // !defined(FLATBUFFERS_LITTLEENDIAN)
#define FLATBUFFERS_VERSION_MAJOR 25 #define FLATBUFFERS_VERSION_MAJOR 25
#define FLATBUFFERS_VERSION_MINOR 2 #define FLATBUFFERS_VERSION_MINOR 9
#define FLATBUFFERS_VERSION_REVISION 10 #define FLATBUFFERS_VERSION_REVISION 23
#define FLATBUFFERS_STRING_EXPAND(X) #X #define FLATBUFFERS_STRING_EXPAND(X) #X
#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X) #define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
namespace flatbuffers { namespace flatbuffers {

View File

@@ -20,12 +20,14 @@
#include <algorithm> #include <algorithm>
#include "flatbuffers/base.h" #include "flatbuffers/base.h"
#include "flatbuffers/stl_emulation.h"
namespace flatbuffers { namespace flatbuffers {
// Wrapper for uoffset_t to allow safe template specialization. // Wrapper for uoffset_t to allow safe template specialization.
// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset). // Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
template<typename T = void> struct Offset { template <typename T = void>
struct Offset {
// The type of offset to use. // The type of offset to use.
typedef uoffset_t offset_type; typedef uoffset_t offset_type;
@@ -36,8 +38,14 @@ template<typename T = void> struct Offset {
bool IsNull() const { return !o; } bool IsNull() const { return !o; }
}; };
template <typename T>
struct is_specialisation_of_Offset : false_type {};
template <typename T>
struct is_specialisation_of_Offset<Offset<T>> : true_type {};
// Wrapper for uoffset64_t Offsets. // Wrapper for uoffset64_t Offsets.
template<typename T = void> struct Offset64 { template <typename T = void>
struct Offset64 {
// The type of offset to use. // The type of offset to use.
typedef uoffset64_t offset_type; typedef uoffset64_t offset_type;
@@ -48,6 +56,11 @@ template<typename T = void> struct Offset64 {
bool IsNull() const { return !o; } bool IsNull() const { return !o; }
}; };
template <typename T>
struct is_specialisation_of_Offset64 : false_type {};
template <typename T>
struct is_specialisation_of_Offset64<Offset64<T>> : true_type {};
// Litmus check for ensuring the Offsets are the expected size. // Litmus check for ensuring the Offsets are the expected size.
static_assert(sizeof(Offset<>) == 4, "Offset has wrong size"); static_assert(sizeof(Offset<>) == 4, "Offset has wrong size");
static_assert(sizeof(Offset64<>) == 8, "Offset64 has wrong size"); static_assert(sizeof(Offset64<>) == 8, "Offset64 has wrong size");
@@ -60,7 +73,8 @@ inline void EndianCheck() {
(void)endiantest; (void)endiantest;
} }
template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() { template <typename T>
FLATBUFFERS_CONSTEXPR size_t AlignOf() {
// clang-format off // clang-format off
#ifdef _MSC_VER #ifdef _MSC_VER
return __alignof(T); return __alignof(T);
@@ -90,7 +104,8 @@ static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
// return type like this. // return type like this.
// The typedef is for the convenience of callers of this function // The typedef is for the convenience of callers of this function
// (avoiding the need for a trailing return decltype) // (avoiding the need for a trailing return decltype)
template<typename T> struct IndirectHelper { template <typename T, typename Enable = void>
struct IndirectHelper {
typedef T return_type; typedef T return_type;
typedef T mutable_return_type; typedef T mutable_return_type;
static const size_t element_stride = sizeof(T); static const size_t element_stride = sizeof(T);
@@ -135,10 +150,20 @@ struct IndirectHelper<OffsetT<T>> {
}; };
// For vector of structs. // For vector of structs.
template<typename T> struct IndirectHelper<const T *> { template <typename T>
typedef const T *return_type; struct IndirectHelper<
typedef T *mutable_return_type; T, typename std::enable_if<
static const size_t element_stride = sizeof(T); !std::is_scalar<typename std::remove_pointer<T>::type>::value &&
!is_specialisation_of_Offset<T>::value &&
!is_specialisation_of_Offset64<T>::value>::type> {
private:
typedef typename std::remove_pointer<typename std::remove_cv<T>::type>::type
pointee_type;
public:
typedef const pointee_type* return_type;
typedef pointee_type* mutable_return_type;
static const size_t element_stride = sizeof(pointee_type);
static return_type Read(const uint8_t* const p, const size_t i) { static return_type Read(const uint8_t* const p, const size_t i) {
// Structs are stored inline, relative to the first struct pointer. // Structs are stored inline, relative to the first struct pointer.
@@ -172,11 +197,11 @@ inline bool BufferHasIdentifier(const void *buf, const char *identifier,
/// @cond FLATBUFFERS_INTERNAL /// @cond FLATBUFFERS_INTERNAL
// Helpers to get a typed pointer to the root object contained in the buffer. // Helpers to get a typed pointer to the root object contained in the buffer.
template<typename T> T *GetMutableRoot(void *buf) { template <typename T>
T* GetMutableRoot(void* buf) {
if (!buf) return nullptr; if (!buf) return nullptr;
EndianCheck(); EndianCheck();
return reinterpret_cast<T *>( return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(buf) +
reinterpret_cast<uint8_t *>(buf) +
EndianScalar(*reinterpret_cast<uoffset_t*>(buf))); EndianScalar(*reinterpret_cast<uoffset_t*>(buf)));
} }
@@ -185,7 +210,8 @@ T *GetMutableSizePrefixedRoot(void *buf) {
return GetMutableRoot<T>(reinterpret_cast<uint8_t*>(buf) + sizeof(SizeT)); return GetMutableRoot<T>(reinterpret_cast<uint8_t*>(buf) + sizeof(SizeT));
} }
template<typename T> const T *GetRoot(const void *buf) { template <typename T>
const T* GetRoot(const void* buf) {
return GetMutableRoot<T>(const_cast<void*>(buf)); return GetMutableRoot<T>(const_cast<void*>(buf));
} }

View File

@@ -27,7 +27,8 @@ namespace flatbuffers {
// A BufferRef does not own its buffer. // A BufferRef does not own its buffer.
struct BufferRefBase {}; // for std::is_base_of struct BufferRefBase {}; // for std::is_base_of
template<typename T> struct BufferRef : BufferRefBase { template <typename T>
struct BufferRef : BufferRefBase {
BufferRef() : buf(nullptr), len(0), must_free(false) {} BufferRef() : buf(nullptr), len(0), must_free(false) {}
BufferRef(uint8_t* _buf, uoffset_t _len) BufferRef(uint8_t* _buf, uoffset_t _len)
: buf(_buf), len(_len), must_free(false) {} : buf(_buf), len(_len), must_free(false) {}

View File

@@ -100,7 +100,9 @@ class DetachedBuffer {
inline void destroy() { inline void destroy() {
if (buf_) Deallocate(allocator_, buf_, reserved_); if (buf_) Deallocate(allocator_, buf_, reserved_);
if (own_allocator_ && allocator_) { delete allocator_; } if (own_allocator_ && allocator_) {
delete allocator_;
}
reset(); reset();
} }

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