[Swift] Migrate to swift 6.0 and Implements support gRPC v2 (#8983)

* Migrate to swift 6.0 & swift-gRPC 2.0

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

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

* Address PR comments regarding misspelling & proper method naming.
This commit is contained in:
mustiikhalil
2026-05-06 04:39:53 +02:00
committed by GitHub
parent a6979fe14a
commit e6bbb3d22e
48 changed files with 2538 additions and 1008 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@
import Foundation
public enum FlexBufferType: UInt64 {
public enum FlexBufferType: UInt64, Sendable {
case null = 0
/// Variable width signed integer: `Int8, Int16, Int32, Int64`
case int = 1

View File

@@ -17,7 +17,7 @@
import Foundation
@usableFromInline
enum BitWidth: UInt64, CaseIterable {
enum BitWidth: UInt64, CaseIterable, Sendable {
case w8 = 0
case w16 = 1
case w32 = 2

View File

@@ -20,10 +20,10 @@ import Foundation
import Common
#endif
public struct Value: Equatable {
public struct Value: Equatable, Sendable {
@usableFromInline
enum Union: Equatable {
enum Union: Equatable, Sendable {
case i(Int64)
case u(UInt64)
case f(Double)

View File

@@ -977,6 +977,9 @@ fileprivate struct Stack: RandomAccessCollection {
mutating func removeAll(keepingCapacity keepCapacity: Bool = false) {
count = 0
if !keepCapacity {
let ptr = storage.memory
defer { ptr.deallocate() }
capacity = Self.initialCapacity
storage.memory = UnsafeMutableRawPointer.allocate(
byteCount: capacity,