-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
sipper
support and some QoL
#2805
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Use the `with!` macro otherwise!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds support for a new crate I recently released called
sipper
.A sipper is a type-safe
Future
that canStream
progress.Effectively, a
Sipper
combines aFuture
and aStream
together to represent an asynchronous task that produces someOutput
and notifies of someProgress
, without both types being necessarily the same.In fact, a
Sipper
implements both theFuture
and theStream
traits—which gives you all the great combinators fromFutureExt
andStreamExt
for free.Generally,
Sipper
should be chosen overStream
when the final value produced—the end of the task—is important and inherently different from the other values.An Example
An example of this could be a file download. When downloading a file, the progress that must be notified is normally a bunch of statistics related to the download; but when the download finishes, the contents of the file need to also be provided.
The Uncomfy Stream
With a
Stream
, you must create some kind of type that unifies both states of the download:If we now wanted to notify progress and—at the same time—do something with the final
File
, we'd need to juggle with theStream
:While we could rewrite the previous snippet using
loop
,expect
, andbreak
to get the final file out of theStream
, we would still be introducing runtime errors and, simply put, working around the fact that aStream
does not encode the idea of a final value.The Chad Sipper
A
Sipper
can precisely describe this dichotomy in a type-safe way:Which can then be easily
usedsipped:The Delicate Straw
How about error handling? Fear not! A
Straw
is aSipper
that can fail. What would our download example look like with an error sprinkled in?Pretty much the same! It's quite easy to add error handling to an existing
Sipper
. In fact,Straw
is actually just an extension trait of aSipper
with aResult
as output. Therefore, all theSipper
methods are available forStraw
as well. It's just nicer to write!The Great Builder
You can build a
Sipper
with thesipper
function. It takes a closure that receives aSender
—for sending progress updates—and must return aFuture
producing the output.Furthermore,
Sipper
has no required methods and is just an extension trait of aFuture
andStream
combo. This means you can come up with new ways to build aSipper
by implementing the async traits on any of your types. Additionally, any foreign type that implements both is already one.The Fancy Composition
A
Sipper
supports a bunch of methods for easy composition; likewith
,filter_with
, andrun
.For instance, let's say we wanted to build a new function that downloads a bunch of files instead of just one:
As you can see, we just leverage
with
to combine the download index with the progress and callrun
to drive theSipper
to completion—notifying properly through theSender
.Of course, this example will download files sequentially; but, since
run
returns a simpleFuture
, a proper collection likeFuturesOrdered
could be used just as easily—if not more! Take a look:The Sip
Task
The changes in this PR introduce a new
Task::sip
builder that can be used to create aTask
that runs aSipper
to completion while listening to its progress. Thedownload_progress
andgallery
examples have been updated to showcase it.And since a
Sipper
is also both aFuture
and aStream
, it can also be directly used withTask::perform
andTask::run
!The
Function
TraitAdditionally, I have introduced a new
Function
trait, available in the root module, which is meant to include methods that can be used to write certain patterns iniced
in a more concise way.For instance,
Function
includes awith
method that can be used to apply a fixed argument to any message constructor: