Search code examples
rusttraitsconst-generics

Const expressions inside trait?


I have a trait that look like this:

pub trait Buf<const N: usize> {
    fn to_buf(&self) -> [u8; N];
    fn from_buf(buf: [u8; N]) -> Self;
}

However I want to do something like this:

trait Buf {
    const N: usize;
    fn to_buf(&self) -> [u8; Self::N];
    fn from_buf(buf: [u8; Self::N]) -> Self;
}

It give me this error (playground):

   |
   |     fn to_buf(&self) -> [u8; Self::N];
   |                              ^^^^^^^ cannot perform const operation using `Self`
   |
   = note: type parameters may not be used in const expressions
   = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions

Is it possible?


Solution

  • After some research, I found out that, In nightly, Rust allow us to use generic const expression, under this (#![feature(generic_const_exprs)]) feature flag,

    However, This is still far from being stable.

    #![allow(warnings)]
    #![feature(generic_const_exprs)]
    
    trait Buf {
        const N: usize;
        fn to_buf(&self) -> [u8; Self::N];
        fn from_buf(buf: [u8; Self::N]) -> Self;
    }
    macro_rules! impl_trait {
        ($name:ident for $($t:ty:$N:literal)*) => ($(
            impl $name for $t {
                const N: usize = $N;
                fn to_buf(&self) -> [u8; $N] {
                    self.to_le_bytes()
                }
                fn from_buf(bytes: [u8; $N]) -> Self {
                    Self::from_le_bytes(bytes)
                }
            }
        )*)
    }
    impl_trait!(Buf for u8:1 u16:2 u32:4 i8:1 i16:2 i32:4);
    
    fn test<T: Buf>(buf: T, rhs: [u8; T::N])
    where
        [u8; T::N]:,
    {
        assert_eq!(buf.to_buf(), rhs);
    }
    
    fn main() {
        test(123_u8,  [123]);
        test(123_u16, [123, 0]);
        test(123_u32, [123, 0, 0, 0]);
    
        test(-123i8,  [133]);
        test(-123i16, [133, 255]);
        test(-123i32, [133, 255, 255, 255]);
    }
    

    Rust Playground