1use alloc::borrow::{Borrow, Cow};
21use alloc::boxed::Box;
22use alloc::vec;
23
24use wasefire_error::{Code, Error, Space};
25
26use crate::{Storage, StorageIndex};
27
28#[derive(Clone)]
38pub struct BufferStorage {
39 storage: Box<[u8]>,
41
42 options: BufferOptions,
44
45 word_writes: Box<[usize]>,
47
48 page_erases: Box<[usize]>,
50
51 interruption: Interruption,
53}
54
55#[derive(Clone, Debug)]
57pub struct BufferOptions {
58 pub word_size: usize,
60
61 pub page_size: usize,
63
64 pub max_word_writes: usize,
66
67 pub max_page_erases: usize,
69
70 pub strict_mode: bool,
77}
78
79pub type BufferCorruptFunction<'a> = Box<dyn FnOnce(&mut [u8], &[u8]) + 'a>;
89
90impl BufferStorage {
91 pub fn new(storage: Box<[u8]>, options: BufferOptions) -> BufferStorage {
101 assert!(options.word_size.is_power_of_two());
102 assert!(options.page_size.is_power_of_two());
103 let num_words = storage.len() / options.word_size;
104 let num_pages = storage.len() / options.page_size;
105 let buffer = BufferStorage {
106 storage,
107 options,
108 word_writes: vec![0; num_words].into_boxed_slice(),
109 page_erases: vec![0; num_pages].into_boxed_slice(),
110 interruption: Interruption::Ready,
111 };
112 assert!(buffer.is_word_aligned(buffer.options.page_size));
113 assert!(buffer.is_page_aligned(buffer.storage.len()));
114 buffer
115 }
116
117 pub fn arm_interruption(&mut self, delay: usize) {
129 self.interruption.arm(delay);
130 }
131
132 pub fn disarm_interruption(&mut self) -> usize {
142 self.interruption.get().err().unwrap()
143 }
144
145 pub fn reset_interruption(&mut self) {
151 let _ = self.interruption.get();
152 }
153
154 pub fn corrupt_operation(&mut self, corrupt: BufferCorruptFunction) {
169 let operation = self.interruption.get().unwrap();
170 let range = self.operation_range(&operation).unwrap();
171 let mut before = self.storage[range.clone()].to_vec().into_boxed_slice();
172 match operation {
173 BufferOperation::Write { value: after, .. } => {
174 corrupt(&mut before, &after);
175 self.incr_word_writes(range.start, &before, &after);
176 }
177 BufferOperation::Erase { page } => {
178 let after = vec![0xff; self.page_size()].into_boxed_slice();
179 corrupt(&mut before, &after);
180 if before == after {
181 self.incr_page_erases(page);
182 }
183 }
184 };
185 self.storage[range].copy_from_slice(&before);
186 }
187
188 pub fn get_word_writes(&self, word: usize) -> usize {
190 self.word_writes[word]
191 }
192
193 pub fn get_page_erases(&self, page: usize) -> usize {
195 self.page_erases[page]
196 }
197
198 pub fn set_page_erases(&mut self, page: usize, cycle: usize) {
200 self.page_erases[page] = cycle;
201 }
202}
203
204pub const INTERRUPTION: Error = Error::new_const(Space::World as u8, INTERRUPT.code());
206const INTERRUPT: Error = Error::new_const(Space::Internal as u8, 0xffff);
210
211impl BufferStorage {
212 fn is_word_aligned(&self, x: usize) -> bool {
214 x & (self.options.word_size - 1) == 0
215 }
216
217 fn is_page_aligned(&self, x: usize) -> bool {
219 x & (self.options.page_size - 1) == 0
220 }
221
222 fn incr_page_erases(&mut self, page: usize) {
231 if self.options.strict_mode {
233 assert!(self.page_erases[page] < self.max_page_erases());
234 }
235 self.page_erases[page] += 1;
236 let num_words = self.page_size() / self.word_size();
237 for word in 0 .. num_words {
238 self.word_writes[page * num_words + word] = 0;
239 }
240 }
241
242 fn incr_word_writes(&mut self, index: usize, value: &[u8], complete: &[u8]) {
258 let word_size = self.word_size();
259 for i in 0 .. value.len() / word_size {
260 let range = core::ops::Range { start: i * word_size, end: (i + 1) * word_size };
261 if value[range.clone()] != complete[range.clone()] {
263 continue;
264 }
265 if value[range.clone()] == self.storage[index ..][range] {
267 continue;
268 }
269 let word = index / word_size + i;
270 if self.options.strict_mode {
272 assert!(self.word_writes[word] < self.max_word_writes());
273 }
274 self.word_writes[word] += 1;
275 }
276 }
277
278 fn operation_range(
280 &self, operation: &BufferOperation<impl Borrow<[u8]>>,
281 ) -> Result<core::ops::Range<usize>, Error> {
282 match *operation {
283 BufferOperation::Write { index, ref value } => index.range(value.borrow().len(), self),
284 BufferOperation::Erase { page } => {
285 StorageIndex { page, byte: 0 }.range(self.page_size(), self)
286 }
287 }
288 }
289}
290
291impl Storage for BufferStorage {
292 fn word_size(&self) -> usize {
293 self.options.word_size
294 }
295
296 fn page_size(&self) -> usize {
297 self.options.page_size
298 }
299
300 fn num_pages(&self) -> usize {
301 self.storage.len() / self.options.page_size
302 }
303
304 fn max_word_writes(&self) -> usize {
305 self.options.max_word_writes
306 }
307
308 fn max_page_erases(&self) -> usize {
309 self.options.max_page_erases
310 }
311
312 fn read_slice(&self, index: StorageIndex, length: usize) -> Result<Cow<'_, [u8]>, Error> {
313 Ok(Cow::Borrowed(&self.storage[index.range(length, self)?]))
314 }
315
316 fn write_slice(&mut self, index: StorageIndex, value: &[u8]) -> Result<(), Error> {
317 if !self.is_word_aligned(index.byte) || !self.is_word_aligned(value.len()) {
318 return Err(Error::user(Code::InvalidAlign));
319 }
320 let operation = BufferOperation::Write { index, value };
321 let range = self.operation_range(&operation)?;
322 self.interruption.tick(&operation)?;
324 self.incr_word_writes(range.start, value, value);
326 if self.options.strict_mode {
328 for (byte, &val) in range.clone().zip(value.iter()) {
329 assert_eq!(self.storage[byte] & val, val);
330 }
331 }
332 self.storage[range].copy_from_slice(value);
334 Ok(())
335 }
336
337 fn erase_page(&mut self, page: usize) -> Result<(), Error> {
338 let operation = BufferOperation::Erase { page };
339 let range = self.operation_range(&operation)?;
340 self.interruption.tick(&operation)?;
342 self.incr_page_erases(page);
344 for byte in &mut self.storage[range] {
346 *byte = 0xff;
347 }
348 Ok(())
349 }
350}
351
352impl core::fmt::Display for BufferStorage {
353 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
354 let num_pages = self.num_pages();
355 let num_words = self.page_size() / self.word_size();
356 let num_bytes = self.word_size();
357 for page in 0 .. num_pages {
358 write!(f, "[{}]", self.page_erases[page])?;
359 for word in 0 .. num_words {
360 write!(f, " [{}]", self.word_writes[page * num_words + word])?;
361 for byte in 0 .. num_bytes {
362 let index = (page * num_words + word) * num_bytes + byte;
363 write!(f, "{:02x}", self.storage[index])?;
364 }
365 }
366 writeln!(f)?;
367 }
368 Ok(())
369 }
370}
371
372#[derive(Clone, Debug, PartialEq, Eq)]
376enum BufferOperation<ByteSlice: Borrow<[u8]>> {
377 Write {
379 index: StorageIndex,
381
382 value: ByteSlice,
384 },
385
386 Erase {
388 page: usize,
390 },
391}
392
393type OwnedBufferOperation = BufferOperation<Box<[u8]>>;
395
396type SharedBufferOperation<'a> = BufferOperation<&'a [u8]>;
398
399impl SharedBufferOperation<'_> {
400 fn to_owned(&self) -> OwnedBufferOperation {
401 match *self {
402 BufferOperation::Write { index, value } => {
403 BufferOperation::Write { index, value: value.to_vec().into_boxed_slice() }
404 }
405 BufferOperation::Erase { page } => BufferOperation::Erase { page },
406 }
407 }
408}
409
410#[derive(Clone)]
415enum Interruption {
416 Ready,
418
419 Armed { delay: usize },
422
423 Saved { operation: OwnedBufferOperation },
425}
426
427impl Interruption {
428 fn arm(&mut self, delay: usize) {
434 match self {
435 Interruption::Ready => *self = Interruption::Armed { delay },
436 _ => panic!(),
437 }
438 }
439
440 fn get(&mut self) -> Result<OwnedBufferOperation, usize> {
448 let mut interruption = Interruption::Ready;
449 core::mem::swap(self, &mut interruption);
450 match interruption {
451 Interruption::Armed { delay } => Err(delay),
452 Interruption::Saved { operation } => Ok(operation),
453 _ => panic!(),
454 }
455 }
456
457 fn tick(&mut self, operation: &SharedBufferOperation) -> Result<(), Error> {
467 match self {
468 Interruption::Ready => (),
469 Interruption::Armed { delay } if *delay == 0 => {
470 let operation = operation.to_owned();
471 *self = Interruption::Saved { operation };
472 return Err(INTERRUPT);
473 }
474 Interruption::Armed { delay } => *delay -= 1,
475 Interruption::Saved { .. } => panic!(),
476 }
477 Ok(())
478 }
479}
480
481#[cfg(test)]
482mod tests {
483 use super::*;
484
485 const NUM_PAGES: usize = 2;
486 const OPTIONS: BufferOptions = BufferOptions {
487 word_size: 4,
488 page_size: 16,
489 max_word_writes: 2,
490 max_page_erases: 3,
491 strict_mode: true,
492 };
493 const BLANK_WORD: &[u8] = &[0xff, 0xff, 0xff, 0xff];
496 const FIRST_WORD: &[u8] = &[0xee, 0xdd, 0xbb, 0x77];
497 const SECOND_WORD: &[u8] = &[0xca, 0xc9, 0xa9, 0x65];
498 const THIRD_WORD: &[u8] = &[0x88, 0x88, 0x88, 0x44];
499
500 fn new_storage() -> Box<[u8]> {
501 vec![0xff; NUM_PAGES * OPTIONS.page_size].into_boxed_slice()
502 }
503
504 #[test]
505 fn words_are_decreasing() {
506 fn assert_is_decreasing(prev: &[u8], next: &[u8]) {
507 for (&prev, &next) in prev.iter().zip(next.iter()) {
508 assert_eq!(prev & next, next);
509 assert!(prev != next);
510 }
511 }
512 assert_is_decreasing(BLANK_WORD, FIRST_WORD);
513 assert_is_decreasing(FIRST_WORD, SECOND_WORD);
514 assert_is_decreasing(SECOND_WORD, THIRD_WORD);
515 }
516
517 #[test]
518 fn options_ok() {
519 let buffer = BufferStorage::new(new_storage(), OPTIONS);
520 assert_eq!(buffer.word_size(), OPTIONS.word_size);
521 assert_eq!(buffer.page_size(), OPTIONS.page_size);
522 assert_eq!(buffer.num_pages(), NUM_PAGES);
523 assert_eq!(buffer.max_word_writes(), OPTIONS.max_word_writes);
524 assert_eq!(buffer.max_page_erases(), OPTIONS.max_page_erases);
525 }
526
527 #[test]
528 fn read_write_ok() {
529 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
530 let index = StorageIndex { page: 0, byte: 0 };
531 let next_index = StorageIndex { page: 0, byte: 4 };
532 assert_eq!(buffer.read_slice(index, 4).unwrap(), BLANK_WORD);
533 buffer.write_slice(index, FIRST_WORD).unwrap();
534 assert_eq!(buffer.read_slice(index, 4).unwrap(), FIRST_WORD);
535 assert_eq!(buffer.read_slice(next_index, 4).unwrap(), BLANK_WORD);
536 }
537
538 #[test]
539 fn erase_ok() {
540 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
541 let index = StorageIndex { page: 0, byte: 0 };
542 let other_index = StorageIndex { page: 1, byte: 0 };
543 buffer.write_slice(index, FIRST_WORD).unwrap();
544 buffer.write_slice(other_index, FIRST_WORD).unwrap();
545 assert_eq!(buffer.read_slice(index, 4).unwrap(), FIRST_WORD);
546 assert_eq!(buffer.read_slice(other_index, 4).unwrap(), FIRST_WORD);
547 buffer.erase_page(0).unwrap();
548 assert_eq!(buffer.read_slice(index, 4).unwrap(), BLANK_WORD);
549 assert_eq!(buffer.read_slice(other_index, 4).unwrap(), FIRST_WORD);
550 }
551
552 #[test]
553 fn invalid_range() {
554 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
555 let index = StorageIndex { page: 0, byte: 12 };
556 let half_index = StorageIndex { page: 0, byte: 14 };
557 let over_index = StorageIndex { page: 0, byte: 16 };
558 let bad_page = StorageIndex { page: 2, byte: 0 };
559
560 assert!(buffer.read_slice(index, 4).is_ok());
562 assert!(buffer.read_slice(half_index, 2).is_ok());
564 assert!(buffer.read_slice(over_index, 1).is_err());
566 assert!(buffer.read_slice(over_index, 0).is_ok());
568 assert!(buffer.read_slice(bad_page, 0).is_err());
570
571 assert!(buffer.write_slice(index, FIRST_WORD).is_ok());
573 assert!(buffer.write_slice(half_index, FIRST_WORD).is_err());
575 assert!(buffer.write_slice(over_index, FIRST_WORD).is_err());
577 assert!(buffer.write_slice(over_index, &[]).is_ok());
579 assert!(buffer.write_slice(bad_page, &[]).is_err());
581
582 assert!(buffer.erase_page(0).is_ok());
584 assert!(buffer.erase_page(2).is_err());
585 }
586
587 #[test]
588 fn write_twice_ok() {
589 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
590 let index = StorageIndex { page: 0, byte: 4 };
591 assert!(buffer.write_slice(index, FIRST_WORD).is_ok());
592 assert!(buffer.write_slice(index, SECOND_WORD).is_ok());
593 }
594
595 #[test]
596 fn write_twice_and_once_ok() {
597 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
598 let index = StorageIndex { page: 0, byte: 0 };
599 let next_index = StorageIndex { page: 0, byte: 4 };
600 assert!(buffer.write_slice(index, FIRST_WORD).is_ok());
601 assert!(buffer.write_slice(index, SECOND_WORD).is_ok());
602 assert!(buffer.write_slice(next_index, THIRD_WORD).is_ok());
603 }
604
605 #[test]
606 #[should_panic]
607 fn write_three_times_panics() {
608 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
609 let index = StorageIndex { page: 0, byte: 4 };
610 assert!(buffer.write_slice(index, FIRST_WORD).is_ok());
611 assert!(buffer.write_slice(index, SECOND_WORD).is_ok());
612 let _ = buffer.write_slice(index, THIRD_WORD);
613 }
614
615 #[test]
616 fn write_twice_then_once_ok() {
617 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
618 let index = StorageIndex { page: 0, byte: 0 };
619 assert!(buffer.write_slice(index, FIRST_WORD).is_ok());
620 assert!(buffer.write_slice(index, SECOND_WORD).is_ok());
621 assert!(buffer.erase_page(0).is_ok());
622 assert!(buffer.write_slice(index, FIRST_WORD).is_ok());
623 }
624
625 #[test]
626 fn erase_three_times_ok() {
627 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
628 assert!(buffer.erase_page(0).is_ok());
629 assert!(buffer.erase_page(0).is_ok());
630 assert!(buffer.erase_page(0).is_ok());
631 }
632
633 #[test]
634 fn erase_three_times_and_once_ok() {
635 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
636 assert!(buffer.erase_page(0).is_ok());
637 assert!(buffer.erase_page(0).is_ok());
638 assert!(buffer.erase_page(0).is_ok());
639 assert!(buffer.erase_page(1).is_ok());
640 }
641
642 #[test]
643 #[should_panic]
644 fn erase_four_times_panics() {
645 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
646 assert!(buffer.erase_page(0).is_ok());
647 assert!(buffer.erase_page(0).is_ok());
648 assert!(buffer.erase_page(0).is_ok());
649 let _ = buffer.erase_page(0).is_ok();
650 }
651
652 #[test]
653 #[should_panic]
654 fn switch_zero_to_one_panics() {
655 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
656 let index = StorageIndex { page: 0, byte: 0 };
657 assert!(buffer.write_slice(index, SECOND_WORD).is_ok());
658 let _ = buffer.write_slice(index, FIRST_WORD);
659 }
660
661 #[test]
662 fn interrupt_delay_ok() {
663 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
664
665 buffer.arm_interruption(1);
667
668 buffer.write_slice(StorageIndex { page: 0, byte: 0 }, &[0x5c; 8]).unwrap();
670 assert_eq!(buffer.disarm_interruption(), 0);
672 assert_eq!(&buffer.storage[.. 8], &[0x5c; 8]);
674 assert!(buffer.storage[8 ..].iter().all(|&x| x == 0xff));
675 }
676
677 #[test]
678 fn interrupt_save_ok() {
679 let mut buffer = BufferStorage::new(new_storage(), OPTIONS);
680
681 buffer.arm_interruption(1);
683
684 buffer.write_slice(StorageIndex { page: 0, byte: 0 }, &[0x5c; 8]).unwrap();
686 assert!(buffer.write_slice(StorageIndex { page: 0, byte: 8 }, &[0x93; 8]).is_err());
687 buffer.corrupt_operation(Box::new(|_, value| assert_eq!(value, &[0x93; 8])));
689 assert_eq!(&buffer.storage[.. 8], &[0x5c; 8]);
691 assert!(buffer.storage[8 ..].iter().all(|&x| x == 0xff));
692 }
693}