@@ -314,108 +314,3 @@ final class SerializedDatabase {
314314// It happens the job of SerializedDatabase is precisely to provide thread-safe
315315// access to `Database`.
316316extension SerializedDatabase : @unchecked Sendable { }
317-
318- // MARK: - Task Cancellation Support
319-
320- enum DatabaseAccessCancellationState : @unchecked Sendable {
321- // @unchecked Sendable because database is only accessed from its
322- // dispatch queue.
323- case notConnected
324- case connected( Database )
325- case cancelled
326- case expired
327- }
328-
329- typealias CancellableDatabaseAccess = Mutex < DatabaseAccessCancellationState >
330-
331- /// Supports Task cancellation in async database accesses.
332- ///
333- /// Usage:
334- ///
335- /// ```swift
336- /// let dbAccess = CancellableDatabaseAccess()
337- /// return try dbAccess.withCancellableContinuation { continuation in
338- /// asyncDatabaseAccess { db in
339- /// do {
340- /// let result = try dbAccess.inDatabase(db) {
341- /// // Perform database operations
342- /// }
343- /// continuation.resume(returning: result)
344- /// } catch {
345- /// continuation.resume(throwing: error)
346- /// }
347- /// }
348- /// }
349- /// ```
350- extension CancellableDatabaseAccess : DatabaseCancellable {
351- convenience init ( ) {
352- self . init ( . notConnected)
353- }
354-
355- func cancel( ) {
356- withLock { state in
357- switch state {
358- case let . connected( db) :
359- db. cancel ( )
360- state = . cancelled
361- case . notConnected:
362- state = . cancelled
363- case . cancelled, . expired:
364- break
365- }
366- }
367- }
368-
369- func withCancellableContinuation< Value> (
370- _ fn: ( UnsafeContinuation < Value , any Error > ) -> Void
371- ) async throws -> Value {
372- try await withTaskCancellationHandler {
373- try checkCancellation ( )
374- return try await withUnsafeThrowingContinuation { continuation in
375- fn ( continuation)
376- }
377- } onCancel: {
378- cancel ( )
379- }
380- }
381-
382- func checkCancellation( ) throws {
383- try withLock { state in
384- if case . cancelled = state {
385- throw CancellationError ( )
386- }
387- }
388- }
389-
390- /// Wraps a full database access with cancellation support. When this
391- /// method returns, the database is NOT cancelled.
392- func inDatabase< Value> ( _ db: Database , execute work: ( ) throws -> Value ) throws -> Value {
393- try withLock { state in
394- switch state {
395- case . connected, . expired:
396- fatalError ( " Can't use a CancellableDatabaseAccess twice " )
397- case . notConnected:
398- state = . connected( db)
399- case . cancelled:
400- throw CancellationError ( )
401- }
402- }
403-
404- return try throwingFirstError {
405- try work ( )
406- } finally: {
407- let cancelled = withLock { state in
408- if case . cancelled = state {
409- db. uncancel ( )
410- return true
411- } else {
412- state = . expired
413- return false
414- }
415- }
416- if cancelled {
417- throw CancellationError ( )
418- }
419- }
420- }
421- }
0 commit comments