Ah, I see what you mean. This should be fine then:
private enum Global {
static var lock: UnsafeMutablePointer<os_unfair_lock> = {
let pointer = UnsafeMutablePointer<os_unfair_lock>.allocate(capacity: 1)
pointer.initialize(to: os_unfair_lock())
return pointer
}()
static var lastSerialTask: Task<Void, Never>?
}
public extension Task where Success == Void, Failure == Never {
/// Serially dispatch async work from the context of the current executor.
///
/// Unlike `Task {}` and `Task.detached {}`, when run from the ``MainActor``, this method
/// guarantees that work will run in the order it was scheduled. Work scheduled from multiple
/// actors will be started in a FIFO order, though the usual asynchronous guarantees apply.
///
/// - Parameters:
/// - priority: The priority of the task. Pass `nil` to use the priority from `Task.currentPriority`.
/// - operation: The operation to perform.
nonisolated static func serial(priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Void) {
os_unfair_lock_lock(Global.lock)
let previousTask = Global.lastSerialTask
Global.lastSerialTask = Self.detached(priority: priority) {
await previousTask?.value
await operation()
}
os_unfair_lock_unlock(Global.lock)
}
}