pasture_core/containers/
point_buffer.rs

1use anyhow::Result;
2use std::{collections::HashMap, iter::FromIterator, ops::Range};
3
4use crate::layout::{
5    PointAttributeDefinition, PointAttributeMember, PointLayout, PointType, PrimitiveType,
6};
7
8use super::{
9    buffer_views::{AttributeView, AttributeViewMut, PointView, PointViewMut},
10    AttributeViewConverting, BufferSliceColumnar, BufferSliceColumnarMut, BufferSliceInterleaved,
11    BufferSliceInterleavedMut, RawAttributeView, RawAttributeViewMut, SliceBuffer, SliceBufferMut,
12};
13
14/// Base trait for all point buffers in pasture. The only assumption this trait makes is that the
15/// underlying memory can be borrowed by the buffer. Provides point and attribute accessors by
16/// untyped value (i.e. copying into a provided `&mut [u8]`)
17pub trait BorrowedBuffer<'a> {
18    /// Returns the length of this buffer, i.e. the number of points
19    ///
20    /// # Example
21    ///
22    /// ```
23    /// use pasture_core::containers::*;
24    /// use pasture_core::layout::*;
25    ///
26    /// let buffer = VectorBuffer::new_from_layout(PointLayout::default());
27    /// assert_eq!(0, buffer.len());
28    /// ```
29    fn len(&self) -> usize;
30    /// Returns `true` if this buffer does not store any points
31    ///
32    /// # Example
33    ///
34    /// ```
35    /// use pasture_core::containers::*;
36    /// use pasture_core::layout::*;
37    ///
38    /// let buffer = VectorBuffer::new_from_layout(PointLayout::default());
39    /// assert!(buffer.is_empty());
40    /// ```
41    fn is_empty(&self) -> bool {
42        self.len() == 0
43    }
44    /// Returns the `PointLayout` of this buffer. The `PointLayout` describes the structure of a single
45    /// point at runtime.
46    ///
47    /// # Example
48    ///
49    /// ```
50    /// use pasture_core::containers::*;
51    /// use pasture_core::layout::*;
52    ///
53    /// let layout = PointLayout::from_attributes(&[attributes::POSITION_3D, attributes::INTENSITY]);
54    /// let buffer = VectorBuffer::new_from_layout(layout.clone());
55    /// assert_eq!(layout, *buffer.point_layout());
56    /// ```
57    fn point_layout(&self) -> &PointLayout;
58    /// Writes the data for the point at `index` from this buffer into `data`
59    ///
60    /// # Panics
61    ///
62    /// May panic if `index` is out of bounds.
63    /// May panic if `data.len()` does not equal `self.point_layout().size_of_point_entry()`
64    fn get_point(&self, index: usize, data: &mut [u8]);
65    /// Writes the data for the given `range` of points from this buffer into `data`
66    ///
67    /// # Panics
68    ///
69    /// May panic if `range` is out of bounds.
70    /// May panic if `data.len()` does not equal `range.len() * self.point_layout().size_of_point_entry()`
71    fn get_point_range(&self, range: Range<usize>, data: &mut [u8]);
72    /// Writes the data for the given `attribute` of the point at `index` into `data`
73    ///
74    /// # Panics
75    ///
76    /// May panic if `attribute` is not part of the `PointLayout` of this buffer. It is implementation-defined
77    /// whether data type conversions are supported (i.e. the buffer stores positions as `Vector3<f64>`, but
78    /// `get_attribute` is called with `Vector3<f32>` as the attribute data type), but generally assume that
79    /// conversions are *not* possible!
80    /// May panic if `data.len()` does not equal the size of a single value of the data type of `attribute`
81    fn get_attribute(&self, attribute: &PointAttributeDefinition, index: usize, data: &mut [u8]) {
82        let attribute_member = self
83            .point_layout()
84            .get_attribute(attribute)
85            .expect("Attribute not found in PointLayout of this buffer");
86        // Is safe because we get the `attribute_member` from this buffer's point layout
87        unsafe {
88            self.get_attribute_unchecked(attribute_member, index, data);
89        }
90    }
91    /// Writes the data for the given `attribute` of the given range of points into `data`. The attribute data will
92    /// be tightly packed in `data`, irregardless of the memory layout of this buffer. The attribute values might not
93    /// be correctly aligned, if the alignment requirement of `attribute.datatype()` is larger than the size of the
94    /// attribute. All of the built-in attributes in pasture have alignments that are less than or equal to their size,
95    /// so for built-in attributes you can assume that the attributes in `data` are correctly aligned.
96    ///
97    /// # Panics
98    ///
99    /// May panic if `attribute` is not part of the `PointLayout` of this buffer.
100    /// May panic if `point_range` is out of bounds.
101    /// May panic if `data.len()` does not equal `attribute.size() * point_range.len()`
102    fn get_attribute_range(
103        &self,
104        attribute: &PointAttributeDefinition,
105        point_range: Range<usize>,
106        data: &mut [u8],
107    ) {
108        let attribute_member = self
109            .point_layout()
110            .get_attribute(attribute)
111            .expect("Attribute not found in PointLayout of this buffer");
112        let attribute_size = attribute_member.size() as usize;
113        let first_point = point_range.start;
114        for point_index in point_range {
115            let zero_based_index = point_index - first_point;
116            let data_slice = &mut data
117                [(zero_based_index * attribute_size)..((zero_based_index + 1) * attribute_size)];
118            // Safe because we checked the attribute and size of the buffer slice
119            unsafe {
120                self.get_attribute_unchecked(attribute_member, point_index, data_slice);
121            }
122        }
123    }
124
125    /// Like `get_attribute`, but performs no check whether the attribute actually is part of this buffers `PointLayout`
126    /// or not. Because of this, this function accepts a `PointAttributeMember` instead of a `PointAttributeDefinition`,
127    /// and this `PointAttributeMember` must come from the `PointLayout` of this buffer! The benefit over `get_attribute`
128    /// is that this function skips the include checks and thus will be faster if you repeatedly want to get data for a
129    /// single attribute
130    ///
131    /// # Safety
132    ///
133    /// Requires `attribute_member` to be a part of this buffer's `PointLayout`
134    unsafe fn get_attribute_unchecked(
135        &self,
136        attribute_member: &PointAttributeMember,
137        index: usize,
138        data: &mut [u8],
139    );
140
141    /// Try to get a reference to `self` as an `InterleavedBuffer`. Returns `None` if `self` does not
142    /// implement `InterleavedBuffer`
143    fn as_interleaved(&self) -> Option<&dyn InterleavedBuffer<'a>> {
144        None
145    }
146
147    /// Try to get a reference to `self` as a `ColumnarBuffer`. Returns `None` if `self` does not
148    /// implement `ColumnarBuffer`
149    fn as_columnar(&self) -> Option<&dyn ColumnarBuffer<'a>> {
150        None
151    }
152}
153
154/// Trait for a point buffer that mutably borrows its memory. Compared to [`BorrowedBuffer`], buffers that implement
155/// this trait support the following additional capabilities:
156/// - Manipulating point and attribute data in-place through `set_point` and `set_attribute`
157/// - Shuffling data through `swap`
158/// - Mutable views to points and attributes through `view_mut` and `view_attribute_mut`
159pub trait BorrowedMutBuffer<'a>: BorrowedBuffer<'a> {
160    /// Sets the data for the point at the given `index`
161    ///
162    /// # Safety
163    ///
164    /// Requires that `point_data` contains memory for a single point with the same `PointLayout` as `self.point_layout()`.
165    /// This property is not enforced at runtime, so this function is very unsafe!
166    ///
167    /// # Panics
168    ///
169    /// May panic if `index` is out of bounds.<br>
170    /// May panic if `point_data.len()` does not equal `self.point_layout().size_of_point_record()`
171    unsafe fn set_point(&mut self, index: usize, point_data: &[u8]);
172    /// Sets the data for the given range of points. This function will generally be more efficient than calling [`set_point`]
173    /// multiple times, as [`set_point`] performs size and index checks on every call, whereas this function can perform them
174    /// only once. Assumes that the `point_data` is tightly packed, i.e. stored in an interleaved format with point alignment
175    /// of `1`.
176    ///
177    /// # Safety
178    ///
179    /// `point_data` must contain correctly initialized data for `point_range.len()` points in interleaved layout. The data
180    /// must be tightly packed (i.e. no padding bytes between adjacent points).
181    ///
182    /// # Panics
183    ///
184    /// May panic if `point_range` is out of bounds.<br>
185    /// May panic if `point_data.len()` does not equal `point_range.len() * self.point_layout().size_of_point_record()`
186    unsafe fn set_point_range(&mut self, point_range: Range<usize>, point_data: &[u8]);
187    /// Sets the data for the given `attribute` of the point at `index`
188    ///
189    /// # Safety
190    ///
191    /// Requires that `attribute_data` contains memory for a single value of the data type of `attribute`. This property
192    /// is not enforced at runtime, so this function is very unsafe!
193    ///
194    /// # Panics
195    ///
196    /// May panic if `attribute` is not part of the `PointLayout` of this buffer.<br>
197    /// May panic if `index` is out of bounds.<br>
198    /// May panic if `attribute_data.len()` does not match the size of the data type of `attribute`
199    unsafe fn set_attribute(
200        &mut self,
201        attribute: &PointAttributeDefinition,
202        index: usize,
203        attribute_data: &[u8],
204    );
205    /// Sets the data for the given `attribute` for all points in `point_range`. This function will generally be more efficient
206    /// than calling [`set_attribute`] multiple times, as [`set_attribute`] has to perform type and bounds checks on each call.
207    ///
208    /// # Safety
209    ///
210    /// Requires that `attribute_data` contains data for `point_range.len()` attribute values. The data must be tightly packed,
211    /// i.e. there must be no padding bytes between adjacent values.
212    ///
213    /// # Panics
214    ///
215    /// May panic if `attribute` is not part of the `PointLayout` of this buffer.<br>
216    /// May panic if `point_range` is out of bounds.<br>
217    /// May panic if `attribute_data.len()` does not equal `point_range.len() * attribute.size()`
218    unsafe fn set_attribute_range(
219        &mut self,
220        attribute: &PointAttributeDefinition,
221        point_range: Range<usize>,
222        attribute_data: &[u8],
223    );
224    /// Swaps the two points at `from_index` and `to_index`. Implementations should allow the case where `from_index == to_index`
225    ///
226    /// # Panics
227    ///
228    /// May panic if any of `from_index` or `to_index` is out of bounds
229    fn swap(&mut self, from_index: usize, to_index: usize);
230
231    /// Try to get a mutable reference to `self` as an `InterleavedBufferMut`. Returns `None` if `self` does not
232    /// implement `InterleavedBufferMut`
233    fn as_interleaved_mut(&mut self) -> Option<&mut dyn InterleavedBufferMut<'a>> {
234        None
235    }
236
237    /// Try to get a mutable reference to `self` as a `ColumnarBufferMut`. Returns `None` if `self` does not
238    /// implement `ColumnarBufferMut`
239    fn as_columnar_mut(&mut self) -> Option<&mut dyn ColumnarBufferMut<'a>> {
240        None
241    }
242}
243
244/// Trait for point buffers that own their memory. Compared to [`BorrowedMutBuffer`], buffers that implement
245/// this trait support the following additional capabilities:
246/// - Pushing point data into the buffer using `push_points`
247/// - Appending other buffers to the end of this buffer using `append`, `append_interleaved`, and `append_columnar`
248/// - Resizing and clearing the contents of the buffer using `resize` and `clear`
249pub trait OwningBuffer<'a>: BorrowedMutBuffer<'a> {
250    /// Push the raw memory for a range of points into this buffer. Works similar to `Vec::push`
251    ///
252    /// # Safety
253    ///
254    /// `point_bytes` must contain the raw memory for a whole number of points in the `PointLayout` of this buffer.
255    /// This property is not checked at runtime, so this function is very unsafe!
256    ///
257    /// # Panics
258    ///
259    /// May panic if `point_bytes.len()` is not a multiple of `self.point_layout().size_of_point_record()`
260    unsafe fn push_points(&mut self, point_bytes: &[u8]);
261    /// Resize this buffer to contain exactly `count` points. If `count` is less than `self.len()`, point data
262    /// is removed, if `count` is greater than `self.len()` new points are default-constructed (i.e. zero-initialized).
263    fn resize(&mut self, count: usize);
264    /// Clears the contents of this buffer, removing all point data and setting the length to `0`
265    fn clear(&mut self);
266}
267
268/// Extension trait for `BorrowedBuffer` that allows obtaining strongly-typed views over points and
269/// attributes.
270///
271/// # Notes
272///
273/// The `view...` methods on this type are implemented in an extension trait and not the base trait
274/// `BorrowedBuffer` so that we retain the option to create trait objects for types implementing
275/// `BorrowedBuffer`, while also allowing both static types `T: BorrowedBuffer` and dynamic trait object
276/// types (`dyn BorrowedBuffer`) to be used for views. I.e. this makes the following code possible:
277///
278/// ```ignore
279/// let layout = ...;
280/// let buffer = VectorBuffer::new_from_layout(layout);
281/// let view_from_sized_type = buffer.view::<Vector3<f64>>(&POSITION_3D);
282///
283/// // In previous pasture version, this code was not possible because views required sized types:
284/// let buffer_trait_object: &dyn InterleavedBuffer = buffer.as_interleaved().unwrap();
285/// let view_from_trait_object = buffer_trait_object.view::<Vector3<f64>>(&POSITION_3D);
286/// ```
287pub trait BorrowedBufferExt<'a>: BorrowedBuffer<'a> {
288    /// Get a strongly typed view of the point data of this buffer
289    ///
290    /// # Panics
291    ///
292    /// Panics if `T::layout()` does not match the `PointLayout` of this buffer
293    fn view<'b, T: PointType>(&'b self) -> PointView<'a, 'b, Self, T>
294    where
295        'a: 'b,
296    {
297        PointView::new(self)
298    }
299
300    /// Gets a strongly typed view of the `attribute` of all points in this buffer
301    ///
302    /// # Panics
303    ///
304    /// If `attribute` is not part of the `PointLayout` of this buffer.
305    /// If `T::data_type()` does not match the data type of the attribute within the buffer
306    fn view_attribute<'b, T: PrimitiveType>(
307        &'b self,
308        attribute: &PointAttributeDefinition,
309    ) -> AttributeView<'a, 'b, Self, T>
310    where
311        'a: 'b,
312    {
313        AttributeView::new(self, attribute)
314    }
315
316    /// Like `view_attribute`, but allows `T::data_type()` to be different from the data type of  
317    /// the `attribute` within this buffer.
318    ///
319    /// # Panics
320    ///
321    /// If `T::data_type()` does not match the data type of `attribute`
322    fn view_attribute_with_conversion<'b, T: PrimitiveType>(
323        &'b self,
324        attribute: &PointAttributeDefinition,
325    ) -> Result<AttributeViewConverting<'a, 'b, Self, T>>
326    where
327        'a: 'b,
328    {
329        AttributeViewConverting::new(self, attribute)
330    }
331}
332
333impl<'a, T: BorrowedBuffer<'a>> BorrowedBufferExt<'a> for T {}
334impl<'a> BorrowedBufferExt<'a> for dyn BorrowedBuffer<'a> + 'a {}
335impl<'a> BorrowedBufferExt<'a> for dyn BorrowedMutBuffer<'a> + 'a {}
336// TODO Make OwningBuffer object safe, e.g. by moving the append functions to another extension trait
337// Open question how to deal with append_interleaved / append_columnar
338// impl<'a> BorrowedBufferExt<'a> for dyn OwningBuffer<'a> + 'a {}
339impl<'a> BorrowedBufferExt<'a> for dyn InterleavedBuffer<'a> + 'a {}
340impl<'a> BorrowedBufferExt<'a> for dyn InterleavedBufferMut<'a> + 'a {}
341impl<'a> BorrowedBufferExt<'a> for dyn ColumnarBuffer<'a> + 'a {}
342impl<'a> BorrowedBufferExt<'a> for dyn ColumnarBufferMut<'a> + 'a {}
343
344/// Extension trait for `BorrowedMutBuffer` that allows obtaining strongly-typed views over points and
345/// attributes.
346pub trait BorrowedMutBufferExt<'a>: BorrowedMutBuffer<'a> {
347    /// Get a strongly typed view of the point data of this buffer. This view allows mutating the point data!
348    ///
349    /// # Panics
350    ///
351    /// If `T::point_layout()` does not match `self.point_layout()`
352    fn view_mut<'b, T: PointType>(&'b mut self) -> PointViewMut<'a, 'b, Self, T>
353    where
354        'a: 'b,
355    {
356        PointViewMut::new(self)
357    }
358
359    /// Get a strongly typed view of the `attribute` of all points in this buffer. This view allows mutating
360    /// the attribute data!
361    ///
362    /// # Panics
363    ///
364    /// If `attribute` is not part of the `PointLayout` of this buffer.<br>
365    /// If `T::data_type()` does not match `attribute.datatype()`
366    fn view_attribute_mut<'b, T: PrimitiveType>(
367        &'b mut self,
368        attribute: &PointAttributeDefinition,
369    ) -> AttributeViewMut<'a, 'b, Self, T>
370    where
371        'a: 'b,
372    {
373        AttributeViewMut::new(self, attribute)
374    }
375
376    /// Apply a transformation function to the given `attribute` of all points within this buffer. This function is
377    /// helpful if you want to modify a single attribute of a buffer in-place and works for buffers of all memory
378    /// layouts. For columnar buffers, prefer using `get_attribute_range_mut` to modify attribute data in-place.
379    ///
380    /// This function does not support attribute type conversion, so the type `T` must match the `PointAttributeDataType`
381    /// of `attribute`!
382    ///
383    /// The conversion function takes the current value of the attribute as a strongly typed `T` and returns the new value
384    /// for the attribute. It also takes the index of the point within the buffer, so that `func` can access additional
385    /// data.
386    ///
387    /// # Panics
388    ///
389    /// If `attribute` is not part of the `PointLayout` of this buffer.<br>
390    /// If `T::data_type()` does not equal `attribute.datatype()`
391    fn transform_attribute<'b, T: PrimitiveType, F: Fn(usize, T) -> T>(
392        &'b mut self,
393        attribute: &PointAttributeDefinition,
394        func: F,
395    ) where
396        'a: 'b,
397    {
398        let num_points = self.len();
399        let mut attribute_view = self.view_attribute_mut(attribute);
400        for point_index in 0..num_points {
401            let attribute_value = attribute_view.at(point_index);
402            attribute_view.set_at(point_index, func(point_index, attribute_value));
403        }
404    }
405}
406
407impl<'a, T: BorrowedMutBuffer<'a>> BorrowedMutBufferExt<'a> for T {}
408impl<'a> BorrowedMutBufferExt<'a> for dyn BorrowedMutBuffer<'a> + 'a {}
409// TODO impl for owning buffer
410impl<'a> BorrowedMutBufferExt<'a> for dyn InterleavedBufferMut<'a> + 'a {}
411impl<'a> BorrowedMutBufferExt<'a> for dyn ColumnarBufferMut<'a> + 'a {}
412
413pub trait OwningBufferExt<'a>: OwningBuffer<'a> {
414    /// Appends data from the given buffer to the end of this buffer
415    ///
416    /// # Panics
417    ///
418    /// If `self.point_layout()` does not equal `other.point_layout()`
419    fn append<'b, B: BorrowedBuffer<'b> + ?Sized>(&mut self, other: &'_ B) {
420        assert_eq!(self.point_layout(), other.point_layout());
421
422        // There are a bunch of ways we can append data, depending on the memory layout. In general, if
423        // the memory layout of this buffer and other match, we can get by with only a few copy operations
424        // (one for interleaved layout, one per attribute for columnar layout)
425        // If we know the specific layout of one buffer but not the other, we can get by without any allocations
426        // If both buffers are neither interleaved nor columnar, we have to resort to the most general, but
427        // slowest methods
428
429        if let (Some(_), Some(other_interleaved)) =
430            (self.as_interleaved_mut(), other.as_interleaved())
431        {
432            // The happy case where append is equal to Vec::append
433            // Safe because both point layouts are equal
434            unsafe {
435                self.push_points(other_interleaved.get_point_range_ref(0..other.len()));
436            }
437            return;
438        }
439
440        let old_self_len = self.len();
441        let new_self_len = old_self_len + other.len();
442        self.resize(new_self_len);
443
444        if let Some(self_interleaved) = self.as_interleaved_mut() {
445            let point_size = self_interleaved.point_layout().size_of_point_entry() as usize;
446            let new_points = self_interleaved.get_point_range_mut(old_self_len..new_self_len);
447            for (index, new_point) in new_points.chunks_exact_mut(point_size).enumerate() {
448                other.get_point(index, new_point);
449            }
450        } else if let Some(self_columnar) = self.as_columnar_mut() {
451            if let Some(other_columnar) = other.as_columnar() {
452                for attribute in other.point_layout().attributes() {
453                    // Safe because point layouts are equal
454                    unsafe {
455                        self_columnar.set_attribute_range(
456                            attribute.attribute_definition(),
457                            old_self_len..new_self_len,
458                            other_columnar.get_attribute_range_ref(
459                                attribute.attribute_definition(),
460                                0..other_columnar.len(),
461                            ),
462                        );
463                    }
464                }
465            } else {
466                for attribute in other.point_layout().attributes() {
467                    let new_attributes = self_columnar.get_attribute_range_mut(
468                        attribute.attribute_definition(),
469                        old_self_len..new_self_len,
470                    );
471                    for (index, new_attribute) in new_attributes
472                        .chunks_exact_mut(attribute.size() as usize)
473                        .enumerate()
474                    {
475                        other.get_attribute(attribute.attribute_definition(), index, new_attribute);
476                    }
477                }
478            }
479        } else {
480            let mut point_buffer = vec![0; self.point_layout().size_of_point_entry() as usize];
481            for point_index in 0..other.len() {
482                other.get_point(point_index, &mut point_buffer);
483                // Is safe because we assert that the point layouts of self and other match
484                unsafe {
485                    self.set_point(old_self_len + point_index, &point_buffer);
486                }
487            }
488        }
489    }
490}
491
492impl<'a, T: OwningBuffer<'a>> OwningBufferExt<'a> for T {}
493impl<'a> OwningBufferExt<'a> for dyn OwningBuffer<'a> + 'a {}
494
495/// Trait for all buffers that can be default-constructed from a given `PointLayout`. This trait is helpful for generic
496/// code that needs to construct an generic buffer type
497pub trait MakeBufferFromLayout<'a>: BorrowedBuffer<'a> + Sized {
498    /// Creates a new empty buffer from the given `PointLayout`
499    fn new_from_layout(point_layout: PointLayout) -> Self;
500}
501
502/// Trait for point buffers that store their point data in interleaved memory layout. This allows accessing
503/// point data by reference
504pub trait InterleavedBuffer<'a>: BorrowedBuffer<'a> {
505    /// Get an immutable slice of the point memory of the point at `index`
506    ///
507    /// # Lifetimes
508    ///
509    /// Has a more relaxed lifetime bound than the underlying buffer, since we should be able to borrow point
510    /// data for a lifetime `'b` that is potentially shorter than the lifetime `'a` of the `BorrowedBuffer`
511    ///
512    /// # Panics
513    ///
514    /// Should panic if `index` is out of bounds
515    fn get_point_ref<'b>(&'b self, index: usize) -> &'b [u8]
516    where
517        'a: 'b;
518    /// Get an immutable slice of the memory for the given `range` of points. This is the range-version of [`get_point_ref`],
519    /// see its documentation for more details
520    ///
521    /// # Panics
522    ///
523    /// If `range` is out of bounds
524    fn get_point_range_ref<'b>(&'b self, range: Range<usize>) -> &'b [u8]
525    where
526        'a: 'b;
527
528    /// Get a raw view over the given `attribute` from this point buffer. Unlike the typed view that `view_attribute`
529    /// returns, this view dereferences to byte slices, but it is potentially more efficient to use than calling
530    /// `get_attribute` repeatedly
531    fn view_raw_attribute<'b>(&'b self, attribute: &PointAttributeMember) -> RawAttributeView<'b>
532    where
533        'a: 'b,
534    {
535        RawAttributeView::from_interleaved_buffer(self, attribute)
536    }
537}
538
539/// Trait for buffers that store point data in interleaved memory layout and also borrow their memory mutably. Compared
540/// to [`InterleavedBuffer`], this allows accessing point data by mutable reference!
541pub trait InterleavedBufferMut<'a>: InterleavedBuffer<'a> + BorrowedMutBuffer<'a> {
542    /// Get a mutable slice of the point memory of the point at `index`. This is the mutable version of [`InterleavedBuffer::get_point_ref`]
543    ///
544    /// # Panics
545    ///
546    /// Should panic if `index` is out of bounds
547    fn get_point_mut<'b>(&'b mut self, index: usize) -> &'b mut [u8]
548    where
549        'a: 'b;
550    /// Get a mutable slice of the memory for the given `range` of points. This is the mutable version of [`InterleavedBuffer::get_point_range_ref`]
551    ///
552    /// # Panics
553    ///
554    /// Should panic if `index` is out of bounds
555    fn get_point_range_mut<'b>(&'b mut self, range: Range<usize>) -> &'b mut [u8]
556    where
557        'a: 'b;
558
559    /// Like `view_raw_attribute`, but returns mutable byte slices of the attribute data
560    fn view_raw_attribute_mut<'b>(
561        &'b mut self,
562        attribute: &PointAttributeMember,
563    ) -> RawAttributeViewMut<'b>
564    where
565        'a: 'b,
566    {
567        RawAttributeViewMut::from_interleaved_buffer(self, attribute)
568    }
569}
570
571/// Trait for point buffers that store their point data in columnar memory layout. This allows accessing point attributes
572/// by reference
573pub trait ColumnarBuffer<'a>: BorrowedBuffer<'a> {
574    /// Get an immutable slice to the memory of the given `attribute` for the point at `index`. See [`InterleavedBuffer::get_point_ref`] for an explanation of the lifetime bounds.
575    ///
576    /// # Panics
577    ///
578    /// Should panic if `attribute` is not part of the `PointLayout` of this buffer.<br>
579    /// Should panic if `index` is out of bounds.
580    fn get_attribute_ref<'b>(
581        &'b self,
582        attribute: &PointAttributeDefinition,
583        index: usize,
584    ) -> &'b [u8]
585    where
586        'a: 'b;
587    /// Get an immutable slice to the memory for the `attribute` of the given `range` of points
588    ///
589    /// # Panics
590    ///
591    /// Should panic if `attribute` is not part of the `PointLayout` of this buffer.<br>
592    /// Should panic if `range` is out of bounds.
593    fn get_attribute_range_ref<'b>(
594        &'b self,
595        attribute: &PointAttributeDefinition,
596        range: Range<usize>,
597    ) -> &'b [u8]
598    where
599        'a: 'b;
600
601    /// Get a raw view over the given `attribute` from this point buffer. Unlike the typed view that `view_attribute`
602    /// returns, this view dereferences to byte slices, but it is potentially more efficient to use than calling
603    /// `get_attribute` repeatedly
604    fn view_raw_attribute<'b>(&'b self, attribute: &PointAttributeMember) -> RawAttributeView<'b>
605    where
606        'a: 'b,
607    {
608        RawAttributeView::from_columnar_buffer(self, attribute.attribute_definition())
609    }
610}
611
612/// Trait for buffers that store point data in columnar memory layout and also borrow their memory mutably. Compared
613/// to [`ColumnarBuffer`], this allows accessing point attributes by mutable reference!
614pub trait ColumnarBufferMut<'a>: ColumnarBuffer<'a> + BorrowedMutBuffer<'a> {
615    /// Get a mutable slice to the memory of the given `attribute` for the point at `index`. This is the mutable
616    /// version of [`ColumnarBuffer::get_attribute_ref`]
617    ///
618    /// # Panics
619    ///
620    /// Should panic if `attribute` is not part of the `PointLayout` of this buffer.<br>
621    /// Should panic if `index` is out of bounds.
622    fn get_attribute_mut<'b>(
623        &'b mut self,
624        attribute: &PointAttributeDefinition,
625        index: usize,
626    ) -> &'b mut [u8]
627    where
628        'a: 'b;
629    /// Get a mutable slice to the memory for the `attribute` of the given `range` of points. This is the mutable
630    /// version of [`ColumnarBuffer::get_attribute_range_ref`]
631    ///
632    /// # Panics
633    ///
634    /// Should panic if `attribute` is not part of the `PointLayout` of this buffer.<br>
635    /// Should panic if `range` is out of bounds.
636    fn get_attribute_range_mut<'b>(
637        &'b mut self,
638        attribute: &PointAttributeDefinition,
639        range: Range<usize>,
640    ) -> &'b mut [u8]
641    where
642        'a: 'b;
643
644    /// Like `view_raw_attribute`, but returns mutable byte slices of the attribute data
645    fn view_raw_attribute_mut<'b>(
646        &'b mut self,
647        attribute: &PointAttributeMember,
648    ) -> RawAttributeViewMut<'b>
649    where
650        'a: 'b,
651    {
652        RawAttributeViewMut::from_columnar_buffer(self, attribute.attribute_definition())
653    }
654}
655
656/// A point buffer that uses a `Vec<u8>` as its underlying storage. It stores point data in interleaved memory
657/// layout and generally behaves like an untyped vector.
658#[derive(Debug, Clone, PartialEq, Eq, Hash)]
659pub struct VectorBuffer {
660    storage: Vec<u8>,
661    point_layout: PointLayout,
662    length: usize,
663}
664
665impl VectorBuffer {
666    /// Creates a new `VectorBuffer` with the given `capacity` and `point_layout`. This preallocates enough memory
667    /// to store at least `capacity` points
668    pub fn with_capacity(capacity: usize, point_layout: PointLayout) -> Self {
669        let required_bytes = capacity * point_layout.size_of_point_entry() as usize;
670        Self {
671            point_layout,
672            storage: Vec::with_capacity(required_bytes),
673            length: 0,
674        }
675    }
676
677    fn get_byte_range_of_point(&self, point_index: usize) -> Range<usize> {
678        let size_of_point = self.point_layout.size_of_point_entry() as usize;
679        (point_index * size_of_point)..((point_index + 1) * size_of_point)
680    }
681
682    fn get_byte_range_of_points(&self, points_range: Range<usize>) -> Range<usize> {
683        let size_of_point = self.point_layout.size_of_point_entry() as usize;
684        (points_range.start * size_of_point)..(points_range.end * size_of_point)
685    }
686
687    fn get_byte_range_of_attribute(
688        &self,
689        point_index: usize,
690        attribute: &PointAttributeMember,
691    ) -> Range<usize> {
692        let start_byte = (point_index * self.point_layout.size_of_point_entry() as usize)
693            + attribute.offset() as usize;
694        let end_byte = start_byte + attribute.size() as usize;
695        start_byte..end_byte
696    }
697}
698
699impl<'a> MakeBufferFromLayout<'a> for VectorBuffer {
700    fn new_from_layout(point_layout: PointLayout) -> Self {
701        Self {
702            point_layout,
703            storage: Default::default(),
704            length: 0,
705        }
706    }
707}
708
709impl<'a> BorrowedBuffer<'a> for VectorBuffer
710where
711    VectorBuffer: 'a,
712{
713    fn len(&self) -> usize {
714        self.length
715    }
716
717    fn point_layout(&self) -> &PointLayout {
718        &self.point_layout
719    }
720
721    fn get_point(&self, index: usize, data: &mut [u8]) {
722        let point_ref = self.get_point_ref(index);
723        data.copy_from_slice(point_ref);
724    }
725
726    fn get_point_range(&self, range: Range<usize>, data: &mut [u8]) {
727        let points_ref = self.get_point_range_ref(range);
728        data.copy_from_slice(points_ref);
729    }
730
731    unsafe fn get_attribute_unchecked(
732        &self,
733        attribute_member: &PointAttributeMember,
734        index: usize,
735        data: &mut [u8],
736    ) {
737        let byte_range = self.get_byte_range_of_attribute(index, attribute_member);
738        data.copy_from_slice(&self.storage[byte_range]);
739    }
740
741    fn as_interleaved(&self) -> Option<&dyn InterleavedBuffer<'a>> {
742        Some(self)
743    }
744}
745
746impl<'a> BorrowedMutBuffer<'a> for VectorBuffer
747where
748    VectorBuffer: 'a,
749{
750    unsafe fn set_point(&mut self, index: usize, point_data: &[u8]) {
751        let point_bytes = self.get_point_mut(index);
752        point_bytes.copy_from_slice(point_data);
753    }
754
755    unsafe fn set_attribute(
756        &mut self,
757        attribute: &PointAttributeDefinition,
758        index: usize,
759        attribute_data: &[u8],
760    ) {
761        let attribute_member = self
762            .point_layout
763            .get_attribute(attribute)
764            .expect("Attribute not found in PointLayout of this buffer");
765        let attribute_byte_range = self.get_byte_range_of_attribute(index, attribute_member);
766        let attribute_bytes = &mut self.storage[attribute_byte_range];
767        attribute_bytes.copy_from_slice(attribute_data);
768    }
769
770    fn swap(&mut self, from_index: usize, to_index: usize) {
771        assert!(from_index < self.len());
772        assert!(to_index < self.len());
773        if from_index == to_index {
774            return;
775        }
776        let size_of_point = self.point_layout.size_of_point_entry() as usize;
777        // Is safe as long as 'from_index' and 'to_index' are not out of bounds, which is asserted
778        unsafe {
779            let from_ptr = self.storage.as_mut_ptr().add(from_index * size_of_point);
780            let to_ptr = self.storage.as_mut_ptr().add(to_index * size_of_point);
781            std::ptr::swap_nonoverlapping(from_ptr, to_ptr, size_of_point);
782        }
783    }
784
785    unsafe fn set_point_range(&mut self, point_range: Range<usize>, point_data: &[u8]) {
786        let point_bytes = self.get_point_range_mut(point_range);
787        point_bytes.copy_from_slice(point_data);
788    }
789
790    unsafe fn set_attribute_range(
791        &mut self,
792        attribute: &PointAttributeDefinition,
793        point_range: Range<usize>,
794        attribute_data: &[u8],
795    ) {
796        let attribute_member = self
797            .point_layout
798            .get_attribute(attribute)
799            .expect("Attribute not found in PointLayout of this buffer");
800        let attribute_size = attribute_member.size() as usize;
801        let first_point = point_range.start;
802        for point_index in point_range {
803            let zero_based_index = point_index - first_point;
804            let src_slice = &attribute_data
805                [(zero_based_index * attribute_size)..((zero_based_index + 1) * attribute_size)];
806            let attribute_byte_range =
807                self.get_byte_range_of_attribute(point_index, attribute_member);
808            let attribute_bytes = &mut self.storage[attribute_byte_range];
809            attribute_bytes.copy_from_slice(src_slice);
810        }
811    }
812
813    fn as_interleaved_mut(&mut self) -> Option<&mut dyn InterleavedBufferMut<'a>> {
814        Some(self)
815    }
816}
817
818impl<'a> OwningBuffer<'a> for VectorBuffer
819where
820    VectorBuffer: 'a,
821{
822    unsafe fn push_points(&mut self, point_bytes: &[u8]) {
823        let size_of_point = self.point_layout.size_of_point_entry() as usize;
824        if size_of_point == 0 {
825            assert_eq!(0, point_bytes.len());
826        } else {
827            assert_eq!(point_bytes.len() % size_of_point, 0);
828            self.storage.extend_from_slice(point_bytes);
829            self.length += point_bytes.len() / size_of_point;
830        }
831    }
832
833    fn resize(&mut self, count: usize) {
834        let size_of_point = self.point_layout.size_of_point_entry() as usize;
835        self.storage.resize(count * size_of_point, 0);
836        self.length = count;
837    }
838
839    fn clear(&mut self) {
840        self.storage.clear();
841        self.length = 0;
842    }
843}
844
845impl<'a> InterleavedBuffer<'a> for VectorBuffer
846where
847    VectorBuffer: 'a,
848{
849    fn get_point_ref<'b>(&'b self, index: usize) -> &'b [u8]
850    where
851        'a: 'b,
852    {
853        &self.storage[self.get_byte_range_of_point(index)]
854    }
855
856    fn get_point_range_ref<'b>(&'b self, range: Range<usize>) -> &'b [u8]
857    where
858        'a: 'b,
859    {
860        &self.storage[self.get_byte_range_of_points(range)]
861    }
862}
863
864impl<'a> InterleavedBufferMut<'a> for VectorBuffer
865where
866    VectorBuffer: 'a,
867{
868    fn get_point_mut<'b>(&'b mut self, index: usize) -> &'b mut [u8]
869    where
870        'a: 'b,
871    {
872        let byte_range = self.get_byte_range_of_point(index);
873        &mut self.storage[byte_range]
874    }
875
876    fn get_point_range_mut<'b>(&'b mut self, range: Range<usize>) -> &'b mut [u8]
877    where
878        'a: 'b,
879    {
880        let byte_range = self.get_byte_range_of_points(range);
881        &mut self.storage[byte_range]
882    }
883}
884
885impl<'a> SliceBuffer<'a> for VectorBuffer
886where
887    Self: 'a,
888{
889    type SliceType = BufferSliceInterleaved<'a, Self>;
890
891    fn slice(&'a self, range: Range<usize>) -> Self::SliceType {
892        BufferSliceInterleaved::new(self, range)
893    }
894}
895
896impl<'a> SliceBufferMut<'a> for VectorBuffer
897where
898    Self: 'a,
899{
900    type SliceTypeMut = BufferSliceInterleavedMut<'a, Self>;
901
902    fn slice_mut(&'a mut self, range: Range<usize>) -> Self::SliceTypeMut {
903        BufferSliceInterleavedMut::new(self, range)
904    }
905}
906
907impl<T: PointType> FromIterator<T> for VectorBuffer {
908    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
909        let point_layout = T::layout();
910        let iter = iter.into_iter();
911        let (_, maybe_known_length) = iter.size_hint();
912        if let Some(known_length) = maybe_known_length {
913            let num_bytes = known_length * point_layout.size_of_point_entry() as usize;
914            let storage = vec![0; num_bytes];
915            let mut buffer = Self {
916                point_layout,
917                storage,
918                length: known_length,
919            };
920            // Overwrite the preallocated memory of the buffer with the points in the iterator:
921            iter.enumerate().for_each(|(index, point)| {
922                let point_bytes = bytemuck::bytes_of(&point);
923                // Safe because we created `buffer` from `T::layout()`, so we know the layouts match
924                unsafe {
925                    buffer.set_point(index, point_bytes);
926                }
927            });
928            buffer
929        } else {
930            let mut buffer = Self {
931                point_layout,
932                storage: Default::default(),
933                length: 0,
934            };
935            iter.for_each(|point| {
936                let point_bytes = bytemuck::bytes_of(&point);
937                // Safe because we know that `buffer` has the same layout as `T`
938                unsafe {
939                    buffer.push_points(point_bytes);
940                }
941            });
942            buffer
943        }
944    }
945}
946
947/// Helper struct to push point data into a `HashMapBuffer` attribute by attribute. This allows constructing a point buffer
948/// from multiple ranges of attribute data, since regular point buffers do not allow pushing just a single attribute into
949/// the buffer, as buffers always have to store complete points (even with columnar memory layout)
950pub struct HashMapBufferAttributePusher<'a> {
951    attributes_storage: HashMap<PointAttributeDefinition, Vec<u8>>,
952    num_new_points: Option<usize>,
953    buffer: &'a mut HashMapBuffer,
954}
955
956impl<'a> HashMapBufferAttributePusher<'a> {
957    pub(crate) fn new(buffer: &'a mut HashMapBuffer) -> Self {
958        let attributes_storage = buffer
959            .point_layout()
960            .attributes()
961            .map(|attribute| (attribute.attribute_definition().clone(), vec![]))
962            .collect();
963        Self {
964            attributes_storage,
965            num_new_points: None,
966            buffer,
967        }
968    }
969
970    /// Push a range of values for the given `attribute` into the underlying buffer. The first range of values that
971    /// is pushed in this way determines the expected number of points that will be added to the buffer. Consecutive
972    /// calls to `push_attribute_range` will assert that `data.len()` matches the expected count.
973    ///
974    /// # Panics
975    ///
976    /// If `attribute` is not part of the `PointLayout` of the underlying buffer.<br>
977    /// If `T::data_type()` does not match `attribute.datatype()`.<br>
978    /// If this is not the first call to `push_attribute_range`, and `data.len()` does not match the length of the
979    /// data that was passed to the first invocation of `push_attribute_range`
980    pub fn push_attribute_range<T: PrimitiveType>(
981        &mut self,
982        attribute: &PointAttributeDefinition,
983        data: &[T],
984    ) {
985        assert_eq!(T::data_type(), attribute.datatype());
986        let storage = self
987            .attributes_storage
988            .get_mut(attribute)
989            .expect("Attribute not found in PointLayout of this buffer");
990        if let Some(point_count) = self.num_new_points {
991            assert_eq!(point_count, data.len());
992        } else {
993            self.num_new_points = Some(data.len());
994        }
995        storage.extend_from_slice(bytemuck::cast_slice(data));
996    }
997
998    /// Commit all pushed data into the underlying buffer. This function checks that there is the correct amount
999    /// of data for all expected attributes in the `PointLayout` of the underlying buffer and will panic otherwise
1000    ///
1001    /// # Panics
1002    ///
1003    /// If there is missing data for at least one of the attributes in the `PointLayout` of the underlying buffer,
1004    /// i.e. if `push_attribute_range` was not called for at least one of these attributes.
1005    pub fn done(self) {
1006        let num_new_points = self.num_new_points.unwrap_or(0);
1007        if num_new_points == 0 {
1008            return;
1009        }
1010
1011        // Check that all attributes are complete! We don't have to check the exact size of the vectors,
1012        // as this is checked in `push_attribute_range`, it is sufficient to verify that no vector is empty
1013        assert!(self
1014            .attributes_storage
1015            .values()
1016            .all(|vector| !vector.is_empty()));
1017
1018        for (attribute, mut data) in self.attributes_storage {
1019            // Can safely unwrap, because self.attributes_storage was initialized from the `PointLayout` of the buffer!
1020            let buffer_storage = self.buffer.attributes_storage.get_mut(&attribute).unwrap();
1021            buffer_storage.append(&mut data);
1022        }
1023
1024        self.buffer.length += num_new_points;
1025    }
1026}
1027
1028/// A point buffer that stores point data in columnar memory layout, using a `HashMap<PointAttributeDefinition, Vec<u8>>` as
1029/// its underlying storage
1030#[derive(Debug, Clone, PartialEq, Eq)]
1031pub struct HashMapBuffer {
1032    attributes_storage: HashMap<PointAttributeDefinition, Vec<u8>>,
1033    point_layout: PointLayout,
1034    length: usize,
1035}
1036
1037impl HashMapBuffer {
1038    /// Creates a new `HashMapBuffer` with the given `capacity` and `point_layout`. It preallocates enough memory to store
1039    /// at least `capacity` points
1040    pub fn with_capacity(capacity: usize, point_layout: PointLayout) -> Self {
1041        let attributes_storage = point_layout
1042            .attributes()
1043            .map(|attribute| {
1044                let bytes_for_attribute = capacity * attribute.size() as usize;
1045                (
1046                    attribute.attribute_definition().clone(),
1047                    Vec::with_capacity(bytes_for_attribute),
1048                )
1049            })
1050            .collect();
1051        Self {
1052            attributes_storage,
1053            point_layout,
1054            length: 0,
1055        }
1056    }
1057
1058    /// Create a new helper object through which ranges of attribute data can be pushed into this buffer
1059    pub fn begin_push_attributes(&mut self) -> HashMapBufferAttributePusher<'_> {
1060        HashMapBufferAttributePusher::new(self)
1061    }
1062
1063    /// Like `Iterator::filter`, but filters into a point buffer of type `B`
1064    pub fn filter<
1065        B: for<'a> OwningBuffer<'a> + for<'a> MakeBufferFromLayout<'a>,
1066        F: Fn(usize) -> bool,
1067    >(
1068        &self,
1069        predicate: F,
1070    ) -> B {
1071        let num_matches = (0..self.len()).filter(|idx| predicate(*idx)).count();
1072        let mut filtered_points = B::new_from_layout(self.point_layout.clone());
1073        filtered_points.resize(num_matches);
1074        self.filter_into(&mut filtered_points, predicate, Some(num_matches));
1075        filtered_points
1076    }
1077
1078    /// Like `filter`, but writes the filtered points into the given `buffer`
1079    ///
1080    /// # panics
1081    ///
1082    /// If `buffer.len()` is less than the number of matching points according to `predicate`
1083    /// If the `PointLayout` of `buffer` does not match the `PointLayout` of `self`
1084    pub fn filter_into<B: for<'a> BorrowedMutBuffer<'a>, F: Fn(usize) -> bool>(
1085        &self,
1086        buffer: &mut B,
1087        predicate: F,
1088        num_matches_hint: Option<usize>,
1089    ) {
1090        if buffer.point_layout() != self.point_layout() {
1091            panic!("PointLayouts must match");
1092        }
1093        let num_matches = num_matches_hint
1094            .unwrap_or_else(|| (0..self.len()).filter(|idx| predicate(*idx)).count());
1095        if buffer.len() < num_matches {
1096            panic!("buffer.len() must be at least as large as the number of predicate matches");
1097        }
1098        if let Some(columnar_buffer) = buffer.as_columnar_mut() {
1099            for attribute in self.point_layout.attributes() {
1100                let src_attribute_data =
1101                    self.get_attribute_range_ref(attribute.attribute_definition(), 0..self.len());
1102                let dst_attribute_data = columnar_buffer
1103                    .get_attribute_range_mut(attribute.attribute_definition(), 0..num_matches);
1104                let stride = attribute.size() as usize;
1105                for (dst_index, src_index) in
1106                    (0..self.len()).filter(|idx| predicate(*idx)).enumerate()
1107                {
1108                    dst_attribute_data[(dst_index * stride)..((dst_index + 1) * stride)]
1109                        .copy_from_slice(
1110                            &src_attribute_data[(src_index * stride)..((src_index + 1) * stride)],
1111                        );
1112                }
1113            }
1114        } else if let Some(interleaved_buffer) = buffer.as_interleaved_mut() {
1115            let dst_data = interleaved_buffer.get_point_range_mut(0..num_matches);
1116            for attribute in self.point_layout.attributes() {
1117                let src_attribute_data =
1118                    self.get_attribute_range_ref(attribute.attribute_definition(), 0..self.len());
1119                let src_stride = attribute.size() as usize;
1120                let dst_offset = attribute.offset() as usize;
1121                let dst_stride = self.point_layout.size_of_point_entry() as usize;
1122                for (dst_index, src_index) in
1123                    (0..self.len()).filter(|idx| predicate(*idx)).enumerate()
1124                {
1125                    let dst_attribute_start = dst_offset + (dst_index * dst_stride);
1126                    let dst_point_range = dst_attribute_start..(dst_attribute_start + src_stride);
1127                    dst_data[dst_point_range].copy_from_slice(
1128                        &src_attribute_data
1129                            [(src_index * src_stride)..((src_index + 1) * src_stride)],
1130                    );
1131                }
1132            }
1133        } else {
1134            unimplemented!()
1135        }
1136    }
1137
1138    fn get_byte_range_for_attribute(
1139        point_index: usize,
1140        attribute: &PointAttributeDefinition,
1141    ) -> Range<usize> {
1142        let attribute_size = attribute.size() as usize;
1143        (point_index * attribute_size)..((point_index + 1) * attribute_size)
1144    }
1145
1146    fn get_byte_range_for_attributes(
1147        points_range: Range<usize>,
1148        attribute: &PointAttributeDefinition,
1149    ) -> Range<usize> {
1150        let attribute_size = attribute.size() as usize;
1151        (points_range.start * attribute_size)..(points_range.end * attribute_size)
1152    }
1153}
1154
1155impl<'a> MakeBufferFromLayout<'a> for HashMapBuffer {
1156    fn new_from_layout(point_layout: PointLayout) -> Self {
1157        let attributes_storage = point_layout
1158            .attributes()
1159            .map(|attribute| (attribute.attribute_definition().clone(), Vec::default()))
1160            .collect();
1161        Self {
1162            attributes_storage,
1163            point_layout,
1164            length: 0,
1165        }
1166    }
1167}
1168
1169impl<'a> BorrowedBuffer<'a> for HashMapBuffer
1170where
1171    HashMapBuffer: 'a,
1172{
1173    fn len(&self) -> usize {
1174        self.length
1175    }
1176
1177    fn point_layout(&self) -> &PointLayout {
1178        &self.point_layout
1179    }
1180
1181    fn get_point(&self, index: usize, data: &mut [u8]) {
1182        for attribute in self.point_layout.attributes() {
1183            let attribute_storage = self
1184                .attributes_storage
1185                .get(attribute.attribute_definition())
1186                .expect("Attribute not found within storage of this PointBuffer");
1187            let src_slice = &attribute_storage
1188                [Self::get_byte_range_for_attribute(index, attribute.attribute_definition())];
1189            let dst_slice = &mut data[attribute.byte_range_within_point()];
1190            dst_slice.copy_from_slice(src_slice);
1191        }
1192    }
1193
1194    fn get_point_range(&self, range: Range<usize>, data: &mut [u8]) {
1195        let size_of_point = self.point_layout.size_of_point_entry() as usize;
1196        for attribute in self.point_layout.attributes() {
1197            let attribute_storage = self
1198                .attributes_storage
1199                .get(attribute.attribute_definition())
1200                .expect("Attribute not found within storage of this PointBuffer");
1201            for point_index in range.clone() {
1202                let src_slice = &attribute_storage[Self::get_byte_range_for_attribute(
1203                    point_index,
1204                    attribute.attribute_definition(),
1205                )];
1206                let dst_point_slice = &mut data[((point_index - range.start) * size_of_point)..];
1207                let dst_slice = &mut dst_point_slice[attribute.byte_range_within_point()];
1208                dst_slice.copy_from_slice(src_slice);
1209            }
1210        }
1211    }
1212
1213    fn get_attribute(&self, attribute: &PointAttributeDefinition, index: usize, data: &mut [u8]) {
1214        let memory = self
1215            .attributes_storage
1216            .get(attribute)
1217            .expect("Attribute not found in PointLayout of this buffer");
1218        let attribute_byte_range = Self::get_byte_range_for_attribute(index, attribute);
1219        data.copy_from_slice(&memory[attribute_byte_range]);
1220    }
1221
1222    unsafe fn get_attribute_unchecked(
1223        &self,
1224        attribute_member: &PointAttributeMember,
1225        index: usize,
1226        data: &mut [u8],
1227    ) {
1228        let memory = self
1229            .attributes_storage
1230            .get(attribute_member.attribute_definition())
1231            .expect("Attribute not found in PointLayout of this buffer");
1232        let attribute_byte_range =
1233            Self::get_byte_range_for_attribute(index, attribute_member.attribute_definition());
1234        data.copy_from_slice(&memory[attribute_byte_range]);
1235    }
1236
1237    fn as_columnar(&self) -> Option<&dyn ColumnarBuffer<'a>> {
1238        Some(self)
1239    }
1240}
1241
1242impl<'a> BorrowedMutBuffer<'a> for HashMapBuffer
1243where
1244    HashMapBuffer: 'a,
1245{
1246    unsafe fn set_point(&mut self, index: usize, point_data: &[u8]) {
1247        for attribute in self.point_layout.attributes() {
1248            let attribute_definition = attribute.attribute_definition();
1249            let attribute_byte_range =
1250                Self::get_byte_range_for_attribute(index, attribute_definition);
1251            let attribute_storage = self
1252                .attributes_storage
1253                .get_mut(attribute_definition)
1254                .expect("Attribute not found within storage of this PointBuffer");
1255            let dst_slice = &mut attribute_storage[attribute_byte_range];
1256            let src_slice = &point_data[attribute.byte_range_within_point()];
1257            dst_slice.copy_from_slice(src_slice);
1258        }
1259    }
1260
1261    unsafe fn set_attribute(
1262        &mut self,
1263        attribute: &PointAttributeDefinition,
1264        index: usize,
1265        attribute_data: &[u8],
1266    ) {
1267        let attribute_byte_range = Self::get_byte_range_for_attribute(index, attribute);
1268        let attribute_storage = self
1269            .attributes_storage
1270            .get_mut(attribute)
1271            .expect("Attribute not found in PointLayout of this buffer");
1272        let attribute_bytes = &mut attribute_storage[attribute_byte_range];
1273        attribute_bytes.copy_from_slice(attribute_data);
1274    }
1275
1276    fn swap(&mut self, from_index: usize, to_index: usize) {
1277        assert!(from_index < self.len());
1278        assert!(to_index < self.len());
1279        if from_index == to_index {
1280            return;
1281        }
1282        for (attribute, storage) in self.attributes_storage.iter_mut() {
1283            let src_byte_range = Self::get_byte_range_for_attribute(from_index, attribute);
1284            let dst_byte_range = Self::get_byte_range_for_attribute(to_index, attribute);
1285            // Is safe as long as 'from_index' and 'to_index' are not out of bounds, which is asserted
1286            unsafe {
1287                let src_ptr = storage.as_mut_ptr().add(src_byte_range.start);
1288                let dst_ptr = storage.as_mut_ptr().add(dst_byte_range.start);
1289                std::ptr::swap_nonoverlapping(src_ptr, dst_ptr, attribute.size() as usize);
1290            }
1291        }
1292    }
1293
1294    unsafe fn set_point_range(&mut self, point_range: Range<usize>, point_data: &[u8]) {
1295        let size_of_point = self.point_layout.size_of_point_entry() as usize;
1296        let first_point = point_range.start;
1297        for attribute in self.point_layout.attributes() {
1298            let attribute_definition = attribute.attribute_definition();
1299            let attribute_storage = self
1300                .attributes_storage
1301                .get_mut(attribute_definition)
1302                .expect("Attribute not found within storage of this PointBuffer");
1303            for point_index in point_range.clone() {
1304                let zero_based_index = point_index - first_point;
1305                let attribute_byte_range =
1306                    Self::get_byte_range_for_attribute(point_index, attribute_definition);
1307
1308                let dst_slice = &mut attribute_storage[attribute_byte_range];
1309                let src_point_slice = &point_data
1310                    [(zero_based_index * size_of_point)..((zero_based_index + 1) * size_of_point)];
1311                let src_slice = &src_point_slice[attribute.byte_range_within_point()];
1312                dst_slice.copy_from_slice(src_slice);
1313            }
1314        }
1315    }
1316
1317    unsafe fn set_attribute_range(
1318        &mut self,
1319        attribute: &PointAttributeDefinition,
1320        point_range: Range<usize>,
1321        attribute_data: &[u8],
1322    ) {
1323        let attribute_range = self.get_attribute_range_mut(attribute, point_range);
1324        attribute_range.copy_from_slice(attribute_data);
1325    }
1326
1327    fn as_columnar_mut(&mut self) -> Option<&mut dyn ColumnarBufferMut<'a>> {
1328        Some(self)
1329    }
1330}
1331
1332impl<'a> OwningBuffer<'a> for HashMapBuffer
1333where
1334    HashMapBuffer: 'a,
1335{
1336    unsafe fn push_points(&mut self, point_bytes: &[u8]) {
1337        let point_size = self.point_layout.size_of_point_entry() as usize;
1338        assert_eq!(point_bytes.len() % point_size, 0);
1339        let num_points_added = point_bytes.len() / point_size;
1340        for attribute in self.point_layout.attributes() {
1341            let storage = self
1342                .attributes_storage
1343                .get_mut(attribute.attribute_definition())
1344                .expect("Attribute not found in storage of this buffer");
1345            for index in 0..num_points_added {
1346                let point_bytes = &point_bytes[(index * point_size)..((index + 1) * point_size)];
1347                let attribute_bytes = &point_bytes[attribute.byte_range_within_point()];
1348                storage.extend_from_slice(attribute_bytes);
1349            }
1350        }
1351        self.length += num_points_added;
1352    }
1353
1354    fn resize(&mut self, count: usize) {
1355        for (attribute, storage) in self.attributes_storage.iter_mut() {
1356            let new_num_bytes = count * attribute.size() as usize;
1357            storage.resize(new_num_bytes, 0);
1358        }
1359        self.length = count;
1360    }
1361
1362    fn clear(&mut self) {
1363        for storage in self.attributes_storage.values_mut() {
1364            storage.clear();
1365        }
1366        self.length = 0;
1367    }
1368}
1369
1370impl<'a> ColumnarBuffer<'a> for HashMapBuffer
1371where
1372    HashMapBuffer: 'a,
1373{
1374    fn get_attribute_ref<'b>(
1375        &'b self,
1376        attribute: &PointAttributeDefinition,
1377        index: usize,
1378    ) -> &'b [u8]
1379    where
1380        'a: 'b,
1381    {
1382        let storage_of_attribute = self
1383            .attributes_storage
1384            .get(attribute)
1385            .expect("Attribute not found in PointLayout of this buffer");
1386        &storage_of_attribute[Self::get_byte_range_for_attribute(index, attribute)]
1387    }
1388
1389    fn get_attribute_range_ref<'b>(
1390        &'b self,
1391        attribute: &PointAttributeDefinition,
1392        range: Range<usize>,
1393    ) -> &'b [u8]
1394    where
1395        'a: 'b,
1396    {
1397        let storage_of_attribute = self
1398            .attributes_storage
1399            .get(attribute)
1400            .expect("Attribute not found in PointLayout of this buffer");
1401        &storage_of_attribute[Self::get_byte_range_for_attributes(range, attribute)]
1402    }
1403}
1404
1405impl<'a> ColumnarBufferMut<'a> for HashMapBuffer
1406where
1407    HashMapBuffer: 'a,
1408{
1409    fn get_attribute_mut<'b>(
1410        &'b mut self,
1411        attribute: &PointAttributeDefinition,
1412        index: usize,
1413    ) -> &'b mut [u8]
1414    where
1415        'a: 'b,
1416    {
1417        let byte_range = Self::get_byte_range_for_attribute(index, attribute);
1418        let storage_of_attribute = self
1419            .attributes_storage
1420            .get_mut(attribute)
1421            .expect("Attribute not found in PointLayout of this buffer");
1422        &mut storage_of_attribute[byte_range]
1423    }
1424
1425    fn get_attribute_range_mut<'b>(
1426        &'b mut self,
1427        attribute: &PointAttributeDefinition,
1428        range: Range<usize>,
1429    ) -> &'b mut [u8]
1430    where
1431        'a: 'b,
1432    {
1433        let byte_range = Self::get_byte_range_for_attributes(range, attribute);
1434        let storage_of_attribute = self
1435            .attributes_storage
1436            .get_mut(attribute)
1437            .expect("Attribute not found in PointLayout of this buffer");
1438        &mut storage_of_attribute[byte_range]
1439    }
1440}
1441
1442impl<'a> SliceBuffer<'a> for HashMapBuffer
1443where
1444    Self: 'a,
1445{
1446    type SliceType = BufferSliceColumnar<'a, Self>;
1447
1448    fn slice(&'a self, range: Range<usize>) -> Self::SliceType {
1449        BufferSliceColumnar::new(self, range)
1450    }
1451}
1452
1453impl<'a> SliceBufferMut<'a> for HashMapBuffer {
1454    type SliceTypeMut = BufferSliceColumnarMut<'a, Self>;
1455
1456    fn slice_mut(&'a mut self, range: Range<usize>) -> Self::SliceTypeMut {
1457        BufferSliceColumnarMut::new(self, range)
1458    }
1459}
1460
1461impl<T: PointType> FromIterator<T> for HashMapBuffer {
1462    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1463        let point_layout = T::layout();
1464        let mut buffer = Self::new_from_layout(point_layout);
1465        iter.into_iter().for_each(|point| {
1466            let point_bytes = bytemuck::bytes_of(&point);
1467            // Safe because we know that `buffer` has the same `PointLayout` as `T`
1468            unsafe {
1469                buffer.push_points(point_bytes);
1470            }
1471        });
1472        buffer
1473    }
1474}
1475
1476/// A point buffer that stores point data in interleaved memory layout in an externally borrowed memory resource.
1477/// This can be any type that is convertible to a `&[u8]`. If `T` also is convertible to a `&mut [u8]`, this buffer
1478/// also implements [`BorrowedMutBuffer`]
1479pub struct ExternalMemoryBuffer<T: AsRef<[u8]>> {
1480    external_memory: T,
1481    point_layout: PointLayout,
1482    length: usize,
1483}
1484
1485impl<T: AsRef<[u8]>> ExternalMemoryBuffer<T> {
1486    /// Creates a new `ExternalMemoryBuffer` from the given `external_memory` resource and the given `PointLayout`
1487    pub fn new(external_memory: T, point_layout: PointLayout) -> Self {
1488        let length = match point_layout.size_of_point_entry() {
1489            0 => {
1490                assert_eq!(0, external_memory.as_ref().len());
1491                0
1492            }
1493            point_size => {
1494                assert!(external_memory.as_ref().len() % point_size as usize == 0);
1495                external_memory.as_ref().len() / point_size as usize
1496            }
1497        };
1498        Self {
1499            external_memory,
1500            point_layout,
1501            length,
1502        }
1503    }
1504
1505    fn get_byte_range_for_point(&self, point_index: usize) -> Range<usize> {
1506        let size_of_point = self.point_layout.size_of_point_entry() as usize;
1507        (point_index * size_of_point)..((point_index + 1) * size_of_point)
1508    }
1509
1510    fn get_byte_range_for_point_range(&self, point_range: Range<usize>) -> Range<usize> {
1511        let size_of_point = self.point_layout.size_of_point_entry() as usize;
1512        (point_range.start * size_of_point)..(point_range.end * size_of_point)
1513    }
1514
1515    fn get_byte_range_of_attribute(
1516        &self,
1517        point_index: usize,
1518        attribute: &PointAttributeMember,
1519    ) -> Range<usize> {
1520        let start_byte = (point_index * self.point_layout.size_of_point_entry() as usize)
1521            + attribute.offset() as usize;
1522        let end_byte = start_byte + attribute.size() as usize;
1523        start_byte..end_byte
1524    }
1525}
1526
1527impl<'a, T: AsRef<[u8]>> BorrowedBuffer<'a> for ExternalMemoryBuffer<T>
1528where
1529    ExternalMemoryBuffer<T>: 'a,
1530{
1531    fn len(&self) -> usize {
1532        self.length
1533    }
1534
1535    fn point_layout(&self) -> &PointLayout {
1536        &self.point_layout
1537    }
1538
1539    fn get_point(&self, index: usize, data: &mut [u8]) {
1540        let point_bytes = &self.external_memory.as_ref()[self.get_byte_range_for_point(index)];
1541        data.copy_from_slice(point_bytes);
1542    }
1543
1544    fn get_point_range(&self, range: Range<usize>, data: &mut [u8]) {
1545        let point_bytes =
1546            &self.external_memory.as_ref()[self.get_byte_range_for_point_range(range)];
1547        data.copy_from_slice(point_bytes);
1548    }
1549
1550    unsafe fn get_attribute_unchecked(
1551        &self,
1552        attribute_member: &PointAttributeMember,
1553        index: usize,
1554        data: &mut [u8],
1555    ) {
1556        let attribute_bytes_range = self.get_byte_range_of_attribute(index, attribute_member);
1557        let attribute_bytes = &self.external_memory.as_ref()[attribute_bytes_range];
1558        data.copy_from_slice(attribute_bytes);
1559    }
1560
1561    fn as_interleaved(&self) -> Option<&dyn InterleavedBuffer<'a>> {
1562        Some(self)
1563    }
1564}
1565
1566impl<'a, T: AsMut<[u8]> + AsRef<[u8]>> BorrowedMutBuffer<'a> for ExternalMemoryBuffer<T>
1567where
1568    ExternalMemoryBuffer<T>: 'a,
1569{
1570    unsafe fn set_point(&mut self, index: usize, point_data: &[u8]) {
1571        let point_byte_range = self.get_byte_range_for_point(index);
1572        let point_memory = &mut self.external_memory.as_mut()[point_byte_range];
1573        point_memory.copy_from_slice(point_data);
1574    }
1575
1576    unsafe fn set_attribute(
1577        &mut self,
1578        attribute: &PointAttributeDefinition,
1579        index: usize,
1580        attribute_data: &[u8],
1581    ) {
1582        let attribute_member = self
1583            .point_layout
1584            .get_attribute(attribute)
1585            .expect("Attribute not found in PointLayout of this buffer");
1586        let attribute_byte_range = self.get_byte_range_of_attribute(index, attribute_member);
1587        let attribute_bytes = &mut self.external_memory.as_mut()[attribute_byte_range];
1588        attribute_bytes.copy_from_slice(attribute_data);
1589    }
1590
1591    fn swap(&mut self, from_index: usize, to_index: usize) {
1592        assert!(from_index < self.len());
1593        assert!(to_index < self.len());
1594        if from_index == to_index {
1595            return;
1596        }
1597        let size_of_point = self.point_layout.size_of_point_entry() as usize;
1598        // Is safe if neither `from_index` nor `to_index` is out of bounds, which is asserted
1599        unsafe {
1600            let from_ptr = self
1601                .external_memory
1602                .as_mut()
1603                .as_mut_ptr()
1604                .add(from_index * size_of_point);
1605            let to_ptr = self
1606                .external_memory
1607                .as_mut()
1608                .as_mut_ptr()
1609                .add(to_index * size_of_point);
1610            std::ptr::swap_nonoverlapping(from_ptr, to_ptr, size_of_point);
1611        }
1612    }
1613
1614    unsafe fn set_point_range(&mut self, point_range: Range<usize>, point_data: &[u8]) {
1615        let point_byte_range = self.get_byte_range_for_point_range(point_range);
1616        let point_memory = &mut self.external_memory.as_mut()[point_byte_range];
1617        point_memory.copy_from_slice(point_data);
1618    }
1619
1620    unsafe fn set_attribute_range(
1621        &mut self,
1622        attribute: &PointAttributeDefinition,
1623        point_range: Range<usize>,
1624        attribute_data: &[u8],
1625    ) {
1626        let attribute_member = self
1627            .point_layout
1628            .get_attribute(attribute)
1629            .expect("Attribute not found in PointLayout of this buffer");
1630        let attribute_size = attribute_member.size() as usize;
1631        let first_point = point_range.start;
1632        for point_index in point_range {
1633            let zero_based_index = point_index - first_point;
1634            let src_slice = &attribute_data
1635                [(zero_based_index * attribute_size)..((zero_based_index + 1) * attribute_size)];
1636            let attribute_byte_range =
1637                self.get_byte_range_of_attribute(point_index, attribute_member);
1638            let attribute_bytes = &mut self.external_memory.as_mut()[attribute_byte_range];
1639            attribute_bytes.copy_from_slice(src_slice);
1640        }
1641    }
1642
1643    fn as_interleaved_mut(&mut self) -> Option<&mut dyn InterleavedBufferMut<'a>> {
1644        Some(self)
1645    }
1646}
1647
1648impl<'a, T: AsRef<[u8]>> InterleavedBuffer<'a> for ExternalMemoryBuffer<T>
1649where
1650    ExternalMemoryBuffer<T>: 'a,
1651{
1652    fn get_point_ref<'b>(&'b self, index: usize) -> &'b [u8]
1653    where
1654        'a: 'b,
1655    {
1656        let memory = self.external_memory.as_ref();
1657        &memory[self.get_byte_range_for_point(index)]
1658    }
1659
1660    fn get_point_range_ref<'b>(&'b self, range: Range<usize>) -> &'b [u8]
1661    where
1662        'a: 'b,
1663    {
1664        let memory = self.external_memory.as_ref();
1665        &memory[self.get_byte_range_for_point_range(range)]
1666    }
1667}
1668
1669impl<'a, T: AsRef<[u8]> + AsMut<[u8]>> InterleavedBufferMut<'a> for ExternalMemoryBuffer<T>
1670where
1671    ExternalMemoryBuffer<T>: 'a,
1672{
1673    fn get_point_mut<'b>(&'b mut self, index: usize) -> &'b mut [u8]
1674    where
1675        'a: 'b,
1676    {
1677        let byte_range = self.get_byte_range_for_point(index);
1678        let memory = self.external_memory.as_mut();
1679        &mut memory[byte_range]
1680    }
1681
1682    fn get_point_range_mut<'b>(&'b mut self, range: Range<usize>) -> &'b mut [u8]
1683    where
1684        'a: 'b,
1685    {
1686        let byte_range = self.get_byte_range_for_point_range(range);
1687        let memory = self.external_memory.as_mut();
1688        &mut memory[byte_range]
1689    }
1690}
1691
1692impl<'a, T: AsRef<[u8]> + 'a> SliceBuffer<'a> for ExternalMemoryBuffer<T>
1693where
1694    Self: 'a,
1695{
1696    type SliceType = BufferSliceInterleaved<'a, Self>;
1697
1698    fn slice(&'a self, range: Range<usize>) -> Self::SliceType {
1699        BufferSliceInterleaved::new(self, range)
1700    }
1701}
1702
1703impl<'a, T: AsRef<[u8]> + AsMut<[u8]> + 'a> SliceBufferMut<'a> for ExternalMemoryBuffer<T> {
1704    type SliceTypeMut = BufferSliceInterleavedMut<'a, Self>;
1705    fn slice_mut(&'a mut self, range: Range<usize>) -> Self::SliceTypeMut {
1706        BufferSliceInterleavedMut::new(self, range)
1707    }
1708}
1709
1710#[cfg(test)]
1711mod tests {
1712    use itertools::Itertools;
1713    use nalgebra::Vector3;
1714    use rand::{prelude::Distribution, thread_rng, Rng};
1715
1716    use crate::layout::{attributes::POSITION_3D, PointAttributeDataType};
1717    use crate::test_utils::*;
1718
1719    use super::*;
1720
1721    fn compare_attributes_typed<'a, U: PrimitiveType + std::fmt::Debug + PartialEq>(
1722        buffer: &'a impl BorrowedBuffer<'a>,
1723        attribute: &PointAttributeDefinition,
1724        expected_points: &'a impl BorrowedBuffer<'a>,
1725    ) {
1726        let collected_values = buffer
1727            .view_attribute::<U>(attribute)
1728            .into_iter()
1729            .collect::<Vec<_>>();
1730        let expected_values = expected_points
1731            .view_attribute::<U>(attribute)
1732            .into_iter()
1733            .collect::<Vec<_>>();
1734        assert_eq!(expected_values, collected_values);
1735    }
1736
1737    /// Compare the given point attribute using the static type corresponding to the attribute's `PointAttributeDataType`
1738    fn compare_attributes<'a>(
1739        buffer: &'a impl BorrowedBuffer<'a>,
1740        attribute: &PointAttributeDefinition,
1741        expected_points: &'a impl BorrowedBuffer<'a>,
1742    ) {
1743        match attribute.datatype() {
1744            PointAttributeDataType::F32 => {
1745                compare_attributes_typed::<f32>(buffer, attribute, expected_points)
1746            }
1747            PointAttributeDataType::F64 => {
1748                compare_attributes_typed::<f64>(buffer, attribute, expected_points)
1749            }
1750            PointAttributeDataType::I16 => {
1751                compare_attributes_typed::<i16>(buffer, attribute, expected_points)
1752            }
1753            PointAttributeDataType::I32 => {
1754                compare_attributes_typed::<i32>(buffer, attribute, expected_points)
1755            }
1756            PointAttributeDataType::I64 => {
1757                compare_attributes_typed::<i64>(buffer, attribute, expected_points)
1758            }
1759            PointAttributeDataType::I8 => {
1760                compare_attributes_typed::<i8>(buffer, attribute, expected_points)
1761            }
1762            PointAttributeDataType::U16 => {
1763                compare_attributes_typed::<u16>(buffer, attribute, expected_points)
1764            }
1765            PointAttributeDataType::U32 => {
1766                compare_attributes_typed::<u32>(buffer, attribute, expected_points)
1767            }
1768            PointAttributeDataType::U64 => {
1769                compare_attributes_typed::<u64>(buffer, attribute, expected_points)
1770            }
1771            PointAttributeDataType::U8 => {
1772                compare_attributes_typed::<u8>(buffer, attribute, expected_points)
1773            }
1774            PointAttributeDataType::Vec3f32 => {
1775                compare_attributes_typed::<Vector3<f32>>(buffer, attribute, expected_points)
1776            }
1777            PointAttributeDataType::Vec3f64 => {
1778                compare_attributes_typed::<Vector3<f64>>(buffer, attribute, expected_points);
1779            }
1780            PointAttributeDataType::Vec3i32 => {
1781                compare_attributes_typed::<Vector3<i32>>(buffer, attribute, expected_points)
1782            }
1783            PointAttributeDataType::Vec3u16 => {
1784                compare_attributes_typed::<Vector3<u16>>(buffer, attribute, expected_points)
1785            }
1786            PointAttributeDataType::Vec3u8 => {
1787                compare_attributes_typed::<Vector3<u8>>(buffer, attribute, expected_points)
1788            }
1789            _ => unimplemented!(),
1790        }
1791    }
1792
1793    fn test_vector_buffer_with_type<T: PointType + std::fmt::Debug + PartialEq + Copy + Clone>()
1794    where
1795        DefaultPointDistribution: Distribution<T>,
1796    {
1797        const COUNT: usize = 16;
1798        let test_data: Vec<T> = thread_rng()
1799            .sample_iter(DefaultPointDistribution)
1800            .take(COUNT)
1801            .collect();
1802        let overwrite_data: Vec<T> = thread_rng()
1803            .sample_iter(DefaultPointDistribution)
1804            .take(COUNT)
1805            .collect();
1806
1807        let test_data_as_buffer = test_data.iter().copied().collect::<VectorBuffer>();
1808
1809        {
1810            let mut buffer = VectorBuffer::new_from_layout(T::layout());
1811            assert_eq!(0, buffer.len());
1812            assert_eq!(T::layout(), *buffer.point_layout());
1813            assert_eq!(0, buffer.view::<T>().into_iter().count());
1814
1815            for (idx, point) in test_data.iter().enumerate() {
1816                buffer.view_mut().push_point(*point);
1817                assert_eq!(idx + 1, buffer.len());
1818                assert_eq!(*point, buffer.view().at(idx));
1819            }
1820
1821            let mut collected_points = buffer.view().into_iter().collect::<Vec<_>>();
1822            assert_eq!(test_data, collected_points);
1823
1824            let collected_points_by_ref = buffer.view().iter().copied().collect::<Vec<_>>();
1825            assert_eq!(test_data, collected_points_by_ref);
1826
1827            for attribute in buffer.point_layout().attributes() {
1828                compare_attributes(
1829                    &buffer,
1830                    attribute.attribute_definition(),
1831                    &test_data_as_buffer,
1832                );
1833            }
1834
1835            let slice = buffer.slice(1..2);
1836            assert_eq!(test_data[1], slice.view().at(0));
1837
1838            for (idx, point) in overwrite_data.iter().enumerate() {
1839                *buffer.view_mut().at_mut(idx) = *point;
1840            }
1841            collected_points = buffer.view().iter().copied().collect();
1842            assert_eq!(overwrite_data, collected_points);
1843        }
1844    }
1845
1846    fn test_hashmap_buffer_with_type<T: PointType + std::fmt::Debug + PartialEq + Copy + Clone>()
1847    where
1848        DefaultPointDistribution: Distribution<T>,
1849    {
1850        const COUNT: usize = 16;
1851        let test_data: Vec<T> = thread_rng()
1852            .sample_iter(DefaultPointDistribution)
1853            .take(COUNT)
1854            .collect();
1855        let overwrite_data: Vec<T> = thread_rng()
1856            .sample_iter(DefaultPointDistribution)
1857            .take(COUNT)
1858            .collect();
1859
1860        let test_data_as_buffer = test_data.iter().copied().collect::<HashMapBuffer>();
1861
1862        {
1863            let mut buffer = HashMapBuffer::new_from_layout(T::layout());
1864            assert_eq!(0, buffer.len());
1865            assert_eq!(T::layout(), *buffer.point_layout());
1866            assert_eq!(0, buffer.view::<T>().into_iter().count());
1867
1868            for (idx, point) in test_data.iter().enumerate() {
1869                buffer.view_mut().push_point(*point);
1870                assert_eq!(idx + 1, buffer.len());
1871                assert_eq!(*point, buffer.view().at(idx));
1872            }
1873
1874            let mut collected_points = buffer.view().into_iter().collect::<Vec<_>>();
1875            assert_eq!(test_data, collected_points);
1876
1877            for attribute in buffer.point_layout().attributes() {
1878                compare_attributes(
1879                    &buffer,
1880                    attribute.attribute_definition(),
1881                    &test_data_as_buffer,
1882                );
1883            }
1884
1885            let slice = buffer.slice(1..2);
1886            assert_eq!(test_data[1], slice.view().at(0));
1887
1888            for (idx, point) in overwrite_data.iter().enumerate() {
1889                buffer.view_mut().set_at(idx, *point);
1890            }
1891            collected_points = buffer.view().into_iter().collect();
1892            assert_eq!(overwrite_data, collected_points);
1893        }
1894    }
1895
1896    fn test_external_memory_buffer_with_type<
1897        T: PointType + std::fmt::Debug + PartialEq + Copy + Clone,
1898    >()
1899    where
1900        DefaultPointDistribution: Distribution<T>,
1901    {
1902        const COUNT: usize = 16;
1903        let test_data: Vec<T> = thread_rng()
1904            .sample_iter(DefaultPointDistribution)
1905            .take(COUNT)
1906            .collect();
1907        let overwrite_data: Vec<T> = thread_rng()
1908            .sample_iter(DefaultPointDistribution)
1909            .take(COUNT)
1910            .collect();
1911
1912        let mut memory_of_buffer: Vec<u8> =
1913            vec![0; COUNT * T::layout().size_of_point_entry() as usize];
1914        let mut test_data_as_buffer = ExternalMemoryBuffer::new(&mut memory_of_buffer, T::layout());
1915        for (idx, point) in test_data.iter().copied().enumerate() {
1916            test_data_as_buffer.view_mut().set_at(idx, point);
1917        }
1918
1919        {
1920            let mut buffer = VectorBuffer::new_from_layout(T::layout());
1921            assert_eq!(0, buffer.len());
1922            assert_eq!(T::layout(), *buffer.point_layout());
1923            assert_eq!(0, buffer.view::<T>().into_iter().count());
1924
1925            for (idx, point) in test_data.iter().enumerate() {
1926                buffer.view_mut().push_point(*point);
1927                assert_eq!(idx + 1, buffer.len());
1928                assert_eq!(*point, buffer.view().at(idx));
1929            }
1930
1931            let mut collected_points = buffer.view().into_iter().collect::<Vec<_>>();
1932            assert_eq!(test_data, collected_points);
1933
1934            let collected_points_by_ref = buffer.view().iter().copied().collect::<Vec<_>>();
1935            assert_eq!(test_data, collected_points_by_ref);
1936
1937            for attribute in buffer.point_layout().attributes() {
1938                compare_attributes(
1939                    &buffer,
1940                    attribute.attribute_definition(),
1941                    &test_data_as_buffer,
1942                );
1943            }
1944
1945            let slice = buffer.slice(1..2);
1946            assert_eq!(test_data[1], slice.view().at(0));
1947
1948            for (idx, point) in overwrite_data.iter().enumerate() {
1949                *buffer.view_mut().at_mut(idx) = *point;
1950            }
1951            collected_points = buffer.view().iter().copied().collect();
1952            assert_eq!(overwrite_data, collected_points);
1953        }
1954    }
1955
1956    #[test]
1957    fn test_vector_buffer() {
1958        test_vector_buffer_with_type::<CustomPointTypeSmall>();
1959        test_vector_buffer_with_type::<CustomPointTypeBig>();
1960    }
1961
1962    #[test]
1963    fn test_hash_map_buffer() {
1964        test_hashmap_buffer_with_type::<CustomPointTypeSmall>();
1965        test_hashmap_buffer_with_type::<CustomPointTypeBig>();
1966    }
1967
1968    #[test]
1969    fn test_hash_map_buffer_mutate_attribute() {
1970        const COUNT: usize = 16;
1971        let test_data: Vec<CustomPointTypeBig> = thread_rng()
1972            .sample_iter(DefaultPointDistribution)
1973            .take(COUNT)
1974            .collect();
1975        let overwrite_data: Vec<CustomPointTypeBig> = thread_rng()
1976            .sample_iter(DefaultPointDistribution)
1977            .take(COUNT)
1978            .collect();
1979
1980        let mut buffer = test_data.iter().copied().collect::<HashMapBuffer>();
1981
1982        for (idx, attribute) in buffer
1983            .view_attribute_mut::<Vector3<f64>>(&POSITION_3D)
1984            .iter_mut()
1985            .enumerate()
1986        {
1987            *attribute = overwrite_data[idx].position;
1988        }
1989
1990        let expected_positions = overwrite_data
1991            .iter()
1992            .map(|point| point.position)
1993            .collect::<Vec<_>>();
1994        let actual_positions = buffer
1995            .view_attribute(&POSITION_3D)
1996            .into_iter()
1997            .collect::<Vec<_>>();
1998        assert_eq!(expected_positions, actual_positions);
1999    }
2000
2001    #[test]
2002    fn test_external_memory_buffer() {
2003        test_external_memory_buffer_with_type::<CustomPointTypeSmall>();
2004        test_external_memory_buffer_with_type::<CustomPointTypeBig>();
2005    }
2006
2007    fn test_transform_attribute_generic<
2008        'a,
2009        B: BorrowedMutBuffer<'a> + FromIterator<CustomPointTypeBig> + 'a,
2010    >() {
2011        const COUNT: usize = 16;
2012        let test_data: Vec<CustomPointTypeBig> = thread_rng()
2013            .sample_iter(DefaultPointDistribution)
2014            .take(COUNT)
2015            .collect();
2016        let overwrite_data: Vec<CustomPointTypeBig> = thread_rng()
2017            .sample_iter(DefaultPointDistribution)
2018            .take(COUNT)
2019            .collect();
2020
2021        let mut buffer = test_data.iter().copied().collect::<B>();
2022        // Overwrite the positions with the positions in `overwrite_data` using the `transform_attribute` function
2023        buffer.transform_attribute(&POSITION_3D, |index, _| -> Vector3<f64> {
2024            overwrite_data[index].position
2025        });
2026
2027        let expected_positions = overwrite_data
2028            .iter()
2029            .map(|point| point.position)
2030            .collect::<Vec<_>>();
2031        let actual_positions = buffer
2032            .view_attribute(&POSITION_3D)
2033            .into_iter()
2034            .collect::<Vec<_>>();
2035        assert_eq!(expected_positions, actual_positions);
2036    }
2037
2038    #[test]
2039    fn test_transform_attribute() {
2040        test_transform_attribute_generic::<VectorBuffer>();
2041        test_transform_attribute_generic::<HashMapBuffer>();
2042    }
2043
2044    #[test]
2045    fn test_append() {
2046        const COUNT: usize = 16;
2047        let test_data: Vec<CustomPointTypeBig> = thread_rng()
2048            .sample_iter(DefaultPointDistribution)
2049            .take(COUNT)
2050            .collect();
2051
2052        let expected_buffer_interleaved = test_data.iter().copied().collect::<VectorBuffer>();
2053        let expected_buffer_columnar = test_data.iter().copied().collect::<HashMapBuffer>();
2054
2055        {
2056            let mut vector_buffer = VectorBuffer::new_from_layout(CustomPointTypeBig::layout());
2057            vector_buffer.append(&expected_buffer_interleaved);
2058            assert_eq!(expected_buffer_interleaved, vector_buffer);
2059        }
2060        {
2061            let mut vector_buffer = VectorBuffer::new_from_layout(CustomPointTypeBig::layout());
2062            vector_buffer.append(&expected_buffer_columnar);
2063            assert_eq!(expected_buffer_interleaved, vector_buffer);
2064        }
2065        {
2066            let mut hashmap_buffer = HashMapBuffer::new_from_layout(CustomPointTypeBig::layout());
2067            hashmap_buffer.append(&expected_buffer_columnar);
2068            assert_eq!(expected_buffer_columnar, hashmap_buffer);
2069        }
2070        {
2071            let mut hashmap_buffer = HashMapBuffer::new_from_layout(CustomPointTypeBig::layout());
2072            hashmap_buffer.append(&expected_buffer_interleaved);
2073            assert_eq!(expected_buffer_columnar, hashmap_buffer);
2074        }
2075    }
2076
2077    #[test]
2078    fn test_buffers_from_empty_layout() {
2079        let empty_layout = PointLayout::default();
2080
2081        {
2082            let buffer = VectorBuffer::new_from_layout(empty_layout.clone());
2083            assert_eq!(0, buffer.len());
2084        }
2085        {
2086            let buffer = HashMapBuffer::new_from_layout(empty_layout.clone());
2087            assert_eq!(0, buffer.len());
2088        }
2089        {
2090            let empty_memory = Vec::default();
2091            let buffer = ExternalMemoryBuffer::new(&empty_memory, empty_layout.clone());
2092            assert_eq!(0, buffer.len());
2093        }
2094    }
2095
2096    fn test_buffer_set_point_range_generic<
2097        B: for<'a> BorrowedMutBuffer<'a>
2098            + FromIterator<CustomPointTypeBig>
2099            + for<'a> SliceBufferMut<'a>,
2100    >() {
2101        const COUNT: usize = 16;
2102        let test_data: Vec<CustomPointTypeBig> = thread_rng()
2103            .sample_iter(DefaultPointDistribution)
2104            .take(COUNT)
2105            .collect();
2106        let overwrite_data: Vec<CustomPointTypeBig> = thread_rng()
2107            .sample_iter(DefaultPointDistribution)
2108            .take(COUNT)
2109            .collect();
2110        let raw_overwrite_data: &[u8] = bytemuck::cast_slice(&overwrite_data);
2111
2112        let mut buffer = test_data.iter().copied().collect::<B>();
2113        // Safe because we know the point layout of buffer is equal to that of CustomPointTypeBig
2114        unsafe {
2115            buffer.set_point_range(0..COUNT, raw_overwrite_data);
2116        }
2117
2118        let actual_data = buffer
2119            .view::<CustomPointTypeBig>()
2120            .into_iter()
2121            .collect_vec();
2122        assert_eq!(overwrite_data, actual_data);
2123
2124        // Do the same thing, but with a slice
2125        buffer = test_data.iter().copied().collect::<B>();
2126        let mut buffer_slice = buffer.slice_mut(0..COUNT);
2127        unsafe {
2128            buffer_slice.set_point_range(0..COUNT, raw_overwrite_data);
2129        }
2130        drop(buffer_slice);
2131
2132        let actual_data = buffer
2133            .view::<CustomPointTypeBig>()
2134            .into_iter()
2135            .collect_vec();
2136        assert_eq!(overwrite_data, actual_data);
2137    }
2138
2139    #[test]
2140    fn test_buffers_set_point_range() {
2141        test_buffer_set_point_range_generic::<VectorBuffer>();
2142        test_buffer_set_point_range_generic::<HashMapBuffer>();
2143    }
2144
2145    fn test_buffer_get_point_range_generic<
2146        B: for<'a> BorrowedMutBuffer<'a>
2147            + FromIterator<CustomPointTypeBig>
2148            + for<'a> SliceBufferMut<'a>,
2149    >() {
2150        const COUNT: usize = 16;
2151        let test_data: Vec<CustomPointTypeBig> = thread_rng()
2152            .sample_iter(DefaultPointDistribution)
2153            .take(COUNT)
2154            .collect();
2155        let raw_test_data: &[u8] = bytemuck::cast_slice(test_data.as_slice());
2156        let size_of_single_point = std::mem::size_of::<CustomPointTypeBig>();
2157
2158        let buffer = test_data.iter().copied().collect::<B>();
2159
2160        let mut actual_point_data = vec![0; raw_test_data.len()];
2161        buffer.get_point_range(0..COUNT, &mut actual_point_data);
2162
2163        assert_eq!(raw_test_data, actual_point_data);
2164
2165        // Check that subset ranges work correctly as well
2166        let subset_slice = &mut actual_point_data[..(6 * size_of_single_point)];
2167        buffer.get_point_range(2..8, subset_slice);
2168        assert_eq!(
2169            &raw_test_data[(2 * size_of_single_point)..(8 * size_of_single_point)],
2170            subset_slice
2171        );
2172    }
2173
2174    #[test]
2175    fn test_buffer_get_point_range() {
2176        test_buffer_get_point_range_generic::<VectorBuffer>();
2177        test_buffer_get_point_range_generic::<HashMapBuffer>();
2178    }
2179
2180    fn test_buffer_set_attribute_range_generic<
2181        B: for<'a> BorrowedMutBuffer<'a>
2182            + FromIterator<CustomPointTypeBig>
2183            + for<'a> SliceBufferMut<'a>,
2184    >() {
2185        const COUNT: usize = 16;
2186        let test_data: Vec<CustomPointTypeBig> = thread_rng()
2187            .sample_iter(DefaultPointDistribution)
2188            .take(COUNT)
2189            .collect();
2190        let overwrite_data: Vec<CustomPointTypeBig> = thread_rng()
2191            .sample_iter(DefaultPointDistribution)
2192            .take(COUNT)
2193            .collect();
2194        let overwrite_positions = overwrite_data
2195            .iter()
2196            .map(|point| point.position)
2197            .collect_vec();
2198        let overwrite_positions_raw_data: &[u8] = bytemuck::cast_slice(&overwrite_positions);
2199
2200        let mut buffer = test_data.iter().copied().collect::<B>();
2201        // Safe because we know the point layout of buffer
2202        unsafe {
2203            buffer.set_attribute_range(&POSITION_3D, 0..COUNT, overwrite_positions_raw_data);
2204        }
2205
2206        let actual_positions = buffer
2207            .view_attribute(&POSITION_3D)
2208            .into_iter()
2209            .collect::<Vec<_>>();
2210        assert_eq!(overwrite_positions, actual_positions);
2211
2212        // Do the same test, but for a slice
2213        buffer = test_data.iter().copied().collect::<B>();
2214        let mut buffer_slice = buffer.slice_mut(0..test_data.len());
2215        unsafe {
2216            buffer_slice.set_attribute_range(&POSITION_3D, 0..COUNT, overwrite_positions_raw_data);
2217        }
2218        drop(buffer_slice);
2219
2220        let actual_positions = buffer
2221            .view_attribute(&POSITION_3D)
2222            .into_iter()
2223            .collect::<Vec<_>>();
2224        assert_eq!(overwrite_positions, actual_positions);
2225    }
2226
2227    #[test]
2228    fn test_buffers_set_attribute_range() {
2229        test_buffer_set_attribute_range_generic::<VectorBuffer>();
2230        test_buffer_set_attribute_range_generic::<HashMapBuffer>();
2231    }
2232
2233    #[test]
2234    fn test_buffers_as_memory_layout_accessors() {
2235        let mut vector_buffer = VectorBuffer::new_from_layout(CustomPointTypeSmall::layout());
2236        let mut hashmap_buffer = HashMapBuffer::new_from_layout(CustomPointTypeSmall::layout());
2237
2238        let mut memory: Vec<u8> = Vec::default();
2239        let mut external_memory_buffer =
2240            ExternalMemoryBuffer::new(memory.as_mut_slice(), CustomPointTypeSmall::layout());
2241
2242        assert!(vector_buffer.as_interleaved().is_some());
2243        assert!(vector_buffer.slice(0..0).as_interleaved().is_some());
2244        assert!(vector_buffer.slice_mut(0..0).as_interleaved().is_some());
2245        assert!(hashmap_buffer.as_interleaved().is_none());
2246        assert!(hashmap_buffer.slice(0..0).as_interleaved().is_none());
2247        assert!(hashmap_buffer.slice_mut(0..0).as_interleaved().is_none());
2248        assert!(external_memory_buffer.as_interleaved().is_some());
2249        assert!(external_memory_buffer
2250            .slice(0..0)
2251            .as_interleaved()
2252            .is_some());
2253        assert!(external_memory_buffer
2254            .slice_mut(0..0)
2255            .as_interleaved()
2256            .is_some());
2257
2258        assert!(vector_buffer.as_interleaved_mut().is_some());
2259        assert!(vector_buffer.slice_mut(0..0).as_interleaved_mut().is_some());
2260        assert!(hashmap_buffer.as_interleaved_mut().is_none());
2261        assert!(hashmap_buffer
2262            .slice_mut(0..0)
2263            .as_interleaved_mut()
2264            .is_none());
2265        assert!(external_memory_buffer.as_interleaved_mut().is_some());
2266        assert!(external_memory_buffer
2267            .slice_mut(0..0)
2268            .as_interleaved_mut()
2269            .is_some());
2270
2271        assert!(vector_buffer.as_columnar().is_none());
2272        assert!(vector_buffer.slice(0..0).as_columnar().is_none());
2273        assert!(vector_buffer.slice_mut(0..0).as_columnar().is_none());
2274        assert!(hashmap_buffer.as_columnar().is_some());
2275        assert!(hashmap_buffer.slice(0..0).as_columnar().is_some());
2276        assert!(hashmap_buffer.slice_mut(0..0).as_columnar().is_some());
2277        assert!(external_memory_buffer.as_columnar().is_none());
2278        assert!(external_memory_buffer.slice(0..0).as_columnar().is_none());
2279        assert!(external_memory_buffer
2280            .slice_mut(0..0)
2281            .as_columnar()
2282            .is_none());
2283
2284        assert!(vector_buffer.as_columnar_mut().is_none());
2285        assert!(vector_buffer.slice_mut(0..0).as_columnar_mut().is_none());
2286        assert!(hashmap_buffer.as_columnar_mut().is_some());
2287        assert!(hashmap_buffer.slice_mut(0..0).as_columnar_mut().is_some());
2288        assert!(external_memory_buffer.as_columnar_mut().is_none());
2289        assert!(external_memory_buffer
2290            .slice_mut(0..0)
2291            .as_columnar_mut()
2292            .is_none());
2293    }
2294
2295    #[test]
2296    fn test_hash_map_buffer_filter() {
2297        const COUNT: usize = 16;
2298        let test_data: Vec<CustomPointTypeBig> = thread_rng()
2299            .sample_iter(DefaultPointDistribution)
2300            .take(COUNT)
2301            .collect();
2302        let even_points = test_data
2303            .iter()
2304            .enumerate()
2305            .filter_map(
2306                |(idx, point)| {
2307                    if idx % 2 == 0 {
2308                        Some(*point)
2309                    } else {
2310                        None
2311                    }
2312                },
2313            )
2314            .collect_vec();
2315
2316        let src_buffer = test_data.iter().copied().collect::<HashMapBuffer>();
2317
2318        let even_points_columnar = src_buffer.filter::<HashMapBuffer, _>(|idx| idx % 2 == 0);
2319        assert_eq!(
2320            even_points_columnar,
2321            even_points.iter().copied().collect::<HashMapBuffer>()
2322        );
2323
2324        let even_points_interleaved = src_buffer.filter::<VectorBuffer, _>(|idx| idx % 2 == 0);
2325        assert_eq!(
2326            even_points_interleaved,
2327            even_points.iter().copied().collect::<VectorBuffer>()
2328        );
2329    }
2330}