#traits #conditional #macro #send-sync #proc-macro

macro maybe-impl

Provides support to conditionally implement one or more traits

1 unstable release

0.1.0 Jan 10, 2024

#1374 in Procedural macros


Used in more-options

MIT license

9KB
93 lines

Maybe Implements   CI Crates.io MIT licensed

Maybe Implements provides Rust procedural macro attributes that can be used to optionally implement traits.

Optional Traits in Action

Technically, the provided attribute always implements the specified traits. It can be combined with the existing cfg_attr attribute to conditionally implement one or more traits. The primary use case for such behavior is optionally implementing Send and Sync.

First, consider that asynchronous behavior is an optional feature in your crate:

[features]
async = ["maybe-impl"]

[dependencies]
maybe-impl = { version = "0.1.0", optional = true }

Consider the crate has the following trait:

#[cfg_attr(feature = "async", maybe_impl::traits(Send,Sync))]
trait Foo {
    fn bar(&self);
}

When the crate is used with the default features, there is no change in behavior. When the async feature is enabled:

cargo add my-crate --features async

The trait is expanded to:

trait Foo: Send + Sync {
    fn bar(&self);
}

Using Generics

If you define a trait with generics that requires Send and/or Sync, specifically, that will require the generic type constraint to match. Trait aliases are currently unstable, however, you can bridge these two concepts with a pseudo trait alias by defining a marker trait with a blanket implementation.

#[cfg(not(feature = "async"))]
trait Bar: Sized {}

#[cfg(not(feature = "async"))]
impl<T> Bar for T {}

#[cfg(feature = "async")]
trait Bar: Sized + Send + Sync {}

#[cfg(feature = "async")]
impl<T: Send + Sync> Bar for T {}

#[cfg_attr(feature = "async", maybe_impl::traits(Send,Sync))]
trait Foo<T: Bar> {
    fn bar(&self, bar: &T);
}

The default, synchronous build remains vanilla, while the asynchronous path expands to the equivalent of:

trait Foo<T: Send + Sync>: Send + Sync {
    fn bar(&self, bar: &T);
}

License

This project is licensed under the MIT license.

Dependencies

~0.4–0.8MB
~19K SLoC