variadic_arguments/argument/
owned.rs1#[cfg(no_std)]
2use ::alloc::{alloc, boxed::Box};
3
4#[cfg(no_std)]
5use core::{
6 any::Any,
7 fmt,
8 mem,
9 ptr::NonNull,
10 ops
11};
12
13#[cfg(not(no_std))]
14use std::{
15 alloc,
16 fmt,
17 any::Any,
18 mem,
19 ptr::NonNull,
20 ops
21};
22
23use super::{
24 discriminant::Discriminant,
25 boxed_argument::BoxedArgument,
26 inlined::Inlined,
27 variant_info::VariantHandle
28};
29
30pub struct OwnedArgument
36{
37 pointer: *mut dyn VariantHandle,
41 inlined: bool,
42 owned: bool
43}
44
45impl fmt::Debug for OwnedArgument
46{
47 #[inline(always)]
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
49 {
50 let mut current = f.debug_struct("OwnedArgument");
51
52 current.field("is_inlined", &self.inlined);
53
54 let ref_ : &dyn Any =
55 unsafe { self.pointer().as_ref() };
56
57 current.field("storage", &ref_);
58
59 current.finish()
60 }
61}
62
63impl Clone for OwnedArgument
64{
65 #[inline(always)]
66 fn clone(&self) -> Self
67 {
68 unsafe
69 {
70 self.pointer()
71 .as_ref()
72 .clone_object()
73 }
74 }
75}
76
77impl Drop for OwnedArgument
78{
79 #[inline(always)]
80 fn drop(&mut self)
81 {
82 let _ =
83 unsafe
84 {
85 BoxedArgument::from_owned(self.pointer,
86 self.owned_discriminant())
87 };
88 }
89}
90
91
92#[cfg(debug_assertions)]
93fn pointer_matches<T>(pointer: *mut dyn VariantHandle) -> bool
94where
95 T: Any + Clone
96{
97 assert!(!pointer.is_null());
98
99 let pointer : *const dyn Any =
100 pointer.cast_const() as *const _ as *const dyn Any;
101
102 let ref_ = unsafe { &*pointer };
103
104 ref_.is::<T>()
105}
106
107impl OwnedArgument
108{
109 #[inline(always)]
114 pub fn new<T>(item: T) -> Self
115 where
116 T: Any + Clone
117 {
118 if size_of::<T>() <= size_of::<*const ()>()
119 {
120 let mut store =
121 mem::MaybeUninit::<*mut dyn VariantHandle>::new((&raw const item).cast_mut());
122
123 unsafe
124 {
125 store.as_mut_ptr().cast::<T>().write(item);
126 }
127
128 Self
129 {
130 pointer:
131 unsafe
132 {
133 store.assume_init()
134 },
135 inlined: true,
136 owned: true
137 }
138 }
139 else
140 {
141 let boxed : Box<dyn VariantHandle> = Box::new(item);
142
143 let pointer = Box::into_raw(boxed);
144
145 Self
146 {
147 pointer,
148 inlined: false,
149 owned: true
150 }
151 }
152 }
153
154 #[inline(always)]
155 unsafe fn pointer_metadata(&self) -> *mut dyn VariantHandle
156 {
157 self.pointer
158 }
159
160 #[inline(always)]
161 fn pointer(&self) -> NonNull<dyn VariantHandle>
162 {
163 match self.owned_discriminant()
164 {
165 Discriminant::Inlined =>
166 unsafe { self.inner_inlined().pointer() },
167 Discriminant::Allocated =>
168 unsafe { NonNull::new_unchecked(self.pointer) },
169 _ => unreachable!()
170 }
171 }
172
173 #[inline(always)]
177 pub(crate) fn owned_discriminant(&self) -> Discriminant
178 {
179 Discriminant::from_owned(self.inlined)
180 }
181
182 #[inline(always)]
184 pub(crate) fn discriminant(&self) -> Discriminant
185 {
186 Discriminant::from_info((self.inlined, self.owned))
187 }
188
189 #[cfg(test)]
193 pub(crate) fn is_inlined(&self) -> bool
194 {
195 self.inlined
196 }
197
198 #[inline(always)]
205 unsafe fn inner_inlined(&self) -> &Inlined
206 {
207 unsafe
208 {
209 &*(&raw const self.pointer)
210 .cast::<Inlined>()
211 }
212 }
213
214 #[inline(always)]
218 pub fn is_type<T>(&self) -> bool
219 where
220 T: Any + Clone
221 {
222 unsafe
223 {
224 let metadata : *const dyn Any =
225 self.pointer_metadata().cast_const() as *const _ as *const dyn Any;
226
227 (*metadata).is::<T>()
228 }
229 }
230
231 #[inline(always)]
235 pub(crate) fn raw_ref(&self) -> &dyn VariantHandle
236 {
237 unsafe
238 {
239 self.pointer()
240 .as_ref()
241 }
242 }
243
244 #[inline(always)]
250 pub fn downcast_owned<T>(self) -> Result<T, Self>
251 where
252 T: Any + Clone
253 {
254 if self.is_type::<T>()
255 {
256 unsafe
257 {
258 Ok(self.downcast_owned_unchecked())
259 }
260 } else { Err(self) }
261 }
262
263 #[inline(always)]
268 pub unsafe fn downcast_owned_unchecked<T>(self) -> T
269 where
270 T: Any + Clone
271 {
272 let owned = mem::ManuallyDrop::new(self);
273
274 let boxed =
275 unsafe
276 {
277 BoxedArgument::from_owned(owned.pointer,
278 owned.owned_discriminant())
279 };
280
281 match boxed
282 {
283 BoxedArgument::Allocated(a) =>
284 {
285 let raw_pointer = Box::into_raw(a);
286
287 #[cfg(debug_assertions)]
288 {
289 assert!(pointer_matches::<T>(raw_pointer));
290 }
291
292 let output =
293 {
294 let pointer : *mut T =
295 raw_pointer.cast();
296
297 unsafe
298 {
299 pointer.read_unaligned()
300 }
301 };
302
303 let layout = alloc::Layout::new::<T>();
304
305 unsafe
306 {
307 alloc::dealloc(raw_pointer.cast::<u8>(),
308 layout);
309 }
310
311 output
312 }
313 BoxedArgument::Inlined(i) =>
314 {
315 #[cfg(debug_assertions)]
316 {
317 let raw_pointer = i.pointer().as_ptr();
318 assert!(pointer_matches::<T>(raw_pointer));
319 }
320
321 let store = mem::ManuallyDrop::new(i);
322
323 let pointer = &raw const store;
324
325 unsafe
326 {
327 pointer.cast::<T>().read()
328 }
329 }
330 }
331 }
332
333 #[inline(always)]
339 pub fn downcast_cloned<T>(&self) -> Option<T>
340 where
341 T: Any + Clone
342 {
343 if self.is_type::<T>()
344 {
345 unsafe
346 {
347 Some(self.downcast_cloned_unchecked())
348 }
349 }
350 else { None }
351 }
352
353 #[inline(always)]
358 pub unsafe fn downcast_cloned_unchecked<T>(&self) -> T
359 where
360 T: Any + Clone
361 {
362 let pointer = self.pointer();
363
364 #[cfg(debug_assertions)]
365 {
366 assert!(pointer_matches::<T>(pointer.as_ptr()));
367 }
368
369 unsafe
370 {
371 pointer.cast::<T>().as_ref().clone()
372 }
373 }
374}
375
376
377impl ops::Deref for OwnedArgument
378{
379 type Target = dyn Any;
380
381 #[inline(always)]
382 fn deref(&self) -> &dyn Any
383 {
384 unsafe
385 {
386 self.pointer()
387 .as_ref()
388 }
389 }
390}
391
392
393impl ops::DerefMut for OwnedArgument
394{
395 #[inline(always)]
396 fn deref_mut(&mut self) -> &mut dyn Any
397 {
398 unsafe
399 {
400 self.pointer()
401 .as_mut()
402 }
403 }
404}
405