reg_map/
arr.rs

1use core::iter::FusedIterator;
2use core::marker::PhantomData;
3use core::ptr::NonNull;
4
5use crate::access::Access;
6use crate::bounds;
7use crate::integers::Integer;
8use crate::iter;
9use crate::reg::{Reg, RegMapPtr};
10
11#[cfg(doc)]
12use crate::RegMap;
13
14/// An array of registers.
15///
16/// Element type can be:
17/// - a basic register of type [`Reg`];
18/// - a custom register map (`struct`) implementing the trait [`RegMapPtr`] through the derive
19///   macro [`RegMap`];
20/// - another `RegArray` (multidimensional array).
21pub struct RegArray<'a, P: ArrayElem<'a>, const N: usize> {
22    ptr: NonNull<[P::Target; N]>,
23    _ref: PhantomData<&'a [P::Target; N]>,
24}
25impl<'a, P: ArrayElem<'a>, const N: usize> RegArray<'a, P, N> {
26    /// Creates a new `RegArray`.
27    ///
28    /// ⚠️ This function is called by the field-access methods defined by the derive macro
29    /// [`RegMap`](crate::RegMap). Do *not* call this function directly. Changes to this function
30    /// are not considered semver breaking.
31    ///
32    /// # Safety
33    /// - `ptr` must be properly aligned;
34    /// - `ptr` must point to `N` contiguous elements of type `P::Target`,
35    /// - `ptr` must be valid for the whole lifetime `'a`.
36    #[doc(hidden)]
37    #[allow(non_snake_case)]
38    #[inline]
39    pub const unsafe fn __MACRO_ONLY__from_ptr(ptr: *mut [P::Target; N]) -> Self {
40        Self::from_nonnull(NonNull::new_unchecked(ptr))
41    }
42    #[inline]
43    const unsafe fn from_nonnull(ptr: NonNull<[P::Target; N]>) -> Self {
44        Self {
45            ptr,
46            _ref: PhantomData,
47        }
48    }
49    /// Returns a raw pointer to the underlying pointer array.
50    #[inline]
51    pub const fn as_ptr(&self) -> *mut [P::Target; N] {
52        self.ptr.as_ptr()
53    }
54    /// Returns the number of pointers in the array.
55    #[allow(clippy::len_without_is_empty)]
56    #[inline]
57    pub const fn len(&self) -> usize {
58        N
59    }
60    /// Access the pointer at `index`.
61    ///
62    /// # Panics
63    /// If `index` is out of bounds, i.e. if `index >= N`.
64    #[inline]
65    pub fn idx(&self, index: usize) -> P {
66        bounds::check_index::<N>(index);
67        // SAFETY: we checked i is in bounds
68        unsafe { self.idx_unchecked(index) }
69    }
70    /// Access the pointer at `index`, without doing bounds checking.
71    ///
72    /// # Safety
73    /// `index` must be in bounds: `index < N`.
74    #[inline]
75    pub unsafe fn idx_unchecked(&self, index: usize) -> P {
76        let base: NonNull<P::Target> = self.ptr.cast();
77        // SAFETY: the caller promises we are in bounds
78        unsafe { P::from_nonnull(base.add(index)) }
79    }
80    /// Returns an iterator over the pointer array.
81    pub fn iter(
82        &self,
83    ) -> impl 'a + ExactSizeIterator<Item = P> + DoubleEndedIterator + FusedIterator + Clone {
84        iter::RegArrayIter::new(self.ptr)
85    }
86    /// Returns an iterator over a subslice `[start..end]` of the pointer array.
87    ///
88    /// # Panics
89    /// If `[start..end]` is out of bounds.
90    pub fn iter_slice(
91        &self,
92        start: usize,
93        end: usize,
94    ) -> impl 'a + ExactSizeIterator<Item = P> + DoubleEndedIterator + FusedIterator + Clone {
95        bounds::check_slice::<N>(start, end);
96        let base: NonNull<P::Target> = self.ptr.cast();
97        // SAFETY: we checked start..end is in bounds
98        unsafe {
99            let slice = NonNull::slice_from_raw_parts(base.add(start), end - start);
100            iter::RegArrayIter::new(slice)
101        }
102    }
103}
104
105/// Types that can be stored in a [`RegArray`].
106///
107/// ⚠️ This trait is sealed and cannot be implemented for types outside of this crate.
108pub trait ArrayElem<'a>: 'a + private::Sealed {
109    /// The target type of the pointer stored in the array.
110    type Target;
111
112    /// Creates a new pointer to `Self::Target`.
113    ///
114    /// # Safety
115    /// - `ptr` must point to a valid instance of `Self::Target`;
116    /// - `ptr` must be valid for the whole lifetime `'a`.
117    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self;
118}
119
120// arrays of basic registers
121impl<'a, T: Integer, A: Access> ArrayElem<'a> for Reg<'a, T, A> {
122    type Target = T;
123
124    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self {
125        Reg::from_nonnull(ptr)
126    }
127}
128
129// arrays of custom register maps (structs)
130impl<'a, T: RegMapPtr<'a>> ArrayElem<'a> for T {
131    type Target = T::RegMap;
132
133    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self {
134        T::from_nonnull(ptr)
135    }
136}
137
138// multidimensional arrays
139impl<'a, T: ArrayElem<'a>, const N: usize> ArrayElem<'a> for RegArray<'a, T, N> {
140    type Target = [T::Target; N];
141
142    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self {
143        RegArray::from_nonnull(ptr)
144    }
145}
146
147mod private {
148    use crate::access::Access;
149    use crate::arr::{ArrayElem, RegArray};
150    use crate::integers::Integer;
151    use crate::reg::{Reg, RegMapPtr};
152
153    pub trait Sealed {}
154    impl<'a, T: Integer, A: Access> Sealed for Reg<'a, T, A> {}
155    impl<'a, T: RegMapPtr<'a>> Sealed for T {}
156    impl<'a, T: ArrayElem<'a>, const N: usize> Sealed for RegArray<'a, T, N> {}
157}