wasefire_slice_cell/
lib.rs1#![no_std]
18#![feature(slice_ptr_get)]
19
20extern crate alloc;
21
22use core::cell::RefCell;
23use core::marker::PhantomData;
24use core::ops::{Range, RangeBounds};
25
26#[cfg(feature = "_internal")]
27pub use internal::*;
28
29pub struct SliceCell<'a, T> {
31 _lifetime: PhantomData<&'a ()>,
32 data: *mut [T],
33 state: RefCell<internal::State>,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum Error {
39 Range,
41
42 Borrow,
44}
45
46impl<'a, T> SliceCell<'a, T> {
47 pub fn new(data: &'a mut [T]) -> Self {
49 Self { _lifetime: PhantomData, data, state: Default::default() }
50 }
51
52 pub fn get(&self, index: usize) -> Result<&T, Error> {
54 Ok(&self.get_range(index ..= index)?[0])
55 }
56
57 pub fn get_mut(&self, index: usize) -> Result<&mut T, Error> {
59 Ok(&mut self.get_range_mut(index ..= index)?[0])
60 }
61
62 pub fn get_range(&self, range: impl RangeBounds<usize>) -> Result<&[T], Error> {
64 let range = self.range(range)?;
65 let false = range.is_empty() else { return Ok(&[]) };
66 let ptr = unsafe { self.data.as_mut_ptr().add(range.start) };
68 let len = range.len();
69 self.borrow(range)?;
70 Ok(unsafe { core::slice::from_raw_parts(ptr, len) })
72 }
73
74 #[allow(clippy::mut_from_ref)]
76 pub fn get_range_mut(&self, range: impl RangeBounds<usize>) -> Result<&mut [T], Error> {
77 let range = self.range(range)?;
78 let false = range.is_empty() else { return Ok(&mut []) };
79 let ptr = unsafe { self.data.as_mut_ptr().add(range.start) };
81 let len = range.len();
82 self.borrow_mut(range)?;
83 Ok(unsafe { core::slice::from_raw_parts_mut(ptr, len) })
85 }
86
87 pub fn reset(&mut self) {
89 self.state.take();
90 }
91
92 fn range(&self, range: impl RangeBounds<usize>) -> Result<Range<usize>, Error> {
93 internal::range_check(self.data.len(), range)
94 }
95
96 fn borrow(&self, range: Range<usize>) -> Result<(), Error> {
97 let access = internal::Access { exclusive: false, range };
98 internal::borrow_check(&mut self.state.borrow_mut(), access)
99 }
100
101 fn borrow_mut(&self, range: Range<usize>) -> Result<(), Error> {
102 let access = internal::Access { exclusive: true, range };
103 internal::borrow_check(&mut self.state.borrow_mut(), access)
104 }
105}
106
107#[cfg_attr(not(feature = "_internal"), allow(unreachable_pub))]
108mod internal {
109 use alloc::vec::Vec;
110 use core::ops::{Bound, Range, RangeBounds};
111
112 use crate::Error;
113
114 pub fn range_check(len: usize, range: impl RangeBounds<usize>) -> Result<Range<usize>, Error> {
116 let start = match range.start_bound() {
117 Bound::Included(x) => *x,
118 Bound::Excluded(x) => x.checked_add(1).ok_or(Error::Range)?,
119 Bound::Unbounded => 0,
120 };
121 let end = match range.end_bound() {
122 Bound::Included(x) => x.checked_add(1).ok_or(Error::Range)?,
123 Bound::Excluded(x) => *x,
124 Bound::Unbounded => len,
125 };
126 if start <= end && end <= len { Ok(start .. end) } else { Err(Error::Range) }
127 }
128
129 pub type State = Vec<Access>;
131
132 #[cfg_attr(feature = "_internal", derive(Clone, PartialEq, Eq))]
134 pub struct Access {
135 pub exclusive: bool,
137 pub range: Range<usize>,
139 }
140
141 #[cfg(feature = "_internal")]
142 impl core::fmt::Debug for Access {
143 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
144 write!(f, "{}{:?}", if self.exclusive { "mut " } else { "" }, self.range)
145 }
146 }
147
148 pub fn borrow_check(state: &mut State, new: Access) -> Result<(), Error> {
152 debug_assert!(!new.range.is_empty());
153 let Some(i) = state.iter().position(|cur| new.range.start < cur.range.end) else {
155 state.push(new);
157 return Ok(());
158 };
159 let j = match state[i ..].iter().position(|cur| new.range.end <= cur.range.start) {
161 None => state.len(),
162 Some(x) => i + x,
163 };
164 if i == j {
165 state.insert(i, new);
167 return Ok(());
168 }
169 if new.exclusive || state[i .. j].iter().any(|x| x.exclusive) {
171 return Err(Error::Borrow);
173 }
174 state[i].range.start = core::cmp::min(state[i].range.start, new.range.start);
176 state[i].range.end = core::cmp::max(state[j - 1].range.end, new.range.end);
177 state.drain(i + 1 .. j);
178 Ok(())
179 }
180}