pasture_core/containers/
raw_attribute_view.rs

1use std::ops::{Index, IndexMut};
2
3use crate::layout::{PointAttributeDefinition, PointAttributeMember};
4
5use super::{ColumnarBuffer, ColumnarBufferMut, InterleavedBuffer, InterleavedBufferMut};
6
7/// A view over raw memory for a point attribute. This view can be obtained from any buffer that
8/// is either interleaved or columnar, and will be more efficient than calling `get_attribute` on
9/// the buffer
10pub 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    /// Creates a `RawAttributeView` for the given `attribute_member` from an interleaved point buffer
19    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    /// Creates a `RawAttributeView` for the given `attribute_definition` from a columnar point buffer
36    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    /// The length of this 'RawAttributeView` (i.e. the number of points within the view)
52    pub fn len(&self) -> usize {
53        self.point_data.len() / self.stride
54    }
55
56    /// Is this `RawAttributeView` empty?
57    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
73/// Like `RawAttributeView`, but for mutable data
74pub 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    /// Creates a `RawAttributeView` for the given `attribute_member` from an interleaved point buffer
83    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    /// Creates a `RawAttributeView` for the given `attribute_definition` from a columnar point buffer
100    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                // Creating the RawAttributeViewMut in the inner loop because otherwise we couldn't call `get_attribute`
167                // on `test_data` since RawAttributeViewMut mutably borrows the buffer
168
169                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                // Creating the RawAttributeViewMut in the inner loop because otherwise we couldn't call `get_attribute`
202                // on `test_data` since RawAttributeViewMut mutably borrows the buffer
203
204                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}