use core::{
cell::Cell,
cmp::Ordering,
fmt::{Debug, Display},
hash::Hash,
mem::{self, ManuallyDrop},
ops::{Deref, DerefMut},
ptr,
};
use crate::Unaligned;
use self::opt::OptUnaligned;
mod opt;
pub struct RefMut<'a, T> {
data: ManuallyDrop<T>,
cell: &'a UnalignedCell<T>,
}
impl<T> Drop for RefMut<'_, T> {
fn drop(&mut self) {
let value = unsafe { ManuallyDrop::take(&mut self.data) };
self.cell.0.set(OptUnaligned::some(value))
}
}
impl<T> Deref for RefMut<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DerefMut for RefMut<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T: Debug> Debug for RefMut<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RefMut").field("data", &*self.data).finish()
}
}
impl<T: Display> Display for RefMut<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
(*self.data).fmt(f)
}
}
#[derive(Debug)]
pub struct BorrowError;
#[cfg(feature = "std")]
impl std::error::Error for BorrowError {}
impl Display for BorrowError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("BorrowError")
}
}
pub struct UnalignedCell<T>(Cell<OptUnaligned<T>>);
impl<T> UnalignedCell<T> {
pub const fn new(value: T) -> Self {
Self(Cell::new(OptUnaligned::some(value)))
}
pub fn into_inner(self) -> T {
self.0
.into_inner()
.into_option()
.expect("value should not be borrowed (was a borrow leaked?)")
.into_inner()
}
pub fn as_ptr(&self) -> *mut T {
unsafe { OptUnaligned::project_ptr(self.0.as_ptr()) }
}
pub fn borrow(&self) -> RefMut<'_, T> {
self.try_borrow().expect("value should not be borrowed")
}
pub fn try_borrow(&self) -> Result<RefMut<'_, T>, BorrowError> {
let data = self.0.take().into_option().ok_or(BorrowError)?.into_inner();
Ok(RefMut {
data: ManuallyDrop::new(data),
cell: self,
})
}
pub fn get_mut(&mut self) -> &mut Unaligned<T> {
self.0.get_mut().as_option_mut().unwrap()
}
pub fn swap(&self, other: &Self) {
mem::swap(&mut *self.borrow(), &mut *other.borrow());
}
pub fn replace(&self, value: T) -> T {
mem::replace(&mut self.borrow(), value)
}
pub fn replace_with<F>(&self, f: F) -> T
where
F: FnOnce(&mut T) -> T,
{
let mut val = self.borrow();
let new_val = f(&mut val);
mem::replace(&mut val, new_val)
}
}
impl<T: Default> UnalignedCell<T> {
pub fn take(&self) -> T {
self.replace(T::default())
}
}
impl<T> From<T> for UnalignedCell<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: Clone> Clone for UnalignedCell<T> {
fn clone(&self) -> Self {
Self::new(self.borrow().clone())
}
}
impl<T: Default> Default for UnalignedCell<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: Debug> Debug for UnalignedCell<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("UnalignedCell")
.field(&*self.borrow())
.finish()
}
}
impl<T: Display> Display for UnalignedCell<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.borrow().fmt(f)
}
}
#[allow(clippy::eq_op)] impl<T: PartialEq> PartialEq for UnalignedCell<T> {
fn eq(&self, other: &Self) -> bool {
if ptr::eq(self, other) {
let value = self.borrow();
*value == *value
} else {
*self.borrow() == *other.borrow()
}
}
}
impl<T: Eq> Eq for UnalignedCell<T> {}
#[allow(clippy::eq_op)] impl<T: PartialOrd> PartialOrd for UnalignedCell<T> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
if ptr::eq(self, other) {
let value = self.borrow();
value.partial_cmp(&value)
} else {
self.borrow().partial_cmp(&other.borrow())
}
}
fn lt(&self, other: &Self) -> bool {
if ptr::eq(self, other) {
let value = self.borrow();
*value < *value
} else {
*self.borrow() < *other.borrow()
}
}
fn le(&self, other: &Self) -> bool {
if ptr::eq(self, other) {
let value = self.borrow();
*value <= *value
} else {
*self.borrow() <= *other.borrow()
}
}
fn gt(&self, other: &Self) -> bool {
if ptr::eq(self, other) {
let value = self.borrow();
*value > *value
} else {
*self.borrow() > *other.borrow()
}
}
fn ge(&self, other: &Self) -> bool {
if ptr::eq(self, other) {
let value = self.borrow();
*value >= *value
} else {
*self.borrow() >= *other.borrow()
}
}
}
impl<T: Ord> Ord for UnalignedCell<T> {
fn cmp(&self, other: &Self) -> Ordering {
if ptr::eq(self, other) {
let value = self.borrow();
value.cmp(&value)
} else {
self.borrow().cmp(&other.borrow())
}
}
fn max(self, other: Self) -> Self {
Self::new(T::max(self.into_inner(), other.into_inner()))
}
fn min(self, other: Self) -> Self {
Self::new(T::min(self.into_inner(), other.into_inner()))
}
fn clamp(self, min: Self, max: Self) -> Self {
Self::new(T::clamp(
self.into_inner(),
min.into_inner(),
max.into_inner(),
))
}
}
impl<T: Hash> Hash for UnalignedCell<T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.borrow().hash(state);
}
}