-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from ra1028/1.4.0
1.4.0
- Loading branch information
Showing
15 changed files
with
259 additions
and
209 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,43 @@ | ||
/// Encapsulate the function and make it cancelable. | ||
/// A function will not be executed after canceling, except already in progress execution. | ||
final class CancelableProcedure<Value> { | ||
/// A Bool value indicating whether canceled. | ||
var isCanceled: Bool { | ||
return _isCanceled.value | ||
} | ||
|
||
private let _isCanceled: AtomicBool = false | ||
private var _execute: ((Value) -> Void)? | ||
|
||
/// Initialize with an arbitrary function. | ||
/// | ||
/// - Parameters: | ||
/// - execute: A function to be executed by calling `execute(with:)` until canceled. | ||
init(_ execute: @escaping (Value) -> Void) { | ||
_execute = execute | ||
} | ||
|
||
/// Synchronously execute the specified function. | ||
/// | ||
/// - Parameters: | ||
/// - value: A value to be pass to specified function. | ||
func execute(with value: @autoclosure () -> Value) { | ||
guard !isCanceled, let execute = _execute else { return } | ||
execute(value()) | ||
} | ||
|
||
/// Cancel the specified function. | ||
/// Cancellation does not affect already in progress execution. | ||
func cancel() { | ||
guard _isCanceled.compareAndSwapBarrier(old: false, new: true) else { return } | ||
_execute = nil | ||
} | ||
} | ||
|
||
extension CancelableProcedure where Value == Void { | ||
/// Synchronously execute the specified function. | ||
@inline(__always) | ||
func execute() { | ||
self.execute(with: ()) | ||
} | ||
} |
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,131 @@ | ||
import XCTest | ||
@testable import VueFlux | ||
@testable import VueFluxReactive | ||
|
||
private protocol CancelableProcedureProtocol { | ||
associatedtype Value | ||
|
||
var isCanceled: Bool { get } | ||
|
||
init(_ execute: @escaping (Value) -> Void) | ||
func execute(with value: @autoclosure () -> Value) | ||
func cancel() | ||
} | ||
|
||
extension VueFlux.CancelableProcedure: CancelableProcedureProtocol {} | ||
extension VueFluxReactive.CancelableProcedure: CancelableProcedureProtocol {} | ||
|
||
final class CancelableProcedureTests: XCTestCase { | ||
func testVoidProcedure() { | ||
func runTest<CancelableProcedure: CancelableProcedureProtocol>(for type: CancelableProcedure.Type) where CancelableProcedure.Value == Void { | ||
|
||
var value = 0 | ||
|
||
let procedure = CancelableProcedure { | ||
value += 1 | ||
} | ||
|
||
XCTAssertEqual(value, 0) | ||
|
||
procedure.execute(with: ()) | ||
|
||
XCTAssertEqual(value, 1) | ||
|
||
procedure.cancel() | ||
procedure.execute(with: ()) | ||
|
||
XCTAssertEqual(value, 1) | ||
|
||
procedure.cancel() | ||
procedure.execute(with: ()) | ||
|
||
XCTAssertEqual(value, 1) | ||
} | ||
|
||
runTest(for: VueFlux.CancelableProcedure<Void>.self) | ||
runTest(for: VueFluxReactive.CancelableProcedure<Void>.self) | ||
} | ||
|
||
func testValueWorkItem() { | ||
func runTest<CancelableProcedure: CancelableProcedureProtocol>(for type: CancelableProcedure.Type) where CancelableProcedure.Value == Int { | ||
var value = 0 | ||
|
||
let procedure = CancelableProcedure { int in | ||
value = int | ||
} | ||
|
||
XCTAssertEqual(value, 0) | ||
|
||
procedure.execute(with: 1) | ||
|
||
XCTAssertFalse(procedure.isCanceled) | ||
XCTAssertEqual(value, 1) | ||
|
||
procedure.cancel() | ||
procedure.execute(with: 2) | ||
|
||
XCTAssertTrue(procedure.isCanceled) | ||
XCTAssertEqual(value, 1) | ||
|
||
procedure.cancel() | ||
procedure.execute(with: 3) | ||
|
||
XCTAssertTrue(procedure.isCanceled) | ||
XCTAssertEqual(value, 1) | ||
} | ||
|
||
runTest(for: VueFlux.CancelableProcedure<Int>.self) | ||
runTest(for: VueFluxReactive.CancelableProcedure<Int>.self) | ||
} | ||
|
||
func testCancelProcedureAsync() { | ||
func runTest<CancelableProcedure: CancelableProcedureProtocol>(for type: CancelableProcedure.Type) where CancelableProcedure.Value == Int { | ||
let queue = DispatchQueue(label: "testCancelProcedureAsync") | ||
|
||
var value = 0 | ||
|
||
let expectation = self.expectation(description: "testCancelProcedureAsync") | ||
|
||
let procedure = CancelableProcedure { int in | ||
value = int | ||
} | ||
|
||
XCTAssertFalse(procedure.isCanceled) | ||
|
||
queue.suspend() | ||
|
||
queue.async { | ||
procedure.execute(with: 1) | ||
} | ||
|
||
procedure.cancel() | ||
queue.resume() | ||
|
||
queue.async(execute: expectation.fulfill) | ||
|
||
waitForExpectations(timeout: 1) { _ in | ||
XCTAssertTrue(procedure.isCanceled) | ||
XCTAssertEqual(value, 0) | ||
} | ||
} | ||
|
||
runTest(for: VueFlux.CancelableProcedure<Int>.self) | ||
runTest(for: VueFluxReactive.CancelableProcedure<Int>.self) | ||
} | ||
|
||
func testExecuteVoidProcedure() { | ||
var value = 0 | ||
let vueFluxProcedure = VueFlux.CancelableProcedure<Void> { | ||
value = 1 | ||
} | ||
|
||
let vueFluxReactiveProcedure = VueFluxReactive.CancelableProcedure<Void> { | ||
value = 2 | ||
} | ||
|
||
vueFluxProcedure.execute() | ||
vueFluxReactiveProcedure.execute() | ||
|
||
XCTAssertEqual(value, 2) | ||
} | ||
} |
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
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 |
---|---|---|
@@ -1,6 +1,6 @@ | ||
Pod::Spec.new do |spec| | ||
spec.name = 'VueFlux' | ||
spec.version = '1.3.1' | ||
spec.version = '1.4.0' | ||
spec.author = { 'ra1028' => '[email protected]' } | ||
spec.homepage = 'https://github.com/ra1028/VueFlux' | ||
spec.summary = 'Unidirectional State Management for Swift - Inspired by Vuex and Flux' | ||
|
Oops, something went wrong.