1use alloc::boxed::Box;
12use alloc::vec;
13use core::fmt;
14use core::ops;
15
16use bonsai_disk::Disk;
17use embedded_io::ErrorType;
18use generic_array::ConstArrayLength;
19use generic_array::IntoArrayLength;
20use generic_array::typenum::Const;
21
22use crate::IecNumber;
23use crate::MetricNumber;
24
25
26
27extern crate alloc;
28
29
30#[derive(Clone, Copy, Default)]
31pub struct AccessStats {
32 pub reads: usize,
33 pub read_bytes: usize,
34 pub writes: usize,
35 pub write_bytes: usize,
36 pub erases: usize,
37}
38impl ops::Add for AccessStats {
39 type Output = Self;
40
41 fn add(self, other: Self) -> Self {
42 Self {
43 reads: self.reads + other.reads,
44 read_bytes: self.read_bytes + other.read_bytes,
45 writes: self.writes + other.writes,
46 write_bytes: self.write_bytes + other.write_bytes,
47 erases: self.erases + other.erases,
48 }
49 }
50}
51impl ops::Sub for AccessStats {
52 type Output = Self;
53
54 fn sub(self, other: Self) -> Self {
55 Self {
56 reads: self.reads.saturating_sub(other.reads),
57 read_bytes: self.read_bytes.saturating_sub(other.read_bytes),
58 writes: self.writes.saturating_sub(other.writes),
59 write_bytes: self.write_bytes.saturating_sub(other.write_bytes),
60 erases: self.erases.saturating_sub(other.erases),
61 }
62 }
63}
64impl ops::AddAssign for AccessStats {
65 fn add_assign(&mut self, other: Self) {
66 *self = self.clone() + other;
67 }
68}
69impl ops::SubAssign for AccessStats {
70 fn sub_assign(&mut self, other: Self) {
71 *self = self.clone() - other;
72 }
73}
74impl ops::Mul<usize> for AccessStats {
75 type Output = Self;
76
77 fn mul(self, rhs: usize) -> Self {
78 Self {
79 reads: self.reads * rhs,
80 read_bytes: self.read_bytes * rhs,
81 writes: self.writes * rhs,
82 write_bytes: self.write_bytes * rhs,
83 erases: self.erases * rhs,
84 }
85 }
86}
87impl ops::Div<usize> for AccessStats {
88 type Output = Self;
89
90 fn div(self, rhs: usize) -> Self {
91 Self {
92 reads: self.reads / rhs,
93 read_bytes: self.read_bytes / rhs,
94 writes: self.writes / rhs,
95 write_bytes: self.write_bytes / rhs,
96 erases: self.erases / rhs,
97 }
98 }
99}
100impl ops::MulAssign<usize> for AccessStats {
101 fn mul_assign(&mut self, rhs: usize) {
102 *self = self.clone() * rhs;
103 }
104}
105impl ops::DivAssign<usize> for AccessStats {
106 fn div_assign(&mut self, rhs: usize) {
107 *self = self.clone() / rhs;
108 }
109}
110impl fmt::Debug for AccessStats {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 if self.writes == 0 && self.write_bytes == 0 && self.erases == 0 {
113 f.debug_struct("ReadStats")
114 .field("reads", &self.reads)
115 .field("read_bytes", &self.read_bytes)
116 .finish()
117 } else {
118 f.debug_struct("AccessStats")
119 .field("reads", &self.reads)
120 .field("read_bytes", &self.read_bytes)
121 .field("writes", &self.writes)
122 .field("write_bytes", &self.write_bytes)
123 .field("erases", &self.erases)
124 .finish()
125 }
126 }
127}
128impl fmt::Display for AccessStats {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 if self.writes == 0 && self.write_bytes == 0 && self.erases == 0 {
131 write!(
132 f,
133 "reads {}, {}B",
134 MetricNumber(self.reads),
135 IecNumber(self.read_bytes)
136 )
137 } else {
138 write!(
139 f,
140 "reads {}, {}B, writes {}, {}B, erases {} pages",
141 MetricNumber(self.reads),
142 IecNumber(self.read_bytes),
143 MetricNumber(self.writes),
144 IecNumber(self.write_bytes),
145 MetricNumber(self.erases),
146 )
147 }
148 }
149}
150
151#[derive(Debug, Clone)]
155pub struct RamDisk<const BLOCK_SIZE: usize, const WRITE_SIZE: usize> {
156 pub data: Box<[u8]>,
157
158 pub stats: AccessStats,
159}
160impl<const BLOCK_SIZE: usize, const WRITE_SIZE: usize> RamDisk<BLOCK_SIZE, WRITE_SIZE> {
161 pub fn new(blocks: usize) -> Self {
162 Self {
163 data: vec![0; blocks * BLOCK_SIZE].into_boxed_slice(),
164 stats: AccessStats::default(),
165 }
166 }
167
168 pub fn new_erased(blocks: usize) -> Self {
169 Self {
170 data: vec![0xFF; blocks * BLOCK_SIZE].into_boxed_slice(),
171 stats: AccessStats::default(),
172 }
173 }
174
175 pub fn clear_stats(&mut self) {
176 self.stats = AccessStats::default();
177 }
178}
179
180
181impl<const BLOCK_SIZE: usize, const WRITE_SIZE: usize> AsMut<Self>
182 for RamDisk<BLOCK_SIZE, WRITE_SIZE>
183{
184 fn as_mut(&mut self) -> &mut Self {
185 self
186 }
187}
188
189impl<const BLOCK_SIZE: usize, const WRITE_SIZE: usize> ErrorType
190 for RamDisk<BLOCK_SIZE, WRITE_SIZE>
191{
192 type Error = core::convert::Infallible;
193}
194impl<const BLOCK_SIZE: usize, const WRITE_SIZE: usize> Disk for RamDisk<BLOCK_SIZE, WRITE_SIZE>
195where
196 Const<WRITE_SIZE>: IntoArrayLength,
197 {
200 type WRITE_GRANULARITY = ConstArrayLength<WRITE_SIZE>;
201
202 const ERASE_BLOCK_SIZE: usize = BLOCK_SIZE;
203
204 #[track_caller]
205 fn read(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize, Self::Error> {
206 assert!(BLOCK_SIZE % WRITE_SIZE == 0);
207 assert!(BLOCK_SIZE >= WRITE_SIZE);
208
209 assert!(
210 offset % WRITE_SIZE == 0,
211 "Unaligned read: {offset} % {WRITE_SIZE}"
212 );
213 assert!(
214 offset + buf.len() <= self.data.len(),
215 "Read out of bounds: {offset} + {} > {}",
216 buf.len(),
217 self.data.len()
218 );
219
220 if buf.len() == 0 {
222 return Ok(0);
223 }
224
225 assert!(
226 buf.len() >= WRITE_SIZE,
227 "Buffer too small: {} < {WRITE_SIZE}",
228 buf.len()
229 );
230
231 let buf_len = buf.len() / WRITE_SIZE * WRITE_SIZE;
233
234 let block_end = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;
236 let read_end = usize::min(block_end, offset + buf_len);
237 let read_len = read_end - offset;
238
239 buf[..read_len].copy_from_slice(&self.data[offset..read_end]);
240 self.stats.reads += 1;
241 self.stats.read_bytes += read_len;
242
243 Ok(read_len)
244 }
245
246 #[track_caller]
247 fn write(&mut self, offset: usize, buf: &[u8]) -> Result<usize, Self::Error> {
248 assert!(BLOCK_SIZE % WRITE_SIZE == 0);
249 assert!(BLOCK_SIZE >= WRITE_SIZE);
250
251 assert!(
252 offset % WRITE_SIZE == 0,
253 "Unaligned write: {offset} % {WRITE_SIZE}"
254 );
255 assert!(
256 offset + buf.len() <= self.data.len(),
257 "Write out of bounds: {offset} + {} > {}",
258 buf.len(),
259 self.data.len()
260 );
261
262 if buf.len() == 0 {
264 return Ok(0);
265 }
266
267 assert!(
268 buf.len() >= WRITE_SIZE,
269 "Buffer too small: {} < {WRITE_SIZE}",
270 buf.len()
271 );
272
273 let buf_len = buf.len() / WRITE_SIZE * WRITE_SIZE;
275
276 let block_end = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE;
278 let write_end = usize::min(block_end, offset + buf_len);
279 let write_len = write_end - offset;
280
281 for i in 0..write_len {
283 self.data[offset + i] &= buf[i];
284 }
285
286 self.stats.writes += 1;
287 self.stats.write_bytes += write_len;
288
289 Ok(write_len)
290 }
291
292 #[track_caller]
293 fn erase(&mut self, block: usize) -> Result<(), Self::Error> {
294 assert!(BLOCK_SIZE % WRITE_SIZE == 0);
295 assert!(BLOCK_SIZE >= WRITE_SIZE);
296
297 let offset = block * BLOCK_SIZE;
298 let len = BLOCK_SIZE;
299
300 for i in (offset)..(offset + len) {
302 self.data[i] = 0xFF;
303 }
304
305 self.stats.erases += 1;
306
307 Ok(())
308 }
309
310 #[track_caller]
311 fn block_count(&self) -> usize {
312 assert!(BLOCK_SIZE % WRITE_SIZE == 0);
313 assert!(BLOCK_SIZE >= WRITE_SIZE);
314
315 debug_assert!(self.data.len() % BLOCK_SIZE == 0);
316
317 self.data.len() / BLOCK_SIZE
318 }
319}
320
321
322#[cfg(test)]
323mod test {
324 use super::*;
325
326 const BLOCK_SIZE: usize = 512;
327 const WRITE_SIZE: usize = 8;
328
329 #[test]
330 fn test_ramdisk_simple_write() {
331 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
332
333 let write_data = [1, 2, 3, 4, 5, 6, 7, 8];
335 let write_result = disk.write(2 * WRITE_SIZE, &write_data);
336 assert!(write_result.is_ok());
337 assert_eq!(write_result.unwrap(), write_data.len());
338
339 for i in 0..write_data.len() {
341 assert_eq!(disk.data[2 * WRITE_SIZE + i], write_data[i]);
342 }
343
344 assert_eq!(disk.stats.writes, 1);
346 assert_eq!(disk.stats.write_bytes, write_data.len());
347 assert_eq!(disk.stats.reads, 0);
348 assert_eq!(disk.stats.read_bytes, 0);
349 assert_eq!(disk.stats.erases, 0);
350 }
351
352 #[test]
353 fn test_ramdisk_partial_write() {
354 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
355
356 let write_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
358 let write_result = disk.write(2 * WRITE_SIZE, &write_data);
359 assert!(write_result.is_ok());
360 assert_eq!(write_result.unwrap(), 8); for i in 0..8 {
364 assert_eq!(disk.data[2 * WRITE_SIZE + i], write_data[i]);
365 }
366
367 for i in 8..12 {
369 assert_eq!(disk.data[2 * WRITE_SIZE + i], 0xFF);
370 }
371
372 assert_eq!(disk.stats.writes, 1);
374 assert_eq!(disk.stats.write_bytes, 8);
375 assert_eq!(disk.stats.reads, 0);
376 assert_eq!(disk.stats.read_bytes, 0);
377 assert_eq!(disk.stats.erases, 0);
378 }
379
380 #[test]
381 fn test_ramdisk_simple_read() {
382 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
383
384 let direct_data = [10, 20, 30, 40, 50, 60, 70, 80];
386 for i in 0..direct_data.len() {
387 disk.data[2 * WRITE_SIZE + i] = direct_data[i];
388 }
389
390 let mut read_data = [0u8; 8];
392 let read_result = disk.read(2 * WRITE_SIZE, &mut read_data);
393 assert!(read_result.is_ok());
394 assert_eq!(read_result.unwrap(), direct_data.len());
395 assert_eq!(read_data, direct_data);
396
397 assert_eq!(disk.stats.reads, 1);
399 assert_eq!(disk.stats.read_bytes, direct_data.len());
400 assert_eq!(disk.stats.writes, 0);
401 assert_eq!(disk.stats.write_bytes, 0);
402 assert_eq!(disk.stats.erases, 0);
403 }
404
405 #[test]
406 fn test_ramdisk_partial_read() {
407 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
408
409 let direct_data = [10, 20, 30, 40, 50, 60, 70, 80];
411 for i in 0..direct_data.len() {
412 disk.data[2 * WRITE_SIZE + i] = direct_data[i];
413 }
414
415 let mut read_data = [0u8; 12];
417 let read_result = disk.read(2 * WRITE_SIZE, &mut read_data);
418 assert!(read_result.is_ok());
419 assert_eq!(read_result.unwrap(), 8); for i in 0..8 {
423 assert_eq!(read_data[i], direct_data[i]);
424 }
425
426 for i in 8..12 {
428 assert_eq!(read_data[i], 0);
429 }
430
431 assert_eq!(disk.stats.reads, 1);
433 assert_eq!(disk.stats.read_bytes, 8);
434 assert_eq!(disk.stats.writes, 0);
435 assert_eq!(disk.stats.write_bytes, 0);
436 assert_eq!(disk.stats.erases, 0);
437 }
438
439 #[test]
440 fn test_ramdisk_read_write() {
441 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
442
443 let write_data = [1, 2, 3, 4, 5, 6, 7, 8];
445 let write_result = disk.write(3 * WRITE_SIZE, &write_data);
446 assert!(write_result.is_ok());
447 assert_eq!(write_result.unwrap(), write_data.len());
448
449 let mut read_data = [0u8; 8];
451 let read_result = disk.read(3 * WRITE_SIZE, &mut read_data);
452 assert!(read_result.is_ok());
453 assert_eq!(read_result.unwrap(), write_data.len());
454 assert_eq!(read_data, write_data);
455
456 assert_eq!(disk.stats.reads, 1);
458 assert_eq!(disk.stats.read_bytes, write_data.len());
459 assert_eq!(disk.stats.writes, 1);
460 assert_eq!(disk.stats.write_bytes, write_data.len());
461 assert_eq!(disk.stats.erases, 0);
462 }
463
464 #[test]
465 fn test_ramdisk_single_write_two_reads() {
466 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
467
468 let write_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
470 let write_result = disk.write(2 * WRITE_SIZE, &write_data);
471 assert!(write_result.is_ok());
472 assert_eq!(write_result.unwrap(), write_data.len());
473
474 let mut read_data1 = [0u8; 8];
476 let read_result1 = disk.read(2 * WRITE_SIZE, &mut read_data1);
477 assert!(read_result1.is_ok());
478 assert_eq!(read_result1.unwrap(), 8);
479 assert_eq!(read_data1, [1, 2, 3, 4, 5, 6, 7, 8]);
480
481 let mut read_data2 = [0u8; 8];
483 let read_result2 = disk.read(2 * WRITE_SIZE + 8, &mut read_data2);
484 assert!(read_result2.is_ok());
485 assert_eq!(read_result2.unwrap(), 8);
486 assert_eq!(read_data2, [9, 10, 11, 12, 13, 14, 15, 16]);
487
488 assert_eq!(disk.stats.reads, 2);
490 assert_eq!(disk.stats.read_bytes, 16);
491 assert_eq!(disk.stats.writes, 1);
492 assert_eq!(disk.stats.write_bytes, 16);
493 assert_eq!(disk.stats.erases, 0);
494 }
495
496 #[test]
497 fn test_ramdisk_two_writes_single_read() {
498 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
499
500 let write_data1 = [1, 2, 3, 4, 5, 6, 7, 8];
502 let write_result1 = disk.write(2 * WRITE_SIZE, &write_data1);
503 assert!(write_result1.is_ok());
504 assert_eq!(write_result1.unwrap(), write_data1.len());
505
506 let write_data2 = [9, 10, 11, 12, 13, 14, 15, 16];
508 let write_result2 = disk.write(3 * WRITE_SIZE, &write_data2);
509 assert!(write_result2.is_ok());
510 assert_eq!(write_result2.unwrap(), write_data2.len());
511
512 let mut read_data = [0u8; 16];
514 let read_result = disk.read(2 * WRITE_SIZE, &mut read_data);
515 assert!(read_result.is_ok());
516 assert_eq!(read_result.unwrap(), 16);
517 assert_eq!(
518 read_data,
519 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
520 );
521
522 assert_eq!(disk.stats.reads, 1);
524 assert_eq!(disk.stats.read_bytes, 16);
525 assert_eq!(disk.stats.writes, 2);
526 assert_eq!(disk.stats.write_bytes, 16);
527 assert_eq!(disk.stats.erases, 0);
528 }
529
530 #[test]
531 fn test_ramdisk_repeated_write() {
532 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
533
534 let write_data = [1, 2, 3, 4, 5, 6, 7, 8];
536 let write_result = disk.write(3 * WRITE_SIZE, &write_data);
537 assert!(write_result.is_ok());
538 assert_eq!(write_result.unwrap(), write_data.len());
539
540 let write_result = disk.write(3 * WRITE_SIZE, &write_data);
542 assert!(write_result.is_ok());
543 assert_eq!(write_result.unwrap(), write_data.len());
544
545 let mut read_data = [0u8; 8];
547 let read_result = disk.read(3 * WRITE_SIZE, &mut read_data);
548 assert!(read_result.is_ok());
549 assert_eq!(read_result.unwrap(), write_data.len());
550 assert_eq!(read_data, write_data);
551
552 assert_eq!(disk.stats.reads, 1);
554 assert_eq!(disk.stats.read_bytes, write_data.len());
555 assert_eq!(disk.stats.writes, 2);
556 assert_eq!(disk.stats.write_bytes, write_data.len() * 2);
557 assert_eq!(disk.stats.erases, 0);
558 }
559
560 #[test]
561 fn test_ramdisk_erase() {
562 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new_erased(4);
563
564 let write_data = [1, 2, 3, 4, 5, 6, 7, 8];
566 let write_result = disk.write(3 * WRITE_SIZE, &write_data);
567 assert!(write_result.is_ok());
568 assert_eq!(write_result.unwrap(), write_data.len());
569
570 let erase_result = disk.erase(0);
572 assert!(erase_result.is_ok());
573
574 let mut read_data = [0u8; 8];
576 let read_result = disk.read(3 * WRITE_SIZE, &mut read_data);
577 assert!(read_result.is_ok());
578 assert_eq!(read_result.unwrap(), write_data.len());
579 assert_ne!(read_data, write_data);
581
582 assert_eq!(disk.stats.reads, 1);
584 assert_eq!(disk.stats.read_bytes, 8);
585 assert_eq!(disk.stats.writes, 1);
586 assert_eq!(disk.stats.write_bytes, 8);
587 assert_eq!(disk.stats.erases, 1);
588 }
589
590 #[test]
591 fn test_ramdisk_write_without_erase() {
592 let mut disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new(4);
593
594 let write_garbage = [0; 8];
596 let write_result = disk.write(3 * WRITE_SIZE, &write_garbage);
597 assert!(write_result.is_ok());
598 assert_eq!(write_result.unwrap(), write_garbage.len());
599
600 let write_data = [1, 2, 3, 4, 5, 6, 7, 8];
602 let write_result = disk.write(3 * WRITE_SIZE, &write_data);
603 assert!(write_result.is_ok());
604 assert_eq!(write_result.unwrap(), write_data.len());
605
606 let mut read_data = [0u8; 8];
608 let read_result = disk.read(3 * WRITE_SIZE, &mut read_data);
609 assert!(read_result.is_ok());
610 assert_eq!(read_result.unwrap(), write_data.len());
611 assert_ne!(read_data, write_data);
613
614 let erase_result = disk.erase(0);
616 assert!(erase_result.is_ok());
617
618 let write_result = disk.write(3 * WRITE_SIZE, &write_data);
620 assert!(write_result.is_ok());
621 assert_eq!(write_result.unwrap(), write_data.len());
622
623 let read_result = disk.read(3 * WRITE_SIZE, &mut read_data);
625 assert!(read_result.is_ok());
626 assert_eq!(read_result.unwrap(), write_data.len());
627 assert_eq!(read_data, write_data);
629
630 assert_eq!(disk.stats.reads, 2);
632 assert_eq!(disk.stats.read_bytes, 16);
633 assert_eq!(disk.stats.writes, 3);
634 assert_eq!(disk.stats.write_bytes, 24);
635 assert_eq!(disk.stats.erases, 1);
636 }
637
638 #[test]
639 fn test_ramdisk_block_count() {
640 let disk = RamDisk::<BLOCK_SIZE, WRITE_SIZE>::new(3);
641
642 assert_eq!(disk.block_count(), 3);
643 }
644}