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
22unsafe impl<'a, T: 'a + Send + ?Sized, U: 'a + Send + ?Sized> Send for BorrowStack<'a, T, U> {}
23
24impl<'a, T: 'a + ?Sized, U: 'a + ?Sized> BorrowStack<'a, T, U> {
25 pub fn new<F>(container: &'a mut T, f: F) -> Result<Self, SoftBufferError>
26 where
27 F: for<'b> FnOnce(&'b mut T) -> Result<&'b mut U, SoftBufferError>,
28 {
29 let container = container as *mut T;
30 let member = f(unsafe { &mut *container })? as *mut U;
31 Ok(Self {
32 container,
33 member,
34 _phantom: std::marker::PhantomData,
35 })
36 }
37
38 pub fn member(&self) -> &U {
39 unsafe { &*self.member }
40 }
41
42 pub fn member_mut(&mut self) -> &mut U {
43 unsafe { &mut *self.member }
44 }
45
46 pub fn into_container(self) -> &'a mut T {
47 // SAFETY: Since we consume self and no longer reference member, this
48 // mutable reference is unique.
49 unsafe { &mut *self.container }
50 }
51}
52
53/// Calculates the smallest `Rect` necessary to represent all damaged `Rect`s.
54pub(crate) fn union_damage(damage: &[Rect]) -> Option<Rect> {
55 struct Region {
56 left: u32,
57 top: u32,
58 bottom: u32,
59 right: u32,
60 }
61
62 let region = damage
63 .iter()
64 .map(|rect| Region {
65 left: rect.x,
66 top: rect.y,
67 right: rect.x + rect.width.get(),
68 bottom: rect.y + rect.height.get(),
69 })
70 .reduce(|mut prev, next| {
71 prev.left = cmp::min(prev.left, next.left);
72 prev.top = cmp::min(prev.top, next.top);
73 prev.right = cmp::max(prev.right, next.right);
74 prev.bottom = cmp::max(prev.bottom, next.bottom);
75 prev
76 })?;
77
78 Some(Rect {
79 x: region.left,
80 y: region.top,
81 width: NonZeroU32::new(region.right - region.left)
82 .expect("`right` must always be bigger then `left`"),
83 height: NonZeroU32::new(region.bottom - region.top)
84 .expect("`bottom` must always be bigger then `top`"),
85 })
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_borrowstack_slice_int() {
94 fn f(mut stack: BorrowStack<[u32], u32>) {
95 assert_eq!(*stack.member(), 3);
96 *stack.member_mut() = 42;
97 assert_eq!(stack.into_container(), &[1, 2, 42, 4, 5]);
98 }
99
100 let mut v = vec![1, 2, 3, 4, 5];
101 f(BorrowStack::new(v.as_mut(), |v: &mut [u32]| Ok(&mut v[2])).unwrap());
102 assert_eq!(&v, &[1, 2, 42, 4, 5]);
103 }
104}
105