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}