rune/runtime/
any_obj.rs

1use core::cell::Cell;
2use core::fmt;
3use core::mem::{replace, ManuallyDrop};
4use core::ptr::{self, addr_of, NonNull};
5
6use crate::alloc::clone::TryClone;
7use crate::alloc::{self, Box};
8use crate::{Any, Hash};
9
10use super::{
11    Access, AccessError, AnyObjVtable, AnyTypeInfo, BorrowMut, BorrowRef, FromValue, Mut,
12    RawAccessGuard, RawAnyGuard, Ref, RefVtable, RuntimeError, Shared, Snapshot, ToValue, TypeInfo,
13    Value,
14};
15
16/// A type-erased wrapper for a reference.
17pub struct AnyObj {
18    shared: NonNull<AnyObjData>,
19}
20
21impl AnyObj {
22    /// Construct a new typed object.
23    ///
24    /// # Safety
25    ///
26    /// Caller must ensure that the type is of the value `T`.
27    #[inline]
28    pub(super) const unsafe fn from_raw(shared: NonNull<AnyObjData>) -> Self {
29        Self { shared }
30    }
31
32    /// Construct an Any that wraps an owned object.
33    ///
34    /// # Examples
35    ///
36    /// ```
37    /// use rune::Value;
38    /// use rune::runtime::AnyObj;
39    /// use rune::alloc::String;
40    ///
41    /// let string = String::try_from("Hello World")?;
42    /// let string = AnyObj::new(string)?;
43    /// let string = Value::from(string);
44    ///
45    /// let string = string.into_shared::<String>()?;
46    /// assert_eq!(string.borrow_ref()?.as_str(), "Hello World");
47    /// # Ok::<_, rune::support::Error>(())
48    /// ```
49    #[inline]
50    pub fn new<T>(data: T) -> alloc::Result<Self>
51    where
52        T: Any,
53    {
54        let shared = AnyObjData {
55            access: Access::new(),
56            count: Cell::new(1),
57            vtable: AnyObjVtable::owned::<T>(),
58            data,
59        };
60
61        let shared = NonNull::from(Box::leak(Box::try_new(shared)?)).cast();
62        Ok(Self { shared })
63    }
64
65    /// Construct an Any that wraps a pointer.
66    ///
67    /// # Safety
68    ///
69    /// Caller must ensure that the returned `AnyObj` doesn't outlive the
70    /// reference it is wrapping.
71    #[inline]
72    pub(crate) unsafe fn from_ref<T>(data: *const T) -> alloc::Result<Self>
73    where
74        T: Any,
75    {
76        let shared = AnyObjData {
77            access: Access::new(),
78            count: Cell::new(1),
79            vtable: AnyObjVtable::from_ref::<T>(),
80            data: NonNull::new_unchecked(data.cast_mut()),
81        };
82
83        let shared = NonNull::from(Box::leak(Box::try_new(shared)?)).cast();
84        Ok(Self { shared })
85    }
86
87    /// Construct an Any that wraps a mutable pointer.
88    ///
89    /// # Safety
90    ///
91    /// Caller must ensure that the returned `AnyObj` doesn't outlive the
92    /// reference it is wrapping.
93    #[inline]
94    pub(crate) unsafe fn from_mut<T>(data: *mut T) -> alloc::Result<Self>
95    where
96        T: Any,
97    {
98        let shared = AnyObjData {
99            access: Access::new(),
100            count: Cell::new(1),
101            vtable: AnyObjVtable::from_mut::<T>(),
102            data: NonNull::new_unchecked(data),
103        };
104
105        let shared = NonNull::from(Box::leak(Box::try_new(shared)?)).cast();
106        Ok(Self { shared })
107    }
108
109    /// Coerce into a typed object.
110    pub(crate) fn into_shared<T>(self) -> Result<Shared<T>, AnyObjError>
111    where
112        T: Any,
113    {
114        let vtable = vtable(&self);
115
116        if !vtable.is::<T>() {
117            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
118                T::ANY_TYPE_INFO,
119                vtable.type_info(),
120            )));
121        }
122
123        // SAFETY: We've typed checked for the appropriate type just above.
124        unsafe { Ok(self.unsafe_into_shared()) }
125    }
126
127    /// Coerce into a typed object.
128    ///
129    /// # Safety
130    ///
131    /// The caller must ensure that the type being convert into is correct.
132    #[inline]
133    pub(crate) unsafe fn unsafe_into_shared<T>(self) -> Shared<T>
134    where
135        T: Any,
136    {
137        let this = ManuallyDrop::new(self);
138        Shared::from_raw(this.shared.cast())
139    }
140
141    /// Downcast into an owned value of type `T`.
142    pub(crate) fn downcast<T>(self) -> Result<T, AnyObjError>
143    where
144        T: Any,
145    {
146        let vtable = vtable(&self);
147
148        if !vtable.is::<T>() {
149            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
150                T::ANY_TYPE_INFO,
151                vtable.type_info(),
152            )));
153        }
154
155        if !vtable.is_owned() {
156            return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
157                vtable.type_info(),
158            )));
159        }
160
161        // SAFETY: We've checked for the appropriate type just above.
162        unsafe {
163            self.shared.as_ref().access.try_take()?;
164            let data = vtable.as_ptr::<T>(self.shared);
165            Ok(data.read())
166        }
167    }
168
169    /// Take the interior value and drop it if necessary.
170    pub(crate) fn drop(self) -> Result<(), AnyObjError> {
171        let vtable = vtable(&self);
172
173        if !vtable.is_owned() {
174            return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
175                vtable.type_info(),
176            )));
177        }
178
179        // SAFETY: We've checked for the appropriate type just above.
180        unsafe {
181            self.shared.as_ref().access.try_take()?;
182
183            if let Some(drop_value) = vtable.drop_value {
184                drop_value(self.shared);
185            }
186
187            Ok(())
188        }
189    }
190
191    /// Take the interior value and return a handle to the taken value.
192    pub fn take(self) -> Result<Self, AnyObjError> {
193        let vtable = vtable(&self);
194
195        // SAFETY: We've checked for the appropriate type just above.
196        unsafe {
197            self.shared.as_ref().access.try_take()?;
198            Ok((vtable.clone)(self.shared)?)
199        }
200    }
201
202    /// Downcast into an owned value of type [`Ref<T>`].
203    ///
204    /// # Errors
205    ///
206    /// This errors in case the underlying value is not owned, non-owned
207    /// references cannot be coerced into [`Ref<T>`].
208    pub(crate) fn into_ref<T>(self) -> Result<Ref<T>, AnyObjError>
209    where
210        T: Any,
211    {
212        let vtable = vtable(&self);
213
214        if !vtable.is::<T>() {
215            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
216                T::ANY_TYPE_INFO,
217                vtable.type_info(),
218            )));
219        }
220
221        if !vtable.is_owned() {
222            return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
223                vtable.type_info(),
224            )));
225        }
226
227        // SAFETY: We've checked for the appropriate type just above.
228        unsafe {
229            self.shared.as_ref().access.try_shared()?;
230            let this = ManuallyDrop::new(self);
231            let data = vtable.as_ptr(this.shared);
232
233            let vtable = &RefVtable {
234                drop: |shared: NonNull<()>| {
235                    let shared = shared.cast::<AnyObjData>();
236                    shared.as_ref().access.release();
237                    AnyObjData::dec(shared)
238                },
239            };
240
241            let guard = RawAnyGuard::new(this.shared.cast(), vtable);
242            Ok(Ref::new(data, guard))
243        }
244    }
245
246    /// Downcast into an owned value of type [`Mut<T>`].
247    ///
248    /// # Errors
249    ///
250    /// This errors in case the underlying value is not owned, non-owned
251    /// references cannot be coerced into [`Mut<T>`].
252    pub(crate) fn into_mut<T>(self) -> Result<Mut<T>, AnyObjError>
253    where
254        T: Any,
255    {
256        let vtable = vtable(&self);
257
258        if !vtable.is::<T>() {
259            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
260                T::ANY_TYPE_INFO,
261                vtable.type_info(),
262            )));
263        }
264
265        if !vtable.is_owned() {
266            return Err(AnyObjError::new(AnyObjErrorKind::NotOwned(
267                vtable.type_info(),
268            )));
269        }
270
271        // SAFETY: We've checked for the appropriate type just above.
272        unsafe {
273            self.shared.as_ref().access.try_exclusive()?;
274            let this = ManuallyDrop::new(self);
275            let data = vtable.as_ptr(this.shared);
276
277            let vtable = &RefVtable {
278                drop: |shared: NonNull<()>| {
279                    let shared = shared.cast::<AnyObjData>();
280                    shared.as_ref().access.release();
281                    AnyObjData::dec(shared)
282                },
283            };
284
285            let guard = RawAnyGuard::new(this.shared.cast(), vtable);
286            Ok(Mut::new(data, guard))
287        }
288    }
289
290    /// Get a reference to the interior value while checking for shared access.
291    ///
292    /// This prevents other exclusive accesses from being performed while the
293    /// guard returned from this function is live.
294    pub fn borrow_ref<T>(&self) -> Result<BorrowRef<'_, T>, AnyObjError>
295    where
296        T: Any,
297    {
298        let vtable = vtable(self);
299
300        if !vtable.is::<T>() {
301            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
302                T::ANY_TYPE_INFO,
303                vtable.type_info(),
304            )));
305        }
306
307        // SAFETY: We've checked for the appropriate type just above.
308        unsafe {
309            let guard = self.shared.as_ref().access.shared()?;
310            let data = vtable.as_ptr(self.shared);
311            Ok(BorrowRef::new(data, guard.into_raw()))
312        }
313    }
314
315    /// Try to borrow a reference to the interior value while checking for
316    /// shared access.
317    ///
318    /// Returns `None` if the interior type is not `T`.
319    ///
320    /// This prevents other exclusive accesses from being performed while the
321    /// guard returned from this function is alive.
322    pub fn try_borrow_ref<T>(&self) -> Result<Option<BorrowRef<'_, T>>, AccessError>
323    where
324        T: Any,
325    {
326        let vtable = vtable(self);
327
328        if !vtable.is::<T>() {
329            return Ok(None);
330        }
331
332        // SAFETY: We've checked for the appropriate type just above.
333        unsafe {
334            let guard = self.shared.as_ref().access.shared()?;
335            let data = vtable.as_ptr(self.shared);
336            Ok(Some(BorrowRef::new(data, guard.into_raw())))
337        }
338    }
339
340    /// Try to borrow a reference to the interior value while checking for
341    /// exclusive access.
342    ///
343    /// Returns `None` if the interior type is not `T`.
344    ///
345    /// This prevents other exclusive accesses from being performed while the
346    /// guard returned from this function is alive.
347    pub fn try_borrow_mut<T>(&self) -> Result<Option<BorrowMut<'_, T>>, AccessError>
348    where
349        T: Any,
350    {
351        let vtable = vtable(self);
352
353        if !vtable.is::<T>() {
354            return Ok(None);
355        }
356
357        // SAFETY: We've checked for the appropriate type just above.
358        unsafe {
359            let guard = self.shared.as_ref().access.exclusive()?;
360            let data = vtable.as_ptr(self.shared);
361            Ok(Some(BorrowMut::new(data, guard.into_raw())))
362        }
363    }
364
365    /// Returns some mutable reference to the boxed value if it is of type `T`.
366    pub fn borrow_mut<T>(&self) -> Result<BorrowMut<'_, T>, AnyObjError>
367    where
368        T: Any,
369    {
370        let vtable = vtable(self);
371
372        if !vtable.is::<T>() || !vtable.is_mutable() {
373            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
374                T::ANY_TYPE_INFO,
375                vtable.type_info(),
376            )));
377        }
378
379        // SAFETY: We've checked for the appropriate type just above.
380        unsafe {
381            let guard = self.shared.as_ref().access.exclusive()?;
382            let data = vtable.as_ptr(self.shared);
383            Ok(BorrowMut::new(data, guard.into_raw()))
384        }
385    }
386
387    /// Get a reference to the interior value while checking for shared access.
388    ///
389    /// This prevents other exclusive accesses from being performed while the
390    /// guard returned from this function is live.
391    pub(crate) fn borrow_ref_ptr<T>(self) -> Result<(NonNull<T>, RawAnyObjGuard), AnyObjError>
392    where
393        T: Any,
394    {
395        let vtable = vtable(&self);
396
397        if !vtable.is::<T>() {
398            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
399                T::ANY_TYPE_INFO,
400                vtable.type_info(),
401            )));
402        }
403
404        // SAFETY: We've checked for the appropriate type just above.
405        unsafe {
406            let guard = self.shared.as_ref().access.shared()?.into_raw();
407            let this = ManuallyDrop::new(self);
408
409            let data = vtable.as_ptr(this.shared);
410
411            let guard = RawAnyObjGuard {
412                guard,
413                dec_shared: AnyObjDecShared {
414                    shared: this.shared,
415                },
416            };
417
418            Ok((data, guard))
419        }
420    }
421
422    /// Returns some mutable reference to the boxed value if it is of type `T`.
423    pub(crate) fn borrow_mut_ptr<T>(self) -> Result<(NonNull<T>, RawAnyObjGuard), AnyObjError>
424    where
425        T: Any,
426    {
427        let vtable = vtable(&self);
428
429        if !vtable.is::<T>() || !vtable.is_mutable() {
430            return Err(AnyObjError::new(AnyObjErrorKind::Cast(
431                T::ANY_TYPE_INFO,
432                vtable.type_info(),
433            )));
434        }
435
436        // SAFETY: We've checked for the appropriate type just above.
437        unsafe {
438            let guard = self.shared.as_ref().access.exclusive()?.into_raw();
439            let this = ManuallyDrop::new(self);
440
441            let data = vtable.as_ptr(this.shared);
442
443            let guard = RawAnyObjGuard {
444                guard,
445                dec_shared: AnyObjDecShared {
446                    shared: this.shared,
447                },
448            };
449
450            Ok((data, guard))
451        }
452    }
453
454    /// Deconstruct the shared value into a guard and shared box.
455    ///
456    /// # Safety
457    ///
458    /// The content of the shared value will be forcibly destructed once the
459    /// returned guard is dropped, unchecked use of the shared value after this
460    /// point will lead to undefined behavior.
461    pub(crate) unsafe fn into_drop_guard(self) -> (Self, AnyObjDrop) {
462        // Increment the reference count by one to account for the guard holding
463        // onto it.
464        AnyObjData::inc(self.shared);
465
466        let guard = AnyObjDrop {
467            shared: self.shared,
468        };
469
470        (self, guard)
471    }
472
473    /// Test if the value is sharable.
474    pub(crate) fn is_readable(&self) -> bool {
475        // Safety: Since we have a reference to this shared, we know that the
476        // inner is available.
477        unsafe { self.shared.as_ref().access.is_shared() }
478    }
479
480    /// Test if the value is exclusively accessible.
481    pub(crate) fn is_writable(&self) -> bool {
482        unsafe {
483            let shared = self.shared.as_ref();
484            shared.vtable.is_mutable() && shared.access.is_exclusive()
485        }
486    }
487
488    /// Get access snapshot of shared value.
489    pub(crate) fn snapshot(&self) -> Snapshot {
490        unsafe { self.shared.as_ref().access.snapshot() }
491    }
492
493    /// Debug format the current any type.
494    pub(crate) fn debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495        vtable(self).debug(f)
496    }
497
498    /// Access the underlying type hash for the data.
499    pub fn type_hash(&self) -> Hash {
500        vtable(self).type_hash()
501    }
502
503    /// Access full type info for the underlying type.
504    pub fn type_info(&self) -> TypeInfo {
505        vtable(self).type_info()
506    }
507}
508
509impl Clone for AnyObj {
510    #[inline]
511    fn clone(&self) -> Self {
512        // SAFETY: We know that the inner value is live in this instance.
513        unsafe {
514            AnyObjData::inc(self.shared);
515        }
516
517        Self {
518            shared: self.shared,
519        }
520    }
521
522    #[inline]
523    fn clone_from(&mut self, source: &Self) {
524        if ptr::eq(self.shared.as_ptr(), source.shared.as_ptr()) {
525            return;
526        }
527
528        let old = replace(&mut self.shared, source.shared);
529
530        // SAFETY: We know that the inner value is live in both instances.
531        unsafe {
532            AnyObjData::dec(old);
533            AnyObjData::inc(self.shared);
534        }
535    }
536}
537
538impl TryClone for AnyObj {
539    #[inline]
540    fn try_clone(&self) -> alloc::Result<Self> {
541        Ok(self.clone())
542    }
543
544    #[inline]
545    fn try_clone_from(&mut self, source: &Self) -> alloc::Result<()> {
546        self.clone_from(source);
547        Ok(())
548    }
549}
550
551impl fmt::Debug for AnyObj {
552    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553        self.debug(f)
554    }
555}
556
557impl Drop for AnyObj {
558    fn drop(&mut self) {
559        // Safety: We know that the inner value is live in this instance.
560        unsafe {
561            AnyObjData::dec(self.shared);
562        }
563    }
564}
565
566impl FromValue for AnyObj {
567    #[inline]
568    fn from_value(value: Value) -> Result<Self, RuntimeError> {
569        value.into_any_obj()
570    }
571}
572
573impl ToValue for AnyObj {
574    #[inline]
575    fn to_value(self) -> Result<Value, RuntimeError> {
576        Ok(Value::from(self))
577    }
578}
579
580#[repr(C)]
581pub(super) struct AnyObjData<T = ()> {
582    /// The currently handed out access to the shared data.
583    pub(super) access: Access,
584    /// The number of strong references to the shared data.
585    pub(super) count: Cell<usize>,
586    /// Vtable of the shared value.
587    pub(super) vtable: &'static AnyObjVtable,
588    /// Data of the shared reference.
589    pub(super) data: T,
590}
591
592impl AnyObjData {
593    /// Increment the reference count of the inner value.
594    #[inline]
595    pub(super) unsafe fn inc(this: NonNull<Self>) {
596        let count_ref = &*addr_of!((*this.as_ptr()).count);
597        let count = count_ref.get();
598
599        debug_assert_ne!(
600            count, 0,
601            "Reference count of zero should only happen if Shared is incorrectly implemented"
602        );
603
604        if count == usize::MAX {
605            crate::alloc::abort();
606        }
607
608        count_ref.set(count + 1);
609    }
610
611    /// Decrement the reference count in inner, and free the underlying data if
612    /// it has reached zero.
613    ///
614    /// # Safety
615    ///
616    /// ProtocolCaller needs to ensure that `this` is a valid pointer.
617    #[inline]
618    pub(super) unsafe fn dec(this: NonNull<Self>) {
619        let count_ref = &*addr_of!((*this.as_ptr()).count);
620        let count = count_ref.get();
621
622        debug_assert_ne!(
623            count, 0,
624            "Reference count of zero should only happen if Shared is incorrectly implemented"
625        );
626
627        let count = count - 1;
628        count_ref.set(count);
629
630        if count == 0 {
631            let vtable = *addr_of!((*this.as_ptr()).vtable);
632
633            if let Some(drop_value) = vtable.drop_value {
634                let access = &*addr_of!((*this.as_ptr()).access);
635
636                if !access.is_taken() {
637                    drop_value(this);
638                }
639            }
640
641            (vtable.drop)(this);
642        }
643    }
644}
645
646#[derive(Debug)]
647#[cfg_attr(test, derive(PartialEq))]
648pub(super) enum AnyObjErrorKind {
649    Alloc(alloc::Error),
650    Cast(AnyTypeInfo, TypeInfo),
651    AccessError(AccessError),
652    NotOwned(TypeInfo),
653}
654
655/// Errors caused when accessing or coercing an [`AnyObj`].
656#[cfg_attr(test, derive(PartialEq))]
657pub struct AnyObjError {
658    kind: AnyObjErrorKind,
659}
660
661impl AnyObjError {
662    #[inline]
663    pub(super) fn new(kind: AnyObjErrorKind) -> Self {
664        Self { kind }
665    }
666
667    #[inline]
668    pub(super) fn into_kind(self) -> AnyObjErrorKind {
669        self.kind
670    }
671}
672
673impl core::error::Error for AnyObjError {}
674
675impl fmt::Display for AnyObjError {
676    #[inline]
677    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
678        match &self.kind {
679            AnyObjErrorKind::Alloc(error) => error.fmt(f),
680            AnyObjErrorKind::Cast(expected, actual) => {
681                write!(f, "Failed to cast `{actual}` to `{expected}`")
682            }
683            AnyObjErrorKind::AccessError(error) => error.fmt(f),
684            AnyObjErrorKind::NotOwned(type_info) => {
685                write!(f, "Cannot use owned operations for {type_info}")
686            }
687        }
688    }
689}
690
691impl fmt::Debug for AnyObjError {
692    #[inline]
693    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
694        self.kind.fmt(f)
695    }
696}
697
698impl From<alloc::Error> for AnyObjError {
699    #[inline]
700    fn from(error: alloc::Error) -> Self {
701        Self::new(AnyObjErrorKind::Alloc(error))
702    }
703}
704
705impl From<AccessError> for AnyObjError {
706    #[inline]
707    fn from(error: AccessError) -> Self {
708        Self::new(AnyObjErrorKind::AccessError(error))
709    }
710}
711
712/// Guard which decrements and releases shared storage for the guarded reference.
713pub(super) struct AnyObjDecShared {
714    pub(super) shared: NonNull<AnyObjData>,
715}
716
717impl Drop for AnyObjDecShared {
718    fn drop(&mut self) {
719        // Safety: We know that the inner value is live in this instance.
720        unsafe {
721            AnyObjData::dec(self.shared);
722        }
723    }
724}
725
726/// Guard which decrements and releases shared storage for the guarded reference.
727pub(crate) struct AnyObjDrop {
728    #[allow(unused)]
729    pub(super) shared: NonNull<AnyObjData>,
730}
731
732impl Drop for AnyObjDrop {
733    #[inline]
734    fn drop(&mut self) {
735        // Safety: We know that the inner value is live in this instance.
736        unsafe {
737            self.shared.as_ref().access.take();
738            AnyObjData::dec(self.shared);
739        }
740    }
741}
742
743/// The guard returned when dealing with raw pointers.
744pub(crate) struct RawAnyObjGuard {
745    #[allow(unused)]
746    pub(super) guard: RawAccessGuard,
747    #[allow(unused)]
748    pub(super) dec_shared: AnyObjDecShared,
749}
750
751#[inline]
752fn vtable(any: &AnyObj) -> &'static AnyObjVtable {
753    unsafe { addr_of!((*any.shared.as_ptr()).vtable).read() }
754}