use std::ops::{Index, IndexMut};
use crate::layout::{PointAttributeDefinition, PointAttributeMember};
use super::{ColumnarBuffer, ColumnarBufferMut, InterleavedBuffer, InterleavedBufferMut};
pub struct RawAttributeView<'a> {
point_data: &'a [u8],
offset: usize,
stride: usize,
size_of_attribute: usize,
}
impl<'a> RawAttributeView<'a> {
pub(crate) fn from_interleaved_buffer<'b, B: InterleavedBuffer<'b> + ?Sized>(
buffer: &'a B,
attribute_member: &PointAttributeMember,
) -> Self
where
'b: 'a,
{
let stride = buffer.point_layout().size_of_point_entry() as usize;
Self {
offset: attribute_member.offset() as usize,
point_data: buffer.get_point_range_ref(0..buffer.len()),
size_of_attribute: attribute_member.size() as usize,
stride,
}
}
pub(crate) fn from_columnar_buffer<'b, B: ColumnarBuffer<'b> + ?Sized>(
buffer: &'a B,
attribute_definition: &PointAttributeDefinition,
) -> Self
where
'b: 'a,
{
Self {
offset: 0,
point_data: buffer.get_attribute_range_ref(attribute_definition, 0..buffer.len()),
size_of_attribute: attribute_definition.size() as usize,
stride: attribute_definition.size() as usize,
}
}
pub fn len(&self) -> usize {
self.point_data.len() / self.stride
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<'a> Index<usize> for RawAttributeView<'a> {
type Output = [u8];
#[inline]
fn index(&self, index: usize) -> &Self::Output {
let start = self.offset + (self.stride * index);
let end = start + self.size_of_attribute;
&self.point_data[start..end]
}
}
pub struct RawAttributeViewMut<'a> {
point_data: &'a mut [u8],
offset: usize,
stride: usize,
size_of_attribute: usize,
}
impl<'a> RawAttributeViewMut<'a> {
pub(crate) fn from_interleaved_buffer<'b, B: InterleavedBufferMut<'b> + ?Sized>(
buffer: &'a mut B,
attribute_member: &PointAttributeMember,
) -> Self
where
'b: 'a,
{
let stride = buffer.point_layout().size_of_point_entry() as usize;
Self {
offset: attribute_member.offset() as usize,
point_data: buffer.get_point_range_mut(0..buffer.len()),
size_of_attribute: attribute_member.size() as usize,
stride,
}
}
pub(crate) fn from_columnar_buffer<'b, B: ColumnarBufferMut<'b> + ?Sized>(
buffer: &'a mut B,
attribute_definition: &PointAttributeDefinition,
) -> Self
where
'b: 'a,
{
Self {
offset: 0,
point_data: buffer.get_attribute_range_mut(attribute_definition, 0..buffer.len()),
size_of_attribute: attribute_definition.size() as usize,
stride: attribute_definition.size() as usize,
}
}
}
impl<'a> Index<usize> for RawAttributeViewMut<'a> {
type Output = [u8];
#[inline]
fn index(&self, index: usize) -> &Self::Output {
let start = self.offset + (self.stride * index);
let end = start + self.size_of_attribute;
&self.point_data[start..end]
}
}
impl<'a> IndexMut<usize> for RawAttributeViewMut<'a> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let start = self.offset + (self.stride * index);
let end = start + self.size_of_attribute;
&mut self.point_data[start..end]
}
}
#[cfg(test)]
mod tests {
use super::*;
use rand::{thread_rng, Rng};
use crate::containers::{BorrowedBuffer, HashMapBuffer, VectorBuffer};
use crate::layout::PointType;
use crate::test_utils::*;
#[test]
fn attribute_view_from_interleaved() {
const COUNT: usize = 64;
let mut test_data: VectorBuffer = thread_rng()
.sample_iter::<CustomPointTypeBig, _>(DefaultPointDistribution)
.take(COUNT)
.collect();
let layout = CustomPointTypeBig::layout();
for attribute in layout.attributes() {
let mut buffer = vec![0; attribute.size() as usize];
for point_idx in 0..COUNT {
test_data.get_attribute(
attribute.attribute_definition(),
point_idx,
&mut buffer[..],
);
let raw_view = RawAttributeView::from_interleaved_buffer(&test_data, attribute);
let data_from_view = &raw_view[point_idx];
assert_eq!(buffer.as_slice(), data_from_view);
let mut raw_view_mut =
RawAttributeViewMut::from_interleaved_buffer(&mut test_data, attribute);
let data_mut_from_view = &mut raw_view_mut[point_idx];
assert_eq!(buffer.as_slice(), data_mut_from_view);
}
}
}
#[test]
fn attribute_view_from_columnar() {
const COUNT: usize = 64;
let mut test_data: HashMapBuffer = thread_rng()
.sample_iter::<CustomPointTypeBig, _>(DefaultPointDistribution)
.take(COUNT)
.collect();
let layout = CustomPointTypeBig::layout();
for attribute in layout.attributes() {
let mut buffer = vec![0; attribute.size() as usize];
for point_idx in 0..COUNT {
test_data.get_attribute(
attribute.attribute_definition(),
point_idx,
&mut buffer[..],
);
let raw_view = RawAttributeView::from_columnar_buffer(
&test_data,
attribute.attribute_definition(),
);
let data_from_view = &raw_view[point_idx];
assert_eq!(buffer.as_slice(), data_from_view);
let mut raw_view_mut = RawAttributeViewMut::from_columnar_buffer(
&mut test_data,
attribute.attribute_definition(),
);
let data_mut_from_view = &mut raw_view_mut[point_idx];
assert_eq!(buffer.as_slice(), data_mut_from_view);
}
}
}
}