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

Functions for working with AsyncSeq and Channel #170

Open
njlr opened this issue Aug 20, 2024 · 2 comments
Open

Functions for working with AsyncSeq and Channel #170

njlr opened this issue Aug 20, 2024 · 2 comments

Comments

@njlr
Copy link
Contributor

njlr commented Aug 20, 2024

I propose adding two functions:

AsyncSeq.toChannel : ChannelWriter<'a> -> AsyncSeq<'a> -> Async<unit>

AsyncSeq.fromChannel : ChannelReader<'a> -> AsyncSeq<'a>

AsyncSeq.toChannel would be used to fill a ChannelWriter from an AsyncSeq

AsyncSeq.fromChannel would be used to empty a ChannelReader into an AsyncSeq

Here is an initial implementation:

#r "nuget: FSharp.Control.AsyncSeq, 2.0.23"

open System.Threading.Channels
open FSharp.Control

[<RequireQualifiedAccess>]
module AsyncSeq =

  let toChannel (writer : ChannelWriter<'a>) (xs :  AsyncSeq<'a>) : Async<unit> =
    async {
      try
        for x in xs do
          if not (writer.TryWrite(x)) then
            let! ct = Async.CancellationToken

            do!
              writer.WriteAsync(x, ct).AsTask()
              |> Async.AwaitTask

        writer.Complete()
      with exn ->
        writer.Complete(error = exn)
    }

  let fromChannel (reader : ChannelReader<'a>) : AsyncSeq<'a> =
    asyncSeq {
      let mutable keepGoing = true

      while keepGoing do
        let mutable item = Unchecked.defaultof<'a>

        if reader.TryRead(&item) then
          yield item
        else
          let! ct = Async.CancellationToken

          let! hasMoreData =
            reader.WaitToReadAsync(ct).AsTask()
            |> Async.AwaitTask

          if not hasMoreData then
            keepGoing <- false
    }
// Demo
async {
  let xs = [ 0 .. 9] |> AsyncSeq.ofSeq

  let channel = Channel.CreateBounded(4)

  do!
    Async.Parallel
      [|
        AsyncSeq.toChannel channel.Writer xs

        async {
          for x in AsyncSeq.fromChannel channel.Reader do
            printfn $"%i{x}"
        }
      |]
    |> Async.Ignore<unit array>
}
|> Async.RunSynchronously

Would a PR be accepted?

Thanks!

@njlr njlr changed the title Function for working with AsyncSeq and Channel Functions for working with AsyncSeq and Channel Aug 20, 2024
@dsyme
Copy link
Contributor

dsyme commented Aug 21, 2024

Hi @njlr!

Yes, a PR with good testing would be accepted

You might need to update the engineering in this repository a bit - I haven't checked lately but I assume we should move to latest .NET etc.

@dsyme
Copy link
Contributor

dsyme commented Aug 21, 2024

Oh also make sure you bump the version numbers too (via CHANGELOG)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants