This commit is contained in:
2026-08-17 01:21:55 +02:00
parent 5761d6e67a
commit 4bd1e24e75
265 changed files with 20617 additions and 24457 deletions
+11 -48
View File
@@ -20,56 +20,22 @@ import Foundation
/// it allows users to write and read data directly from memory thus the use of its
/// functions should be used
@frozen
public struct ByteBuffer: @unchecked Sendable {
public struct ByteBuffer {
/// Storage is a container that would hold the memory pointer to solve the issue of
/// deallocating the memory that was held by (memory: UnsafeMutableRawPointer)
@usableFromInline
final class Storage {
@usableFromInline
@frozen enum Blob: ~Copyable {
enum Blob {
#if !os(WASI)
case data(Data)
case bytes(any ContiguousBytes)
case bytes(ContiguousBytes)
#endif
case byteBuffer(_InternalByteBuffer)
case array([UInt8])
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.
@@ -78,7 +44,7 @@ public struct ByteBuffer: @unchecked Sendable {
private let capacity: Int
/// Retained blob of data that requires the storage to retain a pointer to.
@usableFromInline
let retainedBlob: Blob
var retainedBlob: Blob
@usableFromInline
init(count: Int) {
@@ -91,9 +57,9 @@ public struct ByteBuffer: @unchecked Sendable {
}
@usableFromInline
init(blob: borrowing Blob, capacity count: Int) {
init(blob: Blob, capacity count: Int) {
capacity = count
retainedBlob = .init(blob)
retainedBlob = blob
isOwned = false
}
@@ -184,7 +150,6 @@ public struct ByteBuffer: @unchecked Sendable {
@discardableResult
@inline(__always)
@inlinable
func readWithUnsafeRawPointer<T>(
position: Int,
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T
@@ -313,7 +278,7 @@ public struct ByteBuffer: @unchecked Sendable {
/// - removeBytes: Removes a number of bytes from the current size
@inline(__always)
init(
blob: borrowing Storage.Blob,
blob: Storage.Blob,
count: Int,
removing removeBytes: Int)
{
@@ -353,8 +318,7 @@ public struct ByteBuffer: @unchecked Sendable {
/// - def: Type of the object
/// - position: the index of the object in the buffer
@inline(__always)
@inlinable
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
public func read<T>(def: T.Type, position: Int) -> T {
_storage.readWithUnsafeRawPointer(position: position) {
$0.bindMemory(to: T.self, capacity: 1)
.pointee
@@ -448,7 +412,7 @@ public struct ByteBuffer: @unchecked Sendable {
/// - Parameter removeBytes: the amount of bytes to remove from the current Size
@inline(__always)
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(
removeBytes < capacity,
"Can NOT remove more bytes than the ones allocated")
@@ -500,9 +464,8 @@ public struct ByteBuffer: @unchecked Sendable {
extension ByteBuffer: CustomDebugStringConvertible {
public var debugDescription: String {
let blobDescription = _storage.retainedBlob.description
return """
buffer located at: \(blobDescription),
"""
buffer located at: \(_storage.retainedBlob),
with capacity of \(capacity),
{ writtenSize: \(_readerIndex), readerSize: \(reader),
size: \(size) }
+1 -1
View File
@@ -23,7 +23,7 @@ import Common
/// Enum is a protocol that all flatbuffers enums should conform to
/// Since it allows us to get the actual `ByteSize` and `Value` from
/// a swift enum.
public protocol Enum: Sendable {
public protocol Enum {
/// associatedtype that the type of the enum should conform to
associatedtype T: Scalar & Verifiable
/// Size of the current associatedtype in the enum
@@ -45,10 +45,9 @@ public struct FlatBufferBuilder {
/// Dictonary that stores a map of all the strings that were written to the buffer
private var stringOffsetMap: [String: Offset] = [:]
/// A check to see if finish(::) was ever called to retreive data object
private(set) var finished = false
private var finished = false
/// A check to see if the buffer should serialize Default values
@usableFromInline
let serializeDefaults: Bool
private var serializeDefaults: Bool
/// Current alignment for the buffer
var _minAlignment: Int = 0 {
@@ -489,7 +488,7 @@ public struct FlatBufferBuilder {
///
/// - Parameter bytes: bytes to be written into the buffer
/// - Returns: ``Offset`` of the vector
mutating public func createVector(bytes: any ContiguousBytes) -> Offset {
mutating public func createVector(bytes: ContiguousBytes) -> Offset {
bytes.withUnsafeBytes {
startVector($0.count, elementSize: MemoryLayout<UInt8>.size)
_bb.push(bytes: $0)
@@ -757,7 +756,6 @@ public struct FlatBufferBuilder {
/// - offset: ``Offset`` of another object to be written
/// - position: The predefined position of the object
@inline(__always)
@inlinable
mutating public func add(offset: Offset, at position: VOffset) {
if offset.isEmpty { return }
add(element: refer(to: offset.o), def: 0, at: position)
@@ -796,7 +794,6 @@ public struct FlatBufferBuilder {
/// - def: Default value for that element
/// - position: The predefined position of the element
@inline(__always)
@inlinable
mutating public func add<T: Scalar>(
element: T,
def: T,
@@ -816,7 +813,6 @@ public struct FlatBufferBuilder {
/// - element: Optional element of type scalar
/// - position: The predefined position of the element
@inline(__always)
@inlinable
mutating public func add<T: Scalar>(element: T?, at position: VOffset) {
guard let element = element else { return }
track(offset: push(element: element), at: position)
@@ -829,7 +825,6 @@ public struct FlatBufferBuilder {
/// - Parameter element: Element to insert
/// - returns: position of the Element
@inline(__always)
@inlinable
@discardableResult
mutating public func push<T: Scalar>(element: T) -> UOffset {
let size = MemoryLayout<T>.size
@@ -841,8 +836,7 @@ public struct FlatBufferBuilder {
}
@inline(__always)
@inlinable
public func read<T: BitwiseCopyable>(def: T.Type, position: Int) -> T {
public func read<T>(def: T.Type, position: Int) -> T {
_bb.read(def: def, position: position)
}
}
@@ -18,9 +18,7 @@ import Foundation
/// 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.
public protocol NativeStruct: BitwiseCopyable {}
public protocol FlatBufferVerifiableNativeStruct: NativeStruct, Verifiable {}
public protocol NativeStruct {}
/// FlatbuffersInitializable is a protocol that allows any object to be
/// Initialized from a ByteBuffer
@@ -37,8 +35,6 @@ public protocol FlatBufferTable: FlatbuffersInitializable,
var __buffer: ByteBuffer! { get }
}
public protocol FlatBufferVerifiableTable: FlatBufferTable, Verifiable {}
/// FlatbufferStruct structures all the Flatbuffers structs
public protocol FlatBufferStruct: FlatbuffersInitializable,
FlatbuffersVectorInitializable
+30 -59
View File
@@ -16,52 +16,50 @@
import Foundation
enum FlatbuffersGRPCError: Error {
case finishedNotCalledOnBuilder
}
/// FlatBufferGRPCMessage protocol that should allow us to invoke
/// initializers directly from the GRPC generated code
public protocol FlatBufferGRPCMessage {
/// Size of readable bytes in the buffer
var size: Int { get }
public protocol GRPCVerifiableMessage<Message> {
associatedtype Message
init(pointer: UnsafeRawBufferPointer)
init(byteBuffer: ByteBuffer)
func decode() throws -> Message
func withUnsafeReadableBytes<Data>(
@discardableResult
@inline(__always)
func withUnsafeReadableBytes<T>(
_ body: (UnsafeRawBufferPointer) throws
-> Data) rethrows -> Data
-> T) rethrows -> T
}
public struct GRPCMessage<
Table: FlatBufferVerifiableTable
>: Sendable, GRPCVerifiableMessage {
public typealias Message = Table
/// Message is a wrapper around Buffers to to able to send Flatbuffers `Buffers` through the
/// GRPC library
public struct Message<T: FlatBufferTable>: FlatBufferGRPCMessage {
internal var buffer: ByteBuffer
private let buffer: ByteBuffer
/// Returns the an object of type T that would be read from the buffer
public var object: T {
T.init(
buffer,
o: Int32(buffer.read(def: UOffset.self, position: buffer.reader)) &+
Int32(buffer.reader))
}
public var size: Int { Int(buffer.size) }
public init(pointer: UnsafeRawBufferPointer) {
buffer = ByteBuffer(
copyingMemoryBound: pointer.baseAddress!,
capacity: pointer.count)
}
public init(builder: inout FlatBufferBuilder) throws {
guard builder.finished else {
throw FlatbuffersGRPCError.finishedNotCalledOnBuilder
}
buffer = builder.sizedBuffer
}
/// Initializes the message with the type Flatbuffer.Bytebuffer that is transmitted over
/// GRPC
/// - Parameter byteBuffer: Flatbuffer ByteBuffer object
public init(byteBuffer: ByteBuffer) {
buffer = byteBuffer
}
public func decode() throws -> Table {
var buf = buffer
return try getCheckedRoot(byteBuffer: &buf)
/// Initializes the message by copying the buffer to the message to be sent.
/// from the builder
/// - Parameter builder: FlatbufferBuilder that has the bytes created in
/// - Note: Use `builder.finish(offset)` before passing the builder without prefixing anything to it
public init(builder: inout FlatBufferBuilder) {
buffer = builder.sizedBuffer
builder.clear()
}
@discardableResult
@@ -75,30 +73,3 @@ public struct GRPCMessage<
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
public struct FlatBuffersMessageSerializer<
Message: GRPCVerifiableMessage
>: Sendable {
public init() {}
public func serialize<Data>(
message: Message,
_ completion: (UnsafeRawBufferPointer) throws -> Data) throws -> Data
{
return try message.withUnsafeReadableBytes {
try completion($0)
}
}
}
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
public struct FlatBuffersMessageDeserializer<
Message: GRPCVerifiableMessage
>: Sendable {
public init() {}
public func deserialize(pointer: UnsafeRawBufferPointer) throws -> Message {
Message.init(pointer: pointer)
}
}
+8 -38
View File
@@ -16,30 +16,6 @@
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.
/// And would verify that the buffer passed is a valid `Flatbuffers` Object.
/// - Parameters:
@@ -55,10 +31,6 @@ public func getPrefixedSizeCheckedRoot<T: FlatBufferTable & Verifiable>(
fileId: String? = nil,
options: VerifierOptions = .init()) throws -> T
{
try verifySizePrefix(
byteBuffer: &byteBuffer,
requireExactSize: false,
options: options)
byteBuffer.skipPrefix()
return try getCheckedRoot(
byteBuffer: &byteBuffer,
@@ -81,11 +53,10 @@ public func getCheckedPrefixedSizeRoot<T: FlatBufferTable & Verifiable>(
fileId: String? = nil,
options: VerifierOptions = .init()) throws -> T
{
try verifySizePrefix(
byteBuffer: &byteBuffer,
requireExactSize: true,
options: options)
byteBuffer.skipPrefix()
let prefix = byteBuffer.skipPrefix()
if prefix != byteBuffer.size {
throw FlatbuffersErrors.prefixedSizeNotEqualToBufferSize
}
return try getCheckedRoot(
byteBuffer: &byteBuffer,
fileId: fileId,
@@ -124,15 +95,14 @@ public func getCheckedRoot<T: FlatBufferTable & Verifiable>(
options: VerifierOptions = .init()) throws -> T
{
var verifier = try Verifier(buffer: &byteBuffer, options: options)
let rootPosition = byteBuffer.reader
if let fileId = fileId {
try verifier.verify(id: fileId, at: rootPosition)
try verifier.verify(id: fileId)
}
try ForwardOffset<T>.verify(&verifier, at: rootPosition, of: T.self)
try ForwardOffset<T>.verify(&verifier, at: 0, of: T.self)
return T.init(
byteBuffer,
o: Int32(byteBuffer.read(def: UOffset.self, position: rootPosition))
&+ Int32(rootPosition))
o: Int32(byteBuffer.read(def: UOffset.self, position: byteBuffer.reader))
&+ Int32(byteBuffer.reader))
}
/// Returns a `NON-Checked` flatbuffers object
+7 -7
View File
@@ -49,7 +49,7 @@ public struct Table {
/// the vtable
/// - Parameter o: current offset
/// - Returns: offset of field within buffer
public func offset(_ o: VOffset) -> Int32 {
public func offset(_ o: Int32) -> Int32 {
let vtable = position &- bb.read(def: Int32.self, position: Int(position))
return o
< bb
@@ -57,7 +57,7 @@ public struct Table {
? Int32(
bb.read(
def: Int16.self,
position: Int(vtable &+ Int32(o)))) : 0
position: Int(vtable &+ o))) : 0
}
/// Gets the indirect offset of the current stored object
@@ -82,7 +82,7 @@ public struct Table {
/// - Parameters:
/// - type: Type of Element that needs to be read from the buffer
/// - o: Offset of the Element
public func readBuffer<T: BitwiseCopyable>(of type: T.Type, at o: Int32) -> T {
public func readBuffer<T>(of type: T.Type, at o: Int32) -> T {
bb.read(def: T.self, position: Int(o &+ position))
}
@@ -106,13 +106,13 @@ public struct Table {
/// This should only be used by `Scalars`
/// - Parameter off: Readable offset
/// - Returns: Returns a vector of type [T]
public func getVector<T>(at off: VOffset) -> [T]? {
public func getVector<T>(at off: Int32) -> [T]? {
let o = offset(off)
guard o != 0 else { return nil }
return bb.readSlice(index: Int(vector(at: o)), count: Int(vector(count: o)))
}
public func vector<T>(at off: VOffset, byteSize: Int) -> FlatbufferVector<T> {
public func vector<T>(at off: Int32, byteSize: Int) -> FlatbufferVector<T> {
let off = offset(off)
return FlatbufferVector(
bb: bb,
@@ -122,7 +122,7 @@ public struct Table {
}
public func unionVector(
at off: VOffset,
at off: Int32,
byteSize: Int) -> UnionFlatbufferVector
{
let off = offset(off)
@@ -146,7 +146,7 @@ public struct Table {
/// - Returns: Returns a pointer to the underlying data
@inline(__always)
public func withUnsafePointerToSlice<T>(
at off: VOffset,
at off: Int32,
body: (UnsafeRawBufferPointer, Int) throws -> T) rethrows -> T?
{
let o = offset(off)
@@ -115,7 +115,7 @@ public struct TableVerifier {
unionKeyName: String,
fieldName: String,
required: Bool,
completion: (inout Verifier, T, Int) throws -> Void) throws
completion: @escaping (inout Verifier, T, Int) throws -> Void) throws
where T: UnionEnum
{
let keyPos = try dereference(key)
@@ -68,7 +68,7 @@ public struct FlatbufferVector<
}
extension FlatbufferVector: Encodable where Element: Encodable {
public func encode(to encoder: any Encoder) throws {
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
for element in self {
try container.encode(element)
@@ -49,8 +49,8 @@ public struct UnionFlatbufferVector {
public subscript(
position: Int,
Type: any FlatbuffersVectorInitializable
.Type) -> any FlatbuffersVectorInitializable
Type: FlatbuffersVectorInitializable
.Type) -> FlatbuffersVectorInitializable
{
guard position < count else {
fatalError(
+1 -8
View File
@@ -56,15 +56,8 @@ extension Verifiable {
let len: UOffset = try verifier.getValue(at: position)
let intLen = Int(len)
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.rangeInBuffer(position: start, size: byteCount.partialValue)
try verifier.rangeInBuffer(position: start, size: intLen)
return (start, intLen)
}
}
+4 -8
View File
@@ -163,7 +163,7 @@ public struct Verifier {
/// - Parameter position: Current position to be read
/// - Throws: `inBuffer` errors
/// - Returns: a value of type `T` usually a `VTable` or a table offset
internal func getValue<T: BitwiseCopyable>(at position: Int) throws -> T {
internal func getValue<T>(at position: Int) throws -> T {
try inBuffer(position: position, of: T.self)
return _buffer.read(def: T.self, position: position)
}
@@ -215,16 +215,12 @@ public struct Verifier {
}
@inline(__always)
func verify(id: String, at position: Int) throws {
func verify(id: String) throws {
let size = MemoryLayout<Int32>.size
guard
position >= 0,
position <= storage.capacity,
storage.capacity - position >= size &* 2
else {
guard storage.capacity >= (size &* 2) else {
throw FlatbuffersErrors.bufferDoesntContainID
}
let str = _buffer.readString(at: position &+ size, count: size)
let str = _buffer.readString(at: size, count: size)
if id == str {
return
}
@@ -30,7 +30,7 @@ struct _InternalByteBuffer {
@usableFromInline
final class Storage {
/// pointer to the start of the buffer object in memory
@exclusivity(unchecked) private(set) var memory: UnsafeMutableRawPointer
private(set) var memory: UnsafeMutableRawPointer
@usableFromInline
init(count: Int, alignment: Int) {
@@ -146,7 +146,7 @@ struct _InternalByteBuffer {
#if !os(WASI)
@inline(__always)
@usableFromInline
mutating func push(bytes: any ContiguousBytes) {
mutating func push(bytes: ContiguousBytes) {
bytes.withUnsafeBytes { ptr in
ensureSpace(size: ptr.count)
memcpy(
@@ -333,7 +333,6 @@ struct _InternalByteBuffer {
@discardableResult
@inline(__always)
@usableFromInline
func readWithUnsafeRawPointer<T>(
position: Int,
_ body: (UnsafeRawPointer) throws -> T) rethrows -> T