1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::ptr::NonNull;

use crate::access::Access;
use crate::bounds;
use crate::integers::Integer;
use crate::iter;
use crate::reg::{Reg, RegMapPtr};

#[cfg(doc)]
use crate::RegMap;

/// An array of registers.
///
/// Element type can be:
/// - a basic register of type [`Reg`];
/// - a custom register map (`struct`) implementing the trait [`RegMapPtr`] through the derive
///   macro [`RegMap`];
/// - another `RegArray` (multidimensional array).
pub struct RegArray<'a, P: ArrayElem<'a>, const N: usize> {
    ptr: NonNull<[P::Target; N]>,
    _ref: PhantomData<&'a [P::Target; N]>,
}
impl<'a, P: ArrayElem<'a>, const N: usize> RegArray<'a, P, N> {
    /// Creates a new `RegArray`.
    ///
    /// ⚠️ This function is called by the field-access methods defined by the derive macro
    /// [`RegMap`](crate::RegMap). Do *not* call this function directly. Changes to this function
    /// are not considered semver breaking.
    ///
    /// # Safety
    /// - `ptr` must be properly aligned;
    /// - `ptr` must point to `N` contiguous elements of type `P::Target`,
    /// - `ptr` must be valid for the whole lifetime `'a`.
    #[doc(hidden)]
    #[allow(non_snake_case)]
    #[inline]
    pub const unsafe fn __MACRO_ONLY__from_ptr(ptr: *mut [P::Target; N]) -> Self {
        Self::from_nonnull(NonNull::new_unchecked(ptr))
    }
    #[inline]
    const unsafe fn from_nonnull(ptr: NonNull<[P::Target; N]>) -> Self {
        Self {
            ptr,
            _ref: PhantomData,
        }
    }
    /// Returns a raw pointer to the underlying pointer array.
    #[inline]
    pub const fn as_ptr(&self) -> *mut [P::Target; N] {
        self.ptr.as_ptr()
    }
    /// Returns the number of pointers in the array.
    #[allow(clippy::len_without_is_empty)]
    #[inline]
    pub const fn len(&self) -> usize {
        N
    }
    /// Access the pointer at `index`.
    ///
    /// # Panics
    /// If `index` is out of bounds, i.e. if `index >= N`.
    #[inline]
    pub fn idx(&self, index: usize) -> P {
        bounds::check_index::<N>(index);
        // SAFETY: we checked i is in bounds
        unsafe { self.idx_unchecked(index) }
    }
    /// Access the pointer at `index`, without doing bounds checking.
    ///
    /// # Safety
    /// `index` must be in bounds: `index < N`.
    #[inline]
    pub unsafe fn idx_unchecked(&self, index: usize) -> P {
        let base: NonNull<P::Target> = self.ptr.cast();
        // SAFETY: the caller promises we are in bounds
        unsafe { P::from_nonnull(base.add(index)) }
    }
    /// Returns an iterator over the pointer array.
    pub fn iter(
        &self,
    ) -> impl 'a + ExactSizeIterator<Item = P> + DoubleEndedIterator + FusedIterator + Clone {
        iter::RegArrayIter::new(self.ptr)
    }
    /// Returns an iterator over a subslice `[start..end]` of the pointer array.
    ///
    /// # Panics
    /// If `[start..end]` is out of bounds.
    pub fn iter_slice(
        &self,
        start: usize,
        end: usize,
    ) -> impl 'a + ExactSizeIterator<Item = P> + DoubleEndedIterator + FusedIterator + Clone {
        bounds::check_slice::<N>(start, end);
        let base: NonNull<P::Target> = self.ptr.cast();
        // SAFETY: we checked start..end is in bounds
        unsafe {
            let slice = NonNull::slice_from_raw_parts(base.add(start), end - start);
            iter::RegArrayIter::new(slice)
        }
    }
}

/// Types that can be stored in a [`RegArray`].
///
/// ⚠️ This trait is sealed and cannot be implemented for types outside of this crate.
pub trait ArrayElem<'a>: 'a + private::Sealed {
    /// The target type of the pointer stored in the array.
    type Target;

    /// Creates a new pointer to `Self::Target`.
    ///
    /// # Safety
    /// - `ptr` must point to a valid instance of `Self::Target`;
    /// - `ptr` must be valid for the whole lifetime `'a`.
    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self;
}

// arrays of basic registers
impl<'a, T: Integer, A: Access> ArrayElem<'a> for Reg<'a, T, A> {
    type Target = T;

    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self {
        Reg::from_nonnull(ptr)
    }
}

// arrays of custom register maps (structs)
impl<'a, T: RegMapPtr<'a>> ArrayElem<'a> for T {
    type Target = T::RegMap;

    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self {
        T::from_nonnull(ptr)
    }
}

// multidimensional arrays
impl<'a, T: ArrayElem<'a>, const N: usize> ArrayElem<'a> for RegArray<'a, T, N> {
    type Target = [T::Target; N];

    unsafe fn from_nonnull(ptr: NonNull<Self::Target>) -> Self {
        RegArray::from_nonnull(ptr)
    }
}

mod private {
    use crate::access::Access;
    use crate::arr::{ArrayElem, RegArray};
    use crate::integers::Integer;
    use crate::reg::{Reg, RegMapPtr};

    pub trait Sealed {}
    impl<'a, T: Integer, A: Access> Sealed for Reg<'a, T, A> {}
    impl<'a, T: RegMapPtr<'a>> Sealed for T {}
    impl<'a, T: ArrayElem<'a>, const N: usize> Sealed for RegArray<'a, T, N> {}
}