nvksv / maybe-async-cfg

A procedure macro to unify sync and async implementations depending on the features of your crate
MIT License
5 stars 2 forks source link

Support placing new symbols in a separate module #1

Closed quentinmit closed 2 years ago

quentinmit commented 2 years ago

Right now, the only option for async and sync to coexist at the same time is to rename one or both of them to have Sync / Async suffixes. I think the ergonomics would be much better if you could use a module instead. E.g.:

#[maybe_async_cfg::maybe(sync(keep_self), async(feature="async",self="async"))]
pub mod blocking {
  pub async fn hello_world() {
    "Hellorld"
  }
}

which would expand to

pub mod blocking {
  pub fn hello_world() {
    "Hellorld"
  }
}
pub mod async {
  pub async fn hello_world() {
    "Hellorld"
  }
}

and thereby make the two versions differ only by which module is use'd.

Bonus points if you could have one of the branches omit the mod entirely to put the symbols in the parent module, as a way of migrating existing blocking-only crates.

nvksv commented 2 years ago

I just updated the crate to version 0.2.1. The maybe attribute now can be applied to modules. E.g.:

crates.toml

[package]
name = "maybe-async-cfg-test-1"
version = "0.1.0"
edition = "2021"

[features]
sync = []
async = []
default = ["sync", "async"]

[dependencies]
maybe-async-cfg = "0.2.1"

main.rs

#[maybe_async_cfg::maybe(
    idents(hello_world(fn,keep)),
    sync(feature="sync",keep_self), 
    async(feature="async",self="async_")
)]
pub mod blocking {
  pub async fn hello_world() {
    todo!()
  }
}

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

now is expanding (cargo expand) into

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
#[cfg(feature = "sync")]
pub mod blocking {
    pub fn hello_world() {
        ::core::panicking::panic("not yet implemented")
    }
}
#[cfg(feature = "async")]
pub mod async_ {
    pub async fn hello_world() {
        ::core::panicking::panic("not yet implemented")
    }
}
fn main() {
    {
        ::std::io::_print(::core::fmt::Arguments::new_v1(&["Hello, world!\n"], &[]));
    };
}

Earlier, this required reimport:

#[cfg(feature = "async")]
pub mod async_ftp {
    pub use crate::ftp::FtpStreamAsync as FtpStream;
}
#[cfg(feature = "sync")]
pub mod sync_ftp {
    pub use crate::ftp::FtpStreamSync as FtpStream;
}

Thank you for good idea!

quentinmit commented 2 years ago

Why does your example require specifying hello_world in idents?

I actually already implemented this as well... https://github.com/quentinmit/maybe-async-cfg/tree/mod

and I didn't find any need to specify idents.

nvksv commented 2 years ago

Yes, if the name of hello_world should not change, it is not necessary to specify it in idents.

My mistake. Initially, I tested on the example when the hello_world was supposed to turn into a hello_world_async/hello_world_sync, and then quickly banned such renaming. But it would be more correct to delete idents(hello_world(fn)) entirely, as you noticed.