Split cast into cast and cast_lossy

There is a difference in intent between wishing to cast and truncate the
value, and expecting the input to be within range. To make this clear,
add separate `cast_lossy` and `cast_from_lossy` to indicate what that
truncation is intended, leaving `cast` and `cast_from` to only be casts
that expected not to truncate.

Actually enforcing this at runtime is likely to have a cost, so just
`debug_assert!` that `cast` doesn't truncate.
This commit is contained in:
Trevor Gross 2025-01-11 22:04:32 +00:00 committed by Trevor Gross
parent ab1038a32b
commit beb34db83d

View file

@ -343,18 +343,30 @@ impl_h_int!(
/// Trait to express (possibly lossy) casting of integers
#[allow(unused)]
pub trait CastInto<T: Copy>: Copy {
/// By default, casts should be exact.
fn cast(self) -> T;
/// Call for casts that are expected to truncate.
fn cast_lossy(self) -> T;
}
#[allow(unused)]
pub trait CastFrom<T: Copy>: Copy {
/// By default, casts should be exact.
fn cast_from(value: T) -> Self;
/// Call for casts that are expected to truncate.
fn cast_from_lossy(value: T) -> Self;
}
impl<T: Copy, U: CastInto<T> + Copy> CastFrom<U> for T {
fn cast_from(value: U) -> Self {
value.cast()
}
fn cast_from_lossy(value: U) -> Self {
value.cast_lossy()
}
}
macro_rules! cast_into {
@ -364,6 +376,13 @@ macro_rules! cast_into {
($ty:ty; $($into:ty),*) => {$(
impl CastInto<$into> for $ty {
fn cast(self) -> $into {
// All we can really do to enforce casting rules is check the rules when in
// debug mode.
debug_assert!(<$into>::try_from(self).is_ok(), "failed cast from {self}");
self as $into
}
fn cast_lossy(self) -> $into {
self as $into
}
}