use std::mem::{MaybeUninit, transmute};
enum SrcDestInner<'src, 'dst, T> {
InOut(&'src [T], &'dst mut [MaybeUninit<T>]),
InMut(&'dst mut [T]),
}
pub struct SrcDest<'src, 'dst, T: Copy> {
inner: SrcDestInner<'src, 'dst, T>,
}
impl<'dst, T: Copy> SrcDest<'_, 'dst, T> {
pub fn src(&self) -> &[T] {
match &self.inner {
SrcDestInner::InOut(src, _dest) => src,
SrcDestInner::InMut(src_mut) => src_mut,
}
}
pub fn len(&self) -> usize {
self.src().len()
}
pub fn is_empty(&self) -> bool {
self.src().is_empty()
}
pub fn src_dest_ptr(&mut self) -> (*const T, *mut MaybeUninit<T>, usize) {
match &mut self.inner {
SrcDestInner::InOut(src, dest) => (src.as_ptr(), dest.as_mut_ptr(), src.len()),
SrcDestInner::InMut(src) => (
src.as_ptr(),
src.as_mut_ptr() as *mut MaybeUninit<T>,
src.len(),
),
}
}
pub unsafe fn dest_assume_init(self) -> &'dst mut [T] {
match self.inner {
SrcDestInner::InOut(_src, dest) => unsafe {
transmute::<&mut [MaybeUninit<T>], &mut [T]>(dest)
},
SrcDestInner::InMut(src) => src,
}
}
}
impl<'src, 'dst, T: Copy> From<(&'src [T], &'dst mut [MaybeUninit<T>])> for SrcDest<'src, 'dst, T> {
#[track_caller]
fn from(val: (&'src [T], &'dst mut [MaybeUninit<T>])) -> Self {
let (src, dest) = val;
assert!(
src.len() == dest.len(),
"src len {} != dest len {}",
src.len(),
dest.len(),
);
SrcDest {
inner: SrcDestInner::InOut(src, dest),
}
}
}
impl<'dst, T: Copy> From<&'dst mut [T]> for SrcDest<'dst, 'dst, T> {
fn from(val: &'dst mut [T]) -> Self {
SrcDest {
inner: SrcDestInner::InMut(val),
}
}
}