pasture_core/containers/
raw_attribute_view.rs1use std::ops::{Index, IndexMut};
2
3use crate::layout::{PointAttributeDefinition, PointAttributeMember};
4
5use super::{ColumnarBuffer, ColumnarBufferMut, InterleavedBuffer, InterleavedBufferMut};
6
7pub struct RawAttributeView<'a> {
11 point_data: &'a [u8],
12 offset: usize,
13 stride: usize,
14 size_of_attribute: usize,
15}
16
17impl<'a> RawAttributeView<'a> {
18 pub(crate) fn from_interleaved_buffer<'b, B: InterleavedBuffer<'b> + ?Sized>(
20 buffer: &'a B,
21 attribute_member: &PointAttributeMember,
22 ) -> Self
23 where
24 'b: 'a,
25 {
26 let stride = buffer.point_layout().size_of_point_entry() as usize;
27 Self {
28 offset: attribute_member.offset() as usize,
29 point_data: buffer.get_point_range_ref(0..buffer.len()),
30 size_of_attribute: attribute_member.size() as usize,
31 stride,
32 }
33 }
34
35 pub(crate) fn from_columnar_buffer<'b, B: ColumnarBuffer<'b> + ?Sized>(
37 buffer: &'a B,
38 attribute_definition: &PointAttributeDefinition,
39 ) -> Self
40 where
41 'b: 'a,
42 {
43 Self {
44 offset: 0,
45 point_data: buffer.get_attribute_range_ref(attribute_definition, 0..buffer.len()),
46 size_of_attribute: attribute_definition.size() as usize,
47 stride: attribute_definition.size() as usize,
48 }
49 }
50
51 pub fn len(&self) -> usize {
53 self.point_data.len() / self.stride
54 }
55
56 pub fn is_empty(&self) -> bool {
58 self.len() == 0
59 }
60}
61
62impl<'a> Index<usize> for RawAttributeView<'a> {
63 type Output = [u8];
64
65 #[inline]
66 fn index(&self, index: usize) -> &Self::Output {
67 let start = self.offset + (self.stride * index);
68 let end = start + self.size_of_attribute;
69 &self.point_data[start..end]
70 }
71}
72
73pub struct RawAttributeViewMut<'a> {
75 point_data: &'a mut [u8],
76 offset: usize,
77 stride: usize,
78 size_of_attribute: usize,
79}
80
81impl<'a> RawAttributeViewMut<'a> {
82 pub(crate) fn from_interleaved_buffer<'b, B: InterleavedBufferMut<'b> + ?Sized>(
84 buffer: &'a mut B,
85 attribute_member: &PointAttributeMember,
86 ) -> Self
87 where
88 'b: 'a,
89 {
90 let stride = buffer.point_layout().size_of_point_entry() as usize;
91 Self {
92 offset: attribute_member.offset() as usize,
93 point_data: buffer.get_point_range_mut(0..buffer.len()),
94 size_of_attribute: attribute_member.size() as usize,
95 stride,
96 }
97 }
98
99 pub(crate) fn from_columnar_buffer<'b, B: ColumnarBufferMut<'b> + ?Sized>(
101 buffer: &'a mut B,
102 attribute_definition: &PointAttributeDefinition,
103 ) -> Self
104 where
105 'b: 'a,
106 {
107 Self {
108 offset: 0,
109 point_data: buffer.get_attribute_range_mut(attribute_definition, 0..buffer.len()),
110 size_of_attribute: attribute_definition.size() as usize,
111 stride: attribute_definition.size() as usize,
112 }
113 }
114}
115
116impl<'a> Index<usize> for RawAttributeViewMut<'a> {
117 type Output = [u8];
118
119 #[inline]
120 fn index(&self, index: usize) -> &Self::Output {
121 let start = self.offset + (self.stride * index);
122 let end = start + self.size_of_attribute;
123 &self.point_data[start..end]
124 }
125}
126
127impl<'a> IndexMut<usize> for RawAttributeViewMut<'a> {
128 #[inline]
129 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
130 let start = self.offset + (self.stride * index);
131 let end = start + self.size_of_attribute;
132 &mut self.point_data[start..end]
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 use rand::{thread_rng, Rng};
141
142 use crate::containers::{BorrowedBuffer, HashMapBuffer, VectorBuffer};
143 use crate::layout::PointType;
144 use crate::test_utils::*;
145
146 #[test]
147 fn attribute_view_from_interleaved() {
148 const COUNT: usize = 64;
149 let mut test_data: VectorBuffer = thread_rng()
150 .sample_iter::<CustomPointTypeBig, _>(DefaultPointDistribution)
151 .take(COUNT)
152 .collect();
153
154 let layout = CustomPointTypeBig::layout();
155
156 for attribute in layout.attributes() {
157 let mut buffer = vec![0; attribute.size() as usize];
158
159 for point_idx in 0..COUNT {
160 test_data.get_attribute(
161 attribute.attribute_definition(),
162 point_idx,
163 &mut buffer[..],
164 );
165
166 let raw_view = RawAttributeView::from_interleaved_buffer(&test_data, attribute);
170 let data_from_view = &raw_view[point_idx];
171 assert_eq!(buffer.as_slice(), data_from_view);
172
173 let mut raw_view_mut =
174 RawAttributeViewMut::from_interleaved_buffer(&mut test_data, attribute);
175 let data_mut_from_view = &mut raw_view_mut[point_idx];
176 assert_eq!(buffer.as_slice(), data_mut_from_view);
177 }
178 }
179 }
180
181 #[test]
182 fn attribute_view_from_columnar() {
183 const COUNT: usize = 64;
184 let mut test_data: HashMapBuffer = thread_rng()
185 .sample_iter::<CustomPointTypeBig, _>(DefaultPointDistribution)
186 .take(COUNT)
187 .collect();
188
189 let layout = CustomPointTypeBig::layout();
190
191 for attribute in layout.attributes() {
192 let mut buffer = vec![0; attribute.size() as usize];
193
194 for point_idx in 0..COUNT {
195 test_data.get_attribute(
196 attribute.attribute_definition(),
197 point_idx,
198 &mut buffer[..],
199 );
200
201 let raw_view = RawAttributeView::from_columnar_buffer(
205 &test_data,
206 attribute.attribute_definition(),
207 );
208 let data_from_view = &raw_view[point_idx];
209 assert_eq!(buffer.as_slice(), data_from_view);
210
211 let mut raw_view_mut = RawAttributeViewMut::from_columnar_buffer(
212 &mut test_data,
213 attribute.attribute_definition(),
214 );
215 let data_mut_from_view = &mut raw_view_mut[point_idx];
216 assert_eq!(buffer.as_slice(), data_mut_from_view);
217 }
218 }
219 }
220}