AsyncExtensions aims to mimic Swift Combine operators for async sequences.

Overview

AsyncExtensions

Build Status CombineExt supports Swift Package Manager (SPM)

AsyncExtensions provides a collection of operators, async sequences and async streams that mimics Combine behaviour.

The purpose is to be able to chain operators, just as you would do with any reactive programming framework:

AsyncSequences
    .Merge(sequence1, sequence2, sequence3)
    .prepend(0)
    .handleEvents(onElement: { print($0) }, onFinish: { print("Finished") })
    .scan("") { accumulator, element in accumulator + "\(element)" }
    .collect { print($0) }

Async Sequences

Async Streams

Operators

More operators and extensions are to come. Pull requests are of course welcome.

Async Sequences

Just

Just is an AsyncSequence that outputs a single value and finishes.

let justSequence = AsyncSequences.Just<Int>(1)
for try await element in justSequence {
    // will be called once with element = 1
}

Empty

Empty is an AsyncSequence that immediately finishes without emitting values.

let emptySequence = AsyncSequences.Empty<Int>()
for try await element in emptySequence {
    // will never be called
}

Fail

Fail is an AsyncSequence that outputs no elements and throws an error.

let failSequence = AsyncSequences.Fail<Int, Swift.Error>(error: NSError(domain: "", code: 1))
do {
    for try await element in failSequence {
        // will never be called
    }
} catch {
    // will catch `NSError(domain: "", code: 1)` here
}

From

From is an AsyncSequence that outputs elements from a traditional Sequence.

let fromSequence = AsyncSequences.From([1, 2, 3, 4, 5])

for await element in fromSequence {
    print(element) // will print 1 2 3 4 5
}

A variation offers to set an interval of time between each element.

let fromSequence = AsyncSequences.From([1, 2, 3, 4, 5], interval: .milliSeconds(10))

for await element in fromSequence {
    print(element) // will print 1 2 3 4 5 with an interval of 10ms between elements
}

Merge

Merge is an AsyncSequence that merges several async sequences respecting their temporality while being iterated over. When all the async sequences have finished, so too does the merged async sequence. If an async sequence fails, so too does the merged async sequence.

// 0.1ms   1ms    1.5ms   2ms     3ms     4.5ms
//  4       1       5      2       3        6

let asyncSequence1 = AsyncStream(Int.self, bufferingPolicy: .unbounded) { continuation in
    Task {
        try await Task.sleep(nanoseconds: 1_000_000)
        continuation.yield(1)
        try await Task.sleep(nanoseconds: 1_000_000)
        continuation.yield(2)
        try await Task.sleep(nanoseconds: 1_000_000)
        continuation.yield(3)
        continuation.finish()
    }
}

let asyncSequence2 = AsyncStream(Int.self, bufferingPolicy: .unbounded) { continuation in
    Task {
        try await Task.sleep(nanoseconds: 100_000)
        continuation.yield(4)
        try await Task.sleep(nanoseconds: 1_400_000)
        continuation.yield(5)
        try await Task.sleep(nanoseconds: 3_000_000)
        continuation.yield(6)
        continuation.finish()
    }
}

let mergedAsyncSequence = AsyncSequences.Merge(asyncSequence1, asyncSequence2)

for try await element in mergedAsyncSequence {
    print(element) // will print -> 4 1 5 2 3 6
}

Zip2

Zip2 is an AsyncSequence that combines the latest elements from two sequences according to their temporality and emits a tuple to the client. If any async sequence ends successfully or fails with an error, so too does the zipped async Sequence.

let asyncSequence1 = AsyncSequences.From([1, 2, 3, 4, 5])
let asyncSequence2 = AsyncSequences.From(["5", "4", "3", "2", "1"])

let zippedAsyncSequence = AsyncSequences.Zip2(asyncSequence1, asyncSequence2)

for try await element in zippedAsyncSequence {
    print(element) // will print -> (1, "5") (2, "4") (3, "3") (4, "2") (5, "1")
}

Zip3

Zip3 is an AsyncSequence that combines the latest elements from two sequences according to their temporality and emits a tuple to the client. If any async sequence ends successfully or fails with an error, so too does the zipped async Sequence.

let asyncSequence1 = AsyncSequences.From([1, 2, 3, 4, 5])
let asyncSequence2 = AsyncSequences.From(["5", "4", "3", "2", "1"])
let asyncSequence3 = AsyncSequences.From([true, false, true, false, true])

