softbuffer/
util.rs

1// Not needed on all platforms
2#![allow(dead_code)]
3
4use std::cmp;
5use std::num::NonZeroU32;
6
7use crate::Rect;
8use crate::SoftBufferError;
9
10/// Takes a mutable reference to a container and a function deriving a
11/// reference into it, and stores both, making it possible to get back the
12/// reference to the container once the other reference is no longer needed.
13///
14/// This should be consistent with stacked borrow rules, and miri seems to
15/// accept it at least in simple cases.
16pub struct BorrowStack<'a, T: 'a + ?Sized, U: 'a + ?Sized> {
17    container: *mut T,
18    member: *mut U,
19    _phantom: std::marker::PhantomData<&'a mut T>,
20}
21
22impl<'a, T: 'a + ?Sized, U: 'a + ?Sized> BorrowStack<'a, T, U> {
23    pub fn new<F>(container: &'a mut T, f: F) -> Result<Self, SoftBufferError>
24    where
25        F: for<'b> FnOnce(&'b mut T) -> Result<&'b mut U, SoftBufferError>,
26    {
27        let container = container as *mut T;
28        let member = f(unsafe { &mut *container })? as *mut U;
29        Ok(Self {
30            container,
31            member,
32            _phantom: std::marker::PhantomData,
33        })
34    }
35
36    pub fn member(&self) -> &U {
37        unsafe { &*self.member }
38    }
39
40    pub fn member_mut(&mut self) -> &mut U {
41        unsafe { &mut *self.member }
42    }
43
44    pub fn into_container(self) -> &'a mut T {
45        // SAFETY: Since we consume self and no longer reference member, this
46        // mutable reference is unique.
47        unsafe { &mut *self.container }
48    }
49}
50
51/// Calculates the smallest `Rect` necessary to represent all damaged `Rect`s.
52pub(crate) fn union_damage(damage: &[Rect]) -> Option<Rect> {
53    struct Region {
54        left: u32,
55        top: u32,
56        bottom: u32,
57        right: u32,
58    }
59
60    let region = damage
61        .iter()
62        .map(|rect| Region {
63            left: rect.x,
64            top: rect.y,
65            right: rect.x + rect.width.get(),
66            bottom: rect.y + rect.height.get(),
67        })
68        .reduce(|mut prev, next| {
69            prev.left = cmp::min(prev.left, next.left);
70            prev.top = cmp::min(prev.top, next.top);
71            prev.right = cmp::max(prev.right, next.right);
72            prev.bottom = cmp::max(prev.bottom, next.bottom);
73            prev
74        })?;
75
76    Some(Rect {
77        x: region.left,
78        y: region.top,
79        width: NonZeroU32::new(region.right - region.left)
80            .expect("`right` must always be bigger then `left`"),
81        height: NonZeroU32::new(region.bottom - region.top)
82            .expect("`bottom` must always be bigger then `top`"),
83    })
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn test_borrowstack_slice_int() {
92        fn f(mut stack: BorrowStack<[u32], u32>) {
93            assert_eq!(*stack.member(), 3);
94            *stack.member_mut() = 42;
95            assert_eq!(stack.into_container(), &[1, 2, 42, 4, 5]);
96        }
97
98        let mut v = vec![1, 2, 3, 4, 5];
99        f(BorrowStack::new(v.as_mut(), |v: &mut [u32]| Ok(&mut v[2])).unwrap());
100        assert_eq!(&v, &[1, 2, 42, 4, 5]);
101    }
102}