wiggle_runtime/
borrow.rs

1use crate::region::Region;
2use crate::{GuestError, GuestPtr, GuestType};
3
4#[derive(Debug)]
5pub struct GuestBorrows {
6    borrows: Vec<Region>,
7}
8
9impl GuestBorrows {
10    pub fn new() -> Self {
11        Self {
12            borrows: Vec::new(),
13        }
14    }
15
16    fn is_borrowed(&self, r: Region) -> bool {
17        !self.borrows.iter().all(|b| !b.overlaps(r))
18    }
19
20    pub(crate) fn borrow(&mut self, r: Region) -> Result<(), GuestError> {
21        if self.is_borrowed(r) {
22            Err(GuestError::PtrBorrowed(r))
23        } else {
24            self.borrows.push(r);
25            Ok(())
26        }
27    }
28
29    /// Borrow the region of memory pointed to by a `GuestPtr`. This is required for safety if
30    /// you are dereferencing `GuestPtr`s while holding a reference to a slice via
31    /// `GuestPtr::as_raw`.
32    pub fn borrow_pointee<'a, T>(&mut self, p: &GuestPtr<'a, T>) -> Result<(), GuestError>
33    where
34        T: GuestType<'a>,
35    {
36        self.borrow(Region {
37            start: p.offset(),
38            len: T::guest_size(),
39        })
40    }
41
42    /// Borrow the slice of memory pointed to by a `GuestPtr<[T]>`. This is required for safety if
43    /// you are dereferencing the `GuestPtr`s while holding a reference to another slice via
44    /// `GuestPtr::as_raw`. Not required if using `GuestPtr::as_raw` on this pointer.
45    pub fn borrow_slice<'a, T>(&mut self, p: &GuestPtr<'a, [T]>) -> Result<(), GuestError>
46    where
47        T: GuestType<'a>,
48    {
49        let (start, elems) = p.offset();
50        let len = T::guest_size()
51            .checked_mul(elems)
52            .ok_or_else(|| GuestError::PtrOverflow)?;
53        self.borrow(Region { start, len })
54    }
55
56    /// Borrow the slice of memory pointed to by a `GuestPtr<str>`. This is required for safety if
57    /// you are dereferencing the `GuestPtr`s while holding a reference to another slice via
58    /// `GuestPtr::as_raw`. Not required if using `GuestPtr::as_raw` on this pointer.
59    pub fn borrow_str(&mut self, p: &GuestPtr<str>) -> Result<(), GuestError> {
60        let (start, len) = p.offset();
61        self.borrow(Region { start, len })
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use super::*;
68    #[test]
69    fn nonoverlapping() {
70        let mut bs = GuestBorrows::new();
71        let r1 = Region::new(0, 10);
72        let r2 = Region::new(10, 10);
73        assert!(!r1.overlaps(r2));
74        bs.borrow(r1).expect("can borrow r1");
75        bs.borrow(r2).expect("can borrow r2");
76
77        let mut bs = GuestBorrows::new();
78        let r1 = Region::new(10, 10);
79        let r2 = Region::new(0, 10);
80        assert!(!r1.overlaps(r2));
81        bs.borrow(r1).expect("can borrow r1");
82        bs.borrow(r2).expect("can borrow r2");
83    }
84
85    #[test]
86    fn overlapping() {
87        let mut bs = GuestBorrows::new();
88        let r1 = Region::new(0, 10);
89        let r2 = Region::new(9, 10);
90        assert!(r1.overlaps(r2));
91        bs.borrow(r1).expect("can borrow r1");
92        assert!(bs.borrow(r2).is_err(), "cant borrow r2");
93
94        let mut bs = GuestBorrows::new();
95        let r1 = Region::new(0, 10);
96        let r2 = Region::new(2, 5);
97        assert!(r1.overlaps(r2));
98        bs.borrow(r1).expect("can borrow r1");
99        assert!(bs.borrow(r2).is_err(), "cant borrow r2");
100
101        let mut bs = GuestBorrows::new();
102        let r1 = Region::new(9, 10);
103        let r2 = Region::new(0, 10);
104        assert!(r1.overlaps(r2));
105        bs.borrow(r1).expect("can borrow r1");
106        assert!(bs.borrow(r2).is_err(), "cant borrow r2");
107
108        let mut bs = GuestBorrows::new();
109        let r1 = Region::new(2, 5);
110        let r2 = Region::new(0, 10);
111        assert!(r1.overlaps(r2));
112        bs.borrow(r1).expect("can borrow r1");
113        assert!(bs.borrow(r2).is_err(), "cant borrow r2");
114
115        let mut bs = GuestBorrows::new();
116        let r1 = Region::new(2, 5);
117        let r2 = Region::new(10, 5);
118        let r3 = Region::new(15, 5);
119        let r4 = Region::new(0, 10);
120        assert!(r1.overlaps(r4));
121        bs.borrow(r1).expect("can borrow r1");
122        bs.borrow(r2).expect("can borrow r2");
123        bs.borrow(r3).expect("can borrow r3");
124        assert!(bs.borrow(r4).is_err(), "cant borrow r4");
125    }
126}