Skip to content

Rust macros for aliasing and reuse of generics definitions

License

Notifications You must be signed in to change notification settings

j4r0u53k/generics-alias-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Generics aliasing for Rust

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 by generics_def. The macro injects the defined generics into the definition of the function decorated by this macro.

Example

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)
{
    // ...
}

Details

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.

Usage notes

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.

About

Rust macros for aliasing and reuse of generics definitions

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages