GithubHelp home page GithubHelp logo

async-recursion's People

Contributors

dcchut avatar dependabot-preview[bot] avatar erk- avatar leoniephiline avatar ricogit avatar zicklag avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

async-recursion's Issues

Move documentation from crate root to macro?

This would be convenient for crates which re-export the async_recursion macro, like frameworks whose users need an async_recursion-like macro to function (e.g. to store async functions and closures in a struct).

If the documentation on the macro were on the macro directly, the re-export in dependent crates would show that documentation as well.

Doesn't handle references inside generics (e.g. Option)

#[async_recursion::async_recursion]
async fn meow(n : Option<&str>) -> () {
    meow(n).await
}

expands to (cleaned):

#[must_use]
fn meow(
    n: Option<&str>,
) -> Pin<Box<dyn Future<Output = ()> + Send>> {
    Box::pin(async move { meow(n).await })
}

`no_std` support

Can this crate be made to use just alloc crate instead of being std dependant? That would help a lot of embedded developers given that the most recent version of rust allows async await in no_std scenarios out of the box.

lifetime may not live long enough

Hello,

I am wondering how to deal with this situation.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9c9d1ddc0b3ece4b4bb40280c0fda6ca

use async_recursion::async_recursion;

#[tokio::main]
async fn main() {
    count_down(5, None).await;
}

#[async_recursion]
async fn count_down(num: u32, foo: Option<&str>) {
    if num == 0 {
        return;
    }
    println!("{}, {:?}", num, foo);
    count_down(num - 1, foo);
}

Output:

error: lifetime may not live long enough
 --> src/main.rs:8:1
  |
8 | #[async_recursion]
  | ^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
9 | async fn count_down(num: u32, foo: Option<&str>) {
  |                                           - let's call the lifetime of this reference `'1`
  |
  = note: this error originates in the attribute macro `async_recursion` (in Nightly builds, run with -Z macro-backtrace for more info)
help: to declare that the trait object captures data from argument `foo`, you can add an explicit `'_` lifetime bound
  |
8 | #[async_recursion] + '_
  |                    ++++

The "help" given by rustc is invalid.

Using #[async_recursion] inside a declarative macro

I am trying to implement a declarative macro that, given a type, implements a recursive asynchronous function that takes that type as parameter. However, it seems unfeasible when the given type is a reference, since the type may not live as long as the 'async_recursion lifetime.

A minimal example of the declarative macros is something as following:

macro_rules! help_please {
    ($param:ty) => {
        #[async_recursion]
        async fn recursive_fn<F>(param: $param, f: &F)
        where
            F: Fn($param) + Sync + Send,
        {
            f(param);
        }
    };
}

And then, if I use it like in the example down below, it does not compile and tells me to add explicit lifetime 'async_recursion to the type of 'param': &'async_recursion usize. What cannot be done since the lifetime `async_recursion does not exist at that level.

macros_async::help_please!(&usize);

I am aware that my approach may be weird or absolutely wrong; however, I would like to know if there is any way to tell async_recursion which is the lifetime that should be taken as `async_recursion. Can this situation be resolved somehow? Thanks in advance!

Add `'async_recursion` lifetime to generics

While using the async_recursion proc_macro the lifetime must be set for any generics. It would be nice if proc_macro could add the lifetime to all generics, so that IDE's don't complain about in-band lifetimes.

Now I need to do

#[async_recursion::async_recursion]
fn foo<S: SomeTrait + Send + 'async_recursion>(trait: S) -> u64 {
...
}

Goal would be

#[async_recursion::async_recursion]
fn foo<S: SomeTrait + Send>(trait: S) -> u64 {
...
}

@dcchut I can try adding that.

It breaks when there is another "Box"

For example, this expanded line of return type. I have a Box type defined in the crate. Not sure if that is the reason the Box here is not qualified.

::core::pin::Pin<Box<dyn ::core::future::Future<Output = Result<()>>>>.

Function Not Send?

Hey there, I wanted to use this in my project, but I'm getting an error that I don't get when manually adjusting the function for recursion:


error[E0277]: `(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)` cannot be sent between threads safely
  --> src/subsystems/crawler.rs:64:50
   |
64 |                     let aid = ctx.system.spawn().with(
   |                                                  ^^^^ `(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)`
   = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)>`
   = note: required because it appears within the type `std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)>`
   = note: required because it appears within the type `std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)>>`
   = note: required because of the requirements on the impl of `axiom::actors::Processor<subsystems::crawler::IndexCrawler<P>, std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)>>>` for `fn(subsystems::crawler::IndexCrawler<P>, axiom::actors::Context, axiom::message::Message) -> std::pin::Pin<std::boxed::Box<(dyn core::future::future::Future<Output = std::result::Result<(subsystems::crawler::IndexCrawler<P>, axiom::actors::Status), std::boxed::Box<(dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static)>>> + 'static)>> {subsystems::crawler::IndexCrawler::<P>::index_crawler}`

I noticed a TODO in the code about a Send option that is missing, is that related? Would it be simple enough to explain what must happen so I could make a PR?

Recursive async fns made with the macro are lacking `#[must_use]`

Here is a playground link for demonstration, the function only executes once instead of the expected 10 times. The issue in the example is the missing await on the recursive call.

Functions that are manipulated by this macro lose their #[must_use] warning that usually comes with asyncs. Manually adding the #[must_use] to run highlights the issue. Without the #[must_use], it is very easy for programmers to forget the await and creates a confusing debugging experience with their code paths not executing.

One More Case where 'async_recursion is required

Hey again @dcchut . Just found another case when a manual overwrite of the lifetime is required. I am having a function simillar to

pub async fn execute<T>(&self, executor: &'async_recursion E)  
where
  E: Executor + Send + Sync
{
  *self.counter.lock().await -=1;

  if self.counter.lock().await > 0 {
    self.execute(executor).await;
  }
}

Notice that I had to stipulate 'async_recursion in it. If I remove it I get a wierd error, saying that 'life0 is doubly defined. Have you came accross this case before?

error[E0263]: lifetime name `'life0` declared twice in the same scope

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.