use crate::archive::Struct;
use std::fmt;
use std::iter;
use std::marker;
use std::ops::{Bound, RangeBounds};
#[derive(Clone)]
pub struct ArrayView<'a, T>
where
T: for<'b> Struct<'b>,
{
data: &'a [u8],
_phantom: marker::PhantomData<T>,
}
impl<'a, T> ArrayView<'a, T>
where
T: for<'b> Struct<'b>,
{
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
_phantom: marker::PhantomData,
}
}
pub fn len(&self) -> usize {
self.data.len() / <T as Struct>::SIZE_IN_BYTES
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn at(&self, index: usize) -> <T as Struct<'a>>::Item {
let index = self.data_index(index);
assert!(index + <T as Struct>::SIZE_IN_BYTES <= self.data.len());
T::create(&self.data[index..])
}
pub fn slice<R: RangeBounds<usize>>(&self, range: R) -> Self {
let data_start = match range.start_bound() {
Bound::Included(&idx) => self.data_index(idx),
Bound::Excluded(&idx) => self.data_index(idx + 1),
Bound::Unbounded => 0,
};
let data_end = match range.end_bound() {
Bound::Included(&idx) => self.data_index(idx + 1),
Bound::Excluded(&idx) => self.data_index(idx),
Bound::Unbounded => self.data.len(),
};
Self::new(&self.data[data_start..data_end])
}
pub fn iter(&self) -> ArrayViewIter<'a, T> {
ArrayViewIter {
view: self.clone(),
next_pos: 0,
}
}
pub fn as_bytes(&self) -> &[u8] {
self.data
}
fn data_index(&self, index: usize) -> usize {
index * <T as Struct>::SIZE_IN_BYTES
}
}
impl<'a, T> fmt::Debug for ArrayView<'a, T>
where
T: for<'b> Struct<'b>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let preview: Vec<_> = self.iter().take(super::DEBUG_PREVIEW_LEN).collect();
write!(
f,
"ArrayView {{ len: {}, data: {:?}{} }}",
self.len(),
preview,
if self.len() <= super::DEBUG_PREVIEW_LEN {
""
} else {
"..."
}
)
}
}
impl<'a, T> AsRef<[u8]> for ArrayView<'a, T>
where
T: for<'b> Struct<'b>,
{
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
#[derive(Clone)]
pub struct ArrayViewIter<'a, T>
where
T: for<'b> Struct<'b>,
{
view: ArrayView<'a, T>,
next_pos: usize,
}
impl<'a, T> iter::Iterator for ArrayViewIter<'a, T>
where
T: for<'b> Struct<'b>,
{
type Item = <T as Struct<'a>>::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.next_pos < self.view.len() {
let element = self.view.at(self.next_pos);
self.next_pos += 1;
Some(element)
} else {
None
}
}
}
impl<'a, T> iter::ExactSizeIterator for ArrayViewIter<'a, T>
where
T: for<'b> Struct<'b>,
{
fn len(&self) -> usize {
self.view.len()
}
}
impl<'a, T> fmt::Debug for ArrayViewIter<'a, T>
where
T: for<'b> Struct<'b>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let preview = self
.view
.iter()
.skip(self.next_pos)
.take(super::DEBUG_PREVIEW_LEN);
write!(
f,
"ArrayViewIter {{ data: {:?}{} }}",
preview,
if self.view.len() - self.next_pos <= super::DEBUG_PREVIEW_LEN {
""
} else {
"..."
}
)
}
}
#[cfg(test)]
mod test {
use super::ArrayView;
use crate::archive::Struct;
use crate::memory;
use crate::Vector;
#[test]
#[allow(dead_code)]
fn test() {
define_struct!(
A,
RefA,
RefMutA,
"no_schema",
4,
(x, set_x, u32, 0, 16),
(y, set_y, u32, 16, 16)
);
let mut buffer = vec![255_u8; 4];
buffer.extend(vec![0_u8; A::SIZE_IN_BYTES * 10 + memory::PADDING_SIZE]);
let data = &buffer[..buffer.len() - memory::PADDING_SIZE];
let view: ArrayView<A> = ArrayView::new(&data);
assert_eq!(11, view.len());
let first = view.at(0);
assert_eq!(65535, first.x());
assert_eq!(65535, first.y());
for x in view.iter().skip(1) {
assert_eq!(0, x.x());
assert_eq!(0, x.y());
}
let x = {
let view_copy = view.clone();
view_copy.at(0)
};
assert_eq!(65535, x.x());
assert_eq!(65535, x.y());
let x = {
let view_copy = view.clone();
view_copy.iter().next().unwrap()
};
assert_eq!(65535, x.x());
assert_eq!(65535, x.y());
}
#[test]
#[allow(dead_code)]
fn test_slice() {
define_struct!(
A,
RefA,
RefMutA,
"no_schema",
4,
(value, set_value, u32, 0, 32)
);
let mut v: Vector<A> = Vector::with_len(10);
for i in 0..10 {
let mut a = v.at_mut(i as usize);
a.set_value(i);
}
let view: ArrayView<_> = v.as_view();
assert_eq!(view.len(), 10);
assert_eq!(view.slice(2..).len(), 8);
assert_eq!(view.slice(2..).iter().next().unwrap().value(), 2);
assert_eq!(view.slice(..8).len(), 8);
assert_eq!(view.slice(..8).iter().next().unwrap().value(), 0);
assert_eq!(view.slice(2..8).len(), 6);
assert_eq!(view.slice(2..8).iter().next().unwrap().value(), 2);
}
}