Skip to main content

variadic_arguments/argument/
arg.rs

1mod inner;
2
3#[cfg(no_std)]
4use core::{
5    any::Any,
6    fmt,
7    ops::Deref,
8    mem::ManuallyDrop
9};
10
11#[cfg(not(no_std))]
12use std::{
13    any::Any,
14    fmt,
15    ops::Deref,
16    mem::ManuallyDrop
17};
18
19use super::{OwnedArgument, discriminant::Discriminant};
20
21use inner::{RawArgument, InnerArgument};
22
23pub use inner::ArgumentKind;
24
25/// A variant item that implements Copy-on-Write.
26///
27/// It acts similarly to a [Cow], except for two things:
28/// 1. It is encapsulated, meaning that the inner contents cannot be accessed.
29/// 2. The storage is handled differently compared to [Cow], which allows for a smaller type size.
30///
31/// [Cow]: std::borrow::Cow
32#[repr(transparent)]
33pub struct Argument<'a>
34{
35    inner: InnerArgument<'a>
36}
37
38
39impl fmt::Debug for Argument<'_>
40{
41    #[inline(always)]
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
43    {
44        match self.discriminant()
45        {
46            Discriminant::Borrowed =>
47            {
48                f.debug_tuple("Argument::Borrowed")
49                 .field(&self.inner.to_ref())
50                 .finish()
51            }
52            _ =>
53            {
54                f.debug_tuple("Argument::Owned")
55                 .field(unsafe { self.inner.owned_debug_handle() })
56                 .finish()
57            }
58        }
59    }
60}
61
62
63impl Drop for Argument<'_>
64{
65    #[inline(always)]
66    fn drop(&mut self)
67    {
68        let _ = unsafe { self.inner.take_raw_argument() };
69    }
70}
71
72
73impl<'a> Clone for Argument<'a>
74{
75    #[inline(always)]
76    fn clone(&self) -> Self
77    {
78        let inner =
79        match self.discriminant()
80        {
81            Discriminant::Borrowed =>
82            {
83                let ref_ =
84                unsafe {
85                    self.inner
86                        .ref_unchecked()
87                };
88                
89                InnerArgument::new_ref(ref_)
90            }
91            _ =>
92            {
93                let owned =
94                {
95                    let raw = &raw const self.inner;
96                    unsafe
97                    {
98                        (*raw.cast::<OwnedArgument>()).clone()
99                    }
100                };
101                
102                InnerArgument::new_owned(owned)
103            }
104        };
105        
106        Self
107        {
108            inner
109        }
110    }
111}
112
113impl Deref for Argument<'_>
114{
115    type Target = dyn Any;
116    
117    #[inline(always)]
118    fn deref(&self) -> &dyn Any
119    {
120        self.inner
121            .to_ref()
122    }
123}
124
125impl Argument<'_>
126{
127    /// Creates a new owned Argument.
128    #[inline(always)]
129    pub fn new_owned<T>(item: T) -> Self
130    where
131        T: Any + Clone
132    {
133        let owned = OwnedArgument::new(item);
134        
135        Self
136        {
137            inner: InnerArgument::new_owned(owned)
138        }
139    }
140    
141    /// Checks if the argument is owned.
142    #[inline(always)]
143    pub fn is_owned(&self) -> bool
144    {
145        self.inner
146            .is_owned()
147    }
148    
149    /// Checks if the argument is borrowed.
150    #[inline(always)]
151    pub fn is_borrowed(&self) -> bool
152    {
153        self.inner
154            .is_borrowed()
155    }
156    
157    /// Returns a mutable reference to the item itself.
158    ///
159    /// If the inner contents are borrowed, this creates a new
160    /// owned instance first before returning the reference itself.
161    #[inline(always)]
162    pub fn to_mut(&mut self) -> &mut dyn Any
163    {
164        self.inner
165            .to_mut()
166    }
167    
168    #[inline(always)]
169    fn discriminant(&self) -> Discriminant
170    {
171        self.inner
172            .discriminant()
173    }
174    
175    /// Clones the inner contents of the object, returning an owned argument.
176    #[inline(always)]
177    pub fn to_owned(&self) -> Self
178    {
179        match self.discriminant()
180        {
181            Discriminant::Borrowed =>
182            {
183                let ref_ =
184                unsafe
185                {
186                    self.inner
187                        .ref_unchecked()
188                };
189                
190                let owned = ref_.clone_object();
191                
192                Self
193                {
194                    inner: InnerArgument::new_owned(owned)
195                }
196            }
197            _ => self.clone()
198        }
199    }
200    
201    /// Downcasts an owned argument into type T, returning a result.
202    ///
203    /// # Return values
204    /// Ok(T): The argument gets consumed and returns the inner contents.
205    /// Err(Self): Either the argument is not of type T or the argument itself is not owned.
206    #[inline(always)]
207    pub fn downcast_owned<T>(self) -> Result<T, Self>
208    where
209        T: Clone + Any
210    {
211        match self.inner_contents()
212        {
213            RawArgument::Owned(owned)
214            if owned.is_type::<T>() =>
215            unsafe
216            {
217                Ok(owned.downcast_owned_unchecked())
218            }
219            
220            RawArgument::Owned(o)
221            =>
222            Err(Self { inner: InnerArgument::new_owned(o) }),
223            
224            RawArgument::Borrowed(b)
225            =>
226            Err(Self { inner: InnerArgument::new_ref(b) })
227        }
228    }
229    
230    /// Downcasts an owned argument into type T, without any checks.
231    ///
232    /// # Safety
233    /// The argument must both be owned and of type T.
234    ///
235    /// # Panics
236    /// The function will panic if the argument itself is not owned.
237    #[inline(always)]
238    pub unsafe fn downcast_owned_unchecked<T>(self) -> T
239    where
240        T: Clone + Any
241    {
242        debug_assert!(self.is_owned());
243        
244        let RawArgument::Owned(contents) = self.inner_contents()
245        else
246        {
247            #[cfg(debug_assertions)]
248            {
249                unreachable!()
250            }
251            #[cfg(not(debug_assertions))]
252            {
253                panic!()
254            }
255        };
256        
257        debug_assert!(contents.is_type::<T>());
258        
259        unsafe
260        {
261            contents.downcast_owned_unchecked()
262        }
263    }
264    
265    /// Downcasts the argument into a cloned object of type T.
266    ///
267    /// Returns None if the object's type is not T.
268    #[inline(always)]
269    pub fn downcast_cloned<T>(&self) -> Option<T>
270    where
271        T: Any + Clone
272    {
273        #[allow(clippy::manual_map)]
274        match self.downcast_ref::<T>()
275        {
276            Some(t) => Some(t.clone()),
277            None => None
278        }
279    }
280    
281    /// Binding to downcast a reference to T without checks.
282    ///
283    /// This is similar to Any::downcast_ref_unchecked, except for
284    /// the fact that we can use it outside of nightly. When the former
285    /// gets stabilized, this function will get replaced.
286    ///
287    /// # Safety
288    /// Assumes that the contents are of type T.
289    #[inline(always)]
290    unsafe fn downcast_ref_unchecked<T>(&self) -> &T
291    where
292        T: Any + Clone
293    {
294        let binding = self.inner.to_ref();
295        
296        debug_assert!(binding.is::<T>());
297        
298        unsafe
299        {
300            &*(binding as *const dyn Any as *const T)
301        }
302    }
303    
304    /// Downcasts the argument into a cloned object of T without checking it first.
305    ///
306    /// # Safety
307    /// Assumes that the contents are of type T.
308    #[inline(always)]
309    pub unsafe fn downcast_cloned_unchecked<T>(&self) -> T
310    where
311        T: Any + Clone
312    {
313        unsafe
314        {
315            self.downcast_ref_unchecked::<T>().clone()
316        }
317    }
318}
319
320impl<'a> Argument<'a>
321{
322    /// Creates a borrowed argument of item T.
323    #[inline(always)]
324    pub fn new_borrowed<T>(item: &'a T) -> Self
325    where
326        T: Any + Clone
327    {
328        Self
329        {
330            inner: InnerArgument::new_ref(item)
331        }
332    }
333    
334    /// Creates a borrowed reference to the source argument.
335    #[inline(always)]
336    pub fn as_ref(&'a self) -> Self
337    {
338        Self
339        {
340            inner: self.inner.as_ref()
341        }
342    }
343    
344    /// Consumes the argument, returning a wrapper to the inner argument itself.
345    #[inline(always)]
346    fn inner_contents(self) -> RawArgument<'a>
347    {
348        let mut store = ManuallyDrop::new(self);
349        
350        unsafe
351        {
352            store.inner.take_raw_argument()
353        }
354    }
355    
356    /// Consumes the argument itself, returning what kind of argument it is.
357    #[inline(always)]
358    pub fn into_inner(self) -> ArgumentKind<'a>
359    {
360        let store = ManuallyDrop::new(self);
361        
362        let raw = &raw const store.inner;
363        
364        unsafe
365        {
366            raw.read().into_inner()
367        }
368    }
369}
370
371impl From<OwnedArgument> for Argument<'_>
372{
373    fn from(item: OwnedArgument) -> Self
374    {
375        Self
376        {
377            inner: InnerArgument::new_owned(item)
378        }
379    }
380}