Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor internals (NSLock to DispatchQueue) #39

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions Sources/Promissum/Promise.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ public class Promise<Value, Error> where Error: Swift.Error {
///
/// Example: `Promise<Int, Never>(value: 42)`
public init(value: Value) {
self.source = PromiseSource(value: value)
self.source = PromiseSource(state: .resolved(value), dispatchKey: DispatchSpecificKey(), dispatchMethod: .unspecified, warnUnresolvedDeinit: false)
}

/// Initialize a rejected Promise with an error.
///
/// Example: `Promise<Int, Error>(error: MyError(message: "Oops"))`
public init(error: Error) {
self.source = PromiseSource(error: error)
self.source = PromiseSource(state: .rejected(error), dispatchKey: DispatchSpecificKey(), dispatchMethod: .unspecified, warnUnresolvedDeinit: false)
}

internal init(source: PromiseSource<Value, Error>) {
Expand Down Expand Up @@ -300,7 +300,17 @@ public class Promise<Value, Error> where Error: Swift.Error {
warnUnresolvedDeinit: true
)

source.addOrCallResultHandler(resultSource.resolveResult)
let handler: (Result<Value, Error>) -> Void = { result in
switch result {
case .success(let value):
resultSource.resolve(value)

case .failure(let error):
resultSource.reject(error)
}
}

source.addOrCallResultHandler(handler)

return resultSource.promise
}
Expand Down Expand Up @@ -478,7 +488,7 @@ public class Promise<Value, Error> where Error: Swift.Error {
}

return source.promise
}
}
}
}

Expand Down
85 changes: 36 additions & 49 deletions Sources/Promissum/PromiseSource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,6 @@ public class PromiseSource<Value, Error> where Error: Swift.Error {
/// Print a warning on deinit of an unresolved PromiseSource
public var warnUnresolvedDeinit: Bool

// MARK: Initializers & deinit

internal convenience init(value: Value) {
self.init(state: .resolved(value), dispatchKey: DispatchSpecificKey(), dispatchMethod: .unspecified, warnUnresolvedDeinit: false)
}

internal convenience init(error: Error) {
self.init(state: .rejected(error), dispatchKey: DispatchSpecificKey(), dispatchMethod: .unspecified, warnUnresolvedDeinit: false)
}

/// Initialize a new Unresolved PromiseSource
///
/// - parameter warnUnresolvedDeinit: Print a warning on deinit of an unresolved PromiseSource
Expand Down Expand Up @@ -137,20 +127,19 @@ public class PromiseSource<Value, Error> where Error: Swift.Error {
///
/// When called on a PromiseSource that is already Resolved or Rejected, the call is ignored.
public func resolve(_ value: Value) {
resolveResult(.success(value))
if let action = internalState.resolve(with: .success(value)) {
callHandlers(action.handlers, with: action.result, dispatchKey: dispatchKey, dispatchMethod: dispatchMethod)
}
}


/// Reject an Unresolved PromiseSource with supplied error.
///
/// When called on a PromiseSource that is already Resolved or Rejected, the call is ignored.
public func reject(_ error: Error) {
resolveResult(.failure(error))
}

internal func resolveResult(_ result: Result<Value, Error>) {
let action = internalState.resolve(with: result)
callHandlers(action.handlers, with: action.result, dispatchKey: dispatchKey, dispatchMethod: dispatchMethod)
if let action = internalState.resolve(with: .failure(error)) {
callHandlers(action.handlers, with: action.result, dispatchKey: dispatchKey, dispatchMethod: dispatchMethod)
}
}

// MARK: Adding result handlers
Expand All @@ -171,7 +160,7 @@ extension PromiseSource {
}

fileprivate class PromiseSourceState {
private let lock = NSLock()
private let queue = DispatchQueue(label: "PromiseSource internal state queue")
private var state: State<Value, Error>
private var handlers: [ResultHandler] = []

Expand All @@ -180,44 +169,43 @@ extension PromiseSource {
}

internal func readState() -> State<Value, Error> {
lock.lock(); defer { lock.unlock() }

return state
return queue.sync {
return state
}
}

internal func resolve(with result: Result<Value, Error>) -> PromiseSourceAction {
lock.lock(); defer { lock.unlock() }
internal func resolve(with result: Result<Value, Error>) -> PromiseSourceAction? {
return queue.sync {
switch state {
case .unresolved:
state = result.state
let handlersToExecute = handlers
handlers = []

let handlersToExecute: [ResultHandler]
return PromiseSourceAction(result: result, handlers: handlersToExecute)

switch state {
case .unresolved:
state = result.state
handlersToExecute = handlers
handlers = []
default:
handlersToExecute = []
default:
return nil
}
}

return PromiseSourceAction(result: result, handlers: handlersToExecute)
}

internal func addHandler(_ handler: @escaping ResultHandler) -> PromiseSourceAction? {
lock.lock(); defer { lock.unlock() }

switch state {
case .unresolved:
// Save handler for later
handlers.append(handler)
return nil

case .resolved(let value):
// Value is already available, call handler immediately
return PromiseSourceAction(result: .success(value), handlers: [handler])

case .rejected(let error):
// Error is already available, call handler immediately
return PromiseSourceAction(result: .failure(error), handlers: [handler])
return queue.sync {
switch state {
case .unresolved:
// Save handler for later
handlers.append(handler)
return nil

case .resolved(let value):
// Value is already available, call handler immediately
return PromiseSourceAction(result: .success(value), handlers: [handler])

case .rejected(let error):
// Error is already available, call handler immediately
return PromiseSourceAction(result: .failure(error), handlers: [handler])
}
}
}
}
Expand All @@ -240,7 +228,6 @@ internal func callHandlers<T>(_ handlers: [(T) -> Void], with value: T, dispatch
}

case .synchronous:

handler(value)

case .queue(let targetQueue):
Expand Down