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

Syntactic Sugar #35

Open
wants to merge 4 commits into
base: develop
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
### Added

- Added CIHelper to run test on Linux but not on CI - [#33](https://github.com/FabrizioBrancati/Queuer/pull/33)
- Added syntactic sugar helpers to create and chain operations easier and faster, more info on how to use it [here](https://github.com/FabrizioBrancati/Queuer#syntactic-sugar)

## [3.0.1](https://github.com/FabrizioBrancati/Queuer/releases/tag/3.0.1) - No Loop No Party

Expand Down
10 changes: 9 additions & 1 deletion Sources/Queuer/Queuer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,11 @@ public class Queuer {

/// Blocks the current thread until all of the receiver’s queued and executing
/// `Operation`s finish executing.
public func waitUntilAllOperationsAreFinished() {
/// - Returns: Returns the current `Queuer` instance.
@discardableResult
public func waitUntilAllOperationsAreFinished() -> Queuer {
queue.waitUntilAllOperationsAreFinished()
return self
}
}

Expand Down Expand Up @@ -185,4 +188,9 @@ public extension Queuer {
}
addOperation(completionOperation)
}

@available(macOS 10.15, *)
func addBarrier(_ completionHandler: @escaping @Sendable () -> Void) {
queue.addBarrierBlock(completionHandler)
}
}
135 changes: 135 additions & 0 deletions Sources/Queuer/SyntacticSugar.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//
// SyntaxSugar.swift
// Queuer
//
// MIT License
//
// Copyright (c) 2017 - 2024 Fabrizio Brancati
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Foundation

public extension Queuer {
@discardableResult
func add(_ operation: Operation) -> Queuer {
addOperation(operation)
return self
}

@discardableResult
func maxConcurrentOperationCount(_ count: Int) -> Queuer {
maxConcurrentOperationCount = count
return self
}

@discardableResult
func qualityOfService(_ quality: QualityOfService) -> Queuer {
qualityOfService = quality
return self
}

@discardableResult
func completion(_ completion: @escaping () -> Void) -> Queuer {
addCompletionHandler(completion)
return self
}

@discardableResult
func chained(_ operations: Operation...) -> Queuer {
addChainedOperations(operations)
return self
}

// @discardableResult
// func chained(_ operations: Queuer...) -> Queuer {
// addChainedOperations(operations)
// return self
// }

@discardableResult
// func concurrent(to queue: Queuer = self,_ block: @escaping (_ operation: ConcurrentOperation) -> Void) -> Queuer {
func concurrent(_ block: @escaping (_ operation: ConcurrentOperation) -> Void) -> Queuer {
addOperation(ConcurrentOperation(executionBlock: block))
return self
}

@discardableResult
func group(_ group: ConcurrentOperation...) -> Queuer {
addOperation(GroupOperation(group))
return self
}

@available(macOS 13.0, iOS 16.0, *)
func barrier(_ block: @escaping @Sendable () -> Void) -> Queuer {
addBarrier(block)
return self
}

@available(macOS 13.0, iOS 16.0, *)
@discardableResult
func asyncWait<C>(_ time: C.Instant.Duration, tolerance: C.Instant.Duration? = nil, clock: C = ContinuousClock()) -> Queuer where C: Clock {
let operation = ConcurrentOperation()
operation.manualFinish = true
operation.manualRetry = true
operation.executionBlock { _ in
Task {
try? await Task.sleep<Never, Never>(for: time, tolerance: tolerance, clock: clock)
operation.finish()
}
}
add(operation)
return self
}

@discardableResult
func syncWait(_ time: TimeInterval) -> Queuer {
let operation = ConcurrentOperation { _ in
Thread.sleep(forTimeInterval: time)
}
add(operation)
return self
}
}

public extension ConcurrentOperation {
@discardableResult
func manualFinish(_ manualFinish: Bool = true) -> ConcurrentOperation {
self.manualFinish = manualFinish
return self
}

@discardableResult
func manualRetry(_ manualRetry: Bool = true) -> ConcurrentOperation {
self.manualRetry = manualRetry
return self
}

@discardableResult
func executionBlock(_ block: @escaping (_ operation: ConcurrentOperation) -> Void) -> ConcurrentOperation {
executionBlock = block
return self
}

@discardableResult
func maximumRetries(_ retries: Int) -> ConcurrentOperation {
maximumRetries = retries
return self
}
}
2 changes: 1 addition & 1 deletion Tests/QueuerTests/ConcurrentOperationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ final class ConcurrentOperationTests: XCTestCase {
if CIHelper.isNotRunningOnCI() {
let queue = Queuer(name: "ConcurrentOperationTestChainedRetry")
let testExpectation = expectation(description: "Chained Retry")
let order = OrderHelper()
let order = OrderHelper<Int>()

let concurrentOperation1 = ConcurrentOperation { operation in
Task {
Expand Down
6 changes: 3 additions & 3 deletions Tests/QueuerTests/Helpers/OrderHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@

import Foundation

actor OrderHelper {
var order: [Int] = []
actor OrderHelper<Element: Equatable> {
var order: [Element] = []

func append(_ element: Int) {
func append(_ element: Element) {
order.append(element)
}
}
113 changes: 113 additions & 0 deletions Tests/QueuerTests/SyntacticSugarTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//
// SyntaxSugarTests.swift
// Queuer
//
// MIT License
//
// Copyright (c) 2017 - 2024 Fabrizio Brancati
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Queuer
import XCTest

final class SyntaxSugarTests: XCTestCase {
func testComplexCaseOfSyntaxSugar() {
let testExpectation = expectation(description: "Complex Case Of Syntax Sugar")

var operations: [String] = []

let operation = ConcurrentOperation()
.manualFinish()
.manualRetry()
.maximumRetries(5)
.executionBlock { op in
operations.append("Operation 1")
op.finish()
}

let operation2 = ConcurrentOperation()
.manualRetry()
.maximumRetries(5)
.executionBlock { _ in
operations.append("Operation 2")
}

Queuer(name: "Queue")
.maxConcurrentOperationCount(1)
.waitUntilAllOperationsAreFinished()
.qualityOfService(.background)
.concurrent { _ in
operations.append("Concurrent 1")
}
.add(
ConcurrentOperation { _ in
operations.append("Add")
}
)
.completion {
operations.append("Step 1")
}
.chained(operation, operation2)
.completion {
operations.append("Step 2")
}
// .chained(.concurrent {}, operation2)
.concurrent { _ in
operations.append("Concurrent 2")
}
// .asyncWait(.seconds(1))
.barrier {
// operations.append("Barrier")
}
.chained(
ConcurrentOperation { _ in
operations.append("Chain 1")
},
ConcurrentOperation { _ in
operations.append("Chain 2")
}
)
// here you should have the value from the previous operations
.completion {
operations.append("Step 3")
}
.completion {
operations.append("Step 4")
}
.group(
ConcurrentOperation { _ in
operations.append("Group 1")
},
ConcurrentOperation { _ in
operations.append("Group 2")
}
)
.syncWait(1)
.completion {
operations.append("Finished")
testExpectation.fulfill()
}

waitForExpectations(timeout: 5) { error in
XCTAssertEqual(operations.count, 14)
XCTAssertNil(error)
}
}
}