#synchronous #async #wraps #sync #automatic #order #function

macro syncwrap

Automatically wraps async functions in a synchronous wrapper based on feature flags

6 releases (3 breaking)

0.4.0 Mar 17, 2021
0.3.0 Jan 7, 2021
0.2.2 Dec 28, 2020
0.1.0 Dec 22, 2020

#35 in #wraps

Download history 390/week @ 2023-12-08 264/week @ 2023-12-15 277/week @ 2023-12-29 221/week @ 2024-01-05 571/week @ 2024-01-12 576/week @ 2024-01-19 665/week @ 2024-01-26 280/week @ 2024-02-02 553/week @ 2024-02-09 402/week @ 2024-02-16 243/week @ 2024-02-23 291/week @ 2024-03-01 483/week @ 2024-03-08 216/week @ 2024-03-15 200/week @ 2024-03-22

1,202 downloads per month
Used in tmdb-cli

MIT license

14KB
68 lines

Syncwrap

Wraps asynchronous functions in order to make them synchronous based on if a "sync" feature is enabled. This is useful when writting http clients as you can write async methods and wrap them for use in synchronous code bases automatically.

Usage

[dependencies]
syncwrap = "0.4.0"

Then in the crate that you want to have synchronous functions created for you you create a sync feature. When this feature is enabled syncwrap will create synchronous functions on what you have wrapped.

you can either:

  • Replace your asynchronous function with a synchronous one
  • Clone your asynchronous function with a synchronous one ending in blocking
  • Clone all methods in an impl with synchronous ones

Replacing async functions

You can replace your asynchronous function with a synchronous one by doing something like the following:

#[syncwrap::wrap]
async fn foo(input: &str) -> String {
  format!("I am {} now", input)
}

fn main() {
  let out = foo("sync");
  assert_eq!(out, "I am sync now".to_owned())
}

Cloning async functions

You can clone your asynchronous function with a synchronous one ending in blocking by doing something like the following:

#[syncwrap::clone]
async fn foo(input: &str) -> String {
 format!("I am {} now", input)
}

let out = foo_blocking("sync");
assert_eq!(out, "I am sync now".to_owned())

Cloning async methods in implementations

You can clone all methods in an impl with synchronous ones by using syncwrap::clone_impl. This is useful when you want to support both async and sync functions in a struct implementation.

// The original struct
#[derive(Default)]
pub struct Example {
  pub fooers: Fooers,
}

// You also need to create the struct to place the cloned impls in
// This is done so you can choose what structs/impls to clone/wrap
// The cloned structs/impls should end in Blocking
#[derive(Default)]
pub struct ExampleBlocking {
  pub fooers: FooersBlocking,
}

// The original struct with async functions
#[derive(Default)]
pub struct Fooers;

// The blocking struct that we are cloning impls into
// You have to create this so you can add custom derives
#[derive(Default)]
pub struct FooersBlocking;

// The async impls that you want to wrap
// All methods within this impl must be async
#[syncwrap::clone_impl]
impl Fooers {
  pub async fn foo(&self, input: &str) -> String {
    format!("I am {} now", input)
  }

  pub async fn bar(&self, input: &str) -> String {
    format!("I am also {} now", input)
  }
}
let example = ExampleBlocking::default();
let out = example.fooers.foo("sync");
assert_eq!(out, "I am sync now".to_owned());
let out = example.fooers.bar("sync");
assert_eq!(out, "I am also sync now".to_owned())

Currently the wrapping is very naive and simply wraps the function in tokio::main. This is likely more expensive then it needs to be and I hope to make it more efficient later.

Dependencies

~3–11MB
~90K SLoC