# Maybe Implements   ![CI][ci-badge] [![Crates.io][crates-badge]][crates-url] [![MIT licensed][mit-badge]][mit-url] [crates-badge]: https://img.shields.io/crates/v/maybe-impl.svg [crates-url]: https://crates.io/crates/maybe-impl [mit-badge]: https://img.shields.io/badge/license-MIT-blueviolet.svg [mit-url]: https://github.com/commonsensesoftware/maybe-impl/blob/main/LICENSE [ci-badge]: https://github.com/commonsensesoftware/maybe-impl/actions/workflows/ci.yml/badge.svg 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: ```toml [features] async = ["maybe-impl"] [dependencies] maybe-impl = { version = "0.1.0", optional = true } ``` Consider the crate has the following trait: ```rust #[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: ```bash cargo add my-crate --features async ``` The trait is expanded to: ```rust 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](https://doc.rust-lang.org/unstable-book/language-features/trait-alias.html) are currently unstable, however, you can bridge these two concepts with a _pseudo_ trait alias by defining a marker trait with a blanket implementation. ```rust #[cfg(not(feature = "async"))] trait Bar: Sized {} #[cfg(not(feature = "async"))] impl Bar for T {} #[cfg(feature = "async")] trait Bar: Sized + Send + Sync {} #[cfg(feature = "async")] impl Bar for T {} #[cfg_attr(feature = "async", maybe_impl::traits(Send,Sync))] trait Foo { fn bar(&self, bar: &T); } ``` The default, synchronous build remains vanilla, while the asynchronous path expands to the equivalent of: ```rust trait Foo: Send + Sync { fn bar(&self, bar: &T); } ``` ## License This project is licensed under the [MIT license]. [MIT license]: https://github.com/commonsensesoftware/more-rs-di/blob/main/LICENSE