Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixed:
suggestion
+ autocorrection
+ reentrance
selection flash…
…. Added: `Lock` (again).
- Loading branch information
Showing
3 changed files
with
206 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//=----------------------------------------------------------------------------= | ||
// This source file is part of the DiffableTextViews open source project. | ||
// | ||
// Copyright (c) 2022 Oscar Byström Ericsson | ||
// Licensed under Apache License, Version 2.0 | ||
// | ||
// See http://www.apache.org/licenses/LICENSE-2.0 for license information. | ||
//=----------------------------------------------------------------------------= | ||
|
||
//*============================================================================* | ||
// MARK: * Lock | ||
//*============================================================================* | ||
|
||
@MainActor public final class Lock { | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: State | ||
//=------------------------------------------------------------------------= | ||
|
||
@usableFromInline private(set) var count: UInt = 0 | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Initializers | ||
//=------------------------------------------------------------------------= | ||
|
||
@inlinable public init() { } | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Accessors | ||
//=------------------------------------------------------------------------= | ||
|
||
@inlinable @inline(__always) | ||
public var isLocked: Bool { | ||
self.count != 0 | ||
} | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Transformations | ||
//=------------------------------------------------------------------------= | ||
|
||
@inlinable @inline(__always) func lock() { | ||
self.count += 1 | ||
} | ||
|
||
@inlinable @inline(__always) func open() { | ||
self.count -= 1 | ||
} | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Utilities | ||
//=------------------------------------------------------------------------= | ||
|
||
@inlinable public func perform(action: () throws -> Void) { | ||
self.lock(); try? action(); self.open() | ||
} | ||
|
||
@inlinable public func task(operation: @escaping () async throws -> Void) { | ||
_ = asynchronous(operation: operation) | ||
} | ||
|
||
@inlinable public func task(operation: @escaping () async throws -> Void) async { | ||
await asynchronous(operation: operation).value | ||
} | ||
|
||
@inlinable @inline(__always) @discardableResult func asynchronous( | ||
operation: @escaping () async throws -> Void) -> Task<Void, Never> { | ||
self.lock(); return Task { try? await operation(); self.open() } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
//=----------------------------------------------------------------------------= | ||
// This source file is part of the DiffableTextViews open source project. | ||
// | ||
// Copyright (c) 2022 Oscar Byström Ericsson | ||
// Licensed under Apache License, Version 2.0 | ||
// | ||
// See http://www.apache.org/licenses/LICENSE-2.0 for license information. | ||
//=----------------------------------------------------------------------------= | ||
#if DEBUG | ||
|
||
@testable import DiffableTextKit | ||
|
||
import XCTest | ||
|
||
//*============================================================================* | ||
// MARK: * Lock x Tests | ||
//*============================================================================* | ||
|
||
@MainActor final class LockTests: XCTestCase { | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: State | ||
//=------------------------------------------------------------------------= | ||
|
||
var lock = Lock() | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: State x Setup | ||
//=------------------------------------------------------------------------= | ||
|
||
override func setUp() { | ||
lock = Lock() | ||
} | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Tests x State | ||
//=------------------------------------------------------------------------= | ||
|
||
func testIsNotLockedByDefault() { | ||
XCTAssertFalse(lock.isLocked) | ||
} | ||
|
||
func testIsLockedIsSameAsCountIsZero() { | ||
XCTAssertFalse(lock.isLocked) | ||
XCTAssertEqual(lock.count, 0) | ||
|
||
lock.lock() | ||
XCTAssert(lock.isLocked) | ||
XCTAssertEqual(lock.count, 1) | ||
} | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Tests x Transformations | ||
//=------------------------------------------------------------------------= | ||
|
||
func testLockIncrementsCountOpenDecrementsCount() { | ||
XCTAssertEqual(lock.count, 0) | ||
|
||
lock.lock() | ||
lock.lock() | ||
lock.lock() | ||
|
||
XCTAssertEqual(lock.count, 3) | ||
|
||
lock.open() | ||
lock.open() | ||
lock.open() | ||
|
||
XCTAssertEqual(lock.count, 0) | ||
} | ||
|
||
//=------------------------------------------------------------------------= | ||
// MARK: Tests x Utilities | ||
//=------------------------------------------------------------------------= | ||
|
||
func testSynchronousActionLocksUntilCompletion() { | ||
XCTAssertFalse(lock.isLocked) | ||
//=--------------------------------------= | ||
// Start | ||
//=--------------------------------------= | ||
lock.perform { | ||
XCTAssert(self.lock.isLocked) | ||
} | ||
//=--------------------------------------= | ||
// End | ||
//=--------------------------------------= | ||
XCTAssertFalse(lock.isLocked) | ||
} | ||
|
||
func testAsynchronousOperationLocksUntilCompletion() async { | ||
XCTAssertFalse(lock.isLocked) | ||
//=--------------------------------------= | ||
// Start | ||
//=--------------------------------------= | ||
let task = lock.asynchronous { | ||
XCTAssert(self.lock.isLocked) // 2nd | ||
}; XCTAssert(self.lock.isLocked) // 1st | ||
|
||
await task.value | ||
//=--------------------------------------= | ||
// End | ||
//=--------------------------------------= | ||
XCTAssertFalse(lock.isLocked) | ||
} | ||
} | ||
|
||
#endif |