mod inner;
#[cfg(no_std)]
use core::{
any::Any,
fmt,
ops::Deref,
mem::ManuallyDrop
};
#[cfg(not(no_std))]
use std::{
any::Any,
fmt,
ops::Deref,
mem::ManuallyDrop
};
use super::{OwnedArgument, discriminant::Discriminant};
use inner::{RawArgument, InnerArgument};
pub use inner::ArgumentKind;
#[repr(transparent)]
pub struct Argument<'a>
{
inner: InnerArgument<'a>
}
impl fmt::Debug for Argument<'_>
{
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self.discriminant()
{
Discriminant::Borrowed =>
{
f.debug_tuple("Argument::Borrowed")
.field(&self.inner.to_ref())
.finish()
}
_ =>
{
f.debug_tuple("Argument::Owned")
.field(unsafe { self.inner.owned_debug_handle() })
.finish()
}
}
}
}
impl Drop for Argument<'_>
{
#[inline(always)]
fn drop(&mut self)
{
let _ = unsafe { self.inner.take_raw_argument() };
}
}
impl<'a> Clone for Argument<'a>
{
#[inline(always)]
fn clone(&self) -> Self
{
let inner =
match self.discriminant()
{
Discriminant::Borrowed =>
{
let ref_ =
unsafe {
self.inner
.ref_unchecked()
};
InnerArgument::new_ref(ref_)
}
_ =>
{
let owned =
{
let raw = &raw const self.inner;
unsafe
{
(*raw.cast::<OwnedArgument>()).clone()
}
};
InnerArgument::new_owned(owned)
}
};
Self
{
inner
}
}
}
impl Deref for Argument<'_>
{
type Target = dyn Any;
#[inline(always)]
fn deref(&self) -> &dyn Any
{
self.inner
.to_ref()
}
}
impl Argument<'_>
{
#[inline(always)]
pub fn new_owned<T>(item: T) -> Self
where
T: Any + Clone
{
let owned = OwnedArgument::new(item);
Self
{
inner: InnerArgument::new_owned(owned)
}
}
#[inline(always)]
pub fn is_owned(&self) -> bool
{
self.inner
.is_owned()
}
#[inline(always)]
pub fn is_borrowed(&self) -> bool
{
self.inner
.is_borrowed()
}
#[inline(always)]
pub fn to_mut(&mut self) -> &mut dyn Any
{
self.inner
.to_mut()
}
#[inline(always)]
fn discriminant(&self) -> Discriminant
{
self.inner
.discriminant()
}
#[inline(always)]
pub fn to_owned(&self) -> Self
{
match self.discriminant()
{
Discriminant::Borrowed =>
{
let ref_ =
unsafe
{
self.inner
.ref_unchecked()
};
let owned = ref_.clone_object();
Self
{
inner: InnerArgument::new_owned(owned)
}
}
_ => self.clone()
}
}
#[inline(always)]
pub fn downcast_owned<T>(self) -> Result<T, Self>
where
T: Clone + Any
{
match self.inner_contents()
{
RawArgument::Owned(owned)
if owned.is_type::<T>() =>
unsafe
{
Ok(owned.downcast_owned_unchecked())
}
RawArgument::Owned(o)
=>
Err(Self { inner: InnerArgument::new_owned(o) }),
RawArgument::Borrowed(b)
=>
Err(Self { inner: InnerArgument::new_ref(b) })
}
}
#[inline(always)]
pub unsafe fn downcast_owned_unchecked<T>(self) -> T
where
T: Clone + Any
{
debug_assert!(self.is_owned());
let RawArgument::Owned(contents) = self.inner_contents()
else
{
#[cfg(debug_assertions)]
{
unreachable!()
}
#[cfg(not(debug_assertions))]
{
panic!()
}
};
debug_assert!(contents.is_type::<T>());
unsafe
{
contents.downcast_owned_unchecked()
}
}
#[inline(always)]
pub fn downcast_cloned<T>(&self) -> Option<T>
where
T: Any + Clone
{
#[allow(clippy::manual_map)]
match self.downcast_ref::<T>()
{
Some(t) => Some(t.clone()),
None => None
}
}
#[inline(always)]
unsafe fn downcast_ref_unchecked<T>(&self) -> &T
where
T: Any + Clone
{
let binding = self.inner.to_ref();
debug_assert!(binding.is::<T>());
unsafe
{
&*(binding as *const dyn Any as *const T)
}
}
#[inline(always)]
pub unsafe fn downcast_cloned_unchecked<T>(&self) -> T
where
T: Any + Clone
{
unsafe
{
self.downcast_ref_unchecked::<T>().clone()
}
}
}
impl<'a> Argument<'a>
{
#[inline(always)]
pub fn new_borrowed<T>(item: &'a T) -> Self
where
T: Any + Clone
{
Self
{
inner: InnerArgument::new_ref(item)
}
}
#[inline(always)]
pub fn as_ref(&'a self) -> Self
{
Self
{
inner: self.inner.as_ref()
}
}
#[inline(always)]
fn inner_contents(self) -> RawArgument<'a>
{
let mut store = ManuallyDrop::new(self);
unsafe
{
store.inner.take_raw_argument()
}
}
#[inline(always)]
pub fn into_inner(self) -> ArgumentKind<'a>
{
let store = ManuallyDrop::new(self);
let raw = &raw const store.inner;
unsafe
{
raw.read().into_inner()
}
}
}
impl From<OwnedArgument> for Argument<'_>
{
fn from(item: OwnedArgument) -> Self
{
Self
{
inner: InnerArgument::new_owned(item)
}
}
}