1use core::marker::PhantomData;
2
3use bitmaps::{Bits, BitsImpl};
4
5use crate::{
6 persist::{NoPersist, PersistTrigger},
7 policy::{AccessPolicy, AllowAllPolicy, NoPersistPolicy, PersistPolicy},
8 storage::ShadowStorage,
9};
10
11pub struct NeedTotalSize;
13pub struct NeedBlockSize;
14pub struct NeedBlockCount;
15pub struct NeedAccessPolicy;
16pub struct NeedPersistPolicy;
17pub struct NeedPersistTrigger;
18pub struct Ready;
19
20#[derive(Default)]
21pub struct ShadowStorageBuilder<
22 const TS: usize,
23 const BS: usize,
24 const BC: usize,
25 AP,
26 PP,
27 PT,
28 PK,
29 State,
30> {
31 access_policy: Option<AP>,
32 persist_policy: Option<PP>,
33 persist_trigger: Option<PT>,
34 _phantom: PhantomData<(PK, State)>,
35}
36
37impl ShadowStorageBuilder<0, 0, 0, (), (), (), (), NeedTotalSize> {
39 pub fn new() -> Self {
40 ShadowStorageBuilder {
41 access_policy: None,
42 persist_policy: None,
43 persist_trigger: None,
44 _phantom: PhantomData,
45 }
46 }
47}
48
49impl ShadowStorageBuilder<0, 0, 0, (), (), (), (), NeedTotalSize> {
51 pub fn total_size<const TS: usize>(
52 self,
53 ) -> ShadowStorageBuilder<TS, 0, 0, (), (), (), (), NeedBlockSize> {
54 ShadowStorageBuilder {
55 access_policy: None,
56 persist_policy: None,
57 persist_trigger: None,
58 _phantom: PhantomData,
59 }
60 }
61}
62
63impl<const TS: usize> ShadowStorageBuilder<TS, 0, 0, (), (), (), (), NeedBlockSize> {
65 pub fn block_size<const BS: usize>(
66 self,
67 ) -> ShadowStorageBuilder<TS, BS, 0, (), (), (), (), NeedBlockCount> {
68 ShadowStorageBuilder {
69 access_policy: None,
70 persist_policy: None,
71 persist_trigger: None,
72 _phantom: PhantomData,
73 }
74 }
75}
76
77impl<const TS: usize, const BS: usize>
79 ShadowStorageBuilder<TS, BS, 0, (), (), (), (), NeedBlockCount>
80{
81 pub fn block_count<const BC: usize>(
87 self,
88 ) -> ShadowStorageBuilder<TS, BS, BC, (), (), (), (), NeedAccessPolicy> {
89 assert_eq!(
91 TS,
92 BS * BC,
93 "Total size {} does not match block_size {} * block_count {} = {}",
94 TS,
95 BS,
96 BC,
97 BS * BC
98 );
99
100 ShadowStorageBuilder {
101 access_policy: None,
102 persist_policy: None,
103 persist_trigger: None,
104 _phantom: PhantomData,
105 }
106 }
107}
108
109impl<const TS: usize, const BS: usize, const BC: usize>
111 ShadowStorageBuilder<TS, BS, BC, (), (), (), (), NeedAccessPolicy>
112{
113 pub fn access_policy<AP: AccessPolicy>(
114 self,
115 policy: AP,
116 ) -> ShadowStorageBuilder<TS, BS, BC, AP, (), (), (), NeedPersistPolicy> {
117 ShadowStorageBuilder {
118 access_policy: Some(policy),
119 persist_policy: None,
120 persist_trigger: None,
121 _phantom: PhantomData,
122 }
123 }
124
125 pub fn default_access(
127 self,
128 ) -> ShadowStorageBuilder<TS, BS, BC, AllowAllPolicy, (), (), (), NeedPersistPolicy> {
129 self.access_policy(AllowAllPolicy::default())
130 }
131}
132
133impl<const TS: usize, const BS: usize, const BC: usize, AP>
135 ShadowStorageBuilder<TS, BS, BC, AP, (), (), (), NeedPersistPolicy>
136where
137 AP: AccessPolicy,
138{
139 pub fn persist_policy<PP, PK>(
141 self,
142 policy: PP,
143 ) -> ShadowStorageBuilder<TS, BS, BC, AP, PP, (), PK, NeedPersistTrigger>
144 where
145 PP: PersistPolicy<PK>,
146 {
147 ShadowStorageBuilder {
148 access_policy: self.access_policy,
149 persist_policy: Some(policy),
150 persist_trigger: None,
151 _phantom: PhantomData,
152 }
153 }
154
155 pub fn no_persist(
157 self,
158 ) -> ShadowStorageBuilder<TS, BS, BC, AP, NoPersistPolicy, NoPersist, (), Ready> {
159 ShadowStorageBuilder {
160 access_policy: self.access_policy,
161 persist_policy: Some(NoPersistPolicy::default()),
162 persist_trigger: Some(NoPersist),
163 _phantom: PhantomData,
164 }
165 }
166}
167
168impl<const TS: usize, const BS: usize, const BC: usize, AP, PP, PK>
170 ShadowStorageBuilder<TS, BS, BC, AP, PP, (), PK, NeedPersistTrigger>
171where
172 AP: AccessPolicy,
173 PP: PersistPolicy<PK>,
174{
175 pub fn persist_trigger<PT>(
177 self,
178 trigger: PT,
179 ) -> ShadowStorageBuilder<TS, BS, BC, AP, PP, PT, PK, Ready>
180 where
181 PT: PersistTrigger<PK>,
182 {
183 ShadowStorageBuilder {
184 access_policy: self.access_policy,
185 persist_policy: self.persist_policy,
186 persist_trigger: Some(trigger),
187 _phantom: PhantomData,
188 }
189 }
190}
191
192impl<const TS: usize, const BS: usize, const BC: usize, AP, PP, PT, PK>
194 ShadowStorageBuilder<TS, BS, BC, AP, PP, PT, PK, Ready>
195where
196 AP: AccessPolicy,
197 PP: PersistPolicy<PK>,
198 PT: PersistTrigger<PK>,
199 BitsImpl<BC>: Bits,
200{
201 pub fn build(self) -> ShadowStorage<TS, BS, BC, AP, PP, PT, PK> {
206 ShadowStorage::new(
207 self.access_policy.unwrap(),
208 self.persist_policy.unwrap(),
209 self.persist_trigger.unwrap(),
210 )
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_simple_builder() {
220 let _storage = ShadowStorageBuilder::new()
221 .total_size::<1024>()
222 .block_size::<64>()
223 .block_count::<16>() .default_access()
225 .no_persist()
226 .build();
227 }
228
229 #[test]
230 fn test_builder_with_custom_policies() {
231 struct TestAccessPolicy;
232 impl AccessPolicy for TestAccessPolicy {
233 fn can_read(&self, _addr: u16, _len: usize) -> bool {
234 true
235 }
236 fn can_write(&self, _addr: u16, _len: usize) -> bool {
237 true
238 }
239 }
240
241 struct TestPersistPolicy;
242 impl PersistPolicy<u32> for TestPersistPolicy {
243 fn push_persist_keys_for_range<F>(&self, _addr: u16, _len: usize, _push_key: F) -> bool
244 where
245 F: FnMut(u32),
246 {
247 false
248 }
249 }
250
251 struct TestPersistTrigger;
252 impl PersistTrigger<u32> for TestPersistTrigger {
253 fn push_key(&mut self, _key: u32) {}
254 fn request_persist(&mut self) {}
255 }
256
257 let _storage = ShadowStorageBuilder::new()
258 .total_size::<2048>()
259 .block_size::<128>()
260 .block_count::<16>() .access_policy(TestAccessPolicy)
262 .persist_policy(TestPersistPolicy)
263 .persist_trigger(TestPersistTrigger)
264 .build();
265 }
266
267 #[test]
268 #[should_panic(expected = "Total size 1024 does not match block_size 64 * block_count 15")]
269 fn test_builder_panics_on_mismatch() {
270 let _storage = ShadowStorageBuilder::new()
271 .total_size::<1024>()
272 .block_size::<64>()
273 .block_count::<15>() .default_access()
275 .no_persist()
276 .build();
277 }
278}