Search code examples
rust

How to extend usize?


I'm new to Rust. The following code is my attempt to create an extension of usize that allows for:

  • setting a length in bits
  • printing in bits with leading zeroes based on length
  • most important, shifting to the next lexicographic permutation of bits. (eg 0101 -> 0110)

The struct below does all that, but it doesn't behave like a usize otherwise. Maybe I'm going about this all wrong and a struct isn't the right vehicle for this. As an example of this not working:

let mut permutable_usize = PermutableUsize::new(0b00010011, 8);
permutable_usize += 1;

The above generates an error and says I must implement AddAssign<_>.

I'm sure there's a 'right way' to do this that avoids re-implementing all the usize methods. How should I proceed?

Here's what I have now:

struct PermutableUsize {
    value: usize,
    num_bits: usize,
}

impl PermutableUsize {
    fn new(value: usize, num_bits: usize) -> Self {
        Self {
            value,
            num_bits,
        }
    }

    // Method to compute the next lexicographic permutation of bits
    // The logic comes from bit-twiddling hacks at https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation 
    fn next_permutation(&mut self) {
        let t = self.value | (self.value - 1);
        let ctz_v = self.value.trailing_zeros();
        self.value = (t + 1) | (((!t & (!t).wrapping_neg()) - 1) >> (ctz_v + 1));
    }
}

use std::fmt;

impl fmt::Binary for PermutableUsize {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:0width$b}", self.value, width = self.num_bits)
    }
}

fn main() {
    let mut permutable_usize = PermutableUsize::new(0b00010011, 8); // example with 8 bits
    println!("Initial value: {:08b}", permutable_usize); 

    permutable_usize.next_permutation();
    println!("Next permutation: {:08b}", permutable_usize); 
}

Solution

  • The right way is to implement all methods, but you don't have to do that manually: there are crates that can help with that, for example derive_more. There is also a proposed RFC to help with that. The general pattern is called "delegation".

    If you want all methods of usize to be available, you can implement Deref. The Rust community is divided on whether this is a good idea, though. Also, this doesn't help with traits (there the crates I mentioned help).