esp_partition_table/
estor.rs1use crate::{
2 PartitionBuffer, PartitionEntry, PartitionError, PartitionReaderState, PartitionTable,
3 PartitionWriterState,
4};
5use core::{mem::MaybeUninit, ops::Deref};
6use embedded_storage::{ReadStorage, Storage};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum StorageOpError<S: ReadStorage> {
11 PartitionError(PartitionError),
13 StorageError(S::Error),
15}
16
17impl<S: ReadStorage> From<PartitionError> for StorageOpError<S> {
18 fn from(error: PartitionError) -> Self {
19 Self::PartitionError(error)
20 }
21}
22
23impl PartitionTable {
24 pub fn iter_storage<'s, S>(
28 &self,
29 storage: &'s mut S,
30 calc_md5: bool,
31 ) -> PartitionStorageIter<'s, S>
32 where
33 S: ReadStorage,
34 {
35 PartitionStorageIter {
36 storage,
37 state: PartitionReaderState::new(self.addr, self.size, calc_md5),
38 buffer: MaybeUninit::uninit(),
39 }
40 }
41
42 #[cfg(feature = "embedded-storage")]
51 pub fn read_storage<S, T>(
52 &self,
53 storage: &mut S,
54 check_md5: Option<bool>,
55 ) -> Result<T, StorageOpError<S>>
56 where
57 S: ReadStorage,
58 T: FromIterator<PartitionEntry>,
59 {
60 let mut iter = self.iter_storage(storage, check_md5.is_some());
61 let result = (&mut iter).collect::<Result<_, _>>()?;
62
63 #[cfg(feature = "md5")]
64 if let Some(mandatory_md5) = check_md5 {
65 if !iter.check_md5().unwrap_or(!mandatory_md5) {
66 return Err(PartitionError::InvalidMd5.into());
67 }
68 }
69
70 Ok(result)
71 }
72
73 #[cfg(feature = "embedded-storage")]
77 pub fn write_storage<S>(
78 &self,
79 storage: &mut S,
80 partitions: impl IntoIterator<Item = impl AsRef<PartitionEntry>>,
81 write_md5: bool,
82 ) -> Result<usize, StorageOpError<S>>
83 where
84 S: Storage,
85 {
86 let mut data = MaybeUninit::<PartitionBuffer>::uninit();
87 let mut state = PartitionWriterState::new(self.addr, self.size, write_md5);
88
89 for partition in partitions {
90 if state.is_done() {
91 return Err(PartitionError::TooManyData.into());
92 }
93
94 state.write(unsafe { data.assume_init_mut() }, partition)?;
95
96 storage
97 .write(state.offset(), unsafe { data.assume_init_ref() })
98 .map_err(StorageOpError::StorageError)?;
99 }
100
101 #[cfg(feature = "md5")]
102 if write_md5 {
103 if state.is_done() {
104 return Err(PartitionError::TooManyData.into());
105 }
106
107 state.write_md5(unsafe { data.assume_init_mut() })?;
108
109 storage
110 .write(state.offset(), unsafe { data.assume_init_ref() })
111 .map_err(StorageOpError::StorageError)?;
112 }
113
114 Ok((state.offset() - self.addr) as usize)
115 }
116}
117
118pub struct PartitionStorageIter<'s, S> {
120 storage: &'s mut S,
121 state: PartitionReaderState,
122 buffer: MaybeUninit<PartitionBuffer>,
123}
124
125impl<S> PartitionStorageIter<'_, S> {
126 pub fn next_partition(&mut self) -> Result<PartitionEntry, StorageOpError<S>>
128 where
129 S: ReadStorage,
130 {
131 if self.state.is_done() {
132 return Err(StorageOpError::PartitionError(
133 PartitionError::NotEnoughData,
134 ));
135 }
136
137 if let Err(error) = self.storage.read(self.state.offset(), unsafe {
138 self.buffer.assume_init_mut()
139 }) {
140 return Err(StorageOpError::StorageError(error));
141 }
142
143 self.state
144 .read(unsafe { self.buffer.assume_init_ref() })
145 .map_err(From::from)
146 }
147}
148
149impl<S> Deref for PartitionStorageIter<'_, S> {
150 type Target = PartitionReaderState;
151
152 fn deref(&self) -> &Self::Target {
153 &self.state
154 }
155}
156
157impl<S> Iterator for PartitionStorageIter<'_, S>
158where
159 S: ReadStorage,
160{
161 type Item = Result<PartitionEntry, StorageOpError<S>>;
162
163 fn next(&mut self) -> Option<Self::Item> {
164 self.next_partition()
165 .map(Some)
166 .or_else(|error| {
167 if matches!(
168 error,
169 StorageOpError::PartitionError(PartitionError::NotEnoughData)
170 ) {
171 Ok(None)
172 } else {
173 Err(error)
174 }
175 })
176 .transpose()
177 }
178}