neon/types_impl/buffer/
lock.rsuse std::{cell::RefCell, ops::Range};
use crate::{
context::Context,
types::buffer::{BorrowError, Ref, RefMut},
};
#[derive(Debug)]
pub struct Lock<'cx, C> {
pub(super) cx: &'cx C,
pub(super) ledger: RefCell<Ledger>,
}
impl<'a: 'cx, 'cx, C> Lock<'cx, C>
where
C: Context<'a>,
{
pub fn new(cx: &'cx mut C) -> Lock<'cx, C> {
Lock {
cx,
ledger: Default::default(),
}
}
}
#[derive(Debug, Default)]
pub(super) struct Ledger {
pub(super) owned: Vec<Range<*const u8>>,
pub(super) shared: Vec<Range<*const u8>>,
}
impl Ledger {
pub(super) fn slice_to_range<T>(data: &[T]) -> Range<*const u8> {
let Range { start, end } = data.as_ptr_range();
(start.cast())..(end.cast())
}
pub(super) fn try_borrow<'a, T>(
ledger: &'a RefCell<Self>,
data: &'a [T],
) -> Result<Ref<'a, T>, BorrowError> {
if !data.is_empty() {
ledger.borrow_mut().try_add_borrow(data)?;
}
Ok(Ref { ledger, data })
}
pub(super) fn try_borrow_mut<'a, T>(
ledger: &'a RefCell<Self>,
data: &'a mut [T],
) -> Result<RefMut<'a, T>, BorrowError> {
if !data.is_empty() {
ledger.borrow_mut().try_add_borrow_mut(data)?;
}
Ok(RefMut { ledger, data })
}
fn try_add_borrow<T>(&mut self, data: &[T]) -> Result<(), BorrowError> {
let range = Self::slice_to_range(data);
check_overlap(&self.owned, &range)?;
self.shared.push(range);
Ok(())
}
fn try_add_borrow_mut<T>(&mut self, data: &mut [T]) -> Result<(), BorrowError> {
let range = Self::slice_to_range(data);
check_overlap(&self.owned, &range)?;
check_overlap(&self.shared, &range)?;
self.owned.push(range);
Ok(())
}
}
fn is_disjoint(a: &Range<*const u8>, b: &Range<*const u8>) -> bool {
b.start >= a.end || a.start >= b.end
}
fn check_overlap(
existing: &[Range<*const u8>],
range: &Range<*const u8>,
) -> Result<(), BorrowError> {
if existing.iter().all(|i| is_disjoint(i, range)) {
Ok(())
} else {
Err(BorrowError::new())
}
}
#[cfg(test)]
mod tests {
use std::cell::RefCell;
use std::error::Error;
use std::mem;
use std::slice;
use super::{BorrowError, Ledger};
fn unsafe_aliased_slice<T>(data: &mut [T]) -> &'static mut [T] {
unsafe { slice::from_raw_parts_mut(data.as_mut_ptr(), data.len()) }
}
#[test]
fn test_overlapping_immutable_borrows() -> Result<(), Box<dyn Error>> {
let ledger = RefCell::new(Ledger::default());
let data = [0u8; 128];
Ledger::try_borrow(&ledger, &data[0..10])?;
Ledger::try_borrow(&ledger, &data[0..100])?;
Ledger::try_borrow(&ledger, &data[20..])?;
Ok(())
}
#[test]
fn test_nonoverlapping_borrows() -> Result<(), Box<dyn Error>> {
let ledger = RefCell::new(Ledger::default());
let mut data = [0; 16];
let (a, b) = data.split_at_mut(4);
let _a = Ledger::try_borrow_mut(&ledger, a)?;
let _b = Ledger::try_borrow(&ledger, b)?;
Ok(())
}
#[test]
fn test_overlapping_borrows() -> Result<(), Box<dyn Error>> {
let ledger = RefCell::new(Ledger::default());
let mut data = [0; 16];
let a = unsafe_aliased_slice(&mut data[4..8]);
let b = unsafe_aliased_slice(&mut data[6..12]);
let ab = Ledger::try_borrow(&ledger, a)?;
assert_eq!(
Ledger::try_borrow_mut(&ledger, b).unwrap_err(),
BorrowError::new(),
);
mem::drop(ab);
let bb = Ledger::try_borrow_mut(&ledger, b)?;
assert_eq!(
Ledger::try_borrow(&ledger, a).unwrap_err(),
BorrowError::new(),
);
mem::drop(bb);
let _ab = Ledger::try_borrow(&ledger, a)?;
Ok(())
}
}