1use core::{borrow, cell, cmp, mem, ops, sync::atomic};
5
6use alloc::borrow::ToOwned;
7use alloc::rc::Rc;
8use alloc::sync::Arc;
9use alloc::vec::Vec;
10
11use crate::rec::TexelBuffer;
12use crate::texel::{constants::MAX, AtomicPart, MaxAligned, MaxAtomic, MaxCell, Texel, MAX_ALIGN};
13
14#[derive(Clone, Default)]
28pub struct Buffer {
29 inner: Vec<MaxAligned>,
31}
32
33#[derive(Clone, Default)]
47pub struct AtomicBuffer {
48 inner: Arc<[MaxAtomic]>,
50}
51
52#[derive(Clone, Default)]
66pub struct CellBuffer {
67 inner: Rc<[MaxCell]>,
69}
70
71#[repr(transparent)]
78#[allow(non_camel_case_types)]
79pub struct buf([u8]);
80
81#[repr(transparent)]
95#[allow(non_camel_case_types)]
96pub struct atomic_buf(pub(crate) [AtomicPart]);
97
98#[repr(transparent)]
105#[allow(non_camel_case_types)]
106pub struct cell_buf(cell::Cell<[u8]>);
107
108pub struct AtomicSliceRef<'lt, P = u8> {
125 pub(crate) buf: &'lt atomic_buf,
130 pub(crate) texel: Texel<P>,
132 pub(crate) start: usize,
136 pub(crate) end: usize,
138}
139
140pub struct AtomicRef<'lt, P = u8> {
147 pub(crate) buf: &'lt atomic_buf,
148 pub(crate) texel: Texel<P>,
150 pub(crate) start: usize,
152}
153
154impl Buffer {
155 const ELEMENT: MaxAligned = MaxAligned([0; MAX_ALIGN]);
156
157 pub fn as_buf(&self) -> &buf {
158 buf::new(self.inner.as_slice())
159 }
160
161 pub fn as_buf_mut(&mut self) -> &mut buf {
162 buf::new_mut(self.inner.as_mut_slice())
163 }
164
165 pub fn new(length: usize) -> Self {
169 let alloc_len = Self::alloc_len(length);
170 let inner = alloc::vec![Self::ELEMENT; alloc_len];
171
172 Buffer { inner }
173 }
174
175 pub fn capacity(&self) -> usize {
177 self.inner.capacity() * mem::size_of::<MaxAligned>()
178 }
179
180 pub fn grow_to(&mut self, bytes: usize) {
186 let new_len = Self::alloc_len(bytes);
187 if self.inner.len() < new_len {
188 self.inner.resize(new_len, Self::ELEMENT);
189 }
190 }
191
192 pub fn resize_to(&mut self, bytes: usize) {
196 let new_len = Self::alloc_len(bytes);
197 self.inner.resize(new_len, Self::ELEMENT);
198 self.inner.shrink_to_fit()
199 }
200
201 fn alloc_len(length: usize) -> usize {
203 const CHUNK_SIZE: usize = mem::size_of::<MaxAligned>();
204 assert!(CHUNK_SIZE > 1);
205
206 length / CHUNK_SIZE + usize::from(length % CHUNK_SIZE != 0)
208 }
209}
210
211impl CellBuffer {
212 const ELEMENT: MaxCell = MaxCell::zero();
213
214 pub fn new(length: usize) -> Self {
218 let alloc_len = Buffer::alloc_len(length);
219 let inner: Vec<_> = (0..alloc_len).map(|_| Self::ELEMENT).collect();
220
221 CellBuffer {
222 inner: inner.into(),
223 }
224 }
225
226 pub fn with_buffer(buffer: Buffer) -> Self {
233 let inner: Vec<_> = buffer.inner.into_iter().map(MaxCell::new).collect();
234
235 CellBuffer {
236 inner: inner.into(),
237 }
238 }
239
240 pub fn ptr_eq(&self, other: &Self) -> bool {
242 Rc::ptr_eq(&self.inner, &other.inner)
243 }
244
245 pub fn capacity(&self) -> usize {
247 core::mem::size_of_val(&*self.inner)
248 }
249
250 pub fn get_mut(&mut self) -> Option<&mut cell_buf> {
261 Rc::get_mut(&mut self.inner).map(cell_buf::from_slice_mut)
262 }
263
264 pub fn make_mut(&mut self) -> &mut cell_buf {
280 if Rc::get_mut(&mut self.inner).is_none() {
281 *self = self.to_owned().into();
282 }
283
284 Rc::get_mut(&mut self.inner)
285 .map(cell_buf::from_slice_mut)
286 .expect("we just made a mutable copy")
287 }
288
289 pub fn to_owned(&self) -> Buffer {
291 let inner = self.inner.iter().map(|cell| cell.get()).collect();
292
293 Buffer { inner }
294 }
295
296 pub fn to_resized(&self, bytes: usize) -> Self {
301 let mut working_copy = self.to_owned();
302 working_copy.resize_to(bytes);
303 Self::with_buffer(working_copy)
304 }
305}
306
307impl AtomicBuffer {
308 const ELEMENT: MaxAtomic = MaxAtomic::zero();
309
310 pub fn new(length: usize) -> Self {
314 let alloc_len = Buffer::alloc_len(length);
315 let inner: Vec<_> = (0..alloc_len).map(|_| Self::ELEMENT).collect();
316
317 AtomicBuffer {
318 inner: inner.into(),
319 }
320 }
321
322 pub fn with_buffer(buffer: Buffer) -> Self {
329 let inner: Vec<_> = buffer.inner.into_iter().map(MaxAtomic::new).collect();
330
331 AtomicBuffer {
332 inner: inner.into(),
333 }
334 }
335
336 pub fn ptr_eq(&self, other: &Self) -> bool {
338 Arc::ptr_eq(&self.inner, &other.inner)
339 }
340
341 pub fn capacity(&self) -> usize {
343 core::mem::size_of_val(&*self.inner)
344 }
345
346 pub fn get_mut(&mut self) -> Option<&mut atomic_buf> {
357 Arc::get_mut(&mut self.inner).map(atomic_buf::from_slice_mut)
358 }
359
360 pub fn make_mut(&mut self) -> &mut atomic_buf {
376 if Arc::get_mut(&mut self.inner).is_none() {
377 *self = self.to_owned().into();
378 }
379
380 Arc::get_mut(&mut self.inner)
381 .map(atomic_buf::from_slice_mut)
382 .expect("we just made a mutable copy")
383 }
384
385 pub fn to_owned(&self) -> Buffer {
391 let inner = self
392 .inner
393 .iter()
394 .map(|cell| cell.load(atomic::Ordering::Relaxed))
395 .collect();
396
397 Buffer { inner }
398 }
399
400 pub fn to_resized(&self, bytes: usize) -> Self {
405 let mut working_copy = self.to_owned();
406 working_copy.resize_to(bytes);
407 Self::with_buffer(working_copy)
408 }
409}
410
411impl buf {
412 pub fn new<T>(data: &T) -> &Self
416 where
417 T: AsRef<[MaxAligned]> + ?Sized,
418 {
419 let bytes = MAX.to_bytes(data.as_ref());
420 Self::from_bytes(bytes).unwrap()
421 }
422
423 pub fn new_mut<T>(data: &mut T) -> &mut Self
427 where
428 T: AsMut<[MaxAligned]> + ?Sized,
429 {
430 let bytes = MAX.to_mut_bytes(data.as_mut());
431 Self::from_bytes_mut(bytes).unwrap()
432 }
433
434 #[must_use = "Does not mutate self"]
436 #[track_caller]
437 pub fn truncate(&self, at: usize) -> &Self {
438 Self::from_bytes(&self.as_bytes()[..at]).unwrap()
439 }
440
441 #[must_use = "Does not mutate self"]
443 #[track_caller]
444 pub fn truncate_mut(&mut self, at: usize) -> &mut Self {
445 Self::from_bytes_mut(&mut self.as_bytes_mut()[..at]).unwrap()
446 }
447
448 pub fn as_bytes(&self) -> &[u8] {
449 &self.0
450 }
451
452 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
453 &mut self.0
454 }
455
456 #[track_caller]
458 pub fn split_at(&self, at: usize) -> (&Self, &Self) {
459 assert!(at % MAX_ALIGN == 0);
460 let (a, b) = self.0.split_at(at);
461 let a = MAX.try_to_slice(a).expect("was previously aligned");
462 let b = MAX.try_to_slice(b).expect("asserted to be aligned");
463 (Self::new(a), Self::new(b))
464 }
465
466 pub(crate) fn take_at_mut<'a>(this: &mut &'a mut Self, at: usize) -> &'a mut Self {
468 let (pre, post) = buf::split_at_mut(core::mem::take(this), at);
469 *this = pre;
470 post
471 }
472
473 pub fn split_at_mut(&mut self, at: usize) -> (&mut Self, &mut Self) {
475 assert!(at % MAX_ALIGN == 0);
476 let (a, b) = self.0.split_at_mut(at);
477 let a = MAX.try_to_slice_mut(a).expect("was previously aligned");
478 let b = MAX.try_to_slice_mut(b).expect("asserted to be aligned");
479 (Self::new_mut(a), Self::new_mut(b))
480 }
481
482 pub fn as_texels<P>(&self, pixel: Texel<P>) -> &[P] {
488 pixel.cast_buf(self)
489 }
490
491 pub fn as_mut_texels<P>(&mut self, pixel: Texel<P>) -> &mut [P] {
497 pixel.cast_mut_buf(self)
498 }
499
500 pub fn map_within<P, Q>(
515 &mut self,
516 src: impl ops::RangeBounds<usize>,
517 dest: usize,
518 f: impl Fn(P) -> Q,
519 p: Texel<P>,
520 q: Texel<Q>,
521 ) {
522 TexelMappingBuffer::map_within(self, src, dest, f, p, q)
523 }
524}
525
526impl TexelMappingBuffer for buf {
527 fn map_forward<P, Q>(
529 &mut self,
530 src: usize,
531 dest: usize,
532 len: usize,
533 f: impl Fn(P) -> Q,
534 p: Texel<P>,
535 q: Texel<Q>,
536 ) {
537 for idx in 0..len {
538 let source_idx = idx + src;
539 let target_idx = idx + dest;
540 let source = p.copy_val(&self.as_texels(p)[source_idx]);
541 let target = f(source);
542 self.as_mut_texels(q)[target_idx] = target;
543 }
544 }
545
546 fn map_backward<P, Q>(
548 &mut self,
549 src: usize,
550 dest: usize,
551 len: usize,
552 f: impl Fn(P) -> Q,
553 p: Texel<P>,
554 q: Texel<Q>,
555 ) {
556 for idx in (0..len).rev() {
557 let source_idx = idx + src;
558 let target_idx = idx + dest;
559 let source = p.copy_val(&self.as_texels(p)[source_idx]);
560 let target = f(source);
561 self.as_mut_texels(q)[target_idx] = target;
562 }
563 }
564
565 fn texel_len<P>(&self, texel: Texel<P>) -> usize {
566 self.as_texels(texel).len()
567 }
568}
569
570trait TexelMappingBuffer {
572 fn map_forward<P, Q>(
573 &mut self,
574 src: usize,
575 dest: usize,
576 len: usize,
577 f: impl Fn(P) -> Q,
578 p: Texel<P>,
579 q: Texel<Q>,
580 );
581
582 fn map_backward<P, Q>(
583 &mut self,
584 src: usize,
585 dest: usize,
586 len: usize,
587 f: impl Fn(P) -> Q,
588 p: Texel<P>,
589 q: Texel<Q>,
590 );
591
592 fn texel_len<P>(&self, texel: Texel<P>) -> usize;
593
594 fn map_within<P, Q>(
595 &mut self,
596 src: impl ops::RangeBounds<usize>,
597 dest: usize,
598 f: impl Fn(P) -> Q,
599 p: Texel<P>,
600 q: Texel<Q>,
601 ) {
602 fn backwards_past_the_end(start_byte_diff: isize, size_diff: isize) -> Option<usize> {
649 assert!(size_diff >= 0);
650 if size_diff == 0 {
651 if start_byte_diff > 0 {
652 Some(0)
653 } else {
654 None
655 }
656 } else if start_byte_diff < 0 {
657 Some(0)
658 } else {
659 let floor = start_byte_diff / size_diff;
660 let ceil = (floor as usize) + usize::from(start_byte_diff % size_diff != 0);
661 Some(ceil)
662 }
663 }
664
665 let p_start = match src.start_bound() {
666 ops::Bound::Included(&bound) => bound,
667 ops::Bound::Excluded(&bound) => bound
668 .checked_add(1)
669 .expect("Range does not specify a valid bound start"),
670 ops::Bound::Unbounded => 0,
671 };
672
673 let p_end = match src.end_bound() {
674 ops::Bound::Excluded(&bound) => bound,
675 ops::Bound::Included(&bound) => bound
676 .checked_add(1)
677 .expect("Range does not specify a valid bound end"),
678 ops::Bound::Unbounded => self.texel_len(p),
679 };
680
681 let len = p_end.checked_sub(p_start).expect("Bound violates order");
682
683 let q_start = dest;
684
685 let _ = self
686 .texel_len(p)
687 .checked_sub(p_start)
688 .and_then(|slice| slice.checked_sub(len))
689 .expect("Source out of bounds");
690
691 let _ = self
692 .texel_len(q)
693 .checked_sub(q_start)
694 .and_then(|slice| slice.checked_sub(len))
695 .expect("Destination out of bounds");
696
697 assert!(p.size() as isize > 0);
699 assert!(q.size() as isize > 0);
700
701 if p.size() >= q.size() {
702 let start_diff = (q.size() * q_start).wrapping_sub(p.size() * p_start) as isize;
703 let size_diff = p.size() as isize - q.size() as isize;
704
705 let backwards_end = backwards_past_the_end(start_diff, size_diff)
706 .unwrap_or(len)
707 .min(len);
708
709 self.map_backward(p_start, q_start, backwards_end, &f, p, q);
710 self.map_forward(
711 p_start + backwards_end,
712 q_start + backwards_end,
713 len - backwards_end,
714 &f,
715 p,
716 q,
717 );
718 } else {
719 let start_diff = (p.size() * p_start).wrapping_sub(q.size() * q_start) as isize;
720 let size_diff = q.size() as isize - p.size() as isize;
721
722 let backwards_end = backwards_past_the_end(start_diff, size_diff)
723 .unwrap_or(len)
724 .min(len);
725
726 self.map_backward(
727 p_start + backwards_end,
728 q_start + backwards_end,
729 len - backwards_end,
730 &f,
731 p,
732 q,
733 );
734 self.map_forward(p_start, q_start, backwards_end, &f, p, q);
735 }
736 }
737}
738
739impl From<&'_ [u8]> for Buffer {
740 fn from(content: &'_ [u8]) -> Self {
741 let mut buffer = Buffer::new(content.len());
743 buffer[..content.len()].copy_from_slice(content);
744 buffer
745 }
746}
747
748impl From<&'_ [u8]> for AtomicBuffer {
749 fn from(values: &'_ [u8]) -> Self {
750 let chunks = values.chunks_exact(MAX_ALIGN);
751 let remainder = chunks.remainder();
752
753 let capacity = Buffer::alloc_len(values.len());
754 let mut buffer = Vec::with_capacity(capacity);
755
756 buffer.extend(chunks.map(|arr| {
757 let mut data = MaxAligned([0; MAX_ALIGN]);
758 data.0.copy_from_slice(arr);
759 MaxAtomic::new(data)
760 }));
761
762 if !remainder.is_empty() {
763 let mut data = MaxAligned([0; MAX_ALIGN]);
764 data.0[..remainder.len()].copy_from_slice(remainder);
765 buffer.push(MaxAtomic::new(data));
766 }
767
768 AtomicBuffer {
769 inner: buffer.into(),
770 }
771 }
772}
773
774impl From<Buffer> for AtomicBuffer {
775 fn from(values: Buffer) -> Self {
776 Self::from(values.as_bytes())
778 }
779}
780
781impl From<&'_ [u8]> for CellBuffer {
782 fn from(values: &'_ [u8]) -> Self {
783 let chunks = values.chunks_exact(MAX_ALIGN);
784 let remainder = chunks.remainder();
785
786 let capacity = Buffer::alloc_len(values.len());
787 let mut buffer = Vec::with_capacity(capacity);
788
789 buffer.extend(chunks.map(|arr| {
790 let mut data = [0; MAX_ALIGN];
791 data.copy_from_slice(arr);
792 MaxCell(cell::Cell::new(data))
793 }));
794
795 if !remainder.is_empty() {
796 let mut data = [0; MAX_ALIGN];
797 data[..remainder.len()].copy_from_slice(remainder);
798 buffer.push(MaxCell(cell::Cell::new(data)));
799 }
800
801 CellBuffer {
802 inner: buffer.into(),
803 }
804 }
805}
806
807impl From<Buffer> for CellBuffer {
808 fn from(values: Buffer) -> Self {
809 Self::from(values.as_bytes())
811 }
812}
813
814impl From<&'_ buf> for Buffer {
815 fn from(content: &'_ buf) -> Self {
816 content.to_owned()
817 }
818}
819
820impl Default for &'_ buf {
821 fn default() -> Self {
822 buf::new(&mut [])
823 }
824}
825
826impl Default for &'_ mut buf {
827 fn default() -> Self {
828 buf::new_mut(&mut [])
829 }
830}
831
832impl borrow::Borrow<buf> for Buffer {
833 fn borrow(&self) -> &buf {
834 &**self
835 }
836}
837
838impl borrow::BorrowMut<buf> for Buffer {
839 fn borrow_mut(&mut self) -> &mut buf {
840 &mut **self
841 }
842}
843
844impl alloc::borrow::ToOwned for buf {
845 type Owned = Buffer;
846 fn to_owned(&self) -> Buffer {
847 let mut buffer = Buffer::new(self.len());
848 buffer.as_bytes_mut().copy_from_slice(self);
849 buffer
850 }
851}
852
853impl ops::Deref for Buffer {
854 type Target = buf;
855
856 fn deref(&self) -> &buf {
857 self.as_buf()
858 }
859}
860
861impl ops::DerefMut for Buffer {
862 fn deref_mut(&mut self) -> &mut buf {
863 self.as_buf_mut()
864 }
865}
866
867impl ops::Deref for AtomicBuffer {
868 type Target = atomic_buf;
869
870 fn deref(&self) -> &atomic_buf {
871 atomic_buf::from_slice(&self.inner)
872 }
873}
874
875impl ops::Deref for CellBuffer {
876 type Target = cell_buf;
877
878 fn deref(&self) -> &cell_buf {
879 cell_buf::from_slice(&self.inner)
880 }
881}
882
883impl ops::Deref for buf {
884 type Target = [u8];
885
886 fn deref(&self) -> &[u8] {
887 self.as_bytes()
888 }
889}
890
891impl ops::DerefMut for buf {
892 fn deref_mut(&mut self) -> &mut [u8] {
893 self.as_bytes_mut()
894 }
895}
896
897impl cmp::PartialEq for buf {
898 fn eq(&self, other: &buf) -> bool {
899 self.as_bytes() == other.as_bytes()
900 }
901}
902
903impl cmp::Eq for buf {}
904
905impl cmp::PartialEq for Buffer {
906 fn eq(&self, other: &Buffer) -> bool {
907 self.as_bytes() == other.as_bytes()
908 }
909}
910
911impl cmp::Eq for Buffer {}
912
913impl ops::Index<ops::RangeTo<usize>> for buf {
914 type Output = buf;
915
916 fn index(&self, idx: ops::RangeTo<usize>) -> &buf {
917 self.truncate(idx.end)
918 }
919}
920
921impl ops::IndexMut<ops::RangeTo<usize>> for buf {
922 fn index_mut(&mut self, idx: ops::RangeTo<usize>) -> &mut buf {
923 self.truncate_mut(idx.end)
924 }
925}
926
927impl cell_buf {
928 pub fn new<T>(data: &T) -> &Self
932 where
933 T: AsRef<[MaxCell]> + ?Sized,
934 {
935 cell_buf::from_slice(data.as_ref())
936 }
937
938 pub fn len(&self) -> usize {
940 self.0.as_slice_of_cells().len()
941 }
942
943 #[must_use = "Does not mutate self"]
945 #[track_caller]
946 pub fn truncate(&self, at: usize) -> &Self {
947 Self::from_bytes(&self.0.as_slice_of_cells()[..at]).unwrap()
949 }
950
951 #[track_caller]
958 pub fn split_at(&self, at: usize) -> (&Self, &Self) {
959 assert!(at % MAX_ALIGN == 0);
960 let (a, b) = self.0.as_slice_of_cells().split_at(at);
961 let a = Self::from_bytes(a).expect("was previously aligned");
962 let b = Self::from_bytes(b).expect("asserted to be aligned");
963 (a, b)
964 }
965
966 pub fn as_texels<P>(&self, texel: Texel<P>) -> &cell::Cell<[P]> {
972 let slice = self.0.as_slice_of_cells();
973 texel
974 .try_to_cell(slice)
975 .expect("A cell_buf is always aligned")
976 }
977
978 pub fn map_within<P, Q>(
993 &self,
994 src: impl ops::RangeBounds<usize>,
995 dest: usize,
996 f: impl Fn(P) -> Q,
997 p: Texel<P>,
998 q: Texel<Q>,
999 ) {
1000 let mut that = self;
1001 TexelMappingBuffer::map_within(&mut that, src, dest, f, p, q)
1002 }
1003}
1004
1005impl cmp::PartialEq for cell_buf {
1006 fn eq(&self, other: &Self) -> bool {
1007 crate::texels::U8.cell_memory_eq(self.0.as_slice_of_cells(), other.0.as_slice_of_cells())
1012 }
1013}
1014
1015impl cmp::PartialEq<[u8]> for cell_buf {
1016 fn eq(&self, other: &[u8]) -> bool {
1017 crate::texels::U8.cell_bytes_eq(self.0.as_slice_of_cells(), other)
1018 }
1019}
1020
1021impl cmp::PartialEq<cell_buf> for [u8] {
1022 fn eq(&self, other: &cell_buf) -> bool {
1023 crate::texels::U8.cell_bytes_eq(other.0.as_slice_of_cells(), self)
1024 }
1025}
1026
1027impl cmp::Eq for cell_buf {}
1028
1029impl cmp::PartialEq for CellBuffer {
1030 fn eq(&self, other: &Self) -> bool {
1031 **self == **other
1032 }
1033}
1034
1035impl cmp::Eq for CellBuffer {}
1036
1037impl TexelMappingBuffer for &'_ cell_buf {
1038 fn map_forward<P, Q>(
1040 &mut self,
1041 src: usize,
1042 dest: usize,
1043 len: usize,
1044 f: impl Fn(P) -> Q,
1045 p: Texel<P>,
1046 q: Texel<Q>,
1047 ) {
1048 let src_buffer = self.as_texels(p).as_slice_of_cells();
1049 let target_buffer = self.as_texels(q).as_slice_of_cells();
1050
1051 for idx in 0..len {
1052 let source_idx = idx + src;
1053 let target_idx = idx + dest;
1054 let source = p.copy_cell(&src_buffer[source_idx]);
1055 let target = f(source);
1056 target_buffer[target_idx].set(target);
1057 }
1058 }
1059
1060 fn map_backward<P, Q>(
1062 &mut self,
1063 src: usize,
1064 dest: usize,
1065 len: usize,
1066 f: impl Fn(P) -> Q,
1067 p: Texel<P>,
1068 q: Texel<Q>,
1069 ) {
1070 let src_buffer = self.as_texels(p).as_slice_of_cells();
1071 let target_buffer = self.as_texels(q).as_slice_of_cells();
1072
1073 for idx in (0..len).rev() {
1074 let source_idx = idx + src;
1075 let target_idx = idx + dest;
1076 let source = p.copy_cell(&src_buffer[source_idx]);
1077 let target = f(source);
1078 target_buffer[target_idx].set(target);
1079 }
1080 }
1081
1082 fn texel_len<P>(&self, texel: Texel<P>) -> usize {
1083 self.as_texels(texel).as_slice_of_cells().len()
1084 }
1085}
1086
1087impl atomic_buf {
1088 pub fn new<T>(data: &T) -> &Self
1092 where
1093 T: AsRef<[MaxAtomic]> + ?Sized,
1094 {
1095 atomic_buf::from_slice(data.as_ref())
1096 }
1097
1098 pub fn len(&self) -> usize {
1100 core::mem::size_of_val(self)
1101 }
1102
1103 pub fn as_buf_mut(&mut self) -> &mut buf {
1104 buf::from_bytes_mut(atomic_buf::part_mut_slice(&mut self.0)).unwrap()
1105 }
1106
1107 #[track_caller]
1114 pub fn split_at(&self, at: usize) -> (&Self, &Self) {
1115 use crate::texels::U8;
1116
1117 assert!(at % MAX_ALIGN == 0);
1118 let slice = self.as_texels(U8);
1119 let (a, b) = slice.split_at(at);
1120 let left = atomic_buf::from_bytes(a).expect("was previously aligned");
1121 let right = atomic_buf::from_bytes(b).expect("was previously aligned");
1122
1123 (left, right)
1124 }
1125
1126 pub fn as_texels<P>(&self, texel: Texel<P>) -> AtomicSliceRef<P> {
1132 use crate::texels::U8;
1133
1134 let buffer = AtomicSliceRef {
1135 buf: self,
1136 start: 0,
1137 end: core::mem::size_of_val(self),
1138 texel: U8,
1139 };
1140
1141 texel
1142 .try_to_atomic(buffer)
1143 .expect("An atomic_buf is always aligned")
1144 }
1145
1146 pub fn index<T>(&self, index: TexelRange<T>) -> AtomicSliceRef<'_, T> {
1152 let scale = index.texel.align();
1153
1154 AtomicSliceRef {
1155 buf: self,
1156 start: scale * index.start_per_align,
1157 end: scale * index.end_per_align,
1158 texel: index.texel,
1159 }
1160 }
1161
1162 pub fn map_within<P, Q>(
1177 &self,
1178 src: impl ops::RangeBounds<usize>,
1179 dest: usize,
1180 f: impl Fn(P) -> Q,
1181 p: Texel<P>,
1182 q: Texel<Q>,
1183 ) {
1184 let mut that = self;
1185 TexelMappingBuffer::map_within(&mut that, src, dest, f, p, q)
1186 }
1187}
1188
1189impl cmp::PartialEq for atomic_buf {
1190 fn eq(&self, other: &Self) -> bool {
1191 if self.len() != other.len() {
1192 return false;
1193 }
1194
1195 if (self as *const atomic_buf).addr() == (other as *const atomic_buf).addr() {
1197 return true;
1198 }
1199
1200 let lhs = self.0.iter();
1204 let rhs = other.0.iter();
1205
1206 lhs.zip(rhs)
1207 .all(|(a, b)| a.load(atomic::Ordering::Relaxed) == b.load(atomic::Ordering::Relaxed))
1208 }
1209}
1210
1211impl cmp::PartialEq<[u8]> for atomic_buf {
1212 fn eq(&self, other: &[u8]) -> bool {
1213 if self.len() != other.len() {
1214 return false;
1215 }
1216
1217 let lhs = self.0.iter();
1221 let rhs = other.chunks_exact(mem::size_of::<AtomicPart>());
1222
1223 lhs.zip(rhs)
1224 .all(|(a, b)| a.load(atomic::Ordering::Relaxed).to_ne_bytes() == *b)
1231 }
1232}
1233
1234impl cmp::Eq for atomic_buf {}
1235
1236impl cmp::PartialEq for AtomicBuffer {
1237 fn eq(&self, other: &Self) -> bool {
1238 **self == **other
1239 }
1240}
1241
1242impl cmp::Eq for AtomicBuffer {}
1243
1244impl TexelMappingBuffer for &'_ atomic_buf {
1245 fn map_forward<P, Q>(
1247 &mut self,
1248 src: usize,
1249 dest: usize,
1250 len: usize,
1251 f: impl Fn(P) -> Q,
1252 p: Texel<P>,
1253 q: Texel<Q>,
1254 ) {
1255 let src_buffer = self.as_texels(p);
1256 let target_buffer = self.as_texels(q);
1257
1258 for idx in 0..len {
1262 let source_idx = idx + src;
1263 let target_idx = idx + dest;
1264 let source = p.load_atomic(src_buffer.index_one(source_idx));
1265 let target = f(source);
1266 q.store_atomic(target_buffer.index_one(target_idx), target);
1267 }
1268 }
1269
1270 fn map_backward<P, Q>(
1272 &mut self,
1273 src: usize,
1274 dest: usize,
1275 len: usize,
1276 f: impl Fn(P) -> Q,
1277 p: Texel<P>,
1278 q: Texel<Q>,
1279 ) {
1280 let src_buffer = self.as_texels(p);
1281 let target_buffer = self.as_texels(q);
1282
1283 for idx in (0..len).rev() {
1284 let source_idx = idx + src;
1285 let target_idx = idx + dest;
1286 let source = p.load_atomic(src_buffer.index_one(source_idx));
1287 let target = f(source);
1288 q.store_atomic(target_buffer.index_one(target_idx), target);
1289 }
1290 }
1291
1292 fn texel_len<P>(&self, texel: Texel<P>) -> usize {
1293 self.as_texels(texel).len()
1294 }
1295}
1296
1297impl<'lt, P> AtomicSliceRef<'lt, P> {
1298 #[track_caller]
1304 pub fn index_one(self, idx: usize) -> AtomicRef<'lt, P> {
1305 assert!(idx < self.len());
1306
1307 AtomicRef {
1308 buf: self.buf,
1309 start: self.start + idx * self.texel.size(),
1310 texel: self.texel,
1311 }
1312 }
1313
1314 pub fn get_bounds(self, bounds: (ops::Bound<usize>, ops::Bound<usize>)) -> Option<Self> {
1318 let (start, end) = bounds;
1319 let len = self.len();
1320
1321 let start = match start {
1322 ops::Bound::Included(start) => start,
1323 ops::Bound::Excluded(start) => start.checked_add(1)?,
1324 ops::Bound::Unbounded => 0,
1325 };
1326
1327 let end = match end {
1328 ops::Bound::Included(end) => end.checked_add(1)?,
1329 ops::Bound::Excluded(end) => end,
1330 ops::Bound::Unbounded => len,
1331 };
1332
1333 if start > end || end > len {
1334 None
1335 } else {
1336 Some(AtomicSliceRef {
1337 buf: self.buf,
1338 start: self.start + start * self.texel.size(),
1339 end: self.start + end * self.texel.size(),
1340 texel: self.texel,
1341 })
1342 }
1343 }
1344
1345 pub fn get(self, bounds: impl core::ops::RangeBounds<usize>) -> Option<Self> {
1347 let start = bounds.start_bound().cloned();
1348 let end = bounds.end_bound().cloned();
1349 self.get_bounds((start, end))
1350 }
1351
1352 #[track_caller]
1354 pub fn index(self, bounds: impl core::ops::RangeBounds<usize>) -> Self {
1355 #[cold]
1356 fn panic_on_bounds() -> ! {
1357 panic!("Bounds are out of range");
1358 }
1359
1360 match self.get(bounds) {
1361 Some(some) => some,
1362 None => panic_on_bounds(),
1363 }
1364 }
1365
1366 #[track_caller]
1368 pub fn read_from_slice(&self, data: &[P]) {
1369 self.texel.store_atomic_slice(*self, data);
1370 }
1371
1372 #[track_caller]
1376 pub fn write_to_slice(&self, data: &mut [P]) {
1377 self.texel.load_atomic_slice(*self, data);
1378 }
1379
1380 pub fn to_vec(&self) -> Vec<P> {
1382 let mut fresh: Vec<P> = (0..self.len()).map(|_| self.texel.zeroed()).collect();
1385 self.write_to_slice(&mut fresh);
1386 fresh
1387 }
1388
1389 pub fn to_texel_buffer(&self) -> TexelBuffer<P> {
1391 let mut fresh = TexelBuffer::new_for_texel(self.texel, self.len());
1394 self.write_to_slice(&mut fresh);
1395 fresh
1396 }
1397
1398 #[track_caller]
1399 pub fn split_at(self, at: usize) -> (Self, Self) {
1400 let left = self.index(..at);
1401 let right = self.index(at..);
1402 (left, right)
1403 }
1404
1405 #[must_use = "Does not mutate self"]
1407 #[track_caller]
1408 pub fn truncate_bytes(self, at: usize) -> Self {
1409 let len = (self.end - self.start).min(at);
1410 AtomicSliceRef {
1411 end: self.start + len,
1412 ..self
1413 }
1414 }
1415
1416 pub(crate) fn as_ptr_range(self) -> core::ops::Range<*mut P> {
1417 let base = self.buf.0.as_ptr_range();
1418 ((base.start as *mut u8).wrapping_add(self.start) as *mut P)
1419 ..((base.start as *mut u8).wrapping_add(self.end) as *mut P)
1420 }
1421
1422 pub(crate) fn from_ref(value: AtomicRef<'lt, P>) -> Self {
1424 AtomicSliceRef {
1425 buf: value.buf,
1426 start: value.start,
1427 end: value.start + value.texel.size(),
1428 texel: value.texel,
1429 }
1430 }
1431
1432 pub fn len(&self) -> usize {
1434 self.end.saturating_sub(self.start) / self.texel.size()
1435 }
1436}
1437
1438impl<P> Clone for AtomicSliceRef<'_, P> {
1439 fn clone(&self) -> Self {
1440 AtomicSliceRef { ..*self }
1441 }
1442}
1443
1444impl<P> Copy for AtomicSliceRef<'_, P> {}
1445
1446impl<P> AtomicRef<'_, P> {
1447 pub fn store(self, value: P) {
1456 self.texel.store_atomic(self, value);
1457 }
1458
1459 pub fn load(self) -> P {
1470 self.texel.load_atomic(self)
1471 }
1472}
1473
1474impl<P> Clone for AtomicRef<'_, P> {
1475 fn clone(&self) -> Self {
1476 AtomicRef { ..*self }
1477 }
1478}
1479
1480impl<P> Copy for AtomicRef<'_, P> {}
1481
1482#[derive(Debug)]
1487pub struct TexelRange<T> {
1488 texel: Texel<T>,
1489 start_per_align: usize,
1490 end_per_align: usize,
1491}
1492
1493impl<T> Clone for TexelRange<T> {
1494 fn clone(&self) -> Self {
1495 *self
1496 }
1497}
1498
1499impl<T> Copy for TexelRange<T> {}
1500
1501impl<T> TexelRange<T> {
1502 pub fn new(texel: Texel<T>, range: ops::Range<usize>) -> Option<Self> {
1504 let end_byte = range
1505 .end
1506 .checked_mul(texel.size())
1507 .filter(|&n| n <= isize::MAX as usize)?;
1508 let start_byte = (range.start.min(range.end))
1509 .checked_mul(texel.size())
1510 .filter(|&n| n <= isize::MAX as usize)?;
1511
1512 debug_assert!(
1513 end_byte % texel.align() == 0,
1514 "Texel must be valid for its type layout"
1515 );
1516
1517 debug_assert!(
1518 start_byte % texel.align() == 0,
1519 "Texel must be valid for its type layout"
1520 );
1521
1522 Some(TexelRange {
1523 texel,
1524 start_per_align: start_byte / texel.align(),
1525 end_per_align: end_byte / texel.align(),
1526 })
1527 }
1528
1529 pub fn from_byte_range(texel: Texel<T>, range: ops::Range<usize>) -> Option<Self> {
1552 let start_byte = range.start;
1553 let end_byte = range.end.max(start_byte);
1554
1555 if start_byte % texel.align() != 0
1556 || end_byte % texel.align() != 0
1557 || (end_byte - start_byte) % texel.size() != 0
1558 {
1559 return None;
1560 }
1561
1562 Some(TexelRange {
1563 texel,
1564 start_per_align: start_byte / texel.align(),
1565 end_per_align: end_byte / texel.align(),
1566 })
1567 }
1568
1569 fn aligned_byte_range(self) -> ops::Range<usize> {
1571 let scale = self.texel.align();
1572 scale * self.start_per_align..scale * self.end_per_align
1573 }
1574}
1575
1576impl<T> core::ops::Index<TexelRange<T>> for buf {
1577 type Output = [T];
1578
1579 fn index(&self, index: TexelRange<T>) -> &Self::Output {
1580 let bytes = &self.0[index.aligned_byte_range()];
1581 let slice = index.texel.try_to_slice(bytes);
1582 slice.expect("byte indices validly aligned")
1584 }
1585}
1586
1587impl<T> core::ops::IndexMut<TexelRange<T>> for buf {
1588 fn index_mut(&mut self, index: TexelRange<T>) -> &mut Self::Output {
1589 let bytes = &mut self.0[index.aligned_byte_range()];
1590 let slice = index.texel.try_to_slice_mut(bytes);
1591 slice.expect("byte indices validly aligned")
1593 }
1594}
1595
1596impl<T> core::ops::Index<TexelRange<T>> for cell_buf {
1597 type Output = [cell::Cell<T>];
1598
1599 fn index(&self, index: TexelRange<T>) -> &Self::Output {
1600 let bytes = &self.0.as_slice_of_cells()[index.aligned_byte_range()];
1601 let slice = index.texel.try_to_cell(bytes);
1602 slice
1604 .expect("byte indices validly aligned")
1605 .as_slice_of_cells()
1606 }
1607}
1608
1609impl Default for &'_ cell_buf {
1610 fn default() -> Self {
1611 cell_buf::new(&mut [])
1612 }
1613}
1614
1615impl Default for &'_ atomic_buf {
1616 fn default() -> Self {
1617 atomic_buf::new(&mut [])
1618 }
1619}
1620
1621#[cfg(test)]
1622mod tests {
1623 use super::*;
1624 use crate::texels::{MAX, U16, U32, U8};
1625
1626 struct AlignMeUp<N>([MaxAligned; 0], N);
1628
1629 #[test]
1630 fn single_max_element() {
1631 let mut buffer = Buffer::new(mem::size_of::<MaxAligned>());
1632 let slice = buffer.as_mut_texels(MAX);
1633 assert!(slice.len() == 1);
1634 }
1635
1636 #[test]
1637 fn growing() {
1638 let mut buffer = Buffer::new(0);
1639 assert_eq!(buffer.capacity(), 0);
1640 buffer.grow_to(mem::size_of::<MaxAligned>());
1641 let capacity = buffer.capacity();
1642 assert!(buffer.capacity() > 0);
1643 buffer.grow_to(capacity);
1644 assert_eq!(buffer.capacity(), capacity);
1645 buffer.grow_to(0);
1646 assert_eq!(buffer.capacity(), capacity);
1647 buffer.grow_to(capacity + 1);
1648 assert!(buffer.capacity() > capacity);
1649 }
1650
1651 #[test]
1652 fn reinterpret() {
1653 let mut buffer = Buffer::new(mem::size_of::<u32>());
1654 assert!(buffer.as_mut_texels(U32).len() >= 1);
1655 buffer
1656 .as_mut_texels(U16)
1657 .iter_mut()
1658 .for_each(|p| *p = 0x0f0f);
1659 buffer
1660 .as_texels(U32)
1661 .iter()
1662 .for_each(|p| assert_eq!(*p, 0x0f0f0f0f));
1663 buffer
1664 .as_texels(U8)
1665 .iter()
1666 .for_each(|p| assert_eq!(*p, 0x0f));
1667
1668 buffer
1669 .as_mut_texels(U8)
1670 .iter_mut()
1671 .enumerate()
1672 .for_each(|(idx, p)| *p = idx as u8);
1673 assert_eq!(u32::from_be(buffer.as_texels(U32)[0]), 0x00010203);
1674 }
1675
1676 #[test]
1677 fn mapping_great_to_small() {
1678 const LEN: usize = 10;
1679 let mut buffer = Buffer::new(LEN * mem::size_of::<u32>());
1680 buffer
1681 .as_mut_texels(U32)
1682 .iter_mut()
1683 .enumerate()
1684 .for_each(|(idx, p)| *p = idx as u32);
1685
1686 buffer.map_within(..LEN, 0, |n: u32| n as u8, U32, U8);
1688 buffer.map_within(..LEN, 0, |n: u8| n as u32, U8, U32);
1689
1690 assert_eq!(
1692 buffer.as_texels(U32)[..LEN].to_vec(),
1693 (0..LEN as u32).collect::<Vec<_>>()
1694 );
1695
1696 buffer.map_within(0..LEN, 3 * LEN, |n: u32| n as u8, U32, U8);
1698 buffer.map_within(3 * LEN..4 * LEN, 0, |n: u8| n as u32, U8, U32);
1699
1700 assert_eq!(
1701 buffer.as_texels(U32)[..LEN].to_vec(),
1702 (0..LEN as u32).collect::<Vec<_>>()
1703 );
1704 }
1705
1706 #[test]
1707 fn cell_buffer() {
1708 let data = [0, 0, 255, 0, 255, 0, 255, 0, 0];
1709 let buffer = CellBuffer::from(&data[..]);
1710 assert_eq!(buffer.capacity(), Buffer::alloc_len(data.len()) * MAX_ALIGN);
1712
1713 let alternative = CellBuffer::with_buffer(buffer.to_owned());
1714 assert_eq!(buffer.capacity(), alternative.capacity());
1715
1716 let contents: &cell_buf = &*buffer;
1717 let slice: &[cell::Cell<u8>] = contents.as_texels(U8).as_slice_of_cells();
1718 assert!(cell_buf::from_bytes(slice).is_some());
1719 }
1720
1721 #[test]
1722 fn atomic_buffer() {
1723 let data = [0, 0, 255, 0, 255, 0, 255, 0, 0];
1724 let buffer = AtomicBuffer::from(&data[..]);
1725 assert_eq!(buffer.capacity(), Buffer::alloc_len(data.len()) * MAX_ALIGN);
1727
1728 let alternative = CellBuffer::with_buffer(buffer.to_owned());
1729 assert_eq!(buffer.capacity(), alternative.capacity());
1730
1731 let contents: &atomic_buf = &*buffer;
1732 let slice: AtomicSliceRef<u8> = contents.as_texels(U8);
1733 assert!(atomic_buf::from_bytes(slice).is_some());
1734 }
1735
1736 #[test]
1737 fn mapping_cells() {
1738 const LEN: usize = 10;
1739 let buffer = CellBuffer::new(LEN * mem::size_of::<u32>());
1741 let output_tap = buffer.clone();
1743 assert!(buffer.ptr_eq(&output_tap));
1744
1745 buffer
1746 .as_texels(U32)
1747 .as_slice_of_cells()
1748 .iter()
1749 .enumerate()
1750 .for_each(|(idx, p)| p.set(idx as u32));
1751
1752 buffer.map_within(..LEN, 0, |n: u32| n as u8, U32, U8);
1754 buffer.map_within(..LEN, 0, |n: u8| n as u32, U8, U32);
1755
1756 assert_eq!(
1758 output_tap.as_texels(U32).as_slice_of_cells()[..LEN]
1759 .iter()
1760 .map(cell::Cell::get)
1761 .collect::<Vec<_>>(),
1762 (0..LEN as u32).collect::<Vec<_>>()
1763 );
1764
1765 buffer.map_within(0..LEN, 3 * LEN, |n: u32| n as u8, U32, U8);
1767 buffer.map_within(3 * LEN..4 * LEN, 0, |n: u8| n as u32, U8, U32);
1768
1769 assert_eq!(
1770 output_tap.as_texels(U32).as_slice_of_cells()[..LEN]
1771 .iter()
1772 .map(cell::Cell::get)
1773 .collect::<Vec<_>>(),
1774 (0..LEN as u32).collect::<Vec<_>>()
1775 );
1776 }
1777
1778 #[test]
1779 fn mapping_atomics() {
1780 const LEN: usize = 10;
1781 let mut initial_state = Buffer::new(LEN * mem::size_of::<u32>());
1782
1783 initial_state
1784 .as_mut_texels(U32)
1785 .iter_mut()
1786 .enumerate()
1787 .for_each(|(idx, p)| *p = idx as u32);
1788
1789 let buffer = AtomicBuffer::with_buffer(initial_state);
1791 let output_tap = buffer.clone();
1793
1794 buffer.map_within(..LEN, 0, |n: u32| n as u8, U32, U8);
1796 buffer.map_within(..LEN, 0, |n: u8| n as u32, U8, U32);
1797
1798 assert_eq!(
1800 output_tap.to_owned().as_texels(U32)[..LEN].to_vec(),
1801 (0..LEN as u32).collect::<Vec<_>>()
1802 );
1803
1804 buffer.map_within(0..LEN, 3 * LEN, |n: u32| n as u8, U32, U8);
1806 buffer.map_within(3 * LEN..4 * LEN, 0, |n: u8| n as u32, U8, U32);
1807
1808 assert_eq!(
1809 output_tap.to_owned().as_texels(U32)[..LEN].to_vec(),
1810 (0..LEN as u32).collect::<Vec<_>>()
1811 );
1812 }
1813
1814 #[test]
1815 fn cell_construction() {
1816 let data = [const { MaxCell::zero() }; 10];
1817 let _empty = cell_buf::new(&data[..0]);
1818 let cell = cell_buf::new(&data);
1819
1820 let (first, tail) = cell.split_at(MAX_ALIGN);
1821 let another_first = cell_buf::new(&data[..1]);
1822
1823 let data: Vec<_> = (0u8..).take(MAX_ALIGN).collect();
1824 U8.store_cell_slice(first.as_texels(U8).as_slice_of_cells(), &data);
1825 let mut alternative: Vec<_> = (1u8..).take(MAX_ALIGN).collect();
1826 U8.load_cell_slice(
1827 another_first.as_texels(U8).as_slice_of_cells(),
1828 &mut alternative,
1829 );
1830
1831 assert_eq!(data, alternative);
1833
1834 U8.load_cell_slice(
1835 tail.truncate(MAX_ALIGN).as_texels(U8).as_slice_of_cells(),
1836 &mut alternative,
1837 );
1838 assert_ne!(data, alternative);
1839 }
1840
1841 #[test]
1842 #[should_panic]
1843 fn cell_unaligned_split() {
1844 let data = [const { MaxCell::zero() }; 10];
1845 cell_buf::new(&data).split_at(1);
1847 }
1848
1849 #[test]
1850 #[should_panic]
1851 fn cell_oob_split() {
1852 let data = [const { MaxCell::zero() }; 1];
1853 cell_buf::new(&data).split_at(MAX_ALIGN + 1);
1855 }
1856
1857 #[test]
1858 fn cell_empty() {
1859 let empty = cell_buf::new(&[]);
1860 assert_eq!(empty.len(), 0);
1861 }
1862
1863 #[test]
1864 fn cell_from_bytes() {
1865 const SIZE: usize = 16;
1866
1867 let data = [0u8; SIZE].map(cell::Cell::new);
1868 let data: AlignMeUp<[_; SIZE]> = AlignMeUp([], data);
1869
1870 let empty = cell_buf::from_bytes(&data.1[..]).expect("this was properly aligned");
1871 assert_eq!(empty.len(), SIZE);
1872 }
1873
1874 #[test]
1875 fn cell_unaligned_from_bytes() {
1876 let data = [const { MaxCell::zero() }; 1];
1877 let unaligned = &cell_buf::new(&data).as_texels(U8).as_slice_of_cells()[1..];
1878 assert!(cell_buf::from_bytes(unaligned).is_none());
1879 }
1880
1881 #[test]
1882 fn cell_from_mut_bytes() {
1883 const SIZE: usize = 16;
1884 let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0u8; SIZE]);
1885
1886 let empty = cell_buf::from_bytes_mut(&mut data.1[..]).expect("this was properly aligned");
1887 assert_eq!(empty.len(), SIZE);
1888 }
1889
1890 #[test]
1891 fn cell_unaligned_from_mut_bytes() {
1892 const SIZE: usize = 16;
1893 let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0; SIZE]);
1894
1895 let unaligned = &mut data.1[1..];
1896 assert!(cell_buf::from_bytes_mut(unaligned).is_none());
1898 }
1899
1900 #[test]
1901 fn cell_equality() {
1902 let data = [const { MaxCell::zero() }; 3];
1903 let lhs = cell_buf::new(&data[0..1]);
1904 let rhs = cell_buf::new(&data[1..2]);
1905
1906 let uneq = cell_buf::new(&data[2..3]);
1907 uneq.as_texels(U8).as_slice_of_cells()[0].set(1);
1908
1909 assert!(lhs == lhs, "Must be equal with itself");
1911 assert!(lhs == rhs, "Must be equal with same data");
1912 assert!(lhs != uneq, "Must only be equal with same data");
1913
1914 let mut buffer = [0x42; mem::size_of::<MaxCell>()];
1915 assert!(*lhs != buffer[..], "Must only be equal with its data");
1916
1917 U8.load_cell_slice(lhs.as_texels(U8).as_slice_of_cells(), &mut buffer);
1918 assert!(*lhs == buffer[..], "Must be equal with its data");
1919 }
1920
1921 #[test]
1922 fn atomic_empty() {
1923 let empty = atomic_buf::new(&[]);
1924 assert_eq!(empty.len(), 0);
1925 }
1926
1927 #[test]
1928 fn atomic_construction() {
1929 let data = [const { MaxAtomic::zero() }; 10];
1930 let cell = atomic_buf::new(&data);
1931
1932 let (first, tail) = cell.split_at(MAX_ALIGN);
1933 let another_first = atomic_buf::new(&data[..1]);
1934 assert_eq!(another_first.as_texels(U8).len(), MAX_ALIGN);
1935 assert_eq!(first.as_texels(U8).len(), MAX_ALIGN);
1936
1937 let data: Vec<_> = (0u8..).take(MAX_ALIGN).collect();
1938 first.as_texels(U8).read_from_slice(&data);
1939 let mut alternative: Vec<_> = (1u8..).take(MAX_ALIGN).collect();
1940 another_first.as_texels(U8).write_to_slice(&mut alternative);
1941
1942 assert_eq!(data, alternative);
1944
1945 tail.as_texels(U8)
1947 .index(..MAX_ALIGN)
1948 .write_to_slice(&mut alternative);
1949 assert_ne!(data, alternative);
1950
1951 let another_first = atomic_buf::from_bytes(first.as_texels(U8))
1952 .expect("the whole buffer is always aligned");
1953 another_first.as_texels(U8).write_to_slice(&mut alternative);
1954 assert_eq!(data, alternative);
1955 }
1956
1957 #[test]
1958 fn atomic_from_bytes() {
1959 let data = [const { MaxAtomic::zero() }; 1];
1960 let cell = atomic_buf::new(&data);
1961
1962 let data = cell.as_texels(U8);
1964 let new_buf = atomic_buf::from_bytes(data).expect("this was properly aligned");
1965 assert_eq!(new_buf.len(), MAX_ALIGN);
1966 }
1967
1968 #[test]
1969 fn atomic_unaligned_from_bytes() {
1970 let data = [const { MaxAtomic::zero() }; 1];
1971 let cell = atomic_buf::new(&data);
1972
1973 let unaligned = cell.as_texels(U8).index(1..);
1974 assert!(atomic_buf::from_bytes(unaligned).is_none());
1975 }
1976
1977 #[test]
1978 fn atomic_from_mut_bytes() {
1979 const SIZE: usize = MAX_ALIGN * 2;
1980 let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0u8; SIZE]);
1981
1982 let empty = atomic_buf::from_bytes_mut(&mut data.1[..]).expect("this was properly aligned");
1983 assert_eq!(empty.len(), SIZE);
1984 }
1985
1986 #[test]
1987 fn atomic_too_small_from_mut_bytes() {
1988 const SIZE: usize = MAX_ALIGN / 2;
1989 let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0; SIZE]);
1990
1991 let unaligned = &mut data.1[1..];
1992 assert!(atomic_buf::from_bytes_mut(unaligned).is_none());
1995 }
1996
1997 #[test]
1998 fn atomic_unaligned_from_mut_bytes() {
1999 const SIZE: usize = 16;
2000 let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0; SIZE]);
2001
2002 let unaligned = &mut data.1[1..];
2003 assert!(atomic_buf::from_bytes_mut(unaligned).is_none());
2005 }
2006
2007 #[test]
2008 fn atomic_equality() {
2009 let data = [const { MaxAtomic::zero() }; 3];
2010 let lhs = atomic_buf::new(&data[0..1]);
2011 let rhs = atomic_buf::new(&data[1..2]);
2012
2013 let uneq = atomic_buf::new(&data[2..3]);
2014 U8.store_atomic(uneq.as_texels(U8).index_one(0), 1);
2015
2016 assert!(lhs == lhs, "Must be equal with itself");
2018 assert!(lhs == rhs, "Must be equal with same data");
2019 assert!(lhs != uneq, "Must only be equal with same data");
2020
2021 let mut buffer = [0x42; mem::size_of::<MaxCell>()];
2022 assert!(*lhs != buffer[..], "Must only be equal with its data");
2023
2024 U8.load_atomic_slice(lhs.as_texels(U8), &mut buffer);
2025 assert!(*lhs == buffer[..], "Must be equal with its data");
2026 }
2027
2028 #[test]
2029 fn atomic_with_u8() {
2030 for offset in 0..MAX_ALIGN {
2032 let slice = [const { MaxAtomic::zero() }; 4];
2033 let atomic = atomic_buf::new(&slice[..]);
2034
2035 let mut iota = 0;
2036 let data = [(); 3 * MAX_ALIGN].map(move |_| {
2037 let n = iota;
2038 iota += 1;
2039 n
2040 });
2041
2042 let target = atomic.as_texels(U8).index(offset..).index(..3 * MAX_ALIGN);
2043 U8.store_atomic_slice(target, &data[..]);
2044
2045 let mut check = [0; 3 * MAX_ALIGN];
2046 U8.load_atomic_slice(target, &mut check[..]);
2047
2048 let cells = [const { core::cell::Cell::new(0) }; 3 * MAX_ALIGN];
2049 U8.load_atomic_to_cells(target, &cells[..]);
2050
2051 assert_eq!(data, check);
2052 assert_eq!(data, cells.map(|x| x.into_inner()));
2053
2054 let mut check = [0; 4 * MAX_ALIGN];
2055 U8.load_atomic_slice(atomic.as_texels(U8), &mut check[..]);
2056
2057 assert_eq!(data, check[offset..][..3 * MAX_ALIGN], "offset {offset}");
2058 }
2059 }
2060
2061 #[test]
2062 fn atomic_with_u16() {
2063 use crate::texels::U16;
2064
2065 for offset in 0..MAX_ALIGN / 2 {
2067 let slice = [const { MaxAtomic::zero() }; 4];
2068 let atomic = atomic_buf::new(&slice[..]);
2069
2070 let mut iota = 0;
2071 let data = [(); 3 * MAX_ALIGN / 2].map(move |_| {
2072 let n = iota;
2073 iota += 1;
2074 n
2075 });
2076
2077 let target = atomic
2078 .as_texels(U16)
2079 .index(offset..)
2080 .index(..3 * MAX_ALIGN / 2);
2081 U16.store_atomic_slice(target, &data[..]);
2082
2083 let mut check = [0; 3 * MAX_ALIGN / 2];
2084 U16.load_atomic_slice(target, &mut check[..]);
2085
2086 let cells = [const { core::cell::Cell::new(0) }; 3 * MAX_ALIGN / 2];
2087 U16.load_atomic_to_cells(target, &cells[..]);
2088
2089 assert_eq!(data, check);
2090 assert_eq!(data, cells.map(|x| x.into_inner()));
2091 }
2092 }
2093
2094 #[test]
2095 fn atomic_from_cells() {
2096 for offset in 0..4 {
2097 let data = [const { MaxAtomic::zero() }; 1];
2098 let lhs = atomic_buf::new(&data[0..1]);
2099
2100 let data = [const { MaxCell::zero() }; 1];
2101 let rhs = cell_buf::new(&data[0..1]);
2102
2103 let source = rhs.as_texels(U8).as_slice_of_cells();
2105 U8.store_cell_slice(&source[4..8], &[0x84; 4]);
2106 U8.store_cell_slice(&source[2..4], &[1, 2]);
2107 let source = &source[..8 - offset];
2108 U8.store_atomic_from_cells(lhs.as_texels(U8).index(offset..8), source);
2110
2111 let mut buffer = [0x42; mem::size_of::<MaxCell>()];
2112 U8.load_atomic_slice(lhs.as_texels(U8), &mut buffer);
2113
2114 assert!(
2115 buffer[..offset].iter().all(|&x| x == 0),
2116 "Must still be unset",
2117 );
2118
2119 assert!(
2120 buffer[offset..][..4] == [0, 0, 1, 2],
2121 "Must contain the data",
2122 );
2123
2124 assert!(
2125 buffer[offset..8][4..].iter().all(|&x| x == 0x84),
2126 "Must be initialized by tail {:?}",
2127 &buffer[offset..][4..],
2128 );
2129 }
2130 }
2131
2132 #[test]
2133 fn atomic_to_cells() {
2134 for offset in 0..4 {
2135 let data = [const { MaxAtomic::zero() }; 1];
2136 let lhs = atomic_buf::new(&data[0..1]);
2137
2138 let data = [const { MaxCell::zero() }; 1];
2139 let rhs = cell_buf::new(&data[0..1]);
2140
2141 U8.store_atomic_slice(lhs.as_texels(U8).index(4..8), &[0x84; 4]);
2142 U8.store_atomic_slice(lhs.as_texels(U8).index(offset..).index(..4), &[0, 0, 1, 2]);
2143
2144 let target = rhs.as_texels(U8).as_slice_of_cells();
2146 U8.load_atomic_to_cells(lhs.as_texels(U8).index(offset..8), &target[..8 - offset]);
2148
2149 let mut buffer = [0x42; mem::size_of::<MaxCell>()];
2150 U8.load_cell_slice(target, &mut buffer);
2151
2152 assert!(
2153 buffer[..4] == [0, 0, 1, 2],
2154 "Must contain the data {:?}",
2155 &buffer[..4],
2156 );
2157
2158 assert!(
2159 buffer[..8 - offset][4..].iter().all(|&x| x == 0x84),
2160 "Must be initialized by tail {:?}",
2161 &buffer[..8 - offset][4..],
2162 );
2163 }
2164 }
2165
2166 #[test]
2167 fn atomic_memory_move() {
2168 const COPY_LEN: usize = 3 * core::mem::size_of::<MaxAtomic>();
2169 const TOTAL_LEN: usize = 4 * core::mem::size_of::<MaxAtomic>();
2170
2171 for offset in 0..4 {
2172 let data = [const { MaxAtomic::zero() }; 4];
2173 let lhs = atomic_buf::new(&data[..]);
2174
2175 let data = [const { MaxAtomic::zero() }; 4];
2176 let rhs = atomic_buf::new(&data[..]);
2177
2178 U8.store_atomic_slice(lhs.as_texels(U8).index(0..4), b"helo");
2179
2180 U8.atomic_memory_move(
2181 lhs.as_texels(U8).index(offset..offset + COPY_LEN),
2182 rhs.as_texels(U8).index(0..COPY_LEN),
2183 );
2184
2185 let mut buffer = [0x42; TOTAL_LEN];
2186 U8.load_atomic_slice(rhs.as_texels(U8), &mut buffer);
2187
2188 assert_eq!(buffer[..4], b"helo\0\0\0\0"[offset..][..4]);
2189 }
2190 }
2191}