vec_split/
fast_accessor.rs

1//! Despite the name, FastAccessor is not much less safe than SafeAccessor.
2//! However, it does not require T: Sized, or I: usize.
3
4use std::{
5    marker::PhantomData,
6    ops::{Index, IndexMut},
7};
8
9use crate::*;
10
11/// The immutable fast accessor. Contains a reference to the array, and the
12/// dimension to get from the vectors.
13pub struct FastAccessor<
14    'a,
15    T: Sized,
16    const D: usize,
17    V: RawVector<T, D>,
18    I,
19    VA: SizedVectorArray<T, D, V, I>,
20> {
21    phantom_t: PhantomData<T>,
22    phantom_v: PhantomData<V>,
23    phantom_i: PhantomData<I>,
24    array_ref: &'a VA,
25    dim: usize,
26}
27
28impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>>
29    FastAccessor<'a, T, D, V, I, VA>
30{
31    pub(crate) fn new(array_ref: &'a VA, dim: usize) -> Self {
32        Self {
33            phantom_t: PhantomData,
34            phantom_v: PhantomData,
35            phantom_i: PhantomData,
36            array_ref,
37            dim,
38        }
39    }
40}
41
42impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>>
43    Accessor<T, I> for FastAccessor<'a, T, D, V, I, VA>
44{
45    fn get<'b>(&'b self, index: I) -> Option<&'b T> {
46        let idx = self.array_ref.convert_index(index);
47        if idx > self.array_ref.len() {
48            return None;
49        }
50        // SAFETY: implementing SizedVector requires memory layout to be sound for this operation:
51        // the first dimension MUST be at the memory offset of the object, and it MUST not have padding
52        // in-between dimensions
53        unsafe {
54            (self.array_ref.ptr().add(idx) as *const T)
55                .add(self.dim)
56                .as_ref()
57        }
58    }
59}
60
61impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>> Index<I>
62    for FastAccessor<'a, T, D, V, I, VA>
63{
64    type Output = T;
65
66    fn index(&self, index: I) -> &Self::Output {
67        self.get(index).expect("index is too large for array.")
68    }
69}
70
71/// The mutable fast accessor. Contains a mutable reference to the array, and
72/// the dimension to get from the vectors.
73pub struct FastAccessorMut<
74    'a,
75    T: Sized,
76    const D: usize,
77    V: RawVector<T, D>,
78    I,
79    VA: SizedVectorArray<T, D, V, I>,
80> {
81    phantom_t: PhantomData<T>,
82    phantom_v: PhantomData<V>,
83    phantom_i: PhantomData<I>,
84    array_ref: &'a mut VA,
85    dim: usize,
86}
87
88impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>>
89    FastAccessorMut<'a, T, D, V, I, VA>
90{
91    pub(crate) fn new(array_ref: &'a mut VA, dim: usize) -> Self {
92        Self {
93            phantom_t: PhantomData,
94            phantom_v: PhantomData,
95            phantom_i: PhantomData,
96            array_ref,
97            dim,
98        }
99    }
100}
101
102impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>>
103    Accessor<T, I> for FastAccessorMut<'a, T, D, V, I, VA>
104{
105    fn get<'b>(&'b self, index: I) -> Option<&'b T> {
106        let idx = self.array_ref.convert_index(index);
107        if idx > self.array_ref.len() {
108            return None;
109        }
110        // SAFETY: implementing SizedVector requires memory layout to be sound for this operation:
111        // the first dimension MUST be at the memory offset of the object, and it MUST not have padding
112        // in-between dimensions
113        unsafe {
114            (self.array_ref.ptr().add(idx) as *const T)
115                .add(self.dim)
116                .as_ref()
117        }
118    }
119}
120impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>>
121    AccessorMut<T, I> for FastAccessorMut<'a, T, D, V, I, VA>
122{
123    fn get_mut<'b>(&'b mut self, index: I) -> Option<&'b mut T> {
124        let idx = self.array_ref.convert_index(index);
125        if idx > self.array_ref.len() {
126            return None;
127        }
128        // SAFETY: implementing SizedVector requires memory layout to be sound for this operation:
129        // the first dimension MUST be at the memory offset of the object, and it MUST not have padding
130        // in-between dimensions
131        unsafe {
132            (self.array_ref.ptr().add(idx) as *mut T)
133                .add(self.dim)
134                .as_mut()
135        }
136    }
137}
138
139impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>> Index<I>
140    for FastAccessorMut<'a, T, D, V, I, VA>
141{
142    type Output = T;
143
144    fn index(&self, index: I) -> &Self::Output {
145        self.get(index).expect("index is too large for array.")
146    }
147}
148
149impl<'a, T: Sized, const D: usize, V: RawVector<T, D>, I, VA: SizedVectorArray<T, D, V, I>>
150    IndexMut<I> for FastAccessorMut<'a, T, D, V, I, VA>
151{
152    fn index_mut(&mut self, index: I) -> &mut Self::Output {
153        self.get_mut(index).expect("index is too large for array.")
154    }
155}