1use crate::{
4 access::{Access, Read, Write},
5 endian::Endian,
6};
7use core::{
8 iter::{ExactSizeIterator, FusedIterator},
9 marker::PhantomData,
10 ops::{Bound, RangeBounds},
11};
12use num_traits::PrimInt;
13
14pub trait Memory: Sized {
16 type Memwidth: PrimInt;
18 type Access: Access;
19 type Endian: Endian;
20
21 #[must_use]
22 fn first_entry_ptr(&self) -> *mut Self::Memwidth;
23
24 #[must_use]
26 fn num_entries(&self) -> usize;
27
28 #[must_use]
30 fn width(&self) -> usize;
31
32 #[must_use]
34 fn index(&self, idx: usize) -> MemEntry<Self::Memwidth, Self::Access, Self::Endian> {
35 if idx < self.num_entries() {
36 unsafe { MemEntry::from_ptr(self.first_entry_ptr().wrapping_add(idx)) }
37 } else {
38 panic!(
39 "Tried to index {} in a memory with only {} entries",
40 idx,
41 self.num_entries()
42 );
43 }
44 }
45
46 #[must_use]
48 fn slice(
49 &self,
50 range: impl RangeBounds<usize>,
51 ) -> MemEntryIter<Self::Memwidth, Self::Access, Self::Endian> {
52 let low_idx = match range.start_bound() {
53 Bound::Included(idx) => *idx,
54 Bound::Excluded(idx) => *idx + 1,
55 Bound::Unbounded => 0,
56 };
57 let high_idx = match range.end_bound() {
58 Bound::Included(idx) => *idx,
59 Bound::Excluded(idx) => *idx - 1,
60 Bound::Unbounded => self.num_entries() - 1,
61 };
62 let num_entries = high_idx - low_idx + 1;
63 MemEntryIter {
64 next: self.index(low_idx),
65 remaining: num_entries,
66 }
67 }
68
69 #[must_use]
71 fn iter(&self) -> MemEntryIter<Self::Memwidth, Self::Access, Self::Endian> {
72 self.slice(..)
73 }
74}
75
76#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
78pub struct MemEntry<T: PrimInt, A: Access, E: Endian> {
79 ptr: *mut T,
80 phantom_access: PhantomData<A>,
81 phantom_endian: PhantomData<E>,
82}
83
84impl<T: PrimInt, A: Access, E: Endian> MemEntry<T, A, E> {
85 #[must_use]
90 pub const unsafe fn from_ptr(ptr: *mut T) -> Self {
91 Self {
92 ptr,
93 phantom_access: PhantomData,
94 phantom_endian: PhantomData,
95 }
96 }
97
98 #[must_use]
99 pub const fn as_ptr(&self) -> *mut T {
100 self.ptr
101 }
102}
103
104impl<T: PrimInt, A: Read, E: Endian> MemEntry<T, A, E> {
105 #[must_use]
107 pub fn read(&self) -> T {
108 E::from_register_endian(unsafe { self.ptr.read_volatile() })
112 }
113}
114
115impl<T: PrimInt, A: Write, E: Endian> MemEntry<T, A, E> {
116 pub fn write(&mut self, value: T) {
118 unsafe { self.ptr.write_volatile(E::to_register_endian(value)) }
122 }
123}
124
125#[derive(Debug)]
127pub struct MemEntryIter<T: PrimInt, A: Access, E: Endian> {
128 next: MemEntry<T, A, E>,
129 remaining: usize,
130}
131
132impl<T: PrimInt, A: Access, E: Endian> Iterator for MemEntryIter<T, A, E> {
133 type Item = MemEntry<T, A, E>;
134
135 fn next(&mut self) -> Option<Self::Item> {
136 if self.remaining == 0 {
137 None
138 } else {
139 self.remaining -= 1;
140 let new_next = unsafe { MemEntry::from_ptr(self.next.as_ptr().wrapping_add(1)) };
141 Some(core::mem::replace(&mut self.next, new_next))
142 }
143 }
144
145 fn size_hint(&self) -> (usize, Option<usize>) {
146 (self.remaining, Some(self.remaining))
147 }
148}
149
150impl<T: PrimInt, A: Access, E: Endian> DoubleEndedIterator for MemEntryIter<T, A, E> {
151 fn next_back(&mut self) -> Option<Self::Item> {
152 if self.remaining == 0 {
153 None
154 } else {
155 self.remaining -= 1;
156 unsafe {
157 Some(MemEntry::from_ptr(
158 self.next.as_ptr().wrapping_add(self.remaining),
159 ))
160 }
161 }
162 }
163}
164
165impl<T: PrimInt, A: Access, E: Endian> ExactSizeIterator for MemEntryIter<T, A, E> {}
166impl<T: PrimInt, A: Access, E: Endian> FusedIterator for MemEntryIter<T, A, E> {}