Git Product home page Git Product logo

maybe-async-rs's People

Contributors

dependabot-preview[bot] avatar dtolnay avatar fmeow avatar niederb avatar obi1kenobi avatar qiuchengxuan avatar stefunctional 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

maybe-async-rs's Issues

[Q&A] Would it be possible to have an `is_async` feature as well?

The reason I am asking might very well be ignorance, but here I go.

When transforming the git-transport crate to also support async, I am starting out with blocking code. Right now I use feature toggles as follows:

  • there are no default features
  • no features means is_async
  • A feature called blocking-client makes the existing blocking client code available

The problem I am having with this is my inability to conditionally not compile the async-trait crate, as it's required for the async code, but not for the blocking code. However, cargo features are additive and can't be turned off, leaving the blocking code with the need to compile async-trait.

This issue is certainly minor, but if valid might point at an opportunity.

With a feature flag like maybe-async/is_async, I could have the following configuration.

  • there are no default features, meaning there is neither blocking nor non-blocking client code as the user should choose.
  • with the async-client, we also require maybe-async/is_async and async-trait
  • with blocking-client, we require maybe-async/is_sync
  • if compiled with --all-features, we pick one of the above to be the dominant one

While only having taken a glance at how the is_sync feature toggle is used in this crate, I have a feeling that the addition of is_async would be very possible. If so, I would be happy to contribute it, too.

I am curious to hear what you are thinking. Thanks a lot.

Parenthesis warnings with synchronous code

Hello! First of all, thanks a lot for creating this crate! It's super useful, we're using it at https://github.com/ramsayleung/rspotify.

The only problem we've found is that when maybe-async/is_sync is activated, these warnings appear:

warning: unnecessary parentheses around block return value
  --> src/lib.rs:11:12
   |
11 |     base().await
   |            ^^^^^ help: remove these parentheses
   |
   = note: `#[warn(unused_parens)]` on by default

Here's a minimal snippet:

//! lib.rs
use maybe_async::{sync_impl, maybe_async};

#[sync_impl]
fn base() -> ureq::Response {
  ureq::get("https://myapi.example.com/ingest")
      .call()
}

#[maybe_async]
pub async fn current_user() -> ureq::Response {
    base().await
}
# Cargo.toml
[package]
name = "notworking"
version = "0.1.0"
authors = ["Mario Ortiz Manero <[email protected]>"]
edition = "2018"

[dependencies]
async-trait = "0.1.40"
maybe-async = "0.2.0"
ureq = "1.4.1"

[features]
default = ["maybe-async/is_sync"]

Any idea of what this could be? Thanks in advance.

No current solution for ignoring `#[tokio::main]` on sync

As written in the title, I don't think there is currently a solution to only spit out attributes with maybe_async. Am I overlooking things? I want the following to compile:

#[tokio::main]
 #[maybe_async::maybe_async]
 async fn main() {
     let user = User::new("kasuporo");
     // Now you are able to:

     // Get overview
     let overview = user.overview(None).await;

     // Get submitted posts.
     let submitted = user.submitted(None).await;

     // Get comments.
     let comments = user.comments(None).await;
 }

The maybe_async attribute works fine when is_sync is enabled but the resolved code is the following:

#[tokio::main]
 fn main() {
     let user = User::new("kasuporo");
     // Now you are able to:

     // Get overview
     let overview = user.overview(None);

     // Get submitted posts.
     let submitted = user.submitted(None);

     // Get comments.
     let comments = user.comments(None);
 }

Sadly, tokio::main remains. Is there something I am missing?

`maybe_async::test` does not seem to work in a `test` module

I have the following test case:

#[cfg(test)]
mod tests {

    #[cfg(feature = "async")]
    use tokio;

    #[maybe_async::test(
        feature="blocking",
        async(feature = "async", tokio::test)
    )]
    async fn test_oauth() {
       ... 
      let client = dbg!Reddit::new(&USER_AGENT, &client_id, &client_secret)
                  .username(&username)
                  .password(&password)
                  .login()
                  .await;
    }
}

The compiler throws the following error:

error[E0728]: `await` is only allowed inside `async` functions and blocks
  --> tests\tests.rs:34:21
   |
23 |       async fn test_oauth() {
   |                ---------- this is not `async`
...
34 |               .login()
   |  _____________________^
35 | |             .await);
   | |__________________^ only allowed inside `async` functions and blocks

