#![no_std]
use core::{cell::Cell, fmt, marker::PhantomData, ops, ptr::NonNull};
#[cfg(doc)]
#[doc = include_str!("../Readme.md")]
pub mod docs {
#[doc = include_str!("../docs/development_log.md")]
pub const DEVELOPMENT_NOTES: () = ();
#[doc = include_str!("../Changes.md")]
pub const CHANGELOG: () = ();
}
pub fn from_array_rows<'a, T, const N: usize>(data: &'a [[T; N]]) -> BlockRef<'a, T> {
BlockRef {
block: BlockSlice {
rows: data.len(),
cols: N,
pitch: N,
},
data: NonNull::from_ref(data).cast(),
lifetime: PhantomData,
}
}
#[derive(Copy, Clone)]
pub struct BlockRef<'a, T> {
data: NonNull<T>,
block: BlockSlice,
lifetime: PhantomData<&'a [T]>,
}
unsafe impl<T> Sync for BlockRef<'_, T> where T: Sync {}
unsafe impl<T> Send for BlockRef<'_, T> where T: Sync {}
const _: () = {
fn _coerce_block<'a, 'b: 'a, T>(v: BlockRef<'b, T>) -> BlockRef<'a, T> {
v
}
fn _coerce_covariant<'lt, 'a, 'b: 'a, T>(v: &'lt BlockRef<'b, T>) -> &'lt BlockRef<'a, T> {
v
}
fn _coerce_covariant_fn<'lt, 'a, 'b: 'a, T>(v: fn(BlockRef<'a, T>)) -> fn(BlockRef<'b, T>) {
v
}
fn _coerce_item_covariant<'lt, 'a, 'b: 'a, T>(v: BlockRef<'lt, &'b T>) -> BlockRef<'lt, &'a T> {
v
}
};
impl<T> Default for BlockRef<'_, T> {
fn default() -> Self {
from_array_rows::<T, 0>(&[])
}
}
impl<'data, T> BlockRef<'data, T> {
pub fn new(data: &'data [T], pitch: usize) -> Self {
assert!(data.len().is_multiple_of(pitch));
BlockRef {
block: BlockSlice {
rows: data.len() / pitch,
cols: pitch,
pitch,
},
data: NonNull::from_ref(data).cast(),
lifetime: PhantomData,
}
}
pub fn rows(&self) -> usize {
self.block.rows
}
pub fn cols(&self) -> usize {
self.block.cols
}
pub fn split_at_col(self, mid: usize) -> (BlockRef<'data, T>, BlockRef<'data, T>) {
self.split_at_col_checked(mid).unwrap()
}
pub fn split_at_col_checked(
self,
mid: usize,
) -> Option<(BlockRef<'data, T>, BlockRef<'data, T>)> {
if let Some((lhs, rhs, offset)) = self.block.split_at_col(mid) {
Some((
BlockRef {
data: self.data,
block: lhs,
lifetime: self.lifetime,
},
BlockRef {
data: unsafe { self.data.add(offset) },
block: rhs,
lifetime: self.lifetime,
},
))
} else {
None
}
}
pub fn split_at_row(self, mid: usize) -> (BlockRef<'data, T>, BlockRef<'data, T>) {
self.split_at_row_checked(mid).unwrap()
}
pub fn split_at_row_checked(
self,
mid: usize,
) -> Option<(BlockRef<'data, T>, BlockRef<'data, T>)> {
if let Some((lhs, rhs, offset)) = self.block.split_at_row(mid) {
Some((
BlockRef {
data: self.data,
block: lhs,
lifetime: self.lifetime,
},
BlockRef {
data: unsafe { self.data.add(offset) },
block: rhs,
lifetime: self.lifetime,
},
))
} else {
None
}
}
pub fn row(self, row: usize) -> VecRef<'data, T> {
let (_, block, offset) = self.block.split_at_row(row).unwrap();
assert!(block.rows >= 1);
VecRef {
block: VectorSlice {
count: block.cols,
pitch: 1,
},
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
}
}
pub fn col(self, col: usize) -> VecRef<'data, T> {
let (_, block, offset) = self.block.split_at_col(col).unwrap();
assert!(block.cols >= 1);
VecRef {
block: VectorSlice {
count: block.rows,
pitch: block.pitch,
},
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
}
}
pub fn select_rows<R>(self, range: R) -> Option<BlockRef<'data, T>>
where
R: MatrixIndex,
{
let (start, len) = range.into_start_and_len(self.block.rows)?;
let (_, block, offset) = self.block.split_at_row(start)?;
assert!(block.rows >= len);
Some(BlockRef {
block: BlockSlice { rows: len, ..block },
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
})
}
pub fn select_cols<R>(self, range: R) -> Option<BlockRef<'data, T>>
where
R: MatrixIndex,
{
let (start, len) = range.into_start_and_len(self.block.rows)?;
let (_, block, offset) = self.block.split_at_col(start)?;
assert!(block.cols >= len);
Some(BlockRef {
block: BlockSlice { cols: len, ..block },
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
})
}
pub fn select(
self,
row_range: impl MatrixIndex,
col_range: impl MatrixIndex,
) -> Option<BlockRef<'data, T>> {
let block = self.select_rows(row_range)?;
block.select_cols(col_range)
}
pub fn into_contiguous_slice(self) -> Option<&'data [T]> {
if let Some(items) = self.block.contiguous_span() {
Some(unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), items) })
} else {
None
}
}
fn fake_contiguity(mut self) -> &'data [T] {
self.block.fake_contiguity();
self.into_contiguous_slice().unwrap()
}
pub fn into_array_rows_checked<const N: usize>(self) -> Option<&'data [[T; N]]> {
if self.block.cols == self.block.pitch && self.block.cols == N {
Some(unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.block.rows) })
} else {
None
}
}
pub fn iter_rows(self) -> IterRows<'data, T> {
IterRows { block: self }
}
pub fn reborrow(&self) -> BlockRef<'_, T> {
BlockRef {
data: self.data,
block: self.block,
lifetime: PhantomData,
}
}
}
impl<T> ops::Index<(usize, usize)> for BlockRef<'_, T> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
let idx = self.block.in_bounds_offset(index.0, index.1);
unsafe { &*self.data.as_ptr().add(idx) }
}
}
impl<T: fmt::Debug> fmt::Debug for BlockRef<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.reborrow().iter_rows()).finish()
}
}
pub fn from_array_rows_mut<'a, T, const N: usize>(data: &'a mut [[T; N]]) -> BlockMut<'a, T> {
BlockMut {
block: BlockSlice {
rows: data.len(),
cols: N,
pitch: N,
},
data: NonNull::from_mut(data).cast(),
lifetime: PhantomData,
}
}
pub struct BlockMut<'a, T> {
data: NonNull<T>,
block: BlockSlice,
lifetime: PhantomData<&'a mut [T]>,
}
unsafe impl<T> Sync for BlockMut<'_, T> where T: Sync {}
unsafe impl<T> Send for BlockMut<'_, T> where T: Sync {}
const _: () = {
fn _coerce_block_mut<'a, 'b: 'a, T>(v: BlockMut<'b, T>) -> BlockMut<'a, T> {
v
}
fn _coerce_covariant<'lt, 'a, 'b: 'a, T>(v: &'lt BlockMut<'b, T>) -> &'lt BlockMut<'a, T> {
v
}
fn _coerce_covariant_fn<'lt, 'a, 'b: 'a, T>(v: fn(BlockMut<'a, T>)) -> fn(BlockMut<'b, T>) {
v
}
};
impl<T> Default for BlockMut<'_, T> {
fn default() -> Self {
from_array_rows_mut::<T, 0>(&mut [])
}
}
impl<'data, T> BlockMut<'data, T> {
pub fn new(data: &'data mut [T], pitch: usize) -> Self {
assert!(data.len().is_multiple_of(pitch));
BlockMut {
block: BlockSlice {
rows: data.len() / pitch,
cols: pitch,
pitch,
},
data: NonNull::from_mut(data).cast(),
lifetime: PhantomData,
}
}
pub fn rows(&self) -> usize {
self.block.rows
}
pub fn cols(&self) -> usize {
self.block.cols
}
pub fn split_at_col(self, mid: usize) -> (BlockMut<'data, T>, BlockMut<'data, T>) {
self.split_at_col_checked(mid).unwrap()
}
pub fn split_at_col_checked(
self,
mid: usize,
) -> Option<(BlockMut<'data, T>, BlockMut<'data, T>)> {
if let Some((lhs, rhs, offset)) = self.block.split_at_col(mid) {
Some((
BlockMut {
data: self.data,
block: lhs,
lifetime: self.lifetime,
},
BlockMut {
data: unsafe { self.data.add(offset) },
block: rhs,
lifetime: self.lifetime,
},
))
} else {
None
}
}
pub fn split_at_row(self, mid: usize) -> (BlockMut<'data, T>, BlockMut<'data, T>) {
self.split_at_row_checked(mid).unwrap()
}
pub fn split_at_row_checked(
self,
mid: usize,
) -> Option<(BlockMut<'data, T>, BlockMut<'data, T>)> {
if let Some((lhs, rhs, offset)) = self.block.split_at_row(mid) {
Some((
BlockMut {
data: self.data,
block: lhs,
lifetime: self.lifetime,
},
BlockMut {
data: unsafe { self.data.add(offset) },
block: rhs,
lifetime: self.lifetime,
},
))
} else {
None
}
}
pub fn row(self, row: usize) -> VecMut<'data, T> {
let (_, block, offset) = self.block.split_at_row(row).unwrap();
assert!(block.rows >= 1);
VecMut {
block: VectorSlice {
count: block.cols,
pitch: 1,
},
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
}
}
pub fn col(self, col: usize) -> VecMut<'data, T> {
let (_, block, offset) = self.block.split_at_col(col).unwrap();
assert!(block.cols >= 1);
VecMut {
block: VectorSlice {
count: block.rows,
pitch: block.pitch,
},
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
}
}
pub fn select_rows<R>(self, range: R) -> Option<BlockMut<'data, T>>
where
R: MatrixIndex,
{
let (start, len) = range.into_start_and_len(self.block.rows)?;
let (_, block, offset) = self.block.split_at_row(start)?;
assert!(block.rows >= len);
Some(BlockMut {
block: BlockSlice { rows: len, ..block },
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
})
}
pub fn select_cols<R>(self, range: R) -> Option<BlockMut<'data, T>>
where
R: MatrixIndex,
{
let (start, len) = range.into_start_and_len(self.block.rows)?;
let (_, block, offset) = self.block.split_at_col(start)?;
assert!(block.cols >= len);
Some(BlockMut {
block: BlockSlice { cols: len, ..block },
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
})
}
pub fn select(
self,
row_range: impl MatrixIndex,
col_range: impl MatrixIndex,
) -> Option<BlockMut<'data, T>> {
let block = self.select_rows(row_range)?;
block.select_cols(col_range)
}
pub fn into_contiguous_slice(self) -> Option<&'data mut [T]> {
if let Some(items) = self.block.contiguous_span() {
Some(unsafe { core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), items) })
} else {
None
}
}
fn fake_contiguity(mut self) -> &'data mut [T] {
self.block.fake_contiguity();
self.into_contiguous_slice().unwrap()
}
pub fn into_array_rows_checked<const N: usize>(self) -> Option<&'data mut [[T; N]]> {
if self.block.cols == self.block.pitch && self.block.cols == N {
Some(unsafe {
core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), self.block.rows)
})
} else {
None
}
}
pub fn cast_const(self) -> BlockRef<'data, T> {
BlockRef {
data: self.data,
block: self.block,
lifetime: PhantomData,
}
}
pub fn reborrow(&mut self) -> BlockMut<'_, T> {
BlockMut {
data: self.data,
block: self.block,
lifetime: PhantomData,
}
}
pub fn iter_rows(self) -> IterRows<'data, T> {
self.cast_const().iter_rows()
}
pub fn iter_rows_mut(self) -> IterRowsMut<'data, T> {
IterRowsMut { block: self }
}
pub fn as_cells(self) -> BlockMut<'data, Cell<T>> {
BlockMut {
data: self.data.cast(),
block: self.block,
lifetime: PhantomData,
}
}
}
impl<'data, T> BlockMut<'data, Cell<T>> {
pub fn as_cell_items(self) -> BlockMut<'data, T> {
BlockMut {
data: self.data.cast(),
block: self.block,
lifetime: PhantomData,
}
}
}
impl<T> ops::Index<(usize, usize)> for BlockMut<'_, T> {
type Output = T;
fn index(&self, index: (usize, usize)) -> &Self::Output {
let idx = self.block.in_bounds_offset(index.0, index.1);
unsafe { &*self.data.as_ptr().add(idx) }
}
}
impl<T> ops::IndexMut<(usize, usize)> for BlockMut<'_, T> {
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
let idx = self.block.in_bounds_offset(index.0, index.1);
unsafe { &mut *self.data.as_ptr().add(idx) }
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct BlockSlice {
rows: usize,
cols: usize,
pitch: usize,
}
const _: () = {
use core::{fmt, hash};
fn _can_eventually_be_ptr_metadata<
Metadata: fmt::Debug + Copy + Send + Sync + Ord + hash::Hash + Unpin,
>() {
}
let _ = _can_eventually_be_ptr_metadata::<BlockSlice>;
};
impl BlockSlice {
fn contiguous_span(&self) -> Option<usize> {
if self.cols == self.pitch {
Some(self.rows * self.cols)
} else {
None
}
}
fn total_span(&self) -> usize {
if let Some(all_but_last) = self.rows.checked_sub(1) {
all_but_last * self.pitch + self.cols
} else {
0
}
}
fn fake_contiguity(&mut self) {
debug_assert!(self.rows <= 1);
debug_assert!(self.cols <= self.pitch);
self.rows = self.rows.min(1);
self.pitch = self.cols;
}
fn split_at_row(self, mid: usize) -> Option<(BlockSlice, BlockSlice, usize)> {
let n = self.rows.checked_sub(mid)?;
let lhs = BlockSlice {
rows: mid,
cols: self.cols,
pitch: self.pitch,
};
let rhs = BlockSlice {
rows: n,
cols: self.cols,
pitch: self.pitch,
};
let offset = if n > 0 { mid * self.pitch } else { 0 };
debug_assert!(offset <= self.total_span());
Some((lhs, rhs, offset))
}
fn split_at_col(self, mid: usize) -> Option<(BlockSlice, BlockSlice, usize)> {
let n = self.cols.checked_sub(mid)?;
let lhs = BlockSlice {
rows: self.rows,
cols: mid,
pitch: self.pitch,
};
let rhs = BlockSlice {
rows: self.rows,
cols: n,
pitch: self.pitch,
};
let offset = if self.rows > 0 { mid } else { 0 };
debug_assert!(offset <= self.total_span());
Some((lhs, rhs, offset))
}
fn in_bounds_offset(&self, row: usize, col: usize) -> usize {
assert!(row < self.rows);
assert!(col < self.cols);
let idx = row * self.pitch + col;
debug_assert!(idx < self.total_span());
idx
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct VectorSlice {
count: usize,
pitch: usize,
}
const _: () = {
use core::{fmt, hash};
fn _can_eventually_be_ptr_metadata<
Metadata: fmt::Debug + Copy + Send + Sync + Ord + hash::Hash + Unpin,
>() {
}
let _ = _can_eventually_be_ptr_metadata::<VectorSlice>;
};
impl VectorSlice {
fn split_at(self, mid: usize) -> Option<(VectorSlice, VectorSlice, usize)> {
let right_count = self.count.checked_sub(mid)?;
let left = VectorSlice {
count: mid,
pitch: self.pitch,
};
let right = VectorSlice {
count: right_count,
pitch: self.pitch,
};
let offset = if right_count == 0 {
0
} else {
mid * self.pitch
};
Some((left, right, offset))
}
fn in_bounds_offset(&self, index: usize) -> usize {
assert!(index < self.count);
index * self.pitch
}
}
pub struct IterRows<'a, T> {
block: BlockRef<'a, T>,
}
impl<'data, T> Iterator for IterRows<'data, T> {
type Item = &'data [T];
fn next(&mut self) -> Option<Self::Item> {
if self.block.rows() == 0 {
None
} else {
let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
self.block = rest;
Some(row.fake_contiguity())
}
}
}
pub struct IterRowsMut<'a, T> {
block: BlockMut<'a, T>,
}
impl<'data, T> Iterator for IterRowsMut<'data, T> {
type Item = &'data mut [T];
fn next(&mut self) -> Option<Self::Item> {
if self.block.rows() == 0 {
None
} else {
let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
self.block = rest;
Some(row.fake_contiguity())
}
}
}
pub trait MatrixIndex: sealed::Sealed {}
impl MatrixIndex for ops::Range<usize> {}
impl MatrixIndex for ops::RangeInclusive<usize> {}
impl MatrixIndex for ops::RangeFrom<usize> {}
impl MatrixIndex for ops::RangeTo<usize> {}
impl MatrixIndex for ops::RangeToInclusive<usize> {}
impl MatrixIndex for ops::RangeFull {}
pub trait OneSidedMatrixIndex: sealed::SealedOneSided {}
impl OneSidedMatrixIndex for ops::RangeFrom<usize> {}
impl OneSidedMatrixIndex for ops::RangeTo<usize> {}
impl OneSidedMatrixIndex for ops::RangeToInclusive<usize> {}
mod sealed {
use core::ops;
pub trait Sealed {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)>;
}
pub trait SealedOneSided {
fn into_split_point(self, dim: usize) -> Option<(bool, usize)>;
}
impl Sealed for ops::Range<usize> {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
if self.start <= self.end && self.end <= dim {
Some((self.start, self.end - self.start))
} else {
None
}
}
}
impl Sealed for ops::RangeInclusive<usize> {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
let start = *self.start();
let end = *self.end();
if start <= end && end < dim {
Some((start, end - start + 1))
} else {
None
}
}
}
impl Sealed for ops::RangeFrom<usize> {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
if self.start <= dim {
Some((self.start, dim - self.start))
} else {
None
}
}
}
impl Sealed for ops::RangeTo<usize> {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
if self.end <= dim {
Some((0, self.end))
} else {
None
}
}
}
impl Sealed for ops::RangeToInclusive<usize> {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
if self.end < dim {
Some((0, self.end + 1))
} else {
None
}
}
}
impl Sealed for ops::RangeFull {
fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
Some((0, dim))
}
}
impl SealedOneSided for ops::RangeFrom<usize> {
fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
if self.start <= dim {
Some((false, self.start))
} else {
None
}
}
}
impl SealedOneSided for ops::RangeTo<usize> {
fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
if self.end <= dim {
Some((true, self.end))
} else {
None
}
}
}
impl SealedOneSided for ops::RangeToInclusive<usize> {
fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
if self.end < dim {
Some((true, self.end + 1))
} else {
None
}
}
}
}
#[derive(Copy, Clone)]
pub struct VecRef<'a, T> {
data: NonNull<T>,
block: VectorSlice,
lifetime: PhantomData<&'a [T]>,
}
unsafe impl<T> Sync for VecRef<'_, T> where T: Sync {}
unsafe impl<T> Send for VecRef<'_, T> where T: Sync {}
impl<'data, T> VecRef<'data, T> {
pub fn new(data: &'data [T], pitch: usize) -> Self {
assert_ne!(pitch, 0);
VecRef {
block: VectorSlice {
count: data.len() / pitch,
pitch,
},
data: NonNull::from(data).cast(),
lifetime: PhantomData,
}
}
pub fn from_slice(data: &'data [T]) -> Self {
VecRef {
block: VectorSlice {
count: data.len(),
pitch: 1,
},
data: NonNull::from(data).cast(),
lifetime: PhantomData,
}
}
pub fn len(&self) -> usize {
self.block.count
}
pub fn is_empty(&self) -> bool {
self.block.count == 0
}
pub fn split_at(self, mid: usize) -> (VecRef<'data, T>, VecRef<'data, T>) {
self.split_at_checked(mid).unwrap()
}
pub fn split_at_checked(mut self, mid: usize) -> Option<(VecRef<'data, T>, VecRef<'data, T>)> {
let tail = self.split_off(mid..)?;
Some((self, tail))
}
pub fn split_off<R>(&mut self, range: R) -> Option<Self>
where
R: OneSidedMatrixIndex,
{
let (is_front, split_point) = range.into_split_point(self.block.count)?;
let (left, right, offset) = self.block.split_at(split_point)?;
let ptr = self.data;
let (ours, theirs) = if is_front {
((right, offset), (left, 0))
} else {
((left, 0), (right, offset))
};
self.block = ours.0;
self.data = unsafe { ptr.add(ours.1) };
Some(VecRef {
block: theirs.0,
data: unsafe { ptr.add(theirs.1) },
lifetime: self.lifetime,
})
}
pub fn select<R>(self, range: R) -> Option<VecRef<'data, T>>
where
R: MatrixIndex,
{
let (start, len) = range.into_start_and_len(self.block.count)?;
let (_, block, offset) = self.block.split_at(start)?;
assert!(block.count >= len);
Some(VecRef {
block: VectorSlice {
count: len,
..block
},
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
})
}
pub fn iter(self) -> IterVec<'data, T> {
IterVec { vec: self }
}
}
impl<T> ops::Index<usize> for VecRef<'_, T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
let idx = self.block.in_bounds_offset(index);
unsafe { &*self.data.as_ptr().add(idx) }
}
}
pub struct VecMut<'a, T> {
data: NonNull<T>,
block: VectorSlice,
lifetime: PhantomData<&'a mut [T]>,
}
unsafe impl<T> Sync for VecMut<'_, T> where T: Sync {}
unsafe impl<T> Send for VecMut<'_, T> where T: Sync {}
impl<'data, T> VecMut<'data, T> {
pub fn new(data: &'data mut [T], pitch: usize) -> Self {
VecMut {
block: VectorSlice {
count: data.len() / pitch,
pitch,
},
data: NonNull::from(data).cast(),
lifetime: PhantomData,
}
}
pub fn from_slice(data: &'data mut [T]) -> Self {
VecMut {
block: VectorSlice {
count: data.len(),
pitch: 1,
},
data: NonNull::from(data).cast(),
lifetime: PhantomData,
}
}
pub fn len(&self) -> usize {
self.block.count
}
pub fn is_empty(&self) -> bool {
self.block.count == 0
}
pub fn split_at(self, mid: usize) -> (VecMut<'data, T>, VecMut<'data, T>) {
self.split_at_checked(mid).unwrap()
}
pub fn split_at_checked(self, mid: usize) -> Option<(VecMut<'data, T>, VecMut<'data, T>)> {
if let Some((lhs, rhs, offset)) = self.block.split_at(mid) {
Some((
VecMut {
data: self.data,
block: lhs,
lifetime: self.lifetime,
},
VecMut {
data: unsafe { self.data.add(offset) },
block: rhs,
lifetime: self.lifetime,
},
))
} else {
None
}
}
pub fn split_off<R>(&mut self, range: R) -> Option<Self>
where
R: OneSidedMatrixIndex,
{
let (is_front, split_point) = range.into_split_point(self.block.count)?;
let (left, right, offset) = self.block.split_at(split_point)?;
let ptr = self.data;
let (ours, theirs) = if is_front {
((right, offset), (left, 0))
} else {
((left, 0), (right, offset))
};
self.block = ours.0;
self.data = unsafe { ptr.add(ours.1) };
Some(VecMut {
block: theirs.0,
data: unsafe { ptr.add(theirs.1) },
lifetime: self.lifetime,
})
}
pub fn select<R>(self, range: R) -> Option<VecMut<'data, T>>
where
R: MatrixIndex,
{
let (start, len) = range.into_start_and_len(self.block.count)?;
let (_, block, offset) = self.block.split_at(start)?;
assert!(block.count >= len);
Some(VecMut {
block: VectorSlice {
count: len,
..block
},
data: unsafe { self.data.add(offset) },
lifetime: self.lifetime,
})
}
pub fn cast_const(self) -> VecRef<'data, T> {
VecRef {
data: self.data,
block: self.block,
lifetime: PhantomData,
}
}
pub fn reborrow(&mut self) -> VecMut<'_, T> {
VecMut {
data: self.data,
block: self.block,
lifetime: PhantomData,
}
}
pub fn as_cells(self) -> VecMut<'data, Cell<T>> {
VecMut {
data: self.data.cast(),
block: self.block,
lifetime: PhantomData,
}
}
pub fn iter(self) -> IterVecMut<'data, T> {
IterVecMut { vec: self }
}
}
impl<'data, T> VecMut<'data, Cell<T>> {
pub fn as_cell_items(self) -> VecMut<'data, T> {
VecMut {
data: self.data.cast(),
block: self.block,
lifetime: PhantomData,
}
}
}
impl<T> ops::Index<usize> for VecMut<'_, T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
let idx = self.block.in_bounds_offset(index);
unsafe { &*self.data.as_ptr().add(idx) }
}
}
impl<T> ops::IndexMut<usize> for VecMut<'_, T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let idx = self.block.in_bounds_offset(index);
unsafe { &mut *self.data.as_ptr().add(idx) }
}
}
pub struct IterVec<'a, T> {
vec: VecRef<'a, T>,
}
impl<'data, T> IntoIterator for VecRef<'data, T> {
type Item = &'data T;
type IntoIter = IterVec<'data, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'data, T> Iterator for IterVec<'data, T> {
type Item = &'data T;
fn next(&mut self) -> Option<Self::Item> {
let base = self.vec.split_off(..1)?;
Some(unsafe { &*base.data.as_ptr() })
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remain = self.vec.len();
(remain, Some(remain))
}
fn count(self) -> usize {
self.vec.len()
}
}
impl<'data, T> core::iter::FusedIterator for IterVec<'data, T> {}
pub struct IterVecMut<'a, T> {
vec: VecMut<'a, T>,
}
impl<'data, T> IntoIterator for VecMut<'data, T> {
type Item = &'data mut T;
type IntoIter = IterVecMut<'data, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'data, T> Iterator for IterVecMut<'data, T> {
type Item = &'data mut T;
fn next(&mut self) -> Option<Self::Item> {
let base = self.vec.split_off(..1)?;
Some(unsafe { &mut *base.data.as_ptr() })
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remain = self.vec.len();
(remain, Some(remain))
}
fn count(self) -> usize {
self.vec.len()
}
}
impl<'data, T> core::iter::FusedIterator for IterVecMut<'data, T> {}
#[cfg(test)]
mod tests {
#[test]
fn well_defined_split() {
let data = &[[0u32; 3]; 3];
let block = super::from_array_rows(data);
let (_, block) = block.split_at_row(1);
let (_, block) = block.split_at_col(1);
block.split_at_row_checked(2).unwrap();
}
#[test]
fn well_defined_split_mut() {
let data = &mut [[0u32; 3]; 3];
let block = super::from_array_rows_mut(data);
let (_, block) = block.split_at_row(1);
let (_, block) = block.split_at_col(1);
block.split_at_row_checked(2).unwrap();
}
#[test]
fn soundness_interleaved_block_access() {
let data = &mut [[0u32; 4]; 4];
let block = super::from_array_rows_mut(data);
let (mut lhs, rhs) = block.split_at_col(2);
for (left, right) in lhs.reborrow().iter_rows_mut().zip(rhs.iter_rows_mut()) {
left[0] = right[0];
left[1] = right[1];
right.fill(1);
}
for row in lhs.iter_rows_mut() {
row.fill(2);
}
for row in data.iter() {
assert_eq!(row, &[2, 2, 1, 1]);
}
}
}