1use anyhow::{anyhow, Result};
2use std::{cell::RefCell, marker::PhantomData};
3
4use crate::layout::{
5 conversion::{convert_unit, get_converter_for_attributes, AttributeConversionFn},
6 PointAttributeDefinition, PointAttributeMember, PointType, PrimitiveType,
7};
8
9use super::{
10 attribute_iterators::{
11 AttributeIteratorByMut, AttributeIteratorByRef, AttributeIteratorByValue,
12 },
13 point_buffer::{
14 BorrowedBuffer, BorrowedMutBuffer, ColumnarBuffer, ColumnarBufferMut, InterleavedBuffer,
15 InterleavedBufferMut,
16 },
17 point_iterators::{PointIteratorByMut, PointIteratorByRef, PointIteratorByValue},
18 OwningBuffer,
19};
20
21#[derive(Debug, Copy, Clone)]
36pub struct PointView<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PointType>
37where
38 'a: 'b,
39{
40 buffer: &'b B,
41 _phantom: PhantomData<&'a T>,
42}
43
44impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PointType> PointView<'a, 'b, B, T>
45where
46 'a: 'b,
47{
48 pub(crate) fn new(buffer: &'b B) -> Self {
49 assert_eq!(
50 T::layout(),
51 *buffer.point_layout(),
52 "Layout mismatch\nBuffer layout:\n{}\nRequested layout:\n{}",
53 buffer.point_layout(),
54 T::layout()
55 );
56 Self {
57 buffer,
58 _phantom: Default::default(),
59 }
60 }
61
62 pub fn at(&self, index: usize) -> T {
68 let mut point = T::zeroed();
69 self.buffer
70 .get_point(index, bytemuck::bytes_of_mut(&mut point));
71 point
72 }
73}
74
75impl<'a, 'b, B: InterleavedBuffer<'a> + ?Sized, T: PointType> PointView<'a, 'b, B, T>
76where
77 'a: 'b,
78{
79 pub fn at_ref<'c>(&'c self, index: usize) -> &'c T
92 where
93 'b: 'c,
94 {
95 bytemuck::from_bytes(self.buffer.get_point_ref(index))
96 }
97
98 pub fn iter<'c>(&'c self) -> PointIteratorByRef<'c, T>
100 where
101 'b: 'c,
102 {
103 self.buffer.into()
104 }
105}
106
107impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized + 'a, T: PointType> IntoIterator
108 for PointView<'a, 'b, B, T>
109where
110 'a: 'b,
111{
112 type Item = T;
113 type IntoIter = PointIteratorByValue<'a, 'b, T, B>;
114
115 fn into_iter(self) -> Self::IntoIter {
116 self.buffer.into()
117 }
118}
119
120impl<
121 'a,
122 'b,
123 'c,
124 'd,
125 B1: BorrowedBuffer<'a> + ?Sized + 'a,
126 B2: BorrowedBuffer<'c> + ?Sized + 'c,
127 T: PointType + PartialEq,
128 > PartialEq<PointView<'c, 'd, B2, T>> for PointView<'a, 'b, B1, T>
129{
130 fn eq(&self, other: &PointView<'c, 'd, B2, T>) -> bool {
131 if self.buffer.len() != other.buffer.len() {
132 false
133 } else {
134 (0..self.buffer.len()).all(|idx| self.at(idx) == other.at(idx))
135 }
136 }
137}
138
139impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized + 'a, T: PointType + Eq> Eq
140 for PointView<'a, 'b, B, T>
141{
142}
143
144#[derive(Debug)]
148pub struct PointViewMut<'a, 'b, B: BorrowedMutBuffer<'a> + ?Sized, T: PointType>
149where
150 'a: 'b,
151{
152 buffer: &'b mut B,
153 _phantom: PhantomData<&'a T>,
154}
155
156impl<'a, 'b, B: BorrowedMutBuffer<'a> + ?Sized, T: PointType> PointViewMut<'a, 'b, B, T> {
157 pub(crate) fn new(buffer: &'b mut B) -> Self {
158 assert_eq!(
159 T::layout(),
160 *buffer.point_layout(),
161 "Layout mismatch\nBuffer layout:\n{}\nRequested layout:\n{}",
162 buffer.point_layout(),
163 T::layout()
164 );
165 Self {
166 buffer,
167 _phantom: Default::default(),
168 }
169 }
170
171 pub fn at(&self, index: usize) -> T {
177 let mut point = T::zeroed();
178 self.buffer
179 .get_point(index, bytemuck::bytes_of_mut(&mut point));
180 point
181 }
182
183 pub fn set_at(&mut self, index: usize, point: T) {
189 unsafe {
191 self.buffer.set_point(index, bytemuck::bytes_of(&point));
192 }
193 }
194}
195
196impl<'a, 'b, B: InterleavedBuffer<'a> + BorrowedMutBuffer<'a> + ?Sized, T: PointType>
197 PointViewMut<'a, 'b, B, T>
198{
199 pub fn at_ref<'c>(&'c self, index: usize) -> &'c T
205 where
206 'b: 'c,
207 {
208 bytemuck::from_bytes(self.buffer.get_point_ref(index))
209 }
210
211 pub fn iter<'c>(&'c self) -> PointIteratorByRef<'c, T>
213 where
214 'b: 'c,
215 {
216 (&*self.buffer).into()
217 }
218}
219
220impl<'a, 'b, B: InterleavedBufferMut<'a> + ?Sized, T: PointType> PointViewMut<'a, 'b, B, T> {
221 pub fn at_mut<'c>(&'c mut self, index: usize) -> &'c mut T
227 where
228 'b: 'c,
229 {
230 bytemuck::from_bytes_mut(self.buffer.get_point_mut(index))
231 }
232
233 pub fn iter_mut<'c>(&'c mut self) -> PointIteratorByMut<'c, T>
235 where
236 'b: 'c,
237 {
238 self.buffer.into()
239 }
240
241 pub fn sort_by<F: Fn(&T, &T) -> std::cmp::Ordering>(&mut self, comparator: F) {
243 let typed_points: &mut [T] =
244 bytemuck::cast_slice_mut(self.buffer.get_point_range_mut(0..self.buffer.len()));
245 typed_points.sort_by(comparator);
246 }
247}
248
249impl<'a, 'b, B: OwningBuffer<'a> + ?Sized, T: PointType> PointViewMut<'a, 'b, B, T> {
250 pub fn push_point(&mut self, point: T) {
252 unsafe {
255 self.buffer.push_points(bytemuck::bytes_of(&point));
256 }
257 }
258}
259
260impl<
261 'a,
262 'b,
263 'c,
264 'd,
265 B1: BorrowedMutBuffer<'a> + ?Sized + 'a,
266 B2: BorrowedMutBuffer<'c> + ?Sized + 'c,
267 T: PointType + PartialEq,
268 > PartialEq<PointViewMut<'c, 'd, B2, T>> for PointViewMut<'a, 'b, B1, T>
269{
270 fn eq(&self, other: &PointViewMut<'c, 'd, B2, T>) -> bool {
271 if self.buffer.len() != other.buffer.len() {
272 false
273 } else {
274 (0..self.buffer.len()).all(|idx| self.at(idx) == other.at(idx))
275 }
276 }
277}
278
279impl<'a, 'b, B: BorrowedMutBuffer<'a> + ?Sized + 'a, T: PointType + Eq> Eq
280 for PointViewMut<'a, 'b, B, T>
281{
282}
283
284#[derive(Debug, Copy, Clone)]
291pub struct AttributeView<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType>
292where
293 'a: 'b,
294{
295 buffer: &'b B,
296 attribute: &'b PointAttributeMember,
297 _phantom: PhantomData<&'a T>,
298}
299
300impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType> AttributeView<'a, 'b, B, T> {
301 pub(crate) fn new(buffer: &'b B, attribute: &PointAttributeDefinition) -> Self {
302 assert_eq!(T::data_type(), attribute.datatype());
303 Self {
304 attribute: buffer
305 .point_layout()
306 .get_attribute(attribute)
307 .expect("Attribute not found in PointLayout of buffer"),
308 buffer,
309 _phantom: Default::default(),
310 }
311 }
312
313 pub fn at(&self, index: usize) -> T {
319 let mut attribute = T::zeroed();
320 unsafe {
322 self.buffer.get_attribute_unchecked(
323 self.attribute,
324 index,
325 bytemuck::bytes_of_mut(&mut attribute),
326 );
327 }
328 attribute
329 }
330}
331
332impl<'a, 'b, B: ColumnarBuffer<'a> + ?Sized, T: PrimitiveType> AttributeView<'a, 'b, B, T>
333where
334 'a: 'b,
335{
336 pub fn at_ref<'c>(&'c self, index: usize) -> &'c T
342 where
343 'b: 'c,
344 {
345 bytemuck::from_bytes(
346 self.buffer
347 .get_attribute_ref(self.attribute.attribute_definition(), index),
348 )
349 }
350
351 pub fn iter<'c>(&'c self) -> AttributeIteratorByRef<'c, T>
353 where
354 'b: 'c,
355 {
356 AttributeIteratorByRef::new(self.buffer, self.attribute.attribute_definition())
357 }
358}
359
360impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized + 'a, T: PrimitiveType> IntoIterator
361 for AttributeView<'a, 'b, B, T>
362{
363 type Item = T;
364 type IntoIter = AttributeIteratorByValue<'a, 'b, T, B>;
365
366 fn into_iter(self) -> Self::IntoIter {
367 AttributeIteratorByValue::new(self.buffer, self.attribute.attribute_definition())
368 }
369}
370
371impl<
372 'a,
373 'b,
374 'c,
375 'd,
376 B1: BorrowedBuffer<'a> + ?Sized + 'a,
377 B2: BorrowedBuffer<'c> + ?Sized + 'c,
378 T: PrimitiveType + PartialEq,
379 > PartialEq<AttributeView<'c, 'd, B2, T>> for AttributeView<'a, 'b, B1, T>
380{
381 fn eq(&self, other: &AttributeView<'c, 'd, B2, T>) -> bool {
382 self.buffer.len() == other.buffer.len()
383 && self.attribute.attribute_definition() == other.attribute.attribute_definition()
384 && (0..self.buffer.len()).all(|idx| self.at(idx) == other.at(idx))
385 }
386}
387
388impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized + 'a, T: PrimitiveType + Eq> Eq
389 for AttributeView<'a, 'b, B, T>
390{
391}
392
393#[derive(Debug)]
395pub struct AttributeViewMut<'a, 'b, B: BorrowedMutBuffer<'a> + ?Sized, T: PrimitiveType>
396where
397 'a: 'b,
398{
399 buffer: &'b mut B,
400 attribute: PointAttributeMember,
401 _phantom: PhantomData<&'a T>,
402}
403
404impl<'a, 'b, B: BorrowedMutBuffer<'a> + ?Sized, T: PrimitiveType> AttributeViewMut<'a, 'b, B, T>
405where
406 'a: 'b,
407{
408 pub(crate) fn new(buffer: &'b mut B, attribute: &PointAttributeDefinition) -> Self {
409 assert_eq!(T::data_type(), attribute.datatype());
410 Self {
411 attribute: buffer
412 .point_layout()
413 .get_attribute(attribute)
414 .expect("Attribute not found in PointLayout of buffer")
415 .clone(),
416 buffer,
417 _phantom: Default::default(),
418 }
419 }
420
421 pub fn at(&self, index: usize) -> T {
427 let mut attribute = T::zeroed();
428 unsafe {
430 self.buffer.get_attribute_unchecked(
431 &self.attribute,
432 index,
433 bytemuck::bytes_of_mut(&mut attribute),
434 );
435 }
436 attribute
437 }
438
439 pub fn set_at(&mut self, index: usize, attribute_value: T) {
445 unsafe {
447 self.buffer.set_attribute(
448 self.attribute.attribute_definition(),
449 index,
450 bytemuck::bytes_of(&attribute_value),
451 );
452 }
453 }
454}
455
456impl<'a, 'b, B: ColumnarBuffer<'a> + BorrowedMutBuffer<'a> + ?Sized, T: PrimitiveType>
457 AttributeViewMut<'a, 'b, B, T>
458where
459 'a: 'b,
460{
461 pub fn at_ref<'c>(&'c self, index: usize) -> &'c T
467 where
468 'b: 'c,
469 {
470 bytemuck::from_bytes(
471 self.buffer
472 .get_attribute_ref(self.attribute.attribute_definition(), index),
473 )
474 }
475
476 pub fn iter<'c>(&'c self) -> AttributeIteratorByRef<'c, T>
478 where
479 'b: 'c,
480 {
481 AttributeIteratorByRef::new(self.buffer, self.attribute.attribute_definition())
482 }
483}
484
485impl<'a, 'b, B: ColumnarBufferMut<'a> + BorrowedMutBuffer<'a> + ?Sized, T: PrimitiveType>
486 AttributeViewMut<'a, 'b, B, T>
487{
488 pub fn at_mut(&'b mut self, index: usize) -> &'b mut T {
494 bytemuck::from_bytes_mut(
495 self.buffer
496 .get_attribute_mut(self.attribute.attribute_definition(), index),
497 )
498 }
499
500 pub fn iter_mut(&'b mut self) -> AttributeIteratorByMut<'b, T> {
502 AttributeIteratorByMut::new(self.buffer, self.attribute.attribute_definition())
503 }
504}
505
506impl<
507 'a,
508 'b,
509 'c,
510 'd,
511 B1: BorrowedMutBuffer<'a> + ?Sized + 'a,
512 B2: BorrowedMutBuffer<'c> + ?Sized + 'c,
513 T: PrimitiveType + PartialEq,
514 > PartialEq<AttributeViewMut<'c, 'd, B2, T>> for AttributeViewMut<'a, 'b, B1, T>
515{
516 fn eq(&self, other: &AttributeViewMut<'c, 'd, B2, T>) -> bool {
517 self.buffer.len() == other.buffer.len()
518 && self.attribute.attribute_definition() == other.attribute.attribute_definition()
519 && (0..self.buffer.len()).all(|idx| self.at(idx) == other.at(idx))
520 }
521}
522
523impl<'a, 'b, B: BorrowedMutBuffer<'a> + ?Sized + 'a, T: PrimitiveType + Eq> Eq
524 for AttributeViewMut<'a, 'b, B, T>
525{
526}
527
528#[derive(Debug)]
533pub struct AttributeViewConverting<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType>
534where
535 'a: 'b,
536{
537 buffer: &'b B,
538 attribute: PointAttributeMember,
539 converter_fn: AttributeConversionFn,
540 converter_buffer: RefCell<Vec<u8>>,
541 _phantom: PhantomData<&'a T>,
542}
543
544impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType>
545 AttributeViewConverting<'a, 'b, B, T>
546{
547 pub(crate) fn new(buffer: &'b B, attribute: &PointAttributeDefinition) -> Result<Self> {
548 assert_eq!(T::data_type(), attribute.datatype());
549 let attribute_in_layout: &PointAttributeMember = buffer
550 .point_layout()
551 .get_attribute_by_name(attribute.name())
552 .expect("Attribute not found in PointLayout of buffer");
553 let converter_fn = if attribute_in_layout.datatype() == T::data_type() {
554 convert_unit
555 } else {
556 get_converter_for_attributes(
557 attribute_in_layout.attribute_definition(),
558 &attribute.with_custom_datatype(T::data_type()),
559 )
560 .ok_or(anyhow!("Conversion between attribute types is impossible"))?
561 };
562 let converter_buffer = vec![0; attribute_in_layout.size() as usize];
563 Ok(Self {
564 attribute: attribute_in_layout.clone(),
565 buffer,
566 converter_fn,
567 converter_buffer: RefCell::new(converter_buffer),
568 _phantom: Default::default(),
569 })
570 }
571
572 pub fn at(&self, index: usize) -> T {
574 let mut value = T::zeroed();
575 unsafe {
578 self.buffer.get_attribute_unchecked(
579 &self.attribute,
580 index,
581 self.converter_buffer.borrow_mut().as_mut_slice(),
582 );
583 (self.converter_fn)(
584 self.converter_buffer.borrow().as_slice(),
585 bytemuck::bytes_of_mut(&mut value),
586 );
587 }
588 value
589 }
590}
591
592impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType> IntoIterator
593 for AttributeViewConverting<'a, 'b, B, T>
594{
595 type Item = T;
596 type IntoIter = AttributeViewConvertingIterator<'a, 'b, B, T>;
597
598 fn into_iter(self) -> Self::IntoIter {
599 AttributeViewConvertingIterator {
600 current_index: 0,
601 view: self,
602 }
603 }
604}
605
606impl<
607 'a,
608 'b,
609 'c,
610 'd,
611 B1: BorrowedBuffer<'a> + ?Sized + 'a,
612 B2: BorrowedBuffer<'c> + ?Sized + 'c,
613 T: PrimitiveType + PartialEq,
614 > PartialEq<AttributeViewConverting<'c, 'd, B2, T>> for AttributeViewConverting<'a, 'b, B1, T>
615{
616 fn eq(&self, other: &AttributeViewConverting<'c, 'd, B2, T>) -> bool {
617 self.buffer.len() == other.buffer.len()
618 && self.attribute.attribute_definition() == other.attribute.attribute_definition()
619 && (0..self.buffer.len()).all(|idx| self.at(idx) == other.at(idx))
620 }
621}
622
623impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized + 'a, T: PrimitiveType + Eq> Eq
624 for AttributeViewConverting<'a, 'b, B, T>
625{
626}
627
628pub struct AttributeViewConvertingIterator<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType>
631{
632 view: AttributeViewConverting<'a, 'b, B, T>,
633 current_index: usize,
634}
635
636impl<'a, 'b, B: BorrowedBuffer<'a> + ?Sized, T: PrimitiveType> Iterator
637 for AttributeViewConvertingIterator<'a, 'b, B, T>
638{
639 type Item = T;
640
641 fn next(&mut self) -> Option<Self::Item> {
642 if self.current_index == self.view.buffer.len() {
643 None
644 } else {
645 let ret = self.view.at(self.current_index);
646 self.current_index += 1;
647 Some(ret)
648 }
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use nalgebra::Vector3;
655 use rand::{thread_rng, Rng};
656
657 use crate::{
658 containers::{BorrowedBufferExt, BorrowedMutBufferExt, HashMapBuffer, VectorBuffer},
659 layout::{attributes::POSITION_3D, PointAttributeDataType},
660 test_utils::*,
661 };
662
663 #[test]
664 fn test_sort_buffer() {
665 let rng = thread_rng();
666 let mut test_points = rng
667 .sample_iter::<CustomPointTypeSmall, _>(DefaultPointDistribution)
668 .take(10)
669 .collect::<VectorBuffer>();
670
671 test_points
672 .view_mut::<CustomPointTypeSmall>()
673 .sort_by(|a, b| a.classification.cmp(&b.classification));
674
675 let points = test_points
676 .view::<CustomPointTypeSmall>()
677 .into_iter()
678 .collect::<Vec<_>>();
679 let are_sorted = points
680 .iter()
681 .zip(points.iter().skip(1))
682 .all(|(low, high)| low.classification <= high.classification);
683 assert!(are_sorted, "Points not sorted: {:#?}", test_points);
684 }
685
686 #[test]
687 fn test_point_views_eq() {
688 let rng = thread_rng();
689 let test_points = rng
690 .sample_iter::<CustomPointTypeSmall, _>(DefaultPointDistribution)
691 .take(10)
692 .collect::<Vec<_>>();
693
694 let mut buffer1 = test_points.iter().copied().collect::<VectorBuffer>();
695 let mut buffer2 = test_points.iter().copied().collect::<HashMapBuffer>();
696
697 assert_eq!(
698 buffer1.view::<CustomPointTypeSmall>(),
699 buffer2.view::<CustomPointTypeSmall>()
700 );
701 assert_eq!(
702 buffer1.view_mut::<CustomPointTypeSmall>(),
703 buffer2.view_mut::<CustomPointTypeSmall>()
704 );
705
706 buffer2 = thread_rng()
707 .sample_iter::<CustomPointTypeSmall, _>(DefaultPointDistribution)
708 .take(10)
709 .collect();
710 assert_ne!(
711 buffer1.view::<CustomPointTypeSmall>(),
712 buffer2.view::<CustomPointTypeSmall>()
713 );
714 assert_ne!(
715 buffer1.view_mut::<CustomPointTypeSmall>(),
716 buffer2.view_mut::<CustomPointTypeSmall>()
717 );
718 }
719
720 #[test]
721 fn test_attribute_views_eq() {
722 let rng = thread_rng();
723 let test_points = rng
724 .sample_iter::<CustomPointTypeSmall, _>(DefaultPointDistribution)
725 .take(10)
726 .collect::<Vec<_>>();
727
728 let mut buffer1 = test_points.iter().copied().collect::<VectorBuffer>();
729 let mut buffer2 = test_points.iter().copied().collect::<HashMapBuffer>();
730
731 assert_eq!(
732 buffer1.view_attribute::<Vector3<f64>>(&POSITION_3D),
733 buffer2.view_attribute::<Vector3<f64>>(&POSITION_3D),
734 );
735 assert_eq!(
736 buffer1.view_attribute_mut::<Vector3<f64>>(&POSITION_3D),
737 buffer2.view_attribute_mut::<Vector3<f64>>(&POSITION_3D),
738 );
739 let f32_position = POSITION_3D.with_custom_datatype(PointAttributeDataType::Vec3f32);
740 assert_eq!(
741 buffer1
742 .view_attribute_with_conversion::<Vector3<f32>>(&f32_position)
743 .expect("Invalid attribute conversion"),
744 buffer2
745 .view_attribute_with_conversion::<Vector3<f32>>(&f32_position)
746 .expect("Invalid attribute conversion"),
747 );
748
749 buffer2 = thread_rng()
750 .sample_iter::<CustomPointTypeSmall, _>(DefaultPointDistribution)
751 .take(10)
752 .collect();
753
754 assert_ne!(
755 buffer1.view_attribute::<Vector3<f64>>(&POSITION_3D),
756 buffer2.view_attribute::<Vector3<f64>>(&POSITION_3D),
757 );
758 assert_ne!(
759 buffer1.view_attribute_mut::<Vector3<f64>>(&POSITION_3D),
760 buffer2.view_attribute_mut::<Vector3<f64>>(&POSITION_3D),
761 );
762 assert_ne!(
763 buffer1
764 .view_attribute_with_conversion::<Vector3<f32>>(&f32_position)
765 .expect("Invalid attribute conversion"),
766 buffer2
767 .view_attribute_with_conversion::<Vector3<f32>>(&f32_position)
768 .expect("Invalid attribute conversion"),
769 );
770 }
771}