trait_guard 0.1.0

A Rust library for disallowing usage of certain trait implementations with custom messages.
Documentation
//! # trait_guard
//! 
//! `trait_guard` is a macro used to protect a trait implementation from usage with a custom message, note, and label.
//! 
//! It abuses the `on_unimplemented` attribute to provide a custom error message when the trait is not implemented. It requires
//! the `negative_impls` and `trivial_bounds` nightly features to be enabled.
//! 
//! You can use any trait (even if it's an STD trait or from another crate)!
//! 
//! ## Example usage:
//! 
//! ```rust
//! trait_guard!(
//!     MyType, // the type that will be guarded
//!     MyTrait, // the trait that is being guarded
//! 
//!     trait_guard = MyGuardTrait, // optional: custom name for the guard trait, shown in the diagnostic message
//!     guard_struct = MyGuardStruct, // optional: custom name for the guard struct, shown in the diagnostic message
//! 
//!     {
//!         // this is the body of the trait implementation
//!         fn my_method(&self) {
//!             // implementation
//!         }
//!     },
//! 
//!     message = "MyType does not implement MyTrait",
//! //  note = "This is a custom note",
//! //  label = "MyType needs to implement MyTrait"
//! );
//! ```
//! 
//! The example above will refuse to compile if the `MyTrait` implementation of `MyType` is used anywhere in the user's code. 
//! 
//! If you want to guard multiple traits/types, you can change the name of `trait_guard` and `guard_struct` to avoid conflicts.
//! 
//! ## Example for [`std::fmt::Display`]
//! 
//! ```rust
//! use trait_guard::trait_guard;
//! 
//! #[derive(Debug)]
//! struct A;
//! 
//! trait_guard!(
//!     A, // the type that will be guarded
//!     std::fmt::Display, // the trait that is being guarded
//! 
//!     {
//!        // this is the body of the trait implementation
//!        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//!            unreachable!("It will never be called because A does not implement Display");
//!        }
//!     },
//! 
//!     message = "A does not implement std::fmt::Display",
//! );
//! ```

#[macro_export]
/// A macro to protect a trait implementation from usage with a custom message, note, and label.
/// 
/// This abuses the `on_unimplemented` attribute to provide a custom error message when the trait is not implemented. It requires
/// the `negative_impls` and `trivial_bounds` nightly features to be enabled.
/// 
/// You can use any trait (even if it's an STD trait or from another crate)!
/// 
/// # Example usage:
/// 
/// ```rust
/// trait_guard!(
///     MyType, // the type that will be guarded
///     MyTrait, // the trait that is being guarded
/// 
///     trait_guard = MyGuardTrait, // optional: custom name for the guard trait, shown in the diagnostic message
///     guard_struct = MyGuardStruct, // optional: custom name for the guard struct, shown in the diagnostic message
/// 
///     {
///         // this is the body of the trait implementation
///         fn my_method(&self) {
///             // implementation
///         }
///     },
/// 
///     message = "MyType does not implement MyTrait",
/// //  note = "This is a custom note",
/// //  label = "MyType needs to implement MyTrait"
/// );
/// ```
/// 
/// The example above will refuse to compile if the `MyTrait` implementation of `MyType` is used anywhere in the user's code. 
/// 
/// If you want to guard multiple traits/types, you can change the name of `trait_guard` and `guard_struct` to avoid conflicts.
macro_rules! trait_guard {
    (
        $item:ty, 
        $trait:ty, 
        $body:tt, 
        
        message = $message:expr
        $(, note = $note:expr)?
        $(, label = $label:expr)?
    ) => {
        #[diagnostic::on_unimplemented(message = $message$(, note = $note)?$(, label = $label)?)]
        trait GuardTrait {}

        struct Guard<T>(T);
        impl !GuardTrait for $item {}
        impl $trait for $item where Guard<$item>: GuardTrait $body
    };

    (
        $item:ty, 
        $trait:ty, 
        
        trait_guard = $trait_guard:ident, 
        guard_struct = $guard_struct:ident, 
        
        $body:tt, 
        
        message = $message:expr
        $(, note = $note:expr)?
        $(, label = $label:expr)?
    ) => {
        #[diagnostic::on_unimplemented(message = $message$(, note = $note)?$(, label = $label)?)]
        trait $trait_guard {}

        struct $guard_struct<T>(T);
        impl !$trait_guard for $item {}
        impl $trait for $item where $guard_struct<$item>: $trait_guard $body
    }
}