Skip to content

Commit

Permalink
Merge pull request #1 from sideeffect-io/feature/task-extensions
Browse files Browse the repository at this point in the history
project: add task extensions
  • Loading branch information
twittemb authored Oct 13, 2022
2 parents 8ae6142 + baba499 commit 3dbaf34
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
**v0.2.0:**

- add static factory methods on `Task`

**v0.1.0:**

- Debouncer
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@

**Regulate** is entirely backed by Swift concurrency and limits the number of created `Tasks` to the minimum.

```swift
let regulator = Task.debounce(dueTime: .milliseconds(200)) { (value: Int) in
print(value)
}

// the created `regulator` can be used across `Tasks` and each call to `regulator.push(x)`
// will feed the regulation system

// the execution of the provided closure will be debounced and executed 200ms after the last call to `push(x)`
```

**Regulate** also provides SwiftUI helpers to regulate buttons and bindings out of the box.
You can give a look at the [Sample app](./Sample).

Expand Down
16 changes: 15 additions & 1 deletion Sources/Debouncer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@

import Foundation

public extension Task where Failure == Never {
/// Creates a `Regulator` that executes an output only after a specified time interval elapses between events
/// - Parameters:
/// - dueTime: the time the Debouncer should wait before executing the output
/// - output: the block to execute once the regulation is done
/// - Returns: the debounced regulator
static func debounce(
dueTime: DispatchTimeInterval,
output: @Sendable @escaping (Success) async -> Void
) -> some Regulator<Success> {
Debouncer(dueTime: dueTime, output: output)
}
}

/// Executes an output only after a specified time interval elapses between events
///
/// ```swift
Expand Down Expand Up @@ -79,7 +93,7 @@ public final class Debouncer<Value>: @unchecked Sendable, ObservableObject, Regu
/// A Regulator that executes the output only after a specified time interval elapses between events
/// - Parameters:
/// - dueTime: the time the Debouncer should wait before executing the output
/// - output: the block to execute once the regulationis done
/// - output: the block to execute once the regulation is done
public init(
dueTime: DispatchTimeInterval,
output: (@Sendable (Value) async -> Void)? = nil
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftUI/RegulatedButtonStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public struct RegulatedButtonStyle<R: Regulator<Void>>: PrimitiveButtonStyle {
regulator.dueTime = self.dueTime
regulator.output = { _ in configuration.trigger() }

if #available(iOS 15.0, *) {
if #available(iOS 15.0, macOS 12.0, *) {
return Button(role: configuration.role) {
regulator.push(())
} label: {
Expand Down
18 changes: 17 additions & 1 deletion Sources/Throttler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@

import Foundation

public extension Task where Failure == Never {
/// Creates a `Regulator` that executes the output with either the most-recent or first element
/// pushed in the Throttler in the specified time interval
/// - dueTime: the interval at which to find and emit either the most recent or the first element
/// - latest: true if output should be called with the most-recent element, false otherwise
/// - output: the block to execute once the regulation is done
/// - Returns: the throttled regulator
static func throttle(
dueTime: DispatchTimeInterval,
latest: Bool = true,
output: @Sendable @escaping (Success) async -> Void
) -> some Regulator<Success> {
Throttler(dueTime: dueTime, latest: latest, output: output)
}
}

/// Executes the output with either the most-recent or first element pushed in the Throttler in the specified time interval
///
/// ```swift
Expand Down Expand Up @@ -84,7 +100,7 @@ public final class Throttler<Value>: @unchecked Sendable, ObservableObject, Regu
/// - Parameters:
/// - dueTime: the interval at which to find and emit either the most recent or the first element
/// - latest: true if output should be called with the most-recent element, false otherwise
/// - output: the block to execute once the regulationis done
/// - output: the block to execute once the regulation is done
public init(
dueTime: DispatchTimeInterval,
latest: Bool = true,
Expand Down
2 changes: 1 addition & 1 deletion Tests/DebouncerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class DebouncerTests: XCTestCase {
let hasDebounced = expectation(description: "Has debounced a value")
let spy = Spy<Int>()

let sut = Debouncer<Int>(dueTime: .milliseconds(200)) { value in
let sut = Task.debounce(dueTime: .milliseconds(200)) { value in
await spy.push(value)
hasDebounced.fulfill()
}
Expand Down
6 changes: 3 additions & 3 deletions Tests/ThrottlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ final class ThrottlerTests: XCTestCase {

let spy = Spy<Int>()

let sut = Throttler<Int>(dueTime: .milliseconds(100), latest: false) { value in
let sut = Task.throttle(dueTime: .milliseconds(100), latest: false) { value in
await spy.push(value)
hasThrottledTwoValues.fulfill()
}
Expand All @@ -39,7 +39,7 @@ final class ThrottlerTests: XCTestCase {

let spy = Spy<Int>()

let sut = Throttler<Int>(dueTime: .milliseconds(100), latest: true) { value in
let sut = Task.throttle(dueTime: .milliseconds(100), latest: true) { value in
await spy.push(value)
hasThrottledTwoValues.fulfill()
}
Expand All @@ -63,7 +63,7 @@ final class ThrottlerTests: XCTestCase {

let spy = Spy<Int>()

let sut = Throttler<Int>(dueTime: .milliseconds(100), latest: true) { value in
let sut = Task.throttle(dueTime: .milliseconds(100), latest: true) { value in
await spy.push(value)
hasThrottledTwoValues.fulfill()
}
Expand Down

0 comments on commit 3dbaf34

Please sign in to comment.