neon/types_impl/buffer/
lock.rs1use std::{cell::RefCell, ops::Range};
2
3use crate::{
4 context::Context,
5 types::buffer::{BorrowError, Ref, RefMut},
6};
7
8#[derive(Debug)]
9pub struct Lock<'cx, C> {
16 pub(super) cx: &'cx C,
17 pub(super) ledger: RefCell<Ledger>,
18}
19
20impl<'a: 'cx, 'cx, C> Lock<'cx, C>
21where
22 C: Context<'a>,
23{
24 pub fn new(cx: &'cx mut C) -> Lock<'cx, C> {
26 Lock {
27 cx,
28 ledger: Default::default(),
29 }
30 }
31}
32
33#[derive(Debug, Default)]
34pub(super) struct Ledger {
38 pub(super) owned: Vec<Range<*const u8>>,
40
41 pub(super) shared: Vec<Range<*const u8>>,
43}
44
45impl Ledger {
46 pub(super) fn slice_to_range<T>(data: &[T]) -> Range<*const u8> {
50 let Range { start, end } = data.as_ptr_range();
51
52 (start.cast())..(end.cast())
53 }
54
55 pub(super) fn try_borrow<'a, T>(
58 ledger: &'a RefCell<Self>,
59 data: &'a [T],
60 ) -> Result<Ref<'a, T>, BorrowError> {
61 if !data.is_empty() {
62 ledger.borrow_mut().try_add_borrow(data)?;
63 }
64
65 Ok(Ref { ledger, data })
66 }
67
68 pub(super) fn try_borrow_mut<'a, T>(
71 ledger: &'a RefCell<Self>,
72 data: &'a mut [T],
73 ) -> Result<RefMut<'a, T>, BorrowError> {
74 if !data.is_empty() {
75 ledger.borrow_mut().try_add_borrow_mut(data)?;
76 }
77
78 Ok(RefMut { ledger, data })
79 }
80
81 fn try_add_borrow<T>(&mut self, data: &[T]) -> Result<(), BorrowError> {
83 let range = Self::slice_to_range(data);
84
85 check_overlap(&self.owned, &range)?;
87
88 self.shared.push(range);
90
91 Ok(())
92 }
93
94 fn try_add_borrow_mut<T>(&mut self, data: &mut [T]) -> Result<(), BorrowError> {
96 let range = Self::slice_to_range(data);
97
98 check_overlap(&self.owned, &range)?;
100
101 check_overlap(&self.shared, &range)?;
103
104 self.owned.push(range);
106
107 Ok(())
108 }
109}
110
111fn is_disjoint(a: &Range<*const u8>, b: &Range<*const u8>) -> bool {
112 b.start >= a.end || a.start >= b.end
113}
114
115fn check_overlap(
116 existing: &[Range<*const u8>],
117 range: &Range<*const u8>,
118) -> Result<(), BorrowError> {
119 if existing.iter().all(|i| is_disjoint(i, range)) {
120 Ok(())
121 } else {
122 Err(BorrowError::new())
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use std::cell::RefCell;
129 use std::error::Error;
130 use std::mem;
131 use std::slice;
132
133 use super::{BorrowError, Ledger};
134
135 fn unsafe_aliased_slice<T>(data: &mut [T]) -> &'static mut [T] {
137 unsafe { slice::from_raw_parts_mut(data.as_mut_ptr(), data.len()) }
138 }
139
140 #[test]
141 fn test_overlapping_immutable_borrows() -> Result<(), Box<dyn Error>> {
142 let ledger = RefCell::new(Ledger::default());
143 let data = [0u8; 128];
144
145 Ledger::try_borrow(&ledger, &data[0..10])?;
146 Ledger::try_borrow(&ledger, &data[0..100])?;
147 Ledger::try_borrow(&ledger, &data[20..])?;
148
149 Ok(())
150 }
151
152 #[test]
153 fn test_nonoverlapping_borrows() -> Result<(), Box<dyn Error>> {
154 let ledger = RefCell::new(Ledger::default());
155 let mut data = [0; 16];
156 let (a, b) = data.split_at_mut(4);
157
158 let _a = Ledger::try_borrow_mut(&ledger, a)?;
159 let _b = Ledger::try_borrow(&ledger, b)?;
160
161 Ok(())
162 }
163
164 #[test]
165 fn test_overlapping_borrows() -> Result<(), Box<dyn Error>> {
166 let ledger = RefCell::new(Ledger::default());
167 let mut data = [0; 16];
168 let a = unsafe_aliased_slice(&mut data[4..8]);
169 let b = unsafe_aliased_slice(&mut data[6..12]);
170 let ab = Ledger::try_borrow(&ledger, a)?;
171
172 assert_eq!(
174 Ledger::try_borrow_mut(&ledger, b).unwrap_err(),
175 BorrowError::new(),
176 );
177
178 mem::drop(ab);
180
181 let bb = Ledger::try_borrow_mut(&ledger, b)?;
183
184 assert_eq!(
186 Ledger::try_borrow(&ledger, a).unwrap_err(),
187 BorrowError::new(),
188 );
189
190 mem::drop(bb);
192
193 let _ab = Ledger::try_borrow(&ledger, a)?;
195
196 Ok(())
197 }
198}