let zippedAsyncSequence = AsyncSequences.Zip3(asyncSequence1, asyncSequence2, asyncSequence3)

for try await element in zippedAsyncSequence {
    print(element) // will print -> (1, "5", true) (2, "4", false) (3, "3", true) (4, "2", false) (5, "1", true)
}

Zip

Zip is an AsyncSequence that combines the latest elements from several sequences according to their temporality and emits an array to the client. If any async sequence ends successfully or fails with an error, so too does the zipped async Sequence.

let asyncSequence1 = AsyncSequences.From([1, 2, 3])
let asyncSequence2 = AsyncSequences.From([1, 2, 3])
let asyncSequence3 = AsyncSequences.From([1, 2, 3])
let asyncSequence4 = AsyncSequences.From([1, 2, 3])
let asyncSequence5 = AsyncSequences.From([1, 2, 3])

let zippedAsyncSequence = AsyncSequences.Zip(asyncSequence1, asyncSequence2, asyncSequence3, asyncSequence4, asyncSequence5)

for try await element in zippedAsyncSequence {
    print(element) // will print -> [1, 1, 1, 1, 1] [2, 2, 2, 2, 2] [3, 3, 3, 3, 3]
}

Timer

Timer is an async sequence that repeatedly emits the current date on the given interval, with the given priority.

let timer = AsyncSequences.Timer(priority: .high, every: .seconds(1))

Task {
    for try await element in timer {
        print(element)
    }
}

// will print:
// 2022-03-06 19:31:22 +0000
// 2022-03-06 19:31:23 +0000
// 2022-03-06 19:31:24 +0000
// 2022-03-06 19:31:25 +0000
// 2022-03-06 19:31:26 +0000
// and will stop once timer.cancel() is called or the parent task is cancelled.

Async Streams

Passthrough

Passthrough is an async sequence in which one can send values over time.

let passthrough = AsyncStreams.Passthrough<Int>()

Task {
    for try await element in passthrough {
        print(element) // will print 1 2
    }
}

Task {
    for try await element in passthrough {
        print(element) // will print 1 2
    }
}

.. later in the application flow

passthrough.send(1)
passthrough.send(2)

CurrentValue

CurrentValue is an async sequence in which one can send values over time. The current value is always accessible as an instance variable. The current value is replayed for any new async loop.

let currentValue = AsyncStreams.CurrentValue<Int>(1)

Task {
    for try await element in currentValue {
        print(element) // will print 1 2
    }
}

Task {
    for try await element in currentValue {
        print(element) // will print 1 2
    }
}

.. later in the application flow

currentValue.send(2)

print(currentValue.element) // will print 2

Replay

Replayis an async sequence in which one can send values over time. Values are buffered in a FIFO fashion so they can be iterated over by new loops. When the bufferSize is outreached the oldest value is dropped.

let replay = AsyncStreams.Replay<Int>(bufferSize: 3)

(1...5).forEach { replay.send($0) }

for try await element in replay {
    print(element) // will print 3, 4, 5
}

Streamed

Streamed is a property wrapper that streams a property as an AsyncSequence. It is a structured concurrency equivalent to Combine @Published.

class Weather {
    @Streamed var temperature: Double
    init(temperature: Double) {
        self.temperature = temperature
    }
}

let weather = Weather(temperature: 20)
Task {
    for try await element in weather.$temperature {
        print ("Temperature now: \(element)")
    }
}

// ... later in the application flow

weather.temperature = 25

// will print:
// Temperature now: 20.0
// Temperature now: 25.0

Operators

Collect

collect(_:) iterates over each element of the AsyncSequence and give it to the async block.

let fromSequence = AsyncSequences.From([1, 2, 3])
fromSequence
    .collect { print($0) } // will print 1 2 3

Scan

scan(_:_:) transforms elements from the upstream async sequence by providing the current element to a closure along with the last value returned by the closure. Each intermediate value will be emitted in the downstream async sequence.

let sourceSequence = AsyncSequences.From([1, 2, 3, 4, 5])
let scannedSequence = sourceSequence.scan("") { accumulator, element in accumulator + "\(element)"}

for try await element in scannedSequence {
    print(element)
}

// will print:
1
12
123
1234
12345

SwitchToLatest

