mirror of
https://github.com/google/flatbuffers.git
synced 2026-11-11 22:46:21 +00:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e38e7aa00c | ||
|
|
f58d5768f1 | ||
|
|
7af1efe4b2 | ||
|
|
6dda43bbaa | ||
|
|
9a8a511b52 | ||
|
|
b8431fbcd7 | ||
|
|
5761d6e67a | ||
|
|
81edeb17d9 | ||
|
|
5982eb6495 | ||
|
|
38df29380a | ||
|
|
1f438bd40f |
@@ -545,7 +545,7 @@ jobs:
|
|||||||
# 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
|
- name: pnpm
|
||||||
run: npm install -g pnpm
|
run: npm install -g pnpm@10
|
||||||
- name: deps
|
- name: deps
|
||||||
run: pnpm i
|
run: pnpm i
|
||||||
- name: compile
|
- name: compile
|
||||||
|
|||||||
@@ -75,6 +75,17 @@ extension Array where Element == Package.Dependency {
|
|||||||
.package(
|
.package(
|
||||||
url: "https://github.com/grpc/grpc-swift-nio-transport.git",
|
url: "https://github.com/grpc/grpc-swift-nio-transport.git",
|
||||||
from: "2.0.0"),
|
from: "2.0.0"),
|
||||||
|
// swift-crypto arrives through grpc-swift-nio-transport -> swift-nio-ssl
|
||||||
|
// and is otherwise resolved afresh on every build, because this package
|
||||||
|
// ships no Package.resolved. 5.x asks for swift-tools-version 6.2, so only
|
||||||
|
// the 6.2 CI job selects it - and then fails to compile it, because 5.x
|
||||||
|
// uses `@nonexhaustive`, which the 6.2.x toolchains do not accept yet.
|
||||||
|
// Stay on the last 4.x release that still builds with every toolchain in
|
||||||
|
// the Swift CI matrix (4.3.0 declares swift-tools-version 6.0; 4.4+ asks
|
||||||
|
// for 6.1 and would drop the 6.0 job).
|
||||||
|
.package(
|
||||||
|
url: "https://github.com/apple/swift-crypto.git",
|
||||||
|
"4.0.0" ..< "4.4.0"),
|
||||||
]
|
]
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(ByteBuffer(assumingMemoryBound: memory, capacity: Int(oneGB)))
|
blackHole(ByteBuffer(assumingMemoryBound: memory, capacity: Int(oneGB)))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in
|
Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in
|
||||||
@@ -105,6 +106,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(fb.clear())
|
blackHole(fb.clear())
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Strings 10") { benchmark in
|
Benchmark("Strings 10") { benchmark in
|
||||||
@@ -113,6 +115,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(fb.create(string: str10))
|
blackHole(fb.create(string: str10))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Strings 100") { benchmark in
|
Benchmark("Strings 100") { benchmark in
|
||||||
@@ -121,6 +124,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(fb.create(string: str100))
|
blackHole(fb.create(string: str100))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Vector 1 Bytes") { benchmark in
|
Benchmark("Vector 1 Bytes") { benchmark in
|
||||||
@@ -129,6 +133,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(fb.createVector(bytes: bytes))
|
blackHole(fb.createVector(bytes: bytes))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Vector 1 Ints") { benchmark in
|
Benchmark("Vector 1 Ints") { benchmark in
|
||||||
@@ -137,6 +142,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(fb.createVector(ints))
|
blackHole(fb.createVector(ints))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Vector 100 Ints") { benchmark in
|
Benchmark("Vector 100 Ints") { benchmark in
|
||||||
@@ -145,6 +151,7 @@ let benchmarks = {
|
|||||||
for i in benchmark.scaledIterations {
|
for i in benchmark.scaledIterations {
|
||||||
blackHole(fb.createVector(ints))
|
blackHole(fb.createVector(ints))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Vector 100 Bytes") { benchmark in
|
Benchmark("Vector 100 Bytes") { benchmark in
|
||||||
@@ -153,6 +160,7 @@ let benchmarks = {
|
|||||||
for i in benchmark.scaledIterations {
|
for i in benchmark.scaledIterations {
|
||||||
blackHole(fb.createVector(bytes))
|
blackHole(fb.createVector(bytes))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Vector 100 ContiguousBytes") { benchmark in
|
Benchmark("Vector 100 ContiguousBytes") { benchmark in
|
||||||
@@ -161,6 +169,7 @@ let benchmarks = {
|
|||||||
for i in benchmark.scaledIterations {
|
for i in benchmark.scaledIterations {
|
||||||
blackHole(fb.createVector(bytes: bytes))
|
blackHole(fb.createVector(bytes: bytes))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark(
|
Benchmark(
|
||||||
@@ -178,6 +187,7 @@ let benchmarks = {
|
|||||||
fb.add(offset: off, at: 8)
|
fb.add(offset: off, at: 8)
|
||||||
blackHole(fb.endTable(at: s))
|
blackHole(fb.endTable(at: s))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark(
|
Benchmark(
|
||||||
@@ -190,6 +200,7 @@ let benchmarks = {
|
|||||||
let s = fb.startTable(with: 4)
|
let s = fb.startTable(with: 4)
|
||||||
blackHole(fb.endTable(at: s))
|
blackHole(fb.endTable(at: s))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Struct") { benchmark in
|
Benchmark("Struct") { benchmark in
|
||||||
@@ -198,6 +209,7 @@ let benchmarks = {
|
|||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(fb.create(struct: array.first!))
|
blackHole(fb.create(struct: array.first!))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Structs") { benchmark in
|
Benchmark("Structs") { benchmark in
|
||||||
@@ -219,6 +231,7 @@ let benchmarks = {
|
|||||||
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))
|
||||||
blackHole(fb.finish(offset: root))
|
blackHole(fb.finish(offset: root))
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Vector of Offsets") { benchmark in
|
Benchmark("Vector of Offsets") { benchmark in
|
||||||
@@ -239,12 +252,15 @@ let benchmarks = {
|
|||||||
fb.add(offset: off, at: 2)
|
fb.add(offset: off, at: 2)
|
||||||
blackHole(fb.endTable(at: s))
|
blackHole(fb.endTable(at: s))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
|
|
||||||
Benchmark("Reading Doubles") { benchmark in
|
Benchmark("Reading Doubles") { benchmark in
|
||||||
let byteBuffer = ByteBuffer(data: data)
|
let byteBuffer = ByteBuffer(data: data)
|
||||||
|
benchmark.startMeasurement()
|
||||||
for _ in benchmark.scaledIterations {
|
for _ in benchmark.scaledIterations {
|
||||||
blackHole(byteBuffer.read(def: Double.self, position: 0))
|
blackHole(byteBuffer.read(def: Double.self, position: 0))
|
||||||
}
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Benchmark
|
||||||
|
import FlexBuffers
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
let benchmarks = {
|
||||||
|
let data = {
|
||||||
|
var array = [8888.88, 8888.88]
|
||||||
|
var data = Data()
|
||||||
|
array.withUnsafeBytes { ptr in
|
||||||
|
data.append(contentsOf: ptr)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}()
|
||||||
|
let ints: [Int32] = Array(repeating: 42, count: 100)
|
||||||
|
let str10 = (0...9).map { _ -> String in "x" }.joined()
|
||||||
|
let str100 = (0...99).map { _ -> String in "x" }.joined()
|
||||||
|
|
||||||
|
// A representative map: 50 keyed scalars, a keyed string and a keyed vector
|
||||||
|
// of 100 scalars. Used for the realistic decode benchmarks.
|
||||||
|
let mapBuffer: ByteBuffer = {
|
||||||
|
var fbx = FlexBuffersWriter(initialSize: 1 << 16)
|
||||||
|
fbx.map {
|
||||||
|
for i in 0..<50 { $0.add(int: i, key: "i\(i)") }
|
||||||
|
$0.add(string: "hello world", key: "s")
|
||||||
|
$0.vector(key: "v") { v in
|
||||||
|
for x in 0..<100 { v.add(int: x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fbx.finish()
|
||||||
|
return fbx.sizedByteBuffer
|
||||||
|
}()
|
||||||
|
|
||||||
|
let metrics: [BenchmarkMetric] = [
|
||||||
|
.cpuTotal,
|
||||||
|
.wallClock,
|
||||||
|
.mallocCountTotal,
|
||||||
|
.releaseCount,
|
||||||
|
.peakMemoryResident,
|
||||||
|
]
|
||||||
|
let maxIterations = 1_000_000
|
||||||
|
let maxDuration: Duration = .seconds(3)
|
||||||
|
let megaConfiguration: Benchmark.Configuration = .init(
|
||||||
|
metrics: metrics,
|
||||||
|
warmupIterations: 1,
|
||||||
|
scalingFactor: .mega,
|
||||||
|
maxDuration: maxDuration,
|
||||||
|
maxIterations: maxIterations)
|
||||||
|
|
||||||
|
Benchmark.defaultConfiguration = megaConfiguration
|
||||||
|
|
||||||
|
// Decode (read path)
|
||||||
|
|
||||||
|
// Raw scalar read: isolates `read<T: BitwiseCopyable>` and the `let` blob.
|
||||||
|
Benchmark("Reading Doubles") { benchmark in
|
||||||
|
let byteBuffer = ByteBuffer(data: data)
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
blackHole(byteBuffer.read(def: Double.self, position: 0))
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realistic decode: resolve root map and read a keyed scalar.
|
||||||
|
Benchmark("Decode Map Scalar") { benchmark in
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
let map = try! getRoot(buffer: mapBuffer)!.map!
|
||||||
|
blackHole(map["i25"]?.int)
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realistic decode: resolve root map and read a keyed string.
|
||||||
|
Benchmark("Decode Map String") { benchmark in
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
let map = try! getRoot(buffer: mapBuffer)!.map!
|
||||||
|
blackHole(map["s"]?.string())
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realistic decode: resolve a nested vector and sum its scalars.
|
||||||
|
Benchmark("Decode Vector") { benchmark in
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
let map = try! getRoot(buffer: mapBuffer)!.map!
|
||||||
|
let vector = map["v"]!.vector!
|
||||||
|
var sum: Int64 = 0
|
||||||
|
for i in 0..<vector.count {
|
||||||
|
sum &+= vector[i]?.int ?? 0
|
||||||
|
}
|
||||||
|
blackHole(sum)
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode (write path)
|
||||||
|
// Writers are reused with `reset(keepingCapacity:)` so per-iteration
|
||||||
|
// allocation does not dominate and mask the write-path cost (which is what
|
||||||
|
// the `@exclusivity(unchecked)` storage pointer affects).
|
||||||
|
|
||||||
|
Benchmark("Strings 10") { benchmark in
|
||||||
|
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
fbx.add(string: str10)
|
||||||
|
fbx.finish()
|
||||||
|
blackHole(fbx.sizedByteBuffer)
|
||||||
|
fbx.reset(keepingCapacity: true)
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
Benchmark("Strings 100") { benchmark in
|
||||||
|
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
fbx.add(string: str100)
|
||||||
|
fbx.finish()
|
||||||
|
blackHole(fbx.sizedByteBuffer)
|
||||||
|
fbx.reset(keepingCapacity: true)
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
Benchmark("Encoding Vector Of Ints") { benchmark in
|
||||||
|
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
fbx.vector {
|
||||||
|
$0.create(vector: ints)
|
||||||
|
}
|
||||||
|
fbx.finish()
|
||||||
|
blackHole(fbx.sizedByteBuffer)
|
||||||
|
fbx.reset(keepingCapacity: true)
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
|
||||||
|
Benchmark("Encoding Map") { benchmark in
|
||||||
|
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
|
||||||
|
benchmark.startMeasurement()
|
||||||
|
for _ in benchmark.scaledIterations {
|
||||||
|
fbx.map {
|
||||||
|
for i in 0..<50 { $0.add(int: i, key: "i\(i)") }
|
||||||
|
$0.add(string: "hello world", key: "s")
|
||||||
|
$0.vector(key: "v") { v in
|
||||||
|
for x in 0..<100 { v.add(int: x) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fbx.finish()
|
||||||
|
blackHole(fbx.sizedByteBuffer)
|
||||||
|
fbx.reset(keepingCapacity: true)
|
||||||
|
}
|
||||||
|
benchmark.stopMeasurement()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,4 +39,14 @@ let package = Package(
|
|||||||
plugins: [
|
plugins: [
|
||||||
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
|
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
|
||||||
]),
|
]),
|
||||||
|
.executableTarget(
|
||||||
|
name: "FlexBuffersBenchmarks",
|
||||||
|
dependencies: [
|
||||||
|
.product(name: "FlexBuffers", package: "flatbuffers"),
|
||||||
|
.product(name: "Benchmark", package: "package-benchmark"),
|
||||||
|
],
|
||||||
|
path: "Benchmarks/FlexBuffersBenchmarks",
|
||||||
|
plugins: [
|
||||||
|
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
|
||||||
|
]),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -504,7 +504,6 @@ grpc::string GenerateInterface(grpc_generator::File* file,
|
|||||||
const grpc::string& filename) {
|
const grpc::string& filename) {
|
||||||
grpc::string output;
|
grpc::string output;
|
||||||
|
|
||||||
std::set<grpc::string> generated_functions;
|
|
||||||
std::map<grpc::string, grpc::string> vars;
|
std::map<grpc::string, grpc::string> vars;
|
||||||
|
|
||||||
vars["PATH"] = file->package();
|
vars["PATH"] = file->package();
|
||||||
|
|||||||
@@ -271,7 +271,7 @@ namespace flatbuffers {
|
|||||||
#if (defined(_MSC_VER) && _MSC_VER >= 1800) || \
|
#if (defined(_MSC_VER) && _MSC_VER >= 1800) || \
|
||||||
(defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__>= 26) || \
|
(defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__>= 26) || \
|
||||||
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \
|
(defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700)) && \
|
||||||
!defined(__Fuchsia__)
|
!defined(__Fuchsia__) && (!defined(__linux__) || defined(__GLIBC__))
|
||||||
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
|
#define FLATBUFFERS_LOCALE_INDEPENDENT 1
|
||||||
#else
|
#else
|
||||||
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
|
#define FLATBUFFERS_LOCALE_INDEPENDENT 0
|
||||||
|
|||||||
@@ -24,15 +24,14 @@ class handle:
|
|||||||
struct offset:
|
struct offset:
|
||||||
o:int
|
o:int
|
||||||
|
|
||||||
enum sizeof:
|
let sz_8 = 1
|
||||||
sz_8 = 1
|
let sz_16 = 2
|
||||||
sz_16 = 2
|
let sz_32 = 4
|
||||||
sz_32 = 4
|
let sz_64 = 8
|
||||||
sz_64 = 8
|
let sz_voffset = 2
|
||||||
sz_voffset = 2
|
let sz_uoffset = 4
|
||||||
sz_uoffset = 4
|
let sz_soffset = 4
|
||||||
sz_soffset = 4
|
let sz_metadata_fields = 2
|
||||||
sz_metadata_fields = 2
|
|
||||||
|
|
||||||
class builder:
|
class builder:
|
||||||
buf = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
buf = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
|||||||
@@ -722,8 +722,6 @@ void BinaryAnnotator::BuildTable(const uint64_t table_offset,
|
|||||||
BinaryRegionComment offset_field_comment;
|
BinaryRegionComment offset_field_comment;
|
||||||
offset_field_comment.type = BinaryRegionCommentType::TableOffsetField;
|
offset_field_comment.type = BinaryRegionCommentType::TableOffsetField;
|
||||||
offset_field_comment.name = field->name()->c_str();
|
offset_field_comment.name = field->name()->c_str();
|
||||||
const std::string offset_prefix =
|
|
||||||
"offset to field `" + std::string(field->name()->c_str()) + "`";
|
|
||||||
|
|
||||||
// Validate any field that isn't inline (i.e., non-structs).
|
// Validate any field that isn't inline (i.e., non-structs).
|
||||||
if (!IsInlineField(field)) {
|
if (!IsInlineField(field)) {
|
||||||
|
|||||||
+1
-3
@@ -404,7 +404,7 @@ class CppGenerator : public BaseGenerator {
|
|||||||
code_ += "struct {{STRUCT_NAME}}BinarySchema {";
|
code_ += "struct {{STRUCT_NAME}}BinarySchema {";
|
||||||
code_ += " static const uint8_t *data() {";
|
code_ += " static const uint8_t *data() {";
|
||||||
code_ += " // Buffer containing the binary schema.";
|
code_ += " // Buffer containing the binary schema.";
|
||||||
code_ += " static const uint8_t bfbsData[" +
|
code_ += " alignas(uint64_t) static const uint8_t bfbsData[" +
|
||||||
NumToString(parser_.builder_.GetSize()) + "] = {";
|
NumToString(parser_.builder_.GetSize()) + "] = {";
|
||||||
code_ += binary_schema_hex_text;
|
code_ += binary_schema_hex_text;
|
||||||
code_ += " };";
|
code_ += " };";
|
||||||
@@ -2737,7 +2737,6 @@ class CppGenerator : public BaseGenerator {
|
|||||||
if (!field.IsScalarOptional()) {
|
if (!field.IsScalarOptional()) {
|
||||||
const bool is_scalar = IsScalar(type.base_type);
|
const bool is_scalar = IsScalar(type.base_type);
|
||||||
std::string accessor;
|
std::string accessor;
|
||||||
std::string offset_size = "";
|
|
||||||
if (is_scalar) {
|
if (is_scalar) {
|
||||||
accessor = "GetField<";
|
accessor = "GetField<";
|
||||||
} else if (IsStruct(type)) {
|
} else if (IsStruct(type)) {
|
||||||
@@ -2815,7 +2814,6 @@ class CppGenerator : public BaseGenerator {
|
|||||||
|
|
||||||
void GenTableFieldType(const FieldDef& field) {
|
void GenTableFieldType(const FieldDef& field) {
|
||||||
const auto& type = field.value.type;
|
const auto& type = field.value.type;
|
||||||
const auto offset_str = GenFieldOffsetName(field);
|
|
||||||
if (!field.IsScalarOptional()) {
|
if (!field.IsScalarOptional()) {
|
||||||
std::string afterptr = " *" + NullableExtension();
|
std::string afterptr = " *" + NullableExtension();
|
||||||
code_.SetValue("FIELD_TYPE",
|
code_.SetValue("FIELD_TYPE",
|
||||||
|
|||||||
+6
-27
@@ -654,34 +654,15 @@ class DartGenerator : public BaseGenerator {
|
|||||||
|
|
||||||
std::string NamespaceAliasFromUnionType(Namespace* root_namespace,
|
std::string NamespaceAliasFromUnionType(Namespace* root_namespace,
|
||||||
const Type& type) {
|
const Type& type) {
|
||||||
const std::vector<std::string> qualified_name_parts =
|
const Namespace& type_namespace = *type.struct_def->defined_namespace;
|
||||||
type.struct_def->defined_namespace->components;
|
if (root_namespace->components == type_namespace.components) {
|
||||||
if (std::equal(root_namespace->components.begin(),
|
|
||||||
root_namespace->components.end(),
|
|
||||||
qualified_name_parts.begin())) {
|
|
||||||
return namer_.Type(*type.struct_def);
|
return namer_.Type(*type.struct_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ns;
|
const std::string ns = namer_.Namespace(type_namespace);
|
||||||
|
return ns.empty()
|
||||||
for (auto it = qualified_name_parts.begin();
|
? namer_.Type(*type.struct_def)
|
||||||
it != qualified_name_parts.end(); ++it) {
|
: ImportAliasName(ns) + "." + namer_.Type(*type.struct_def);
|
||||||
auto& part = *it;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < part.length(); i++) {
|
|
||||||
if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) {
|
|
||||||
ns += "_";
|
|
||||||
ns += CharToLower(part[i]);
|
|
||||||
} else {
|
|
||||||
ns += CharToLower(part[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (it != qualified_name_parts.end() - 1) {
|
|
||||||
ns += "_";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ns + "." + namer_.Type(*type.struct_def);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenImplementationGetters(
|
void GenImplementationGetters(
|
||||||
@@ -1168,8 +1149,6 @@ static bool GenerateDart(const Parser& parser, const std::string& path,
|
|||||||
|
|
||||||
static std::string DartMakeRule(const Parser& parser, const std::string& path,
|
static std::string DartMakeRule(const Parser& parser, const std::string& path,
|
||||||
const std::string& file_name) {
|
const std::string& file_name) {
|
||||||
auto filebase =
|
|
||||||
flatbuffers::StripPath(flatbuffers::StripExtension(file_name));
|
|
||||||
dart::DartGenerator generator(parser, path, file_name);
|
dart::DartGenerator generator(parser, path, file_name);
|
||||||
auto make_rule = generator.Filename("") + ": ";
|
auto make_rule = generator.Filename("") + ": ";
|
||||||
|
|
||||||
|
|||||||
@@ -966,8 +966,6 @@ class KotlinGenerator : public BaseGenerator {
|
|||||||
auto bbgetter = ByteBufferGetter(field.value.type, "bb");
|
auto bbgetter = ByteBufferGetter(field.value.type, "bb");
|
||||||
auto ucast = CastToUsigned(field);
|
auto ucast = CastToUsigned(field);
|
||||||
auto offset_val = NumToString(field.value.offset);
|
auto offset_val = NumToString(field.value.offset);
|
||||||
auto offset_prefix =
|
|
||||||
"val o = __offset(" + offset_val + "); return o != 0 ? ";
|
|
||||||
auto value_base_type = field.value.type.base_type;
|
auto value_base_type = field.value.type.base_type;
|
||||||
// Most field accessors need to retrieve and test the field offset
|
// Most field accessors need to retrieve and test the field offset
|
||||||
// first, this is the offset value for that:
|
// first, this is the offset value for that:
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ class KotlinKMPGenerator : public BaseGenerator {
|
|||||||
|
|
||||||
std::string code =
|
std::string code =
|
||||||
"// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
|
"// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
|
||||||
auto qualified = ns.GetFullyQualifiedName("");
|
|
||||||
std::string namespace_name = namer_.Namespace(ns);
|
std::string namespace_name = namer_.Namespace(ns);
|
||||||
if (!namespace_name.empty()) {
|
if (!namespace_name.empty()) {
|
||||||
code += "package " + namespace_name;
|
code += "package " + namespace_name;
|
||||||
@@ -341,7 +340,6 @@ class KotlinKMPGenerator : public BaseGenerator {
|
|||||||
std::string GenDefaultBufferValue(const FieldDef& field) const {
|
std::string GenDefaultBufferValue(const FieldDef& field) const {
|
||||||
auto& value = field.value;
|
auto& value = field.value;
|
||||||
auto base_type = value.type.base_type;
|
auto base_type = value.type.base_type;
|
||||||
auto field_name = field.name;
|
|
||||||
std::string suffix = IsScalar(base_type) ? LiteralSuffix(value.type) : "";
|
std::string suffix = IsScalar(base_type) ? LiteralSuffix(value.type) : "";
|
||||||
if (field.IsScalarOptional()) {
|
if (field.IsScalarOptional()) {
|
||||||
return "null";
|
return "null";
|
||||||
@@ -373,7 +371,6 @@ class KotlinKMPGenerator : public BaseGenerator {
|
|||||||
std::string GenDefaultValue(const FieldDef& field) const {
|
std::string GenDefaultValue(const FieldDef& field) const {
|
||||||
auto& value = field.value;
|
auto& value = field.value;
|
||||||
auto base_type = value.type.base_type;
|
auto base_type = value.type.base_type;
|
||||||
auto field_name = field.name;
|
|
||||||
std::string suffix = LiteralSuffix(value.type);
|
std::string suffix = LiteralSuffix(value.type);
|
||||||
if (field.IsScalarOptional()) {
|
if (field.IsScalarOptional()) {
|
||||||
return "null";
|
return "null";
|
||||||
@@ -1082,8 +1079,6 @@ class KotlinKMPGenerator : public BaseGenerator {
|
|||||||
auto return_type = GetterReturnType(field);
|
auto return_type = GetterReturnType(field);
|
||||||
auto bbgetter = ByteBufferGetter(field.value.type, "bb");
|
auto bbgetter = ByteBufferGetter(field.value.type, "bb");
|
||||||
auto offset_val = NumToString(field.value.offset);
|
auto offset_val = NumToString(field.value.offset);
|
||||||
auto offset_prefix =
|
|
||||||
"val o = offset(" + offset_val + "); return o != 0 ? ";
|
|
||||||
auto value_base_type = field.value.type.base_type;
|
auto value_base_type = field.value.type.base_type;
|
||||||
// Most field accessors need to retrieve and test the field offset
|
// Most field accessors need to retrieve and test the field offset
|
||||||
// first, this is the offset value for that:
|
// first, this is the offset value for that:
|
||||||
|
|||||||
@@ -2010,8 +2010,6 @@ class PythonGenerator : public BaseGenerator {
|
|||||||
void InitializeFromPackedBuf(const StructDef& struct_def,
|
void InitializeFromPackedBuf(const StructDef& struct_def,
|
||||||
std::string* code_ptr) const {
|
std::string* code_ptr) const {
|
||||||
auto& code = *code_ptr;
|
auto& code = *code_ptr;
|
||||||
const auto struct_var = namer_.Variable(struct_def);
|
|
||||||
const auto struct_type = namer_.Type(struct_def);
|
|
||||||
|
|
||||||
code += GenIndents(1) + "@classmethod";
|
code += GenIndents(1) + "@classmethod";
|
||||||
code += GenIndents(1) + "def InitFromPackedBuf(cls, buf, pos=0):";
|
code += GenIndents(1) + "def InitFromPackedBuf(cls, buf, pos=0):";
|
||||||
|
|||||||
@@ -787,7 +787,6 @@ class SwiftGenerator : public BaseGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GenTableReaderFields(const FieldDef& field) {
|
void GenTableReaderFields(const FieldDef& field) {
|
||||||
const auto offset = NumToString(field.value.offset);
|
|
||||||
const auto field_field = namer_.Field(field);
|
const auto field_field = namer_.Field(field);
|
||||||
const auto type = GenType(field.value.type);
|
const auto type = GenType(field.value.type);
|
||||||
code_.SetValue("FIELDVAR", namer_.Variable(field));
|
code_.SetValue("FIELDVAR", namer_.Variable(field));
|
||||||
@@ -1382,7 +1381,6 @@ class SwiftGenerator : public BaseGenerator {
|
|||||||
const auto& field = **it;
|
const auto& field = **it;
|
||||||
if (field.deprecated) continue;
|
if (field.deprecated) continue;
|
||||||
|
|
||||||
const auto type = GenType(field.value.type);
|
|
||||||
code_.SetValue("FIELDVAR", namer_.Variable(field));
|
code_.SetValue("FIELDVAR", namer_.Variable(field));
|
||||||
if (IsArray(field.value.type)) {
|
if (IsArray(field.value.type)) {
|
||||||
code_.SetValue(
|
code_.SetValue(
|
||||||
|
|||||||
@@ -196,7 +196,6 @@ class TsGenerator : public BaseGenerator {
|
|||||||
SkipDir::OutputPathAndTrailingPathSeparator);
|
SkipDir::OutputPathAndTrailingPathSeparator);
|
||||||
symbolic_name = definition.defined_namespace->components.back();
|
symbolic_name = definition.defined_namespace->components.back();
|
||||||
} else {
|
} else {
|
||||||
auto def_mod_name = namer_.File(definition, SkipFile::SuffixAndExtension);
|
|
||||||
symbolic_name = file_name_;
|
symbolic_name = file_name_;
|
||||||
filepath = path_ + symbolic_name + ".ts";
|
filepath = path_ + symbolic_name + ".ts";
|
||||||
}
|
}
|
||||||
@@ -286,12 +285,10 @@ class TsGenerator : public BaseGenerator {
|
|||||||
auto base_name =
|
auto base_name =
|
||||||
namer_.Directories(it.second.ns->components, SkipDir::OutputPath) +
|
namer_.Directories(it.second.ns->components, SkipDir::OutputPath) +
|
||||||
base_file_name;
|
base_file_name;
|
||||||
auto ts_file_path = base_name + ".ts";
|
|
||||||
auto base_name_rel = std::string("./");
|
auto base_name_rel = std::string("./");
|
||||||
base_name_rel +=
|
base_name_rel +=
|
||||||
namer_.Directories(rel_components, SkipDir::OutputPath);
|
namer_.Directories(rel_components, SkipDir::OutputPath);
|
||||||
base_name_rel += base_file_name;
|
base_name_rel += base_file_name;
|
||||||
auto ts_file_path_rel = base_name_rel + ".ts";
|
|
||||||
auto type_name = def.first;
|
auto type_name = def.first;
|
||||||
auto fully_qualified_type_name =
|
auto fully_qualified_type_name =
|
||||||
it.second.ns->GetFullyQualifiedName(type_name);
|
it.second.ns->GetFullyQualifiedName(type_name);
|
||||||
@@ -311,7 +308,6 @@ class TsGenerator : public BaseGenerator {
|
|||||||
const auto child_ns_level = it.second.ns->components.size() + 1;
|
const auto child_ns_level = it.second.ns->components.size() + 1;
|
||||||
for (const auto& it2 : ns_defs_) {
|
for (const auto& it2 : ns_defs_) {
|
||||||
if (it2.second.ns->components.size() != child_ns_level) continue;
|
if (it2.second.ns->components.size() != child_ns_level) continue;
|
||||||
auto ts_file_path = it2.second.path + ".ts";
|
|
||||||
code += "export * as " + it2.second.symbolic_name + " from './";
|
code += "export * as " + it2.second.symbolic_name + " from './";
|
||||||
int count = it2.second.ns->components.size() > 1 ? 2 : 1;
|
int count = it2.second.ns->components.size() > 1 ? 2 : 1;
|
||||||
std::vector<std::string> rel_path;
|
std::vector<std::string> rel_path;
|
||||||
@@ -1176,7 +1172,6 @@ class TsGenerator : public BaseGenerator {
|
|||||||
if (union_type.enum_def) {
|
if (union_type.enum_def) {
|
||||||
const auto& enum_def = *union_type.enum_def;
|
const auto& enum_def = *union_type.enum_def;
|
||||||
const auto enum_type = AddImport(imports, dependent, enum_def).name;
|
const auto enum_type = AddImport(imports, dependent, enum_def).name;
|
||||||
const std::string union_accessor = "this." + field_name;
|
|
||||||
|
|
||||||
const auto union_has_string = UnionHasStringType(enum_def);
|
const auto union_has_string = UnionHasStringType(enum_def);
|
||||||
const auto field_binded_method = "this." + field_name + ".bind(this)";
|
const auto field_binded_method = "this." + field_name + ".bind(this)";
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public let FileIdLength = 4
|
|||||||
/// Protocol that All Scalars should conform to
|
/// Protocol that All Scalars should conform to
|
||||||
///
|
///
|
||||||
/// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
|
/// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
|
||||||
public protocol Scalar: Equatable {
|
public protocol Scalar: Equatable, BitwiseCopyable {
|
||||||
associatedtype NumericValue
|
associatedtype NumericValue
|
||||||
var convertedEndian: NumericValue { get }
|
var convertedEndian: NumericValue { get }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
@usableFromInline
|
@usableFromInline
|
||||||
final class Storage {
|
final class Storage {
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
enum Blob {
|
@frozen enum Blob: ~Copyable {
|
||||||
#if !os(WASI)
|
#if !os(WASI)
|
||||||
case data(Data)
|
case data(Data)
|
||||||
case bytes(any ContiguousBytes)
|
case bytes(any ContiguousBytes)
|
||||||
@@ -36,6 +36,40 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
case byteBuffer(_InternalByteBuffer)
|
case byteBuffer(_InternalByteBuffer)
|
||||||
case array([UInt8])
|
case array([UInt8])
|
||||||
case pointer(UnsafeMutableRawPointer)
|
case pointer(UnsafeMutableRawPointer)
|
||||||
|
|
||||||
|
init(_ other: borrowing Blob) {
|
||||||
|
switch other {
|
||||||
|
#if !os(WASI)
|
||||||
|
case .data(let data):
|
||||||
|
self = .data(data)
|
||||||
|
case .bytes(let contiguousBytes):
|
||||||
|
self = .bytes(contiguousBytes)
|
||||||
|
#endif
|
||||||
|
case .byteBuffer(let internalByteBuffer):
|
||||||
|
self = .byteBuffer(internalByteBuffer)
|
||||||
|
case .array(let array):
|
||||||
|
self = .array(array)
|
||||||
|
case .pointer(let unsafeMutableRawPointer):
|
||||||
|
self = .pointer(unsafeMutableRawPointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
switch self {
|
||||||
|
#if !os(WASI)
|
||||||
|
case .data(let data):
|
||||||
|
"data: \(data)"
|
||||||
|
case .bytes(let contiguousBytes):
|
||||||
|
"bytes: \(contiguousBytes)"
|
||||||
|
#endif
|
||||||
|
case .byteBuffer(let internalByteBuffer):
|
||||||
|
"byteBuffer: \(internalByteBuffer)"
|
||||||
|
case .array(let array):
|
||||||
|
"array: \(array)"
|
||||||
|
case .pointer(let unsafeMutableRawPointer):
|
||||||
|
"pointer: \(unsafeMutableRawPointer)"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
|
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
|
||||||
@@ -44,7 +78,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
private let capacity: Int
|
private let capacity: Int
|
||||||
/// Retained blob of data that requires the storage to retain a pointer to.
|
/// Retained blob of data that requires the storage to retain a pointer to.
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
var retainedBlob: Blob
|
let retainedBlob: Blob
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(count: Int) {
|
init(count: Int) {
|
||||||
@@ -57,9 +91,9 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(blob: Blob, capacity count: Int) {
|
init(blob: borrowing Blob, capacity count: Int) {
|
||||||
capacity = count
|
capacity = count
|
||||||
retainedBlob = blob
|
retainedBlob = .init(blob)
|
||||||
isOwned = false
|
isOwned = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +184,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@inlinable
|
||||||
func readWithUnsafeRawPointer<T>(
|
func readWithUnsafeRawPointer<T>(
|
||||||
position: Int,
|
position: Int,
|
||||||
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
|
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
|
||||||
@@ -278,7 +313,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
/// - removeBytes: Removes a number of bytes from the current size
|
/// - removeBytes: Removes a number of bytes from the current size
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
init(
|
init(
|
||||||
blob: Storage.Blob,
|
blob: borrowing Storage.Blob,
|
||||||
count: Int,
|
count: Int,
|
||||||
removing removeBytes: Int)
|
removing removeBytes: Int)
|
||||||
{
|
{
|
||||||
@@ -318,7 +353,8 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
/// - def: Type of the object
|
/// - def: Type of the object
|
||||||
/// - position: the index of the object in the buffer
|
/// - position: the index of the object in the buffer
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public func read<T>(def: T.Type, position: Int) -> T {
|
@inlinable
|
||||||
|
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
|
||||||
_storage.readWithUnsafeRawPointer(position: position) {
|
_storage.readWithUnsafeRawPointer(position: position) {
|
||||||
$0.bindMemory(to: T.self, capacity: 1)
|
$0.bindMemory(to: T.self, capacity: 1)
|
||||||
.pointee
|
.pointee
|
||||||
@@ -412,7 +448,7 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
/// - Parameter removeBytes: the amount of bytes to remove from the current Size
|
/// - Parameter removeBytes: the amount of bytes to remove from the current Size
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
|
public func duplicate(removing removeBytes: Int = 0) -> ByteBuffer {
|
||||||
assert(removeBytes > 0, "Can NOT remove negative bytes")
|
assert(removeBytes >= 0, "Can NOT remove negative bytes")
|
||||||
assert(
|
assert(
|
||||||
removeBytes < capacity,
|
removeBytes < capacity,
|
||||||
"Can NOT remove more bytes than the ones allocated")
|
"Can NOT remove more bytes than the ones allocated")
|
||||||
@@ -464,8 +500,9 @@ public struct ByteBuffer: @unchecked Sendable {
|
|||||||
extension ByteBuffer: CustomDebugStringConvertible {
|
extension ByteBuffer: CustomDebugStringConvertible {
|
||||||
|
|
||||||
public var debugDescription: String {
|
public var debugDescription: String {
|
||||||
"""
|
let blobDescription = _storage.retainedBlob.description
|
||||||
buffer located at: \(_storage.retainedBlob),
|
return """
|
||||||
|
buffer located at: \(blobDescription),
|
||||||
with capacity of \(capacity),
|
with capacity of \(capacity),
|
||||||
{ writtenSize: \(_readerIndex), readerSize: \(reader),
|
{ writtenSize: \(_readerIndex), readerSize: \(reader),
|
||||||
size: \(size) }
|
size: \(size) }
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ public struct FlatBufferBuilder {
|
|||||||
/// A check to see if finish(::) was ever called to retreive data object
|
/// A check to see if finish(::) was ever called to retreive data object
|
||||||
private(set) var finished = false
|
private(set) var finished = false
|
||||||
/// A check to see if the buffer should serialize Default values
|
/// A check to see if the buffer should serialize Default values
|
||||||
private var serializeDefaults: Bool
|
@usableFromInline
|
||||||
|
let serializeDefaults: Bool
|
||||||
|
|
||||||
/// Current alignment for the buffer
|
/// Current alignment for the buffer
|
||||||
var _minAlignment: Int = 0 {
|
var _minAlignment: Int = 0 {
|
||||||
@@ -756,6 +757,7 @@ public struct FlatBufferBuilder {
|
|||||||
/// - offset: ``Offset`` of another object to be written
|
/// - offset: ``Offset`` of another object to be written
|
||||||
/// - position: The predefined position of the object
|
/// - position: The predefined position of the object
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@inlinable
|
||||||
mutating public func add(offset: Offset, at position: VOffset) {
|
mutating public func add(offset: Offset, at position: VOffset) {
|
||||||
if offset.isEmpty { return }
|
if offset.isEmpty { return }
|
||||||
add(element: refer(to: offset.o), def: 0, at: position)
|
add(element: refer(to: offset.o), def: 0, at: position)
|
||||||
@@ -794,6 +796,7 @@ public struct FlatBufferBuilder {
|
|||||||
/// - def: Default value for that element
|
/// - def: Default value for that element
|
||||||
/// - position: The predefined position of the element
|
/// - position: The predefined position of the element
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@inlinable
|
||||||
mutating public func add<T: Scalar>(
|
mutating public func add<T: Scalar>(
|
||||||
element: T,
|
element: T,
|
||||||
def: T,
|
def: T,
|
||||||
@@ -813,6 +816,7 @@ public struct FlatBufferBuilder {
|
|||||||
/// - element: Optional element of type scalar
|
/// - element: Optional element of type scalar
|
||||||
/// - position: The predefined position of the element
|
/// - position: The predefined position of the element
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@inlinable
|
||||||
mutating public func add<T: Scalar>(element: T?, at position: VOffset) {
|
mutating public func add<T: Scalar>(element: T?, at position: VOffset) {
|
||||||
guard let element = element else { return }
|
guard let element = element else { return }
|
||||||
track(offset: push(element: element), at: position)
|
track(offset: push(element: element), at: position)
|
||||||
@@ -825,6 +829,7 @@ public struct FlatBufferBuilder {
|
|||||||
/// - Parameter element: Element to insert
|
/// - Parameter element: Element to insert
|
||||||
/// - returns: position of the Element
|
/// - returns: position of the Element
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@inlinable
|
||||||
@discardableResult
|
@discardableResult
|
||||||
mutating public func push<T: Scalar>(element: T) -> UOffset {
|
mutating public func push<T: Scalar>(element: T) -> UOffset {
|
||||||
let size = MemoryLayout<T>.size
|
let size = MemoryLayout<T>.size
|
||||||
@@ -836,7 +841,8 @@ public struct FlatBufferBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public func read<T>(def: T.Type, position: Int) -> T {
|
@inlinable
|
||||||
|
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
|
||||||
_bb.read(def: def, position: position)
|
_bb.read(def: def, position: position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import Foundation
|
|||||||
|
|
||||||
/// NativeStruct is a protocol that indicates if the struct is a native `swift` struct
|
/// NativeStruct is a protocol that indicates if the struct is a native `swift` struct
|
||||||
/// since now we will be serializing native structs into the buffer.
|
/// since now we will be serializing native structs into the buffer.
|
||||||
public protocol NativeStruct {}
|
public protocol NativeStruct: BitwiseCopyable {}
|
||||||
|
|
||||||
public protocol FlatBufferVerifiableNativeStruct: NativeStruct, Verifiable {}
|
public protocol FlatBufferVerifiableNativeStruct: NativeStruct, Verifiable {}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,30 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
|
private func verifySizePrefix(
|
||||||
|
byteBuffer: inout ByteBuffer,
|
||||||
|
requireExactSize: Bool,
|
||||||
|
options: VerifierOptions) throws
|
||||||
|
{
|
||||||
|
let verifier = try Verifier(buffer: &byteBuffer, options: options)
|
||||||
|
let prefixPosition = byteBuffer.reader
|
||||||
|
let prefix: UOffset = try verifier.getValue(at: prefixPosition)
|
||||||
|
let availableSize = byteBuffer.size &- UOffset(MemoryLayout<UOffset>.size)
|
||||||
|
|
||||||
|
if requireExactSize {
|
||||||
|
guard prefix == availableSize else {
|
||||||
|
throw FlatbuffersErrors.prefixedSizeNotEqualToBufferSize
|
||||||
|
}
|
||||||
|
} else if prefix > availableSize {
|
||||||
|
throw FlatbuffersErrors.outOfBounds(
|
||||||
|
position: UInt(prefixPosition)
|
||||||
|
&+ UInt(MemoryLayout<UOffset>.size)
|
||||||
|
&+ UInt(prefix),
|
||||||
|
end: byteBuffer.capacity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Takes in a prefixed sized buffer, where the prefixed size would be skipped.
|
/// Takes in a prefixed sized buffer, where the prefixed size would be skipped.
|
||||||
/// And would verify that the buffer passed is a valid `Flatbuffers` Object.
|
/// And would verify that the buffer passed is a valid `Flatbuffers` Object.
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
@@ -31,6 +55,10 @@ public func getPrefixedSizeCheckedRoot<T: FlatBufferTable & Verifiable>(
|
|||||||
fileId: String? = nil,
|
fileId: String? = nil,
|
||||||
options: VerifierOptions = .init()) throws -> T
|
options: VerifierOptions = .init()) throws -> T
|
||||||
{
|
{
|
||||||
|
try verifySizePrefix(
|
||||||
|
byteBuffer: &byteBuffer,
|
||||||
|
requireExactSize: false,
|
||||||
|
options: options)
|
||||||
byteBuffer.skipPrefix()
|
byteBuffer.skipPrefix()
|
||||||
return try getCheckedRoot(
|
return try getCheckedRoot(
|
||||||
byteBuffer: &byteBuffer,
|
byteBuffer: &byteBuffer,
|
||||||
@@ -53,10 +81,11 @@ public func getCheckedPrefixedSizeRoot<T: FlatBufferTable & Verifiable>(
|
|||||||
fileId: String? = nil,
|
fileId: String? = nil,
|
||||||
options: VerifierOptions = .init()) throws -> T
|
options: VerifierOptions = .init()) throws -> T
|
||||||
{
|
{
|
||||||
let prefix = byteBuffer.skipPrefix()
|
try verifySizePrefix(
|
||||||
if prefix != byteBuffer.size {
|
byteBuffer: &byteBuffer,
|
||||||
throw FlatbuffersErrors.prefixedSizeNotEqualToBufferSize
|
requireExactSize: true,
|
||||||
}
|
options: options)
|
||||||
|
byteBuffer.skipPrefix()
|
||||||
return try getCheckedRoot(
|
return try getCheckedRoot(
|
||||||
byteBuffer: &byteBuffer,
|
byteBuffer: &byteBuffer,
|
||||||
fileId: fileId,
|
fileId: fileId,
|
||||||
@@ -95,14 +124,15 @@ public func getCheckedRoot<T: FlatBufferTable & Verifiable>(
|
|||||||
options: VerifierOptions = .init()) throws -> T
|
options: VerifierOptions = .init()) throws -> T
|
||||||
{
|
{
|
||||||
var verifier = try Verifier(buffer: &byteBuffer, options: options)
|
var verifier = try Verifier(buffer: &byteBuffer, options: options)
|
||||||
|
let rootPosition = byteBuffer.reader
|
||||||
if let fileId = fileId {
|
if let fileId = fileId {
|
||||||
try verifier.verify(id: fileId)
|
try verifier.verify(id: fileId, at: rootPosition)
|
||||||
}
|
}
|
||||||
try ForwardOffset<T>.verify(&verifier, at: 0, of: T.self)
|
try ForwardOffset<T>.verify(&verifier, at: rootPosition, of: T.self)
|
||||||
return T.init(
|
return T.init(
|
||||||
byteBuffer,
|
byteBuffer,
|
||||||
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader))
|
o: Int32(byteBuffer.read(def: UOffset.self, position: rootPosition))
|
||||||
&+ Int32(byteBuffer.reader))
|
&+ Int32(rootPosition))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a `NON-Checked` flatbuffers object
|
/// Returns a `NON-Checked` flatbuffers object
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public struct Table {
|
|||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - type: Type of Element that needs to be read from the buffer
|
/// - type: Type of Element that needs to be read from the buffer
|
||||||
/// - o: Offset of the Element
|
/// - o: Offset of the Element
|
||||||
public func readBuffer<T>(of type: T.Type, at o: Int32) -> T {
|
public func readBuffer<T: BitwiseCopyable>(of type: T.Type, at o: Int32) -> T {
|
||||||
bb.read(def: T.self, position: Int(o &+ position))
|
bb.read(def: T.self, position: Int(o &+ position))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,15 @@ extension Verifiable {
|
|||||||
let len: UOffset = try verifier.getValue(at: position)
|
let len: UOffset = try verifier.getValue(at: position)
|
||||||
let intLen = Int(len)
|
let intLen = Int(len)
|
||||||
let start = Int(clamping: (position &+ MemoryLayout<Int32>.size).magnitude)
|
let start = Int(clamping: (position &+ MemoryLayout<Int32>.size).magnitude)
|
||||||
|
let byteCount = intLen.multipliedReportingOverflow(
|
||||||
|
by: MemoryLayout<T>.size)
|
||||||
|
guard !byteCount.overflow else {
|
||||||
|
throw FlatbuffersErrors.outOfBounds(
|
||||||
|
position: UInt.max,
|
||||||
|
end: verifier.capacity)
|
||||||
|
}
|
||||||
try verifier.isAligned(position: start, type: type.self)
|
try verifier.isAligned(position: start, type: type.self)
|
||||||
try verifier.rangeInBuffer(position: start, size: intLen)
|
try verifier.rangeInBuffer(position: start, size: byteCount.partialValue)
|
||||||
return (start, intLen)
|
return (start, intLen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ public struct Verifier {
|
|||||||
/// - Parameter position: Current position to be read
|
/// - Parameter position: Current position to be read
|
||||||
/// - Throws: `inBuffer` errors
|
/// - Throws: `inBuffer` errors
|
||||||
/// - Returns: a value of type `T` usually a `VTable` or a table offset
|
/// - Returns: a value of type `T` usually a `VTable` or a table offset
|
||||||
internal func getValue<T>(at position: Int) throws -> T {
|
internal func getValue<T: BitwiseCopyable>(at position: Int) throws -> T {
|
||||||
try inBuffer(position: position, of: T.self)
|
try inBuffer(position: position, of: T.self)
|
||||||
return _buffer.read(def: T.self, position: position)
|
return _buffer.read(def: T.self, position: position)
|
||||||
}
|
}
|
||||||
@@ -215,12 +215,16 @@ public struct Verifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
func verify(id: String) throws {
|
func verify(id: String, at position: Int) throws {
|
||||||
let size = MemoryLayout<Int32>.size
|
let size = MemoryLayout<Int32>.size
|
||||||
guard storage.capacity >= (size &* 2) else {
|
guard
|
||||||
|
position >= 0,
|
||||||
|
position <= storage.capacity,
|
||||||
|
storage.capacity - position >= size &* 2
|
||||||
|
else {
|
||||||
throw FlatbuffersErrors.bufferDoesntContainID
|
throw FlatbuffersErrors.bufferDoesntContainID
|
||||||
}
|
}
|
||||||
let str = _buffer.readString(at: size, count: size)
|
let str = _buffer.readString(at: position &+ size, count: size)
|
||||||
if id == str {
|
if id == str {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ struct _InternalByteBuffer {
|
|||||||
@usableFromInline
|
@usableFromInline
|
||||||
final class Storage {
|
final class Storage {
|
||||||
/// pointer to the start of the buffer object in memory
|
/// pointer to the start of the buffer object in memory
|
||||||
private(set) var memory: UnsafeMutableRawPointer
|
@exclusivity(unchecked) private(set) var memory: UnsafeMutableRawPointer
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(count: Int, alignment: Int) {
|
init(count: Int, alignment: Int) {
|
||||||
@@ -333,6 +333,7 @@ struct _InternalByteBuffer {
|
|||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
|
@usableFromInline
|
||||||
func readWithUnsafeRawPointer<T>(
|
func readWithUnsafeRawPointer<T>(
|
||||||
position: Int,
|
position: Int,
|
||||||
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
|
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public struct ByteBuffer {
|
|||||||
@usableFromInline
|
@usableFromInline
|
||||||
final class Storage {
|
final class Storage {
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
enum Blob {
|
@frozen enum Blob: ~Copyable {
|
||||||
#if !os(WASI)
|
#if !os(WASI)
|
||||||
case data(Data)
|
case data(Data)
|
||||||
case bytes(any ContiguousBytes)
|
case bytes(any ContiguousBytes)
|
||||||
@@ -36,6 +36,23 @@ public struct ByteBuffer {
|
|||||||
case byteBuffer(_InternalByteBuffer)
|
case byteBuffer(_InternalByteBuffer)
|
||||||
case array([UInt8])
|
case array([UInt8])
|
||||||
case pointer(UnsafeMutableRawPointer)
|
case pointer(UnsafeMutableRawPointer)
|
||||||
|
|
||||||
|
init(_ other: borrowing Blob) {
|
||||||
|
switch other {
|
||||||
|
#if !os(WASI)
|
||||||
|
case .data(let data):
|
||||||
|
self = .data(data)
|
||||||
|
case .bytes(let contiguousBytes):
|
||||||
|
self = .bytes(contiguousBytes)
|
||||||
|
#endif
|
||||||
|
case .byteBuffer(let internalByteBuffer):
|
||||||
|
self = .byteBuffer(internalByteBuffer)
|
||||||
|
case .array(let array):
|
||||||
|
self = .array(array)
|
||||||
|
case .pointer(let unsafeMutableRawPointer):
|
||||||
|
self = .pointer(unsafeMutableRawPointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
|
/// This storage doesn't own the memory, therefore, we won't deallocate on deinit.
|
||||||
@@ -44,7 +61,7 @@ public struct ByteBuffer {
|
|||||||
private let capacity: Int
|
private let capacity: Int
|
||||||
/// Retained blob of data that requires the storage to retain a pointer to.
|
/// Retained blob of data that requires the storage to retain a pointer to.
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
var retainedBlob: Blob
|
let retainedBlob: Blob
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(count: Int) {
|
init(count: Int) {
|
||||||
@@ -57,9 +74,9 @@ public struct ByteBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(blob: Blob, capacity count: Int) {
|
init(blob: borrowing Blob, capacity count: Int) {
|
||||||
capacity = count
|
capacity = count
|
||||||
retainedBlob = blob
|
retainedBlob = .init(blob)
|
||||||
isOwned = false
|
isOwned = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +293,7 @@ public struct ByteBuffer {
|
|||||||
/// - removeBytes: Removes a number of bytes from the current size
|
/// - removeBytes: Removes a number of bytes from the current size
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
init(
|
init(
|
||||||
blob: Storage.Blob,
|
blob: borrowing Storage.Blob,
|
||||||
count: Int,
|
count: Int,
|
||||||
removing removeBytes: Int)
|
removing removeBytes: Int)
|
||||||
{
|
{
|
||||||
@@ -316,7 +333,7 @@ public struct ByteBuffer {
|
|||||||
/// - def: Type of the object
|
/// - def: Type of the object
|
||||||
/// - position: the index of the object in the buffer
|
/// - position: the index of the object in the buffer
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
public func read<T>(def: T.Type, position: Int) -> T {
|
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
|
||||||
_storage.readWithUnsafeRawPointer(position: position) {
|
_storage.readWithUnsafeRawPointer(position: position) {
|
||||||
$0.bindMemory(to: T.self, capacity: 1)
|
$0.bindMemory(to: T.self, capacity: 1)
|
||||||
.pointee
|
.pointee
|
||||||
@@ -360,10 +377,10 @@ public struct ByteBuffer {
|
|||||||
@inline(__always)
|
@inline(__always)
|
||||||
func readSizedScalar<
|
func readSizedScalar<
|
||||||
T: BinaryInteger,
|
T: BinaryInteger,
|
||||||
T1: BinaryInteger,
|
T1: BinaryInteger & BitwiseCopyable,
|
||||||
T2: BinaryInteger,
|
T2: BinaryInteger & BitwiseCopyable,
|
||||||
T3: BinaryInteger,
|
T3: BinaryInteger & BitwiseCopyable,
|
||||||
T4: BinaryInteger
|
T4: BinaryInteger & BitwiseCopyable
|
||||||
>(
|
>(
|
||||||
def: T.Type,
|
def: T.Type,
|
||||||
t1: T1.Type,
|
t1: T1.Type,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ struct _InternalByteBuffer {
|
|||||||
@usableFromInline
|
@usableFromInline
|
||||||
final class Storage {
|
final class Storage {
|
||||||
/// pointer to the start of the buffer object in memory
|
/// pointer to the start of the buffer object in memory
|
||||||
var memory: UnsafeMutableRawPointer
|
@exclusivity(unchecked) private(set) var memory: UnsafeMutableRawPointer
|
||||||
|
|
||||||
@usableFromInline
|
@usableFromInline
|
||||||
init(count: Int, alignment: Int) {
|
init(count: Int, alignment: Int) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Example {
|
|||||||
struct MonsterBinarySchema {
|
struct MonsterBinarySchema {
|
||||||
static const uint8_t *data() {
|
static const uint8_t *data() {
|
||||||
// Buffer containing the binary schema.
|
// Buffer containing the binary schema.
|
||||||
static const uint8_t bfbsData[14520] = {
|
alignas(uint64_t) static const uint8_t bfbsData[14520] = {
|
||||||
0x20,0x00,0x00,0x00,0x42,0x46,0x42,0x53,0x00,0x00,0x00,0x00,0x14,0x00,0x20,0x00,0x04,0x00,0x08,0x00,
|
0x20,0x00,0x00,0x00,0x42,0x46,0x42,0x53,0x00,0x00,0x00,0x00,0x14,0x00,0x20,0x00,0x04,0x00,0x08,0x00,
|
||||||
0x0C,0x00,0x10,0x00,0x14,0x00,0x18,0x00,0x00,0x00,0x1C,0x00,0x14,0x00,0x00,0x00,0x58,0x00,0x00,0x00,
|
0x0C,0x00,0x10,0x00,0x14,0x00,0x18,0x00,0x00,0x00,0x1C,0x00,0x14,0x00,0x00,0x00,0x58,0x00,0x00,0x00,
|
||||||
0x34,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x70,0x0D,0x00,0x00,0x08,0x00,0x00,0x00,
|
0x34,0x00,0x00,0x00,0x24,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x70,0x0D,0x00,0x00,0x08,0x00,0x00,0x00,
|
||||||
|
|||||||
@@ -373,6 +373,58 @@ final class FlatbuffersVerifierTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
func testSizePrefixedVerifierUsesPostPrefixRoot() throws {
|
||||||
|
// The size prefix points to a valid empty decoy table at byte 44. The real
|
||||||
|
// root at byte 4 points to a truncated UInt64 vector that must be rejected.
|
||||||
|
let bytes: [UInt8] = [
|
||||||
|
44, 0, 0, 0,
|
||||||
|
16, 0, 0, 0,
|
||||||
|
6, 0, 8, 0, 4, 0,
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
12, 0, 0, 0,
|
||||||
|
8, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
2, 0, 0, 0, 65, 66,
|
||||||
|
0, 0,
|
||||||
|
4, 0, 4, 0,
|
||||||
|
4, 0, 0, 0,
|
||||||
|
]
|
||||||
|
|
||||||
|
var strictBuffer = ByteBuffer(bytes: bytes)
|
||||||
|
#expect(throws: FlatbuffersErrors.self) {
|
||||||
|
try getCheckedPrefixedSizeRoot(
|
||||||
|
byteBuffer: &strictBuffer) as Swift_Tests_Vectors
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefixedBuffer = ByteBuffer(bytes: bytes)
|
||||||
|
#expect(throws: FlatbuffersErrors.self) {
|
||||||
|
try getPrefixedSizeCheckedRoot(
|
||||||
|
byteBuffer: &prefixedBuffer) as Swift_Tests_Vectors
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = FlatBufferBuilder()
|
||||||
|
let movie = Movie.createMovie(&builder)
|
||||||
|
Movie.finish(&builder, end: movie, prefix: true)
|
||||||
|
var validBuffer = builder.sizedBuffer
|
||||||
|
let _: Movie = try getCheckedPrefixedSizeRoot(
|
||||||
|
byteBuffer: &validBuffer,
|
||||||
|
fileId: Movie.id)
|
||||||
|
|
||||||
|
var shortBuffer = ByteBuffer(bytes: [0, 0, 0, 0])
|
||||||
|
#expect(throws: FlatbuffersErrors.bufferDoesntContainID) {
|
||||||
|
try getCheckedRoot(
|
||||||
|
byteBuffer: &shortBuffer,
|
||||||
|
fileId: Movie.id) as Movie
|
||||||
|
}
|
||||||
|
|
||||||
|
var oversizedPrefix = ByteBuffer(bytes: [5, 0, 0, 0, 0, 0, 0, 0])
|
||||||
|
#expect(throws: FlatbuffersErrors.outOfBounds(position: 9, end: 8)) {
|
||||||
|
try getPrefixedSizeCheckedRoot(
|
||||||
|
byteBuffer: &oversizedPrefix) as Movie
|
||||||
|
}
|
||||||
|
#expect(oversizedPrefix.reader == 0)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func testFullVerifier() throws {
|
func testFullVerifier() throws {
|
||||||
_ =
|
_ =
|
||||||
@@ -411,6 +463,27 @@ final class FlatbuffersVerifierTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(.bug("https://github.com/google/flatbuffers/issues/9082"))
|
||||||
|
func testRejectsTruncatedScalarVector() {
|
||||||
|
// swiftformat:disable all
|
||||||
|
var byteBuffer = ByteBuffer(bytes: [
|
||||||
|
16, 0, 0, 0,
|
||||||
|
6, 0, 8, 0,
|
||||||
|
4, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
12, 0, 0, 0,
|
||||||
|
8, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
2, 0, 0, 0,
|
||||||
|
65, 66,
|
||||||
|
])
|
||||||
|
// swiftformat:enable all
|
||||||
|
|
||||||
|
#expect(throws: FlatbuffersErrors.self) {
|
||||||
|
try getCheckedRoot(byteBuffer: &byteBuffer) as Swift_Tests_Vectors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
func testValidUnionBuffer() {
|
func testValidUnionBuffer() {
|
||||||
let string = "Awesome \\\\t\t\nstring!"
|
let string = "Awesome \\\\t\t\nstring!"
|
||||||
|
|||||||
Reference in New Issue
Block a user