mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-21 14:22:26 +00:00
no_std + alloc
This commit is contained in:
parent
a45102007c
commit
0bae2db1b8
134
src/allocation.rs
Normal file
134
src/allocation.rs
Normal file
@ -0,0 +1,134 @@
|
||||
//! Stuff to boost things in the `alloc` crate.
|
||||
|
||||
use super::*;
|
||||
use alloc::{boxed::Box, rc::Rc, sync::Arc, vec::Vec};
|
||||
|
||||
/// As [`try_cast_arc`](try_cast_arc), but unwraps for you.
|
||||
#[inline]
|
||||
pub fn cast_arc<A: Pod, B: Pod>(input: Arc<A>) -> Arc<B> {
|
||||
try_cast_arc(input).map_err(|(e, _v)| e).unwrap()
|
||||
}
|
||||
|
||||
/// Attempts to cast the content type of a [`Arc`](alloc::sync::Arc).
|
||||
///
|
||||
/// On failure you get back an error along with the starting `Arc`.
|
||||
///
|
||||
/// ## Failure
|
||||
///
|
||||
/// * The start and end content type of the `Arc` must have the exact same
|
||||
/// alignment.
|
||||
/// * The start and end size of the `Arc` must have the exact same size.
|
||||
#[inline]
|
||||
pub fn try_cast_arc<A: Pod, B: Pod>(input: Arc<A>) -> Result<Arc<B>, (PodCastError, Arc<A>)> {
|
||||
if align_of::<A>() != align_of::<B>() {
|
||||
Err((PodCastError::AlignmentMismatch, input))
|
||||
} else if size_of::<A>() != size_of::<B>() {
|
||||
Err((PodCastError::SizeMismatch, input))
|
||||
} else {
|
||||
// Note(Lokathor): This is much simpler than with the Vec casting!
|
||||
let ptr: *mut B = Arc::into_raw(input) as *mut B;
|
||||
Ok(unsafe { Arc::from_raw(ptr) })
|
||||
}
|
||||
}
|
||||
|
||||
/// As [`try_cast_box`](try_cast_box), but unwraps for you.
|
||||
#[inline]
|
||||
pub fn cast_box<A: Pod, B: Pod>(input: Box<A>) -> Box<B> {
|
||||
try_cast_box(input).map_err(|(e, _v)| e).unwrap()
|
||||
}
|
||||
|
||||
/// Attempts to cast the content type of a [`Box`](alloc::boxed::Box).
|
||||
///
|
||||
/// On failure you get back an error along with the starting `Box`.
|
||||
///
|
||||
/// ## Failure
|
||||
///
|
||||
/// * The start and end content type of the `Box` must have the exact same
|
||||
/// alignment.
|
||||
/// * The start and end size of the `Box` must have the exact same size.
|
||||
#[inline]
|
||||
pub fn try_cast_box<A: Pod, B: Pod>(input: Box<A>) -> Result<Box<B>, (PodCastError, Box<A>)> {
|
||||
if align_of::<A>() != align_of::<B>() {
|
||||
Err((PodCastError::AlignmentMismatch, input))
|
||||
} else if size_of::<A>() != size_of::<B>() {
|
||||
Err((PodCastError::SizeMismatch, input))
|
||||
} else {
|
||||
// Note(Lokathor): This is much simpler than with the Vec casting!
|
||||
let ptr: *mut B = Box::into_raw(input) as *mut B;
|
||||
Ok(unsafe { Box::from_raw(ptr) })
|
||||
}
|
||||
}
|
||||
|
||||
/// As [`try_cast_rc`](try_cast_rc), but unwraps for you.
|
||||
#[inline]
|
||||
pub fn cast_rc<A: Pod, B: Pod>(input: Rc<A>) -> Rc<B> {
|
||||
try_cast_rc(input).map_err(|(e, _v)| e).unwrap()
|
||||
}
|
||||
|
||||
/// Attempts to cast the content type of a [`Rc`](alloc::rc::Rc).
|
||||
///
|
||||
/// On failure you get back an error along with the starting `Rc`.
|
||||
///
|
||||
/// ## Failure
|
||||
///
|
||||
/// * The start and end content type of the `Rc` must have the exact same
|
||||
/// alignment.
|
||||
/// * The start and end size of the `Rc` must have the exact same size.
|
||||
#[inline]
|
||||
pub fn try_cast_rc<A: Pod, B: Pod>(input: Rc<A>) -> Result<Rc<B>, (PodCastError, Rc<A>)> {
|
||||
if align_of::<A>() != align_of::<B>() {
|
||||
Err((PodCastError::AlignmentMismatch, input))
|
||||
} else if size_of::<A>() != size_of::<B>() {
|
||||
Err((PodCastError::SizeMismatch, input))
|
||||
} else {
|
||||
// Note(Lokathor): This is much simpler than with the Vec casting!
|
||||
let ptr: *mut B = Rc::into_raw(input) as *mut B;
|
||||
Ok(unsafe { Rc::from_raw(ptr) })
|
||||
}
|
||||
}
|
||||
|
||||
/// As [`try_cast_vec`](try_cast_vec), but unwraps for you.
|
||||
#[inline]
|
||||
pub fn cast_vec<A: Pod, B: Pod>(input: Vec<A>) -> Vec<B> {
|
||||
try_cast_vec(input).map_err(|(e, _v)| e).unwrap()
|
||||
}
|
||||
|
||||
/// Attempts to cast the content type of a [`Vec`](alloc::vec::Vec).
|
||||
///
|
||||
/// On failure you get back an error along with the starting `Vec`.
|
||||
///
|
||||
/// ## Failure
|
||||
///
|
||||
/// * The start and end content type of the `Vec` must have the exact same
|
||||
/// alignment.
|
||||
/// * The start and end size of the `Vec` must have the exact same size.
|
||||
/// * In the future this second restriction might be lessened by having the
|
||||
/// capacity and length get adjusted during transmutation, but for now it's
|
||||
/// absolute.
|
||||
#[inline]
|
||||
pub fn try_cast_vec<A: Pod, B: Pod>(input: Vec<A>) -> Result<Vec<B>, (PodCastError, Vec<A>)> {
|
||||
if align_of::<A>() != align_of::<B>() {
|
||||
Err((PodCastError::AlignmentMismatch, input))
|
||||
} else if size_of::<A>() != size_of::<B>() {
|
||||
// Note(Lokathor): Under some conditions it would be possible to cast
|
||||
// between Vec content types of the same alignment but different sizes by
|
||||
// changing the capacity and len values in the output Vec. However, we will
|
||||
// not attempt that for now.
|
||||
Err((PodCastError::SizeMismatch, input))
|
||||
} else {
|
||||
// Note(Lokathor): First we record the length and capacity, which don't have
|
||||
// any secret provenance metadata.
|
||||
let length: usize = input.len();
|
||||
let capacity: usize = input.capacity();
|
||||
// Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with
|
||||
// ManuallyDrop, because if we used `core::mem::forget` after taking the
|
||||
// pointer then that would invalidate our pointer.
|
||||
let mut manual_drop_vec = ManuallyDrop::new(input);
|
||||
// Note(Lokathor): Finally, we carefully get the pointer we need, cast the
|
||||
// type, and then make a new Vec to return. This works all the way back to
|
||||
// 1.7, if you're on 1.37 or later you can use `Vec::as_mut_ptr` directly.
|
||||
let vec_ptr = *mut A = Vec::as_mut_slice(&mut manual_drop_vec).as_mut_ptr();
|
||||
let ptr: *mut B = vec_ptr as *mut B;
|
||||
Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) })
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub(crate) use core::arch::x86;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@ -11,6 +13,13 @@ macro_rules! impl_unsafe_marker_for_array {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "extern_crate_alloc")]
|
||||
extern crate alloc;
|
||||
#[cfg(feature = "extern_crate_alloc")]
|
||||
mod allocation;
|
||||
#[cfg(feature = "extern_crate_alloc")]
|
||||
pub use allocation::*;
|
||||
|
||||
mod zeroable;
|
||||
pub use zeroable::*;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user