switchToLatest() re-emits elements sent by the most recently received async sequence. This operator applies only in the case where the upstream async sequence's Element is it-self an async sequence.

let sourceSequence = AsyncSequences.From([1, 2, 3])
let mappedSequence = sourceSequence.map { element in
	AsyncSequences.From(["a\(element)", "b\(element)"])
}
let switchedSequence = mappedSequence.switchToLatest()

for try await element in switchedSequence {
    print(element) // will print a3 b3
}

FlatMapLatest

flatMapLatest(_:) transforms the upstream async sequence elements into an async sequence and flattens the sequence of events from these multiple sources async sequences to appear as if they were coming from a single async sequence of events. Mapping to a new async sequence will cancel the task related to the previous one.

This operator is basically a shortcut for map() and switchToLatest().

let sourceSequence = AsyncSequences.From([1, 2, 3])
let flatMapLatestSequence = sourceSequence.flatMapLatest { element in
	AsyncSequences.From(["a\(element)", "b\(element)"])
}

for try await element in flatMapLatestSequence {
    print(element) // will print a3 b3
}

Prepend

prepend(_:) prepends an element to the upstream async sequence.

let sourceSequence = AsyncSequences.From([1, 2, 3])
let prependSequence = sourceSequence.prepend(0)

for try await element in prependSequence {
    print(element) // will print 0 1 2 3
}

HandleEvents

handleEvents(onStart:onElement:onCancel:onFinish) performs the specified closures when async sequences events occur.

let sourceSequence = AsyncSequences.From([1, 2, 3, 4, 5])
let handledSequence = sourceSequence.handleEvents {
   print("Begin iterating")
} onElement: { element in
   print("Element is \(element)")
} onCancel: {
   print("Cancelled")
} onFinish: { termination in
   print(termination)
}

for try await element in handledSequence {}

// will print:
// Begin iterating
// Element is 1
// Element is 2
// Element is 3
// Element is 4
// Element is 5
// finished

Assign

assign(to:on:) assigns each element from the async sequence to a property on an object.

class Root {
    var property: String = ""
}

let root = Root()
let fromSequence = AsyncSequences.From(["1", "2", "3"])
try await fromSequence.assign(to: \.property, on: root) // will set the property value to "1", "2", "3"

Multicast

multicast(_:) is useful when you have multiple client loops, but you want the upstream async sequence to only produce a single AsyncIterator.

let stream = AsyncStreams.Passthrough<(String, Int)>()
let multicastedAsyncSequence = ["First", "Second", "Third"]
    .asyncElements
    .map { ($0, Int.random(in: 0...100)) }
    .handleEvents(onElement: { print("AsyncSequence produces: ($0)") })
    .multicast(stream)

Task {
    try await multicastedAsyncSequence
        .collect { print ("Task 1 received: \($0)") }
}

Task {
    try await multicastedAsyncSequence
        .collect { print ("Task 2 received: \($0)") }
}

multicastedAsyncSequence.connect()

// will print:
// AsyncSequence produces: ("First", 78)
// Stream 2 received: ("First", 78)
// Stream 1 received: ("First", 78)
// AsyncSequence produces: ("Second", 98)
// Stream 2 received: ("Second", 98)
// Stream 1 received: ("Second", 98)
// AsyncSequence produces: ("Third", 61)
// Stream 2 received: ("Third", 61)
// Stream 1 received: ("Third", 61)

Share

share() shares the output of an upstream async sequence with multiple client loops. share() is effectively a shortcut for multicast(_:) using a Passthrough stream, with an implicit autoconnect().

let sharedAsyncSequence = AsyncSequences.From(["first", "second", "third"], interval: .seconds(1))
    .map { ($0, Int.random(in: 0...100)) }
    .handleEvents(onElement: { print("AsyncSequence produces: \($0)") })
    .share()

Task {
    try await sharedAsyncSequence
        .collect { print ("Task 1 received: \($0)") }
}

Task {
    try await sharedAsyncSequence
        .collect { print ("Task 2 received: \($0)") }
}

// will print:
// AsyncSequence produces: ("First", 78)
// Stream 2 received: ("First", 78)
// Stream 1 received: ("First", 78)
// AsyncSequence produces: ("Second", 98)
// Stream 2 received: ("Second", 98)
// Stream 1 received: ("Second", 98)
// AsyncSequence produces: ("Third", 61)
// Stream 2 received: ("Third", 61)
// Stream 1 received: ("Third", 61)

