Unwieldy duplication of the public API
notgull opened this issue · 1 comments
As mentioned here, bytemuck
's public API is very quickly becoming very unwieldy. Here's a screenshot of the current docs.rs
main page. This doesn't include the functions in the allocation
and checked
modules.
My proposed solution is as follows:
Since bytemuck
is essentially just a wrapper around "safe transmute", I propose that the current set of functions is replaced with a try_cast
function and a cast
function, that operates like this:
pub fn try_cast<Out, In: TransmutableTo<Out>>(input: In) -> Result<Out, In::Error> {
if let Err(e) = input.can_transmute() {
Err(e)
} else {
Ok(unsafe { transmute!(input) })
}
}
pub fn cast<Out, In: TransmutableTo<Out>>(input: In) -> Out {
try_cast(input).expect("Failed to transmute value")
}
pub unsafe trait TransmutableTo<T: Copy> : Copy {
type Error;
fn can_transmute(&self) -> Result<(), Self::Error>;
}
Where try_cast
is basically just a wrapper around the transmute!
macro.
The individual functions (i.e. cast_ref
or cast_slice
) could be replaced with #[repr(transparent)]
helper structs. For instance, to emulate the current behavior of cast
, there would be a Raw
structure, implemented like so:
pub struct Raw<T>(pub T);
unsafe impl<In: NoUninit, Out: AnyBitPattern> TransmutableTo<Out> for Raw<In> {
type Error = PodCastError;
fn can_transmute(&self) -> Result<(), Self::Error> {
// do the checks on size/alignment/et al
}
}
// in user code
let a: u16 = bytemuck::cast(bytemuck::Raw(-3i16));
Then, you could implement cast_ref
like so:
pub struct Ref<'a, T>(pub &'a T);
unsafe impl<'a, In: NoUninit, Out: AnyBitPattern> TransmutableTo<&'a Out> for Raw<'a In> {
type Error = PodCastError;
fn can_transmute(&self) -> Result<(), Self::Error> {
// do the checks on size/alignment/et al
}
}
let a: &u16 = bytemuck::cast(bytemuck::Raw(&-3i16));
And so on and so forth. I also imagine you could then implement Box
and all through combinations of some kind.
I haven't thought this through all the way, though, so someone more clever than I am could probably come up with something better.
I'm not keen on the idea that someone has to wrap their data in some extra wrapper type we provide them for the functions to work.