rune/runtime/
borrow_ref.rs

1use core::fmt;
2use core::marker::PhantomData;
3use core::ops::Deref;
4use core::ptr::NonNull;
5
6use super::RawAccessGuard;
7
8/// Guard for a data borrowed from a slot in the virtual machine.
9///
10/// These guards are necessary, since we need to guarantee certain forms of
11/// access depending on what we do. Releasing the guard releases the access.
12pub struct BorrowRef<'a, T: ?Sized + 'a> {
13    data: NonNull<T>,
14    guard: Option<RawAccessGuard>,
15    _marker: PhantomData<&'a T>,
16}
17
18impl<'a, T: ?Sized> BorrowRef<'a, T> {
19    /// Construct a borrow ref from static data.
20    pub(crate) fn from_static(data: &'static T) -> Self {
21        Self {
22            data: NonNull::from(data),
23            guard: None,
24            _marker: PhantomData,
25        }
26    }
27
28    /// Construct a new shared guard.
29    ///
30    /// # Safety
31    ///
32    /// since this has implications for releasing access, the caller must
33    /// ensure that access has been acquired correctly using e.g.
34    /// [Access::shared]. Otherwise access can be release incorrectly once
35    /// this guard is dropped.
36    pub(crate) unsafe fn new(data: NonNull<T>, guard: RawAccessGuard) -> Self {
37        Self {
38            data,
39            guard: Some(guard),
40            _marker: PhantomData,
41        }
42    }
43
44    /// Map the reference.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// use rune::runtime::{BorrowRef, Bytes};
50    /// use rune::alloc::try_vec;
51    ///
52    /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?;
53    /// let bytes = bytes.borrow_ref::<Bytes>()?;
54    ///
55    /// let bytes: BorrowRef<[u8]> = BorrowRef::map(bytes, |bytes| &bytes[0..2]);
56    ///
57    /// assert_eq!(&bytes[..], &[1u8, 2u8][..]);
58    /// # Ok::<_, rune::support::Error>(())
59    /// ```
60    pub fn map<U: ?Sized>(this: Self, m: impl FnOnce(&T) -> &U) -> BorrowRef<'a, U> {
61        unsafe {
62            BorrowRef {
63                data: NonNull::from(m(this.data.as_ref())),
64                guard: this.guard,
65                _marker: PhantomData,
66            }
67        }
68    }
69
70    /// Try to map the reference to a projection.
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use rune::runtime::{BorrowRef, Bytes};
76    /// use rune::alloc::try_vec;
77    ///
78    /// let bytes = rune::to_value(Bytes::from_vec(try_vec![1, 2, 3, 4]))?;
79    /// let bytes = bytes.borrow_ref::<Bytes>()?;
80    ///
81    /// let Ok(bytes) = BorrowRef::try_map(bytes, |bytes| bytes.get(0..2)) else {
82    ///     panic!("Conversion failed");
83    /// };
84    ///
85    /// assert_eq!(&bytes[..], &[1u8, 2u8][..]);
86    /// # Ok::<_, rune::support::Error>(())
87    /// ```
88    pub fn try_map<U: ?Sized>(
89        this: Self,
90        m: impl FnOnce(&T) -> Option<&U>,
91    ) -> Result<BorrowRef<'a, U>, Self> {
92        unsafe {
93            let Some(data) = m(this.data.as_ref()) else {
94                return Err(BorrowRef {
95                    data: this.data,
96                    guard: this.guard,
97                    _marker: PhantomData,
98                });
99            };
100
101            Ok(BorrowRef {
102                data: NonNull::from(data),
103                guard: this.guard,
104                _marker: PhantomData,
105            })
106        }
107    }
108}
109
110impl<T: ?Sized> Deref for BorrowRef<'_, T> {
111    type Target = T;
112
113    #[inline]
114    fn deref(&self) -> &Self::Target {
115        unsafe { self.data.as_ref() }
116    }
117}
118
119impl<T: ?Sized> AsRef<T> for BorrowRef<'_, T> {
120    #[inline]
121    fn as_ref(&self) -> &T {
122        unsafe { self.data.as_ref() }
123    }
124}
125
126impl<T: ?Sized> fmt::Debug for BorrowRef<'_, T>
127where
128    T: fmt::Debug,
129{
130    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
131        fmt::Debug::fmt(&**self, fmt)
132    }
133}