WithLatestFrom

withLatestFrom(_:) merges two async sequences into a single one by combining each value from self with the latest value from the other sequence, if any.

let seq1 = AsyncStreams.CurrentValue<Int>(1)
let seq2 = AsyncStreams.CurrentValue<String>("1")

let combinedSeq = seq1.withLatestFrom(seq2)

Task {
   for try await element in combinedSeq {
       print(element)
   }
}

seq1.send(2)
seq2.send("2")
seq1.send(3)

// will print:
(1, "1")
(2, "1")
(3, "2")

EraseToAnyAsyncSequence

eraseToAnyAsyncSequence() type-erases the async sequence into an AnyAsyncSequence.

Comments
  • [BUG] Latest Main branch commit breaks AsyncStreams (CurrentValue, Passthrough etc)

    [BUG] Latest Main branch commit breaks AsyncStreams (CurrentValue, Passthrough etc)

    Describe the bug I noticed a code behavior change since adding the actor code. For example, I use Passthrough as a way to pass events to an onReceive method. That stopped as it supposed the moment I updated to the updated main. The best I can describe the behavior is that fires once and then stops working after that.

    To Reproduce Steps to reproduce the behavior:

    var events = AsyncStreams.Passthrough<Event>()
    
    // I used 
    events.nonBlockingSend(.myEvent)
    

    then

    
    // I have a modifier that wraps this in SwiftUI (onReceive)
    task {
     do {
             for try await event in viewModel.events {
                   switch event {
                       ...
                   }
             }
         } catch {}
    }
    
    

    Expected behavior AsyncStreams works like the commit e4aeb0f and before.

    Environment:

    • Main

    ** Additional Info **

    I'm not sure how to really explain what is going on here. This is the best I can do.

    bug 
    opened by Prince2k3 8
  • Swift Concurrency warning flags

    Swift Concurrency warning flags

    Q: Is there a reason you're not yet using the warnings to help ensure accuracy?

    .target(
      ...,
      swiftSettings: [
        .unsafeFlags([
          "-Xfrontend", "-warn-concurrency",
          "-Xfrontend", "-enable-actor-data-race-checks",
        ])
      ]
    )
    

    Perhaps it shouldn't be shipped that way, perhaps adding a new target just for development?

    (Fantastic library, btw)

    opened by rjchatfield 3
  • made element public

    made element public

    Description

    This change makes element property in CurrentValue public

    Checklist

    • [X] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [X] the commits inside this PR have explicit commit messages
    • [X] unit tests cover the new feature or the bug fix
    • [X] the feature is documented in the README.md if it makes sense
    • [X] the CHANGELOG is up-to-date
    opened by Prince2k3 2
  • Fix typo in README.md

    Fix typo in README.md

    Description

    Fix typo: Suject -> Subject

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [ ] unit tests cover the new feature or the bug fix
    • [ ] the feature is documented in the README.md if it makes sense
    • [ ] the CHANGELOG is up-to-date
    opened by jordanekay 1
  • project: bump CHANGELOG for 0.3.0

    project: bump CHANGELOG for 0.3.0

    Description

    This PR supports the release of the version 0.3.0 Beryllium

    Checklist

    • [X] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [X] the commits inside this PR have explicit commit messages
    • [X] unit tests cover the new feature or the bug fix
    • [X] the feature is documented in the README.md if it makes sense
    • [X] the CHANGELOG is up-to-date
    opened by twittemb 1
  • operators: handle errors in other for withLatestFrom

    operators: handle errors in other for withLatestFrom

    Description

    This PR improves the error management for withLatestFrom when the other sequence fails.

    Checklist

    • [X] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [X] the commits inside this PR have explicit commit messages
    • [X] unit tests cover the new feature or the bug fix
    • [X] the feature is documented in the README.md if it makes sense
    • [X] the CHANGELOG is up-to-date
    opened by twittemb 1
  • asyncSequences: Add Timer AsyncSequence

    asyncSequences: Add Timer AsyncSequence

    Description

    This PR brings a new Timer AsyncSequence. Timer is an async sequence that repeatedly emits the current date on the given interval, with the given priority.

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [x] unit tests cover the new feature or the bug fix
    • [x] the feature is documented in the README.md if it makes sense
    • [x] the CHANGELOG is up-to-date
    opened by twittemb 1
  • operators: add a Share operator

    operators: add a Share operator

    Description

    This PR adds the share() operator, which is a shortcut for multicast(_:) using a Passthrough stream.

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [x] unit tests cover the new feature or the bug fix
    • [x] the feature is documented in the README.md if it makes sense
    • [x] the CHANGELOG is up-to-date
    opened by twittemb 1
  • project: fix onNext scheduling in ConcurrentAccessRegulator

    project: fix onNext scheduling in ConcurrentAccessRegulator

    Description

    This PR fixes a potential issue where the onNext function could be called in non deterministic order.

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [x] unit tests cover the new feature or the bug fix
    • [x] the feature is documented in the README.md if it makes sense
    • [x] the CHANGELOG is up-to-date
    opened by twittemb 1
  • project: fix Multicast link in README

    project: fix Multicast link in README

    Description

    This PR fixes the broken Multicast link in the README file.

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [x] unit tests cover the new feature or the bug fix
    • [x] the feature is documented in the README.md if it makes sense
    • [x] the CHANGELOG is up-to-date
    opened by twittemb 1
  • project: make streams async (using actors) + improve concurrent iterators

    project: make streams async (using actors) + improve concurrent iterators

    Description

    make streams async (using actors) + improve concurrent iterators

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [x] unit tests cover the new feature or the bug fix
    • [x] the feature is documented in the README.md if it makes sense
    • [x] the CHANGELOG is up-to-date
    opened by twittemb 1
  • Avoid sharing schemes with library users

    Avoid sharing schemes with library users

    Description

    When consuming this library as a dependency in my project, I noticed Xcode autogenerated a scheme for the library among my local schemes, which is not desirable behavior.

    As a workaround, this PR gitignores .swiftpm altogether and introduces an xcworkspace as a scheme container that disallows SPM from leaking schemes onto consumers.

    Libraries as big as TCA use this approach to effectively hide away all its schemes (and subdependency schemes) from users.

    Checklist

    • [x] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [x] the commits inside this PR have explicit commit messages
    • [x] ~~unit tests cover the new feature or the bug fix~~
    • [x] ~~the feature is documented in the README.md if it makes sense~~
    • [ ] the CHANGELOG is up-to-date
    opened by davdroman 3
  • flatMapLatest + Just issues

    flatMapLatest + Just issues

    I don't know if I'm writing an issue or a feature request or just question. I have the following scenario, very simplified:

    let root = CurrentValue(false)
    let results = root.flatMapLatest {
        $0 ? Just(...).eraseToAnyAsyncSequence() : AsyncStream { ... }.eraseToAnyAsyncSequence()
    }
    
    // later...
    for await result in results { ... }
    fatalError()
    

    I put the fatalError after the loop because as I see it, root never completes and so we'd never reach that point. However, whenever the condition becomes true and we use Just, collection of results also exits. Now I have a few questions:

    • Is this expected? Shouldn't flatMapLatest continue even after some inner children completes, given that the outer sequence has not completed?

    • Is there anything else in the library that would help me? I tried using CurrentValue(...) instead of Just, but in that case I get no results. I think it has to do with CurrentValue being garbage collected, if I store it in a local variable it works. I'm not 100% clear on the mechanics that lead to this though (shouldn't eraseToAnySequence keep a ref to the class?)

    • Would it make sense to add something like Just(value, completeImmediately: Bool) for this use case? In the spirit of https://developer.apple.com/documentation/combine/empty/init(completeimmediately:)

    • Side note, https://github.com/sideeffect-io/AsyncExtensions/blob/main/Sources/Operators/AsyncSequence%2BEraseToAnyAsyncSequence.swift#L28 wraps the closure twice, should just invoke it I think

    enhancement 
    opened by natario1 13
  • next() can hang indefinitely if the Task is already cancelled.

    next() can hang indefinitely if the Task is already cancelled.

    ~The unstructured child task used to track iterators is not cancelled when the parent task is cancelled.~

    ~An explicit cancellation handler is required.~

    Updated for mainline branch changes. In some situations I observe that the next() never returns if the calling task is already cancelled. This fix is required.

    opened by swhitty 0
  • Youre missing async sequence builder like kotlin's

    Youre missing async sequence builder like kotlin's

    I'm a kotlin developer familiar with kotlin coroutines and Flow, which is direct mapping to async/await + AsyncSequence.

    The most powerful thing that kotlin flow has is the builder, which allows you to emit values arbitrarily and use all the async stuff since the closure is async, like so (I'll write it in async/await syntax so you understand better)

    flow { emitter in
       await emitter.emit(1)
       await Task.sleep(1_000)
       await emitter.emit(10)
       await Task.sleep(1_000)
       for 0...10 {
          await emitter.emit(100)
       }
    }
    

    when the closure returns, the flow terminates, if you throw inside the closure, then error is propagated as usual

    It allow you to then create arbitrary custom operators, or simply way to pipe async function into AsyncSequence like

    asyncSequence {
       await someFunction()
    }
    .flatMapLatest { ... }
    .collect { ... }
    

    this is very needed

    enhancement 
    opened by ursusursus 4
  • opeators: add a MapError opeator

    opeators: add a MapError opeator

    Description

    This PR adds MapError Operator, which is transforms error upstream emits

    Checklist

    • [ ] this PR is based on the main branch and is up-to-date, if not please rebase your branch on the top of main
    • [ ] the commits inside this PR have explicit commit messages
    • [ ] unit tests cover the new feature or the bug fix
    • [ ] the feature is documented in the README.md if it makes sense
    • [ ] the CHANGELOG is up-to-date
    opened by JCSooHwanCho 3
Releases(0.5.1)
  • 0.5.1(Sep 29, 2022)

  • 0.5.0(Sep 26, 2022)

    This version brings a lot of internal refactoring and breaking changes + some new operators.

    Now swift-async-algorithms has been anounced, this library can be seen as a companion for the Apple repo. For now there is an overlap between both libraries, but when swift-async-algorithms becomes stable the overlapping operators while be deprecated in AsyncExtensions.

    Nevertheless AsyncExtensions will continue to provide the operators that the community needs and are not provided by Apple.

    • AsyncBufferedChannel/AsyncThrowingBufferedChannel: is the equivalent to AsyncChannel from Apple. The difference is that back-pressure is handled with a stack and the send operation is not suspending.
    • Subjects: the subject suffix has been adopted to all the "hot" AsyncSequence with a shared output. A throwing counterpart has been added.
    • zip and merge are top level functions to match Apple repo.
    • AsyncThrowingJustSequence: an AsyncSequence that takes a throwing closure to compute the only element to emit.
    • AsyncStream.pipe(): creates and AsyncStream by escaping the Continuation and returning a tuple to manipulate the inputs and outputs of the stream.
    • mapToResult(): maps events (elements or failure) from an AsyncSequence to a Result. The resulting AsyncSequence cannot fail.
    • AsyncLazySequence: is a renaming to match Apple repo for creating an AsyncSequence from a Sequence.
    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Mar 21, 2022)

  • 0.3.0(Mar 13, 2022)

    • Operators: new share() operator
    • Operators: new withLatestFrom(_:) operator
    • AsyncSequences: new Timer AsyncSequence
    • AsyncStreams: send() functions are now synchronous
    Source code(tar.gz)
    Source code(zip)
  • 0.2.1(Mar 2, 2022)

    This release fixes a potential issue where ConcurrentAccessRegulator could call the onNext function in a non deterministic way timeline wise.

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Mar 2, 2022)

    This release brings:

    • AsyncStreams.CurrentValue element made public and available with get/set
    • A new Multicast operator
    • A new Assign operator
    Source code(tar.gz)
    Source code(zip)
  • 0.1.0(Jan 31, 2022)

    This release brings the first set of operators:

    Async Sequences:

    • Just
    • Empty
    • Fail
    • From
    • Merge
    • Zip2
    • Zip3
    • Zip

    Async Streams:

    • Passthrough
    • CurrentValue
    • Replay

    Operators:

    • Collect
    • Scan
    • SwitchToLatest
    • FlatMapLatest
    • HandleEvents
    • EraseToAnyAsyncSequence
    Source code(tar.gz)
    Source code(zip)
