Deprecate an implementation

I found a way using associated constants to cause a custom compiler error whenever an implementation is used (which can be suppressed by requesting a crate feature then). I don't think I will use it, but want to share it nonetheless:

pub trait Tr {
    const _DEPRECATE: () = ();
    fn repr(&self) -> &[u8];
}

struct NoValue;

impl Tr for NoValue {
    fn repr(&self) -> &[u8] {
        b""
    }
}

trait DeprecateTr {}
impl DeprecateTr for () {}

impl<T: ?Sized + DeprecateTr> Tr for T {
    const _DEPRECATE: () = {
        #[cfg(not(feature = "compat"))]
        panic!("Implementation of Tr for () is deprecated. Enable feature 'compat' to suppress this error.");
    };
    fn repr(&self) -> &[u8] {
        let _ = Self::_DEPRECATE;
        b"\x00"
    }
}

fn main() {
    assert_eq!(NoValue.repr(), b"");
    
    // The following line gives a custom compile time error
    // unless the `compat` feature is used:
    
    //assert_eq!(().repr(), b"\x00");
}

(Playground)


Or a simpler version:

const fn impl_deprecated() {
    #[cfg(not(feature = "compat"))]
    panic!("Implementation of Tr for () is deprecated. Enable feature 'compat' to suppress this error.");
}

impl Tr for () {
    fn repr(&self) -> &[u8] {
        let _ = impl_deprecated();
        b"\x00"
    }
}

(Playground)

Not sure, however, if it's guaranteed that the constant doesn't get evaluated unless the trait implementation is used. But I feel like it's too hackery anyway.

2 Likes