field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraMediaWorkQueue.swift (1438B)


      1 import Foundation
      2 
      3 /// Cancelled work retains its physical slot until its operation returns.
      4 @MainActor
      5 final class TeraMediaWorkQueue {
      6   private struct Pending {
      7     let id: UUID
      8     let operation: @MainActor () async -> Void
      9   }
     10 
     11   private let limits: TeraMediaPresentationLimits
     12   private var active: [UUID: Task<Void, Never>] = [:]
     13   private var pending: [Pending] = []
     14 
     15   init(limits: TeraMediaPresentationLimits) {
     16     self.limits = limits
     17   }
     18 
     19   deinit { for task in active.values {
     20     task.cancel()
     21   } }
     22 
     23   var activeCount: Int {
     24     active.count
     25   }
     26 
     27   var queuedCount: Int {
     28     pending.count
     29   }
     30 
     31   func submit(id: UUID, operation: @escaping @MainActor () async -> Void) -> Bool {
     32     guard active[id] == nil, !pending.contains(where: { $0.id == id }),
     33       active.count < limits.workers || pending.count < limits.queuedRequests else { return false }
     34     pending.append(Pending(id: id, operation: operation))
     35     drain()
     36     return true
     37   }
     38 
     39   func cancel(id: UUID) {
     40     pending.removeAll { $0.id == id }
     41     active[id]?.cancel()
     42   }
     43 
     44   func cancelAll() {
     45     pending.removeAll()
     46     for task in active.values {
     47       task.cancel()
     48     }
     49   }
     50 
     51   private func drain() {
     52     while active.count < limits.workers, !pending.isEmpty {
     53       let work = pending.removeFirst()
     54       active[work.id] = Task { [weak self] in
     55         await work.operation()
     56         self?.active[work.id] = nil
     57         self?.drain()
     58       }
     59     }
     60   }
     61 }