Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Rust have an equivalent to C++'s decltype() to get the type of an expression?

Tags:

rust

My code looks like:

macro_rules! mask {
    ($bitmap: tt, [..$count: tt], for type = $ty: ty) => {
        {
            let bit_count = std::mem::size_of::<$ty>() * 8;
            let dec_bit_count = bit_count - 1;
            $bitmap & [(1 << ($count & dec_bit_count)) - 1, <$ty>::MAX][((($count & !dec_bit_count)) != 0) as usize]
        }
    };
}

fn main() {
    let bitmap: u8 = 0b_1111_1111;
    let masked_bitmap = mask!(bitmap, [..5], for type = u8);
    println!("{:#010b}", masked_bitmap);
}

The above code will mask the bitmap. In the above example, 0b_1111_1111 on being masked by [..5] will become 0b_0001_1111.

I want my macro to be like this:

macro_rules! mask {
    ($bitmap: tt, [..$count: tt]) => {
        {
            let bit_count = std::mem::size_of::<decltype($bitmap)>() * 8;
            let dec_bit_count = bit_count - 1;
            $bitmap & [(1 << ($count & dec_bit_count)) - 1, <decltype($bitmap)>::MAX][((($count & !dec_bit_count)) != 0) as usize]
        }
    };
}

But I have to pass type to the macro to get this done. Is there something like decltype() from C++ that I could use?

like image 403
Mihir Luthra Avatar asked Nov 18 '20 09:11

Mihir Luthra


1 Answers

No, Rust does not have the ability to get the type of an arbitrary expression. typeof is a reserved keyword to potentially allow it in the future:

fn main() {
    let a: i32 = 42;
    let b: typeof(a) = a;
}
error[E0516]: `typeof` is a reserved keyword but unimplemented
 --> src/main.rs:3:12
  |
3 |     let b: typeof(a) = a;
  |            ^^^^^^^^^ reserved keyword

There are RFCs suggesting that it be added.

See also:

  • How do I match the type of an expression in a Rust macro?
  • Is it possible to access the type of a struct member for function signatures or declarations?
  • .type` for getting concrete type of a binding — issue #2704

For your specific case, I would use traits instead:

use std::ops::RangeTo;

trait Mask {
    fn mask(self, range: RangeTo<usize>) -> Self;
}

impl Mask for u8 {
    #[inline]
    fn mask(self, range: RangeTo<usize>) -> Self {
        // Feel free to make this your more complicated bitwise logic
        let mut m = 0;
        for _ in 0..range.end {
            m <<= 1;
            m |= 1;
        }
        self & m
    }
}


fn main() {
    let bitmap: u8 = 0b_1111_1111;
    let masked_bitmap = bitmap.mask(..5);
    println!("{:#010b}", masked_bitmap);
}

You could use macros to implement the trait however:

macro_rules! impl_mask {
    ($($typ:ty),*) => {
        $(
            impl Mask for $typ {
                #[inline]
                fn mask(self, range: RangeTo<usize>) -> Self {
                    let mut m = 0;
                    for _ in 0..range.end {
                        m <<= 1;
                        m |= 1;
                    }
                    self & m
                }
            }
        )*
    };
}

impl_mask!(u8, u16, u32, u64, u128);
like image 120
Shepmaster Avatar answered Nov 05 '22 22:11

Shepmaster