This crate provides proc macros to define aliases for generic parameters and apply them on functions or other objects.
There are two macros provided:
generics_def!(Ident <Generic1, Generic2, ...>)
: A proc macro that takes an identifier followed by generics definition (enclosed in<>
) as the argument.#[generics(Ident1, Ident2, ...)]
: An attribute macro with a comma separated list of parameters, each of which is an identifier defined bygenerics_def
. The macro injects the defined generics into the definition of the function decorated by this macro.
use generics_alias::*;
generics_def!(
ConnectBounds<
F: Future<Output = shv::Result<(R, W)>>,
R: futures::AsyncRead + Send + Unpin,
W: futures::AsyncWrite + Send + Unpin,
>
);
#[generics(ConnectBounds)]
async fn connection_task<C>(config: ClientConfig, conn_event_sender: Sender<ConnectionEvent>, connect: C) -> shv::Result<()>
where
C: FnOnce(String) -> F + Clone
{
// ...
connection_loop(config, conn_event_sender, connect.clone()).await?;
// ...
}
#[generics(ConnectBounds)]
async fn connection_loop<C>(config: &ClientConfig, conn_event_sender: &Sender<ConnectionEvent>, connect: C) -> shv::Result<()>
where
C: FnOnce(String) -> F,
{
let url = Url::parse(&config.url)?;
connect(url).await?;
// ...
}
Multiple definitions can be applied at once:
use generics_alias::*;
generics_def!(Reader<R: futures::AsyncRead + Send + Unpin>);
generics_def!(Writer<W: futures::AsyncWrite + Send + Unpin>);
#[generics(Reader, Writer)]
fn foo(reader: &R, writer: &mut W)
{
// ...
}
The crate uses features of macro_magic crate to export and import tokens between the macros.
generics_def
basically defines a trait with attached generics and exports its tokens that are later applied whenever generics
macro is invoked.
Very simple.
The reason for such construct is that generics cannot exist on its own as a valid syntactic construct, so using a trait as its holder is probably the most convenient choice, easier than e.g. importing and parsing a module holding a variable with a string, or so.
Users should bring items exported by this crate into scope:
use generics_alias::*;
Even though this crate reexports macro_magic
as a dependency, users still have to include it in their own Cargo.toml
or else the build will
fail with an error:
could not find `macro_magic` in the list of imported crates`
The reason is probably because macro_magic::import_tokens_attr
gets called during the expansion of generics_inner
macro and it has to be available as a direct dependency at the caller's crate.