#![no_std]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![warn(unsafe_op_in_unsafe_fn)]
use core::mem::MaybeUninit;
mod pin;
pub use field_projection_internal::*;
pub use pin::*;
pub struct FieldName<const N: u64>(());
pub use const_fnv1a_hash::fnv1a_hash_str_64 as field_name_hash;
pub unsafe trait Field<Base> {
type Type: ?Sized;
const NAME: &'static str;
unsafe fn map(ptr: *const Base) -> *const Self::Type;
}
pub trait Projectable<T, F: Field<T>> {
type Target;
unsafe fn project(self) -> Self::Target;
#[doc(hidden)]
unsafe fn project_with_check(this: Self, _check: fn(&T)) -> Self::Target
where
Self: Sized,
{
unsafe { Self::project(this) }
}
}
impl<'a, T, F> Projectable<T, F> for &'a MaybeUninit<T>
where
F: Field<T>,
F::Type: Sized + 'a,
{
type Target = &'a MaybeUninit<F::Type>;
unsafe fn project(self) -> Self::Target {
unsafe { &*F::map(self.as_ptr()).cast::<MaybeUninit<F::Type>>() }
}
}
impl<'a, T, F> Projectable<T, F> for &'a mut MaybeUninit<T>
where
F: Field<T>,
F::Type: Sized + 'a,
{
type Target = &'a mut MaybeUninit<F::Type>;
unsafe fn project(self) -> Self::Target {
unsafe {
&mut *F::map(self.as_mut_ptr())
.cast_mut()
.cast::<MaybeUninit<F::Type>>()
}
}
}
#[macro_export]
macro_rules! project {
($a:expr => $b:ident) => {
match $a {
__expr => unsafe {
$crate::Projectable::<
_,
$crate::FieldName<{ $crate::field_name_hash(core::stringify!($b)) }>,
>::project_with_check(__expr, |__check| {
let _ = __check.$b;
})
},
}
};
}