Repository: apple/swift-nio
File: Sources/NIOCore/EventLoop+SerialExecutor.swift (Swift)

Code before:
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
extension NIOSerialEventLoopExecutor {
    @inlinable
    public func enqueue(_ job: consuming ExecutorJob) {
        // By default we are just going to use execute to run the job
        // this is quite heavy since it allocates the closure for
        // every single job.
        let unownedJob = UnownedJob(job)
        self.execute {
            unownedJob.runSynchronously(on: self.asUnownedSerialExecutor())
        }
    }

    @inlinable
    public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
        UnownedSerialExecutor(ordinary: self)
    }

    @inlinable
    public var executor: any SerialExecutor {
        self
    }

    @available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
    @inlinable
    public func isSameExclusiveExecutionContext(other: Self) -> Bool {
        other === self
    }

    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
    @inlinable
    public func checkIsolated() {
        self.preconditionInEventLoop()
    }
}

/// A type that wraps a NIO ``EventLoop`` into a `SerialExecutor`
/// for use with Swift concurrency.
///
/// This type is not recommended for use because it risks problems with unowned
/// executors. Adopters are recommended to conform their own event loop
/// types to `SerialExecutor`.
final class NIODefaultSerialEventLoopExecutor {
    @usableFromInline
    let loop: EventLoop

    @inlinable
    init(_ loop: EventLoop) {
        self.loop = loop
    }
}

Review comment (suggestion):
This is not going to be called yet.

You must adjust `asUnownedSerialExecutor` to return `UnownedSerialExecutor` with the marker flag (there's a `complexEquality:` initializer.

Code after:
@available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
extension NIOSerialEventLoopExecutor {
    @inlinable
    public func enqueue(_ job: consuming ExecutorJob) {
        // By default we are just going to use execute to run the job
        // this is quite heavy since it allocates the closure for
        // every single job.
        let unownedJob = UnownedJob(job)
        self.execute {
            unownedJob.runSynchronously(on: self.asUnownedSerialExecutor())
        }
    }

    @inlinable
    public func asUnownedSerialExecutor() -> UnownedSerialExecutor {
        UnownedSerialExecutor(complexEquality: self)
    }

    @inlinable
    public var executor: any SerialExecutor {
        self
    }

    @available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *)
    @inlinable
    public func isSameExclusiveExecutionContext(other: Self) -> Bool {
        other === self
    }

    @available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *)
    @inlinable
    public func checkIsolated() {
        self.preconditionInEventLoop()
    }
}

/// A type that wraps a NIO ``EventLoop`` into a `SerialExecutor`
/// for use with Swift concurrency.
///
/// This type is not recommended for use because it risks problems with unowned
/// executors. Adopters are recommended to conform their own event loop
/// types to `SerialExecutor`.
final class NIODefaultSerialEventLoopExecutor {
    @usableFromInline
    let loop: EventLoop

    @inlinable
    init(_ loop: EventLoop) {
        self.loop = loop
    }
}