I'd like to create a trait — call it IntWrapper
— for a type which wraps an integer. When IntWrapper
is satisfied, the concrete type should also automatically implement a bunch of other traits like std::ops::BitOr.
I've succeeded in writing an impl
for one specific concrete type, but not in creating a generic impl
which will work for all concrete types. Is the problem that I am not specifying the bounds properly in the generic BitOr implementation for the trait IntWrapper?
use std::ops::BitOr;
pub trait IntWrapper {
// An integer type like `u32`.
//
// I chose not to make IntWrapper generic (i.e. `pub trait IntWrapper<T>`)
// because there must be only a single implementation of IntWrapper for
// any concrete type. In other words, a type must not be able to
// implement both `IntWrapper<u32>` and `IntWrapper<u64>` — it can only
// implement IntWrapper once, and it must choose a specific type for
// `InternalStorage`.
type InternalStorage;
fn bits(&self) -> Self::InternalStorage;
fn set_bits(&mut self, bits: Self::InternalStorage);
fn new() -> Self
where
Self: Sized;
fn from_bits(bits: Self::InternalStorage) -> Self
where
Self: Sized,
{
let mut wrapper = Self::new();
wrapper.set_bits(bits);
wrapper
}
}
// The test passes if we uncomment this `impl` for the concrete type
// `MyStruct` and comment out the failing generic `impl` below. However, I'd
// like a generic `impl` instead so that we don't have to create an
// `impl BitOr` for every concrete type.
/*
impl BitOr for MyStruct {
type Output = Self;
fn bitor(self, other: Self) -> Self {
Self::from_bits(self.bits() | other.bits())
}
}
*/
// How do we specify the bounds on this impl, such that they are satisfied
// for any concrete type which meets the following conditions?
//
// - The size of the concrete type is known at compile time.
// - The type implements the `IntWrapper` trait.
// - The associated type `IntWrapper::InternalStorage` implements `BitOr` and
// `BitOr<Output = T>` (which will be true for any integer type like `u32`,
// etc.)
impl<T> BitOr for IntWrapper<InternalStorage = T>
where
Self: Sized,
T: BitOr + BitOr<Output = T>
{
type Output = Self;
fn bitor(self, other: Self) -> Self {
Self::from_bits(self.bits() | other.bits())
}
}
#[derive(Debug, PartialEq)]
struct MyStruct {
bits: u32,
}
impl IntWrapper for MyStruct {
type InternalStorage = u32;
fn new() -> Self {
MyStruct { bits: 0 }
}
fn bits(&self) -> u32 {
self.bits
}
fn set_bits(&mut self, bits: u32) {
self.bits = bits;
}
}
#[test]
fn my_struct_bitor_correct() {
let four = MyStruct::from_bits(0b_0100);
let eight = MyStruct::from_bits(0b_1000);
let twelve = MyStruct::from_bits(0b_1100);
assert_eq!(four | eight, twelve);
}
PS: My Playground code panics the compiler.