1use alloc::{boxed::Box, vec::Vec};
2
3use crate::types::BLOCK_SIZE;
4
5#[derive(Default)]
6pub struct BlockStorage {
7 blocks: Vec<Option<Box<[u8; BLOCK_SIZE]>>>,
8 size: usize, }
10
11impl BlockStorage {
12 pub fn new() -> Self {
13 Self {
14 blocks: Vec::new(),
15 size: 0,
16 }
17 }
18
19 pub fn read(&self, offset: usize, buf: &mut [u8]) -> usize {
20 if offset >= self.size {
21 return 0;
22 }
23
24 let mut bytes_read = 0;
25 let mut current_offset = offset;
26
27 while bytes_read < buf.len() && current_offset < self.size {
28 let block_index = current_offset / BLOCK_SIZE;
29 let block_offset = current_offset % BLOCK_SIZE;
30
31 if block_index >= self.blocks.len() {
32 break;
33 }
34
35 if let Some(block) = &self.blocks[block_index] {
36 let bytes_in_block = BLOCK_SIZE - block_offset;
37 let bytes_to_copy = core::cmp::min(
38 bytes_in_block,
39 core::cmp::min(buf.len() - bytes_read, self.size - current_offset),
40 );
41
42 buf[bytes_read..bytes_read + bytes_to_copy]
43 .copy_from_slice(&block[block_offset..block_offset + bytes_to_copy]);
44
45 bytes_read += bytes_to_copy;
46 current_offset += bytes_to_copy;
47 } else {
48 let bytes_in_block = BLOCK_SIZE - block_offset;
50 let bytes_to_copy = core::cmp::min(
51 bytes_in_block,
52 core::cmp::min(buf.len() - bytes_read, self.size - current_offset),
53 );
54
55 for i in 0..bytes_to_copy {
56 buf[bytes_read + i] = 0;
57 }
58
59 bytes_read += bytes_to_copy;
60 current_offset += bytes_to_copy;
61 }
62 }
63
64 bytes_read
65 }
66
67 pub fn write(&mut self, offset: usize, data: &[u8]) -> usize {
68 if data.is_empty() {
69 return 0;
70 }
71
72 let mut bytes_written = 0;
73 let mut current_offset = offset;
74
75 while bytes_written < data.len() {
76 let block_index = current_offset / BLOCK_SIZE;
77 let block_offset = current_offset % BLOCK_SIZE;
78
79 while block_index >= self.blocks.len() {
81 self.blocks.push(None);
82 }
83
84 if self.blocks[block_index].is_none() {
86 self.blocks[block_index] = Some(Box::new([0u8; BLOCK_SIZE]));
87 }
88
89 if let Some(block) = &mut self.blocks[block_index] {
90 let bytes_in_block = BLOCK_SIZE - block_offset;
91 let bytes_to_copy = core::cmp::min(bytes_in_block, data.len() - bytes_written);
92
93 block[block_offset..block_offset + bytes_to_copy]
94 .copy_from_slice(&data[bytes_written..bytes_written + bytes_to_copy]);
95
96 bytes_written += bytes_to_copy;
97 current_offset += bytes_to_copy;
98 }
99 }
100
101 if current_offset > self.size {
103 self.size = current_offset;
104 }
105
106 bytes_written
107 }
108
109 pub fn size(&self) -> usize {
110 self.size
111 }
112
113 pub fn truncate(&mut self, new_size: usize) {
114 if new_size < self.size {
115 let new_block_count = new_size.div_ceil(BLOCK_SIZE);
117
118 self.blocks.truncate(new_block_count);
120
121 if new_size > 0 && new_block_count > 0 {
123 let last_block_index = new_block_count - 1;
124 let offset_in_last_block = new_size % BLOCK_SIZE;
125
126 if offset_in_last_block > 0
127 && let Some(block) = self
128 .blocks
129 .get_mut(last_block_index)
130 .and_then(|opt| opt.as_mut())
131 {
132 for byte in &mut block[offset_in_last_block..] {
134 *byte = 0;
135 }
136 }
137 }
138
139 self.size = new_size;
140 } else if new_size > self.size {
141 self.size = new_size;
145 }
146 }
148}