1#![no_std]
2
3use core::ptr::read_unaligned;
4
5use tinyvec::ArrayVec;
6
7pub struct ArrayMap<K, V, const N: usize>
10where
11 K: PartialEq + Default,
12 V: Default,
13{
14 entries: ArrayVec<[(K, V); N]>,
15 last_updated_index: Option<usize>,
16}
17
18impl<K, V, const N: usize> ArrayMap<K, V, N>
19where
20 K: PartialEq + Default,
21 V: Default,
22{
23 pub fn new() -> Self {
24 Self {
25 entries: ArrayVec::new(),
26 last_updated_index: None,
27 }
28 }
29
30 pub fn len(&self) -> usize {
31 self.entries.len()
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.entries.is_empty()
36 }
37
38 pub fn last_updated_index(&self) -> Option<usize> {
39 self.last_updated_index
40 }
41
42 pub fn get(&self, index: usize) -> Option<&(K, V)> {
43 self.entries.get(index)
44 }
45
46 pub fn get_mut(&mut self, index: usize) -> Option<&mut (K, V)> {
47 self.entries.get_mut(index)
48 }
49
50 pub fn get_u8(&self, index: u8) -> Option<&(K, V)> {
51 self.get(index as usize)
52 }
53
54 pub fn get_mut_u8(&mut self, index: u8) -> Option<&mut (K, V)> {
55 self.get_mut(index as usize)
56 }
57
58 pub fn get_by_key(&self, key: &K) -> Option<&V> {
59 self.entries.iter().find(|(k, _)| k == key).map(|(_, v)| v)
60 }
61
62 pub fn get_mut_by_key(&mut self, key: &K) -> Option<&mut V> {
63 self.entries
64 .iter_mut()
65 .find(|(k, _)| k == key)
66 .map(|(_, v)| v)
67 }
68
69 pub fn find(&self, key: &K) -> Option<(usize, &(K, V))> {
70 self.entries.iter().enumerate().find(|(_, (k, _))| k == key)
71 }
72
73 pub fn find_mut(&mut self, key: &K) -> Option<(usize, &mut (K, V))> {
74 self.entries
75 .iter_mut()
76 .enumerate()
77 .find(|(_, (k, _))| k == key)
78 }
79
80 pub fn find_index(&self, key: &K) -> Option<usize> {
81 self.find(key).map(|(idx, _)| idx)
82 }
83
84 pub fn set_last_updated_index<E>(&mut self, index: usize) -> Result<(), E>
85 where
86 E: From<ArrayMapError>,
87 {
88 if index < self.entries.len() {
89 self.last_updated_index = Some(index);
90 Ok(())
91 } else {
92 Err(ArrayMapError::IndexOutOfBounds.into())
93 }
94 }
95
96 pub fn insert<E>(&mut self, key: K, value: V, error: E) -> Result<usize, E> {
97 let new_idx = self.entries.len();
98 if self.entries.try_push((key, value)).is_some() {
100 return Err(error);
101 }
102 self.last_updated_index = Some(new_idx);
103 Ok(new_idx)
104 }
105}
106
107impl<K, V, const N: usize> Default for ArrayMap<K, V, N>
108where
109 K: PartialEq + Default,
110 V: Default,
111{
112 fn default() -> Self {
113 Self::new()
114 }
115}
116
117impl<V, const N: usize> ArrayMap<[u8; 32], V, N>
119where
120 V: Default,
121{
122 pub fn get_by_pubkey(&self, key: &[u8; 32]) -> Option<&V> {
123 self.entries
124 .iter()
125 .find(|(k, _)| pubkey_eq(k, key))
126 .map(|(_, v)| v)
127 }
128
129 pub fn get_mut_by_pubkey(&mut self, key: &[u8; 32]) -> Option<&mut V> {
130 self.entries
131 .iter_mut()
132 .find(|(k, _)| pubkey_eq(k, key))
133 .map(|(_, v)| v)
134 }
135
136 pub fn find_by_pubkey(&self, key: &[u8; 32]) -> Option<(usize, &([u8; 32], V))> {
137 self.entries
138 .iter()
139 .enumerate()
140 .find(|(_, (k, _))| pubkey_eq(k, key))
141 }
142
143 pub fn find_mut_by_pubkey(&mut self, key: &[u8; 32]) -> Option<(usize, &mut ([u8; 32], V))> {
144 self.entries
145 .iter_mut()
146 .enumerate()
147 .find(|(_, (k, _))| pubkey_eq(k, key))
148 }
149
150 pub fn find_pubkey_index(&self, key: &[u8; 32]) -> Option<usize> {
151 self.find_by_pubkey(key).map(|(idx, _)| idx)
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
156pub enum ArrayMapError {
157 CapacityExceeded,
158 IndexOutOfBounds,
159}
160
161impl core::fmt::Display for ArrayMapError {
162 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
163 match self {
164 ArrayMapError::CapacityExceeded => write!(f, "ArrayMap capacity exceeded"),
165 ArrayMapError::IndexOutOfBounds => write!(f, "ArrayMap index out of bounds"),
166 }
167 }
168}
169
170#[inline(always)]
171pub const fn pubkey_eq(p1: &[u8; 32], p2: &[u8; 32]) -> bool {
172 let p1_ptr = p1.as_ptr() as *const u64;
173 let p2_ptr = p2.as_ptr() as *const u64;
174
175 unsafe {
176 read_unaligned(p1_ptr) == read_unaligned(p2_ptr)
177 && read_unaligned(p1_ptr.add(1)) == read_unaligned(p2_ptr.add(1))
178 && read_unaligned(p1_ptr.add(2)) == read_unaligned(p2_ptr.add(2))
179 && read_unaligned(p1_ptr.add(3)) == read_unaligned(p2_ptr.add(3))
180 }
181}