error[E0728]: `await` is only allowed inside `async` functions and blocks
  --> tests\tests.rs:41:28
   |
23 |     async fn test_oauth() {
   |              ---------- this is not `async`
...
41 |             assert!(me.me().await.is_ok());
   |                            ^^^^^^ only allowed inside `async` functions and blocks

error[E0277]: `Result<Me, RouxError>` is not a future
  --> tests\tests.rs:34:21
   |
34 |               .login()
   |  _____________________^
35 | |             .await);
   | |__________________^ `Result<Me, RouxError>` is not a future
   |
   = help: the trait `Future` is not implemented for `Result<Me, RouxError>`
   = note: Result<Me, RouxError> must be a future or must implement `IntoFuture` to be awaited
   = note: required because of the requirements on the impl of `IntoFuture` for `Result<Me, RouxError>`
help: remove the `.await`
   |
34 -             .login()
34 +             .login());
   | 

`maybe_async` on structs

According to the readme I can apply the macro to struct definitions. However if I do this on an impl block for a struct (without trait) I get an error due to this check:

if item.trait_.is_none() {

If I apply it directly on the struct I get this error:
"expected trait impl, trait or fn",

I was hoping to apply the macro on a struct or its impl in order to affect all its methods. Is there something wrong with my line of thinking? If not I could try to come up with an PR for this.

maybe-async breaks crates

Hey!

I just noticed something that seems kind of bad! The is_sync feature of maybe-async breaks stuff. Here's an example:

Create a new, empty crate, add these dependencies:

crates-index = { version = "2.1.1", features = ["git", "git-https"] }
rust-s3 = "0.33.0"

Building this will break hard. Disabling either one of the dependencies makes the build work.

Why? Both of these crates us maybe-async. The crates-index crate enables the is_sync feature. The presence of this feature breaks rust-s3.

My understanding is that this feature is not "additive".

Can someone look into this? In my project, I am able to work around this, but this issue currently makes doing cargo build on the workspace level broken. In my workspace I can work around it by always compiling crates individually. But maybe it would be a good idea to peek into this and see if there was some way to solve this.

Cheers!

Handle generic type with trait bound `Future`

Hello,

I use the maybe_async crate for a few projects, and it works great. I only have a issue on the tests:

This is a test from my crate aragog based on your arangors crate.

#[maybe_async::test(
        feature = "blocking",
        async(all(not(feature = "blocking")), tokio::test)
    )]
    async fn can_be_recorded_and_retrieved() -> Result<(), String> {
        with_db(|pool| async move {
            let dish = init_dish();
            let dish_record = DatabaseRecord::create(dish, &pool).await.unwrap();
            let found_record = Dish::find(&dish_record.key, &pool).await.unwrap();
            common::expect_assert_eq(dish_record.record, found_record.record)?;
            Ok(())
        })
        .await
    }

When async it works fine, but when I use the blocking feature the async move is not changed making the test build fail.
I'm wondering if handling this case could be done through mabe_async

Otherwise I can chang the way I write my db-related tests.

EDIT:

the with_dbfunction is the following:

#[maybe_async::maybe_async]
pub async fn with_db<T, F>(test: T) -> Result<(), String>
where
    T: FnOnce(DatabaseConnectionPool) -> F,
    F: Future<Output = Result<(), String>>,
{
    let db_pool = setup_db().await;
    test(db_pool).await
}

Mybe the issue is comming for the F bound to a Future

Unable to compile a project with two different crates that use maybe_async (one async and another blocking)

Hi,

I am trying to compile a project that depends on two crates that use maybe-async internally. One crate sets the is_sync flag while the other doesn't. The problem I am having is that the is_sync flag set by one crate is applied also to the other crate that requires async and the project fails to compile. All projects use resolver v2.

I believe this problem was discussed in this Reddit post.

#[sync_impl] not switching off compilation for block

I have created a minimal example to show this problem:

main.rs

use maybe_async::{async_impl, sync_impl};

#[cfg(not(feature = "is_sync"))]
use async_std::{io, task::{Context, Poll}};
#[cfg(feature = "is_sync")]
use std::io;

struct ReadInner<R> {
    inner: R,
}

