Trait enum_like::EnumLike

source ·
pub unsafe trait EnumLike: Copy {
    const NUM_VARIANTS: usize;

    fn to_discr(self) -> usize;
    fn from_discr(x: usize) -> Self;
}
Expand description

The EnumLike trait specifies how a type will be stored inside the EnumVec.

It associates every possible instance of the type with a number. However this number does not need to be the same as the result of a simple enum as usize cast.

This trait is unsafe because implementations must follow the contract, especially the first rule:

  • self.to_discr() returns a value x < NUM_VARIANTS
  • Self::from_discr(self.to_discr()) == self
  • Self::from_discr(x) is only required to handle valid values of x

Example 1

use enum_like::EnumLike;

#[derive(Copy, Clone, Debug)]
enum ExtendedBool {
    True,
    False,
    FileNotFound,
}

unsafe impl EnumLike for ExtendedBool {
    const NUM_VARIANTS: usize = 3;

    fn to_discr(self) -> usize {
        match self {
            ExtendedBool::True => 0,
            ExtendedBool::False => 1,
            ExtendedBool::FileNotFound => 2,
        }
    }

    fn from_discr(x: usize) -> Self {
        match x {
            0 => ExtendedBool::True,
            1 => ExtendedBool::False,
            2 => ExtendedBool::FileNotFound,
            _ => unreachable!(),
        }
    }
}

Example 2

use enum_like::EnumLike;

#[derive(Copy, Clone, Debug)]
enum SomeFlags {
    Read = 4,
    Write = 2,
    Exec = 1,
}

unsafe impl EnumLike for SomeFlags {
    const NUM_VARIANTS: usize = 3;

    fn to_discr(self) -> usize {
        match self {
            // We override the default values, because 4 is out of range,
            // but we could also increase NUM_VARIANTS to 5 instead.
            SomeFlags::Read => 0,
            SomeFlags::Write => 1,
            SomeFlags::Exec => 2,

        }
    }

    fn from_discr(x: usize) -> Self {
        match x {
            0 => SomeFlags::Read,
            1 => SomeFlags::Write,
            2 => SomeFlags::Exec,
            _ => unreachable!(),
        }
    }
}

Example 3

Of course, it is not limited to enums:

use enum_like::EnumLike;

#[derive(Copy, Clone, Debug)]
struct Digit {
    x: u8, // x >= 0 && x <= 9
}

unsafe impl EnumLike for Digit {
    const NUM_VARIANTS: usize = 10;
    fn to_discr(self) -> usize {
        self.x as usize
    }
    fn from_discr(x: usize) -> Self {
        let x = x as u8;
        Self { x }
    }
}

Here it is important to make sure that the Digit will always have a valid value in the [0, 9] range. Otherwise, if self.to_discr() returns any number bigger than NUM_VARIANTS, everything breaks.

Required Associated Constants

The number of variants of this type

Required Methods

Convert type to discriminant

Get type instance from discriminant

Implementations on Foreign Types

Implementors