#![no_std]
#![feature(slice_ptr_get)]
extern crate alloc;
use core::cell::RefCell;
use core::marker::PhantomData;
use core::ops::{Range, RangeBounds};
#[cfg(feature = "_internal")]
pub use internal::*;
pub struct SliceCell<'a, T> {
_lifetime: PhantomData<&'a ()>,
data: *mut [T],
state: RefCell<internal::State>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
Range,
Borrow,
}
impl<'a, T> SliceCell<'a, T> {
pub fn new(data: &'a mut [T]) -> Self {
Self { _lifetime: PhantomData, data, state: Default::default() }
}
pub fn get(&self, index: usize) -> Result<&T, Error> {
Ok(&self.get_range(index ..= index)?[0])
}
pub fn get_mut(&self, index: usize) -> Result<&mut T, Error> {
Ok(&mut self.get_range_mut(index ..= index)?[0])
}
pub fn get_range(&self, range: impl RangeBounds<usize>) -> Result<&[T], Error> {
let range = self.range(range)?;
let false = range.is_empty() else { return Ok(&[]) };
let ptr = unsafe { self.data.as_mut_ptr().add(range.start) };
let len = range.len();
self.borrow(range)?;
Ok(unsafe { core::slice::from_raw_parts(ptr, len) })
}
#[allow(clippy::mut_from_ref)]
pub fn get_range_mut(&self, range: impl RangeBounds<usize>) -> Result<&mut [T], Error> {
let range = self.range(range)?;
let false = range.is_empty() else { return Ok(&mut []) };
let ptr = unsafe { self.data.as_mut_ptr().add(range.start) };
let len = range.len();
self.borrow_mut(range)?;
Ok(unsafe { core::slice::from_raw_parts_mut(ptr, len) })
}
pub fn reset(&mut self) {
self.state.take();
}
fn range(&self, range: impl RangeBounds<usize>) -> Result<Range<usize>, Error> {
internal::range_check(self.data.len(), range)
}
fn borrow(&self, range: Range<usize>) -> Result<(), Error> {
let access = internal::Access { exclusive: false, range };
internal::borrow_check(&mut self.state.borrow_mut(), access)
}
fn borrow_mut(&self, range: Range<usize>) -> Result<(), Error> {
let access = internal::Access { exclusive: true, range };
internal::borrow_check(&mut self.state.borrow_mut(), access)
}
}
#[cfg_attr(not(feature = "_internal"), allow(unreachable_pub))]
mod internal {
use alloc::vec::Vec;
use core::ops::{Bound, Range, RangeBounds};
use crate::Error;
pub fn range_check(len: usize, range: impl RangeBounds<usize>) -> Result<Range<usize>, Error> {
let start = match range.start_bound() {
Bound::Included(x) => *x,
Bound::Excluded(x) => x.checked_add(1).ok_or(Error::Range)?,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(x) => x.checked_add(1).ok_or(Error::Range)?,
Bound::Excluded(x) => *x,
Bound::Unbounded => len,
};
if start <= end && end <= len { Ok(start .. end) } else { Err(Error::Range) }
}
pub type State = Vec<Access>;
#[cfg_attr(feature = "_internal", derive(Clone, PartialEq, Eq))]
pub struct Access {
pub exclusive: bool,
pub range: Range<usize>,
}
#[cfg(feature = "_internal")]
impl core::fmt::Debug for Access {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}{:?}", if self.exclusive { "mut " } else { "" }, self.range)
}
}
pub fn borrow_check(state: &mut State, new: Access) -> Result<(), Error> {
debug_assert!(!new.range.is_empty());
let Some(i) = state.iter().position(|cur| new.range.start < cur.range.end) else {
state.push(new);
return Ok(());
};
let j = match state[i ..].iter().position(|cur| new.range.end <= cur.range.start) {
None => state.len(),
Some(x) => i + x,
};
if i == j {
state.insert(i, new);
return Ok(());
}
if new.exclusive || state[i .. j].iter().any(|x| x.exclusive) {
return Err(Error::Borrow);
}
state[i].range.start = core::cmp::min(state[i].range.start, new.range.start);
state[i].range.end = core::cmp::max(state[j - 1].range.end, new.range.end);
state.drain(i + 1 .. j);
Ok(())
}
}