#synchronization

async_progress

Create sync points across async tasks

3 unstable releases

0.2.0 Jun 11, 2021
0.1.1 Nov 13, 2019
0.1.0 Oct 7, 2019

#70 in Testing


Used in ws_stream_tungstenite

Unlicense

14KB
116 lines

async_progress

standard-readme compliant Build Status Docs crates.io

Create synchronization points between concurrent async tasks.

Sometimes, especially in order to test async code, we need code to run in a specific order. Making certain tasks wait on things that happen in others. You can create such synchronization by creating (oneshot) channels. When you have more than 2 steps in your flow, channels quickly become quite unwieldy to keep track of and to name. async_progress allows you to create a state enum with steps and simply trigger them with [Progress::set_state] and wait on them with [Progress::once] or [Progress::wait].

Warning: Since this is a convenience crate for testing, I haven't yet been bothered to write tests for it. Some things could be buggy.

Table of Contents

Install

With cargo add: cargo add async_progress

With cargo yaml:

dependencies:

   async_progress: ^0.1

With raw Cargo.toml

[dependencies]

    async_progress = "^0.1"

Upgrade

Please check out the changelog when upgrading.

Dependencies

This crate has few dependencies. Cargo will automatically handle it's dependencies for you.

There are no optional features.

Security

This crate has #![ forbid( unsafe_code ) ], but notably the futures library on which it depends uses quite some unsafe. It is mainly meant for convenience in tests, so it hasn't been scrutinized for security or performance.

Usage

It's important to understand that [Progress] uses pharos to be observable, and that observers that subscribe after an event is triggered will not get that event.

Therefor it's recommended to make all calls to [Progress::once], [Progress::wait] and [Progress::observe] before you start any work that might call [Progress::set_state]. You can then pass those futures to the tasks that need to await them. This also allows triggering events multiple times, which wouldn't be possible otherwise.

Sometimes your next call will be pending, but you need to give green light to some other task to do some stuff. In general it's safe to call [Progress::set_state] before the call that will pend. Your pending call will be polled before the other task will observe the new state.

Basic example

use
{
   async_progress :: Progress,
   futures        :: { executor::block_on, future::join } ,
};

// Some hypothetical steps in our flow.
//
#[ derive( Debug, Clone, PartialEq, Eq )]
//
enum Step
{
   FillQueue,
   SendText,
   ReadText,
}


#[ test ]
//
fn test_something()
{
   let steps     = Progress::new( Step::FillQueue );
   let send_text = steps.once( Step::SendText );
   let read_text = steps.once( Step::ReadText );

   // Remark we don't need to move here, we can work on shared references of the local vars.
   // We also don't need to clone steps, since all the methods on it only require a shared reference.
   //
   let server = async
   {
      // Fill some queue...

      steps.set_state( Step::SendText ).await;

      read_text.await;

      // Now we can read the text
   };

   let client = async
   {
      send_text.await;

      // Now we can send some text...

      steps.set_state( Step::ReadText ).await;
   };


   block_on( join( server, client ) );
}

API

API documentation can be found on docs.rs.

Contributing

This repository accepts contributions. Ideas, questions, feature requests and bug reports can be filed through Github issues.

Pull Requests are welcome on Github. By committing pull requests, you accept that your code might be modified and reformatted to fit the project coding style or to improve the implementation. Please discuss what you want to see modified before filing a pull request if you don't want to be doing work that might be rejected.

Please file PR's against the dev branch, don't forget to update the changelog and the documentation.

Testing

There are no tests for the moment. cargo doc --no-deps --all-features will test the example in this readme.

Code of conduct

Any of the behaviors described in point 4 "Unacceptable Behavior" of the Citizens Code of Conduct are not welcome here and might get you banned. If anyone including maintainers and moderators of the project fail to respect these/your limits, you are entitled to call them out.

License

Unlicence

Dependencies

~2MB
~34K SLoC