pub unsafe trait Contiguous: Copy + 'static {
type Int: Copy + Ord;
const MAX_VALUE: Self::Int;
const MIN_VALUE: Self::Int;
// Provided methods
fn from_integer(value: Self::Int) -> Option<Self> { ... }
fn into_integer(self) -> Self::Int { ... }
}
Expand description
A trait indicating that:
- A type has an equivalent representation to some known integral type.
- All instances of this type fall in a fixed range of values.
- Within that range, there are no gaps.
This is generally useful for fieldless enums (aka “c-style” enums), however
it’s important that it only be used for those with an explicit #[repr]
, as
#[repr(Rust)]
fieldess enums have an unspecified layout.
Additionally, you shouldn’t assume that all implementations are enums. Any type which meets the requirements above while following the rules under “Safety” below is valid.
§Example
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq)]
enum Foo {
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
}
unsafe impl Contiguous for Foo {
type Int = u8;
const MIN_VALUE: u8 = Foo::A as u8;
const MAX_VALUE: u8 = Foo::E as u8;
}
assert_eq!(Foo::from_integer(3).unwrap(), Foo::D);
assert_eq!(Foo::from_integer(8), None);
assert_eq!(Foo::C.into_integer(), 2);
§Safety
This is an unsafe trait, and incorrectly implementing it is undefined behavior.
Informally, by implementing it, you’re asserting that C
is identical to
the integral type C::Int
, and that every C
falls between C::MIN_VALUE
and C::MAX_VALUE
exactly once, without any gaps.
Precisely, the guarantees you must uphold when implementing Contiguous
for
some type C
are:
-
The size of
C
andC::Int
must be the same, and neither may be a ZST. (Note: alignment is explicitly allowed to differ) -
C::Int
must be a primitive integer, and not a wrapper type. In the future, this may be lifted to include cases where the behavior is identical for a relevant set of traits (Ord, arithmetic, …). -
All
C::Int
s which are in the inclusive range betweenC::MIN_VALUE
andC::MAX_VALUE
are bitwise identical to unique valid instances ofC
. -
There exist no instances of
C
such that their bitpatterns, when interpreted as instances ofC::Int
, fall outside of theMAX_VALUE
/MIN_VALUE
range – It is legal for unsafe code to assume that if it gets aC
that implementsContiguous
, it is in the appropriate range. -
Finally, you promise not to provide overridden implementations of
Contiguous::from_integer
andContiguous::into_integer
.
For clarity, the following rules could be derived from the above, but are listed explicitly:
-
C::MAX_VALUE
must be greater or equal toC::MIN_VALUE
(therefore,C
must be an inhabited type). -
There exist no two values between
MIN_VALUE
andMAX_VALUE
such that when interpreted as aC
they are considered identical (by, say, match).
Required Associated Constants§
Required Associated Types§
sourcetype Int: Copy + Ord
type Int: Copy + Ord
The primitive integer type with an identical representation to this type.
Contiguous is broadly intended for use with fieldless enums, and for
these the correct integer type is easy: The enum should have a
#[repr(Int)]
or #[repr(C)]
attribute, (if it does not, it is
unsound to implement Contiguous
!).
-
For
#[repr(Int)]
, use the listedInt
. e.g.#[repr(u8)]
should usetype Int = u8
. -
For
#[repr(C)]
, use whichever type the C compiler will use to represent the given enum. This is usuallyc_int
(fromstd::os::raw
orlibc
), but it’s up to you to make the determination as the implementer of the unsafe trait.
For precise rules, see the list under “Safety” above.
Provided Methods§
sourcefn from_integer(value: Self::Int) -> Option<Self>
fn from_integer(value: Self::Int) -> Option<Self>
If value
is within the range for valid instances of this type,
returns Some(converted_value)
, otherwise, returns None
.
This is a trait method so that you can write value.into_integer()
in
your code. It is a contract of this trait that if you implement
Contiguous
on your type you must not override this method.
§Panics
We will not panic for any correct implementation of Contiguous
, but
may panic if we detect an incorrect one.
This is undefined behavior regardless, so it could have been the nasal demons at that point anyway ;).
sourcefn into_integer(self) -> Self::Int
fn into_integer(self) -> Self::Int
Perform the conversion from C
into the underlying integral type. This
mostly exists otherwise generic code would need unsafe for the value as integer
This is a trait method so that you can write value.into_integer()
in
your code. It is a contract of this trait that if you implement
Contiguous
on your type you must not override this method.
§Panics
We will not panic for any correct implementation of Contiguous
, but
may panic if we detect an incorrect one.
This is undefined behavior regardless, so it could have been the nasal demons at that point anyway ;).