impl<R: io::Read> io::Read for ReadInner<R> {
    #[sync_impl]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.read(buf)
    }

    #[async_impl]
    fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<Result<usize>> {
        self.inner.poll_read(cx, buf)
    }
}

fn main() {
    println!("Hello, world!");
}

Cargo.toml

[dependencies]
async-std = "1.9"
maybe-async = {version = "0.2", features = ["is_sync"]}

[features]
is_sync = []
$ cargo check --features is_sync
    Checking asyncer v0.1.0 (/home/geoff/temp/asyncer)
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
$ cargo check 
    Checking asyncer v0.1.0 (/home/geoff/temp/asyncer)
error[E0407]: method `read` is not a member of trait `io::Read`
  --> src/main.rs:14:5
   |
14 | /     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
15 | |         self.inner.read(buf)
16 | |     }
   | |_____^ not a member of trait `io::Read`

warning: unused imports: `Context`, `Poll`
 --> src/main.rs:4:28
  |
4 | use async_std::{io, task::{Context, Poll}};
  |                            ^^^^^^^  ^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

error[E0046]: not all trait items implemented, missing: `poll_read`
  --> src/main.rs:12:1
   |
12 | impl<R: io::Read> io::Read for ReadInner<R> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `poll_read` in implementation
   |
   = help: implement the missing item: `fn poll_read(self: Pin<&mut Self>, _: &mut Context<'_>, _: &mut [u8]) -> Poll<Result<usize, std::io::Error>> { todo!() }`

error[E0599]: no method named `read` found for type parameter `R` in the current scope
  --> src/main.rs:15:20
   |
15 |         self.inner.read(buf)
   |                    ^^^^ method not found in `R`
   |
   = help: items from traits can only be used if the trait is in scope
help: the following traits are implemented but not in scope; perhaps add a `use` for one of them:
   |
1  | use std::io::Read;
   |
1  | use async_std::io::ReadExt;
   |
1  | use futures_lite::io::AsyncReadExt;
   |

error: aborting due to 3 previous errors; 1 warning emitted

Some errors have detailed explanations: E0046, E0407, E0599.
For more information about an error, try `rustc --explain E0046`.
error: could not compile `asyncer`

To learn more, run the command again with --verbose.

async and sync in the same program

I maintain some libraries that have sync and async users. The async users wrap calls in spawn_blocking, which works, but isn't ergonomic and may be suboptimal. maybe_async looks like it could potentially be (part of) an alternative approach.

If I read the docs right, maybe_async can support both sync and async users, but by using a cargo feature, it can't support both in the same program. If the library gets used in multiple places in the same program, and one of them enables is_sync, it would break the other places that need async.

It seems like it would be useful to have a macro that expands to both sync and async, using different names, so that they can coexist. For example,

#[maybe_async::both]
async fn foo() -> bool {
    true
}

might expand to:

#[cfg(feature = "async")]
async fn async_foo() -> bool {
    true
}
#[cfg(feature = "sync")]
fn sync_foo() -> bool {
    true
}

so that users can call whichever form they need by name (though I'm not attached to the particular naming convention here).

pub(crate) trait compile fail

Change unit test as following:

diff --git a/tests/ui/03-must-be-sync.rs b/tests/ui/03-must-be-sync.rs
index 0bccfcc..69be40c 100644
--- a/tests/ui/03-must-be-sync.rs
+++ b/tests/ui/03-must-be-sync.rs
@@ -22,6 +22,17 @@ pub trait PubTrait {
     }
 }
 
+#[maybe_async::maybe_async]
+pub(crate) trait CratePubTrait {
+    fn sync_fn() {}
+
+    async fn declare_async(&self);
+
+    async fn async_fn(&self) {
+        self.declare_async().await
+    }
+}
+
 #[maybe_async::maybe_async]
 async fn async_fn() {}
 
@@ -52,7 +63,6 @@ fn main() -> std::result::Result<(), ()> {
     Ok(())
 }
 
-
 #[cfg(not(feature = "is_sync"))]
 #[async_std::main]
 async fn main() {}

then simply run cargo test, failed as following:

test tests/ui/03-must-be-sync.rs [should pass] ... error
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈                                                                                   
error: expected `fn`
  --> tests/ui/03-must-be-sync.rs:26:12                                                                                                        
   |                                                                                                                                           
26 | pub(crate) trait CratePubTrait {                       
   |            ^^^^^                                                                                                                          
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈

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.