use crate::*;
use core::{
fmt::{Debug, Display},
hash::Hash,
};
#[must_use = "dropping a `Loaned` panics; use `loaned::drop!` instead"]
#[repr(transparent)]
pub struct Loaned<'t, T> {
pub(crate) inner: RawLoaned<T>,
pub(crate) _contravariant: PhantomData<fn(&'t ())>,
}
unsafe impl<'t, T: Sync> Send for Loaned<'t, T> {}
impl<'t, T> Loaned<'t, T> {
#[inline]
pub fn loan(value: T) -> (&'t T::Target, Self)
where
T: Loanable<'t>,
{
let loaned = unsafe { Loaned::from_raw(RawLoaned::new(value)) };
(loaned.borrow(), loaned)
}
#[inline(always)]
pub fn new(value: T) -> Self {
unsafe { Loaned::from_raw(RawLoaned::new(value)) }
}
#[inline(always)]
pub fn place(self, place: &'t mut impl Place<'t, T>) {
Place::place(self.into(), place)
}
#[inline(always)]
pub fn borrow(&self) -> &'t T::Target
where
T: Loanable<'t>,
{
unsafe { &*(&**self.inner.as_ref() as *const _) }
}
#[inline(always)]
pub(crate) fn into_raw(self) -> RawLoaned<T> {
unsafe { ptr::read(&ManuallyDrop::new(self).inner) }
}
#[inline(always)]
pub(crate) unsafe fn from_raw(inner: RawLoaned<T>) -> Self {
Loaned {
inner,
_contravariant: PhantomData,
}
}
}
impl<'t, T> Deref for Loaned<'t, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { self.inner.as_ref() }
}
}
impl<'t, T> Drop for Loaned<'t, T> {
#[cold]
fn drop(&mut self) {
#[cfg(feature = "std")]
if mem::needs_drop::<T>() && !std::thread::panicking() {
panic!(
"memory leak: cannot drop `{Self}`
if leaking is desired, use `ManuallyDrop<{Self}>` or `mem::forget`
otherwise, use `drop!(loaned)` to drop the inner value",
Self = core::any::type_name::<Self>()
)
}
}
}
impl<'t, T: Debug> Debug for Loaned<'t, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Loaned").field(&**self).finish()
}
}
impl<'t, T: Display> Display for Loaned<'t, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
(**self).fmt(f)
}
}
impl<'t, T: Clone> Clone for Loaned<'t, T> {
fn clone(&self) -> Self {
Loaned::new((**self).clone())
}
}
impl<'t, T: Default> Default for Loaned<'t, T> {
fn default() -> Self {
Loaned::new(Default::default())
}
}
impl<'t, 'u, T: PartialEq<U>, U> PartialEq<Loaned<'u, U>> for Loaned<'t, T> {
fn eq(&self, other: &Loaned<'u, U>) -> bool {
(&**self) == (&**other)
}
}
impl<'t, T: Eq> Eq for Loaned<'t, T> {}
impl<'t, 'u, T: PartialOrd<U>, U> PartialOrd<Loaned<'u, U>> for Loaned<'t, T> {
fn partial_cmp(&self, other: &Loaned<'u, U>) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<'t, T: Ord> Ord for Loaned<'t, T> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<'t, T: Hash> Hash for Loaned<'t, T> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<'t, T> From<T> for Loaned<'t, T> {
fn from(value: T) -> Self {
Loaned::new(value)
}
}
impl<'t, T> Loaned<'t, T> {
pub fn merge(value: T, f: impl for<'i> FnOnce(&'i mut T, &'i Merge<'t, 'i>)) -> Self {
unsafe {
let mut inner = RawLoaned::new(value);
f(inner.as_mut(), &Merge(PhantomData));
Loaned::from_raw(inner)
}
}
}
#[doc(hidden)]
pub struct Merge<'t, 'i>(PhantomData<(&'t mut &'t (), &'i mut &'i ())>);
impl<'t, 'i> Merge<'t, 'i> {
pub fn place<T>(&'i self, loaned: Loaned<'t, T>, place: &'i mut impl Place<'i, T>) {
Place::place(unsafe { LoanedMut::from_raw(loaned.into_raw()) }, place)
}
}
impl<'t, T> Loaned<'t, T> {
pub fn loan_with<L>(
value: T,
f: impl for<'i> FnOnce(&'i mut T, &'i LoanWith<'t, 'i>) -> L,
) -> (L, Self) {
unsafe {
let mut inner = RawLoaned::new(value);
let loans = f(inner.as_mut(), &LoanWith(PhantomData));
(loans, Loaned::from_raw(inner))
}
}
}
#[doc(hidden)]
pub struct LoanWith<'t, 'i>(PhantomData<(&'t mut &'t (), &'i mut &'i ())>);
impl<'t, 'i> LoanWith<'t, 'i> {
pub fn loan<T: Loanable<'i>>(&'i self, value: &'i T) -> &'t T::Target {
unsafe { &*(&**value as *const _) }
}
}