Owner
AsyncCommunity
All projects related to Swift structured concurrency
AsyncCommunity
A demonstration for bridging between Combine and your new async functions

CombineAsyncually This is a DEMONSTRATION of how you can bridge the new async / await functionality in Swift 5.5 with Combine. There is NO WARRANTY. T

null 48 Dec 4, 2022
Hydra ⚡️ Lightweight full-featured Promises, Async & Await Library in Swift

Lightweight full-featured Promises, Async & Await Library in Swift What's this? Hydra is full-featured lightweight library which allows you to write b

Daniele Margutti 2k Dec 24, 2022
⏳ Collection of Swift 5.5 async/await utility functions.

⏳ FunAsync Collection of Swift 5.5 async/await utility functions. Throw <-> Result conversion asyncThrowsToAsyncResult asyncResultToAsyncThrows More C

Yasuhiro Inami 23 Oct 14, 2022
🎭 Swift async/await & Actor-powered effectful state-management framework.

?? Actomaton ??‍?? Actor + ?? Automaton = ?? Actomaton Actomaton is Swift async/await & Actor-powered effectful state-management framework inspired by

Yasuhiro Inami 199 Dec 20, 2022
⚡️ Fast async task based Swift framework with focus on type safety, concurrency and multi threading

Our apps constantly do work. The faster you react to user input and produce an output, the more likely is that the user will continue to use your appl

Said Sikira 814 Oct 30, 2022
Async and concurrent versions of Swift’s forEach, map, flatMap, and compactMap APIs.

CollectionConcurrencyKit Welcome to CollectionConcurrencyKit, a lightweight Swift package that adds asynchronous and concurrent versions of the standa

John Sundell 684 Jan 9, 2023
Hydra: Lightweight full-featured Promises, Async-Await Library in Swift

Async Functions for ECMAScript The introduction of Promises and Generators in EC

Ecma TC39 1.6k Oct 17, 2022
Swift TableView pagination with async API request.

SwiftTableViewPagination Swift TableView pagination with async API request. Output UML Create puml file. $ cd SwiftTableViewPagination/scripts/swiftum

y-okudera 1 Dec 26, 2021
AsyncLocationKit - Async/await CoreLocation With Swift

AsyncLocationKit Wrapper for Apple CoreLocation framework with new Concurency Mo

AsyncSwift 89 Dec 30, 2022
Edit images and video with async / await in Swift, powered by Metal.

AsyncGraphics The core value type in AsyncGraphics is a Graphic. It's like an image, tho it can be used with various async methods. Documentation Swif

Anton Heestand 33 Dec 27, 2022
A Swift lib for network with async/await

SmileNetwork A Swift network utility with async/await applied UseAge enum MockEndpoint { case weather(cityId: String) } extension MockEndpoint: S

null 2 Jul 13, 2022
A simple network layer for use in small iOS projects with async/await support

SimpleNetwork Intro SimpleNetwork is simple network layer for use in small projects. Swift Package Manager Note: Instructions below are for using Swif

Alexandre Garrefa 1 Nov 30, 2021
Example project showing how to use async/await with iOS 13

ios13AsyncAwait Example project showing how to use async/await with iOS 13 Article This source code is a part of an article published at This Dev Brai

Michał Tynior 7 Oct 2, 2022
Using async / await on iOS 13: everything you need to know

Using async / await on iOS 13: everything you need to know! ?? Content This repository contains the code sample I've used during December 14th's lives

Vincent Pradeilles 11 Feb 1, 2022
iOS 13-compatible backports of commonly used async/await-based system APIs that are only available from iOS 15 by default.

AsyncCompatibilityKit Welcome to AsyncCompatibilityKit, a lightweight Swift package that adds iOS 13-compatible backports of commonly used async/await

John Sundell 367 Jan 5, 2023
straightforward networking and error handling with async-await and URLSession

AsyncAwaitNetworkingPlayground How To Run Just clone the project, open it and run. Some notes about AsyncAwaitNetworkingPlayground It's a straightforw

Fırat Yenidünya 17 Dec 11, 2022
PixabayImageSearchSample - SwiftUI + LazyVGrid + Pixabay API + Codable + sync/async Sample

PixabayImageSearchSample SwiftUI + LazyVGrid + Pixabay API + Codable + sync/asyn

null 3 Nov 23, 2022
AsyncTaskKit - contains some additions to async/await Task

AsyncTaskKit This repo contains some additions to async/await Task. In general i

Michał Zaborowski 0 Jan 2, 2022
Lightweight async/await networking library with interceptor support - usable from iOS 13+.

Lightweight async/await networking library with interceptor support. ?? Getting started AsyncNetwork's session acts as a wrapper to URLSession by addi

Paul 9 Oct 4, 2022