Skip to content

Commit 53fb533

Browse files
committed
Add try_from_iter for ArrayMemoryRegion and VecMemoryRegion
1 parent f2d838c commit 53fb533

File tree

1 file changed

+121
-72
lines changed

1 file changed

+121
-72
lines changed

core/src/memory_region.rs

Lines changed: 121 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,56 @@ impl<const SIZE: usize> ArrayMemoryRegion<SIZE> {
103103
self.data.set_len(data_len);
104104
self.data.as_mut_ptr().copy_from(data_ptr, data_len);
105105
}
106+
107+
/// Try to build a [ArrayMemoryRegion] from an [IntoIterator<Item = u8>]
108+
pub fn try_from_iter<I: IntoIterator<Item = u8>>(
109+
iter: I,
110+
) -> Result<Self, MemoryRegionFromIterError> {
111+
use MemoryRegionFromIterError::*;
112+
let mut iter = iter.into_iter();
113+
114+
match iter.next() {
115+
Some(MEMORY_REGION_IDENTIFIER) => {}
116+
Some(id) => return Err(InvalidIdentifier(id)),
117+
None => return Err(NotEnoughItems),
118+
}
119+
120+
let start_address = u64::from_le_bytes([
121+
iter.next().ok_or(NotEnoughItems)?,
122+
iter.next().ok_or(NotEnoughItems)?,
123+
iter.next().ok_or(NotEnoughItems)?,
124+
iter.next().ok_or(NotEnoughItems)?,
125+
iter.next().ok_or(NotEnoughItems)?,
126+
iter.next().ok_or(NotEnoughItems)?,
127+
iter.next().ok_or(NotEnoughItems)?,
128+
iter.next().ok_or(NotEnoughItems)?,
129+
]);
130+
131+
let length = u64::from_le_bytes([
132+
iter.next().ok_or(NotEnoughItems)?,
133+
iter.next().ok_or(NotEnoughItems)?,
134+
iter.next().ok_or(NotEnoughItems)?,
135+
iter.next().ok_or(NotEnoughItems)?,
136+
iter.next().ok_or(NotEnoughItems)?,
137+
iter.next().ok_or(NotEnoughItems)?,
138+
iter.next().ok_or(NotEnoughItems)?,
139+
iter.next().ok_or(NotEnoughItems)?,
140+
]);
141+
142+
if length > SIZE as u64 {
143+
return Err(LengthTooBig(length));
144+
}
145+
146+
// This call panics if length > SIZE
147+
// and `iter` does indeed contain more than SIZE items,
148+
// but we've just covered that case
149+
let data = ArrayVec::from_iter(iter.take(length as usize));
150+
151+
Ok(Self {
152+
start_address,
153+
data,
154+
})
155+
}
106156
}
107157

108158
#[cfg(feature = "std")]
@@ -134,42 +184,7 @@ impl<'a, const SIZE: usize> FromIterator<&'a u8> for ArrayMemoryRegion<SIZE> {
134184

135185
impl<const SIZE: usize> FromIterator<u8> for ArrayMemoryRegion<SIZE> {
136186
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
137-
let mut iter = iter.into_iter();
138-
139-
assert_eq!(
140-
iter.next().unwrap(),
141-
MEMORY_REGION_IDENTIFIER,
142-
"The given iterator is not for a memory region"
143-
);
144-
145-
let start_address = u64::from_le_bytes([
146-
iter.next().unwrap(),
147-
iter.next().unwrap(),
148-
iter.next().unwrap(),
149-
iter.next().unwrap(),
150-
iter.next().unwrap(),
151-
iter.next().unwrap(),
152-
iter.next().unwrap(),
153-
iter.next().unwrap(),
154-
]);
155-
156-
let length = u64::from_le_bytes([
157-
iter.next().unwrap(),
158-
iter.next().unwrap(),
159-
iter.next().unwrap(),
160-
iter.next().unwrap(),
161-
iter.next().unwrap(),
162-
iter.next().unwrap(),
163-
iter.next().unwrap(),
164-
iter.next().unwrap(),
165-
]);
166-
167-
let data = ArrayVec::from_iter(iter.take(length as usize));
168-
169-
Self {
170-
start_address,
171-
data,
172-
}
187+
Self::try_from_iter(iter).unwrap()
173188
}
174189
}
175190

@@ -234,6 +249,49 @@ impl VecMemoryRegion {
234249

235250
self.data.as_mut_ptr().copy_from(data_ptr, data_len);
236251
}
252+
253+
/// Try to build a [VecMemoryRegion] from an [IntoIterator<Item = u8>]
254+
pub fn try_from_iter<I: IntoIterator<Item = u8>>(
255+
iter: I,
256+
) -> Result<Self, MemoryRegionFromIterError> {
257+
use MemoryRegionFromIterError::*;
258+
let mut iter = iter.into_iter();
259+
260+
match iter.next() {
261+
Some(MEMORY_REGION_IDENTIFIER) => {}
262+
Some(id) => return Err(InvalidIdentifier(id)),
263+
None => return Err(NotEnoughItems),
264+
}
265+
266+
let start_address = u64::from_le_bytes([
267+
iter.next().ok_or(NotEnoughItems)?,
268+
iter.next().ok_or(NotEnoughItems)?,
269+
iter.next().ok_or(NotEnoughItems)?,
270+
iter.next().ok_or(NotEnoughItems)?,
271+
iter.next().ok_or(NotEnoughItems)?,
272+
iter.next().ok_or(NotEnoughItems)?,
273+
iter.next().ok_or(NotEnoughItems)?,
274+
iter.next().ok_or(NotEnoughItems)?,
275+
]);
276+
277+
let length = u64::from_le_bytes([
278+
iter.next().ok_or(NotEnoughItems)?,
279+
iter.next().ok_or(NotEnoughItems)?,
280+
iter.next().ok_or(NotEnoughItems)?,
281+
iter.next().ok_or(NotEnoughItems)?,
282+
iter.next().ok_or(NotEnoughItems)?,
283+
iter.next().ok_or(NotEnoughItems)?,
284+
iter.next().ok_or(NotEnoughItems)?,
285+
iter.next().ok_or(NotEnoughItems)?,
286+
]);
287+
288+
let data = Vec::from_iter(iter.take(length as usize));
289+
290+
Ok(Self {
291+
start_address,
292+
data,
293+
})
294+
}
237295
}
238296

239297
#[cfg(feature = "std")]
@@ -267,42 +325,7 @@ impl<'a> FromIterator<&'a u8> for VecMemoryRegion {
267325
#[cfg(feature = "std")]
268326
impl FromIterator<u8> for VecMemoryRegion {
269327
fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self {
270-
let mut iter = iter.into_iter();
271-
272-
assert_eq!(
273-
iter.next().unwrap(),
274-
MEMORY_REGION_IDENTIFIER,
275-
"The given iterator is not for a memory region"
276-
);
277-
278-
let start_address = u64::from_le_bytes([
279-
iter.next().unwrap(),
280-
iter.next().unwrap(),
281-
iter.next().unwrap(),
282-
iter.next().unwrap(),
283-
iter.next().unwrap(),
284-
iter.next().unwrap(),
285-
iter.next().unwrap(),
286-
iter.next().unwrap(),
287-
]);
288-
289-
let length = u64::from_le_bytes([
290-
iter.next().unwrap(),
291-
iter.next().unwrap(),
292-
iter.next().unwrap(),
293-
iter.next().unwrap(),
294-
iter.next().unwrap(),
295-
iter.next().unwrap(),
296-
iter.next().unwrap(),
297-
iter.next().unwrap(),
298-
]);
299-
300-
let data = Vec::from_iter(iter.take(length as usize));
301-
302-
Self {
303-
start_address,
304-
data,
305-
}
328+
Self::try_from_iter(iter).unwrap()
306329
}
307330
}
308331

@@ -433,6 +456,32 @@ impl<'a> Iterator for MemoryRegionIterator<'a> {
433456

434457
impl<'a> ExactSizeIterator for MemoryRegionIterator<'a> {}
435458

459+
#[derive(Debug)]
460+
/// Specifies what went wrong building a [MemoryRegion] from an iterator
461+
pub enum MemoryRegionFromIterError {
462+
/// The given iterator is not for a memory region.
463+
/// First item from iterator yielded invalid identifier. Expected [MEMORY_REGION_IDENTIFIER]
464+
InvalidIdentifier(u8),
465+
/// Iterator specified length too big for declared region
466+
LengthTooBig(u64),
467+
/// Iterator did not yield enough items to build memory region
468+
NotEnoughItems,
469+
}
470+
471+
impl core::fmt::Display for MemoryRegionFromIterError {
472+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
473+
use MemoryRegionFromIterError::*;
474+
match self {
475+
InvalidIdentifier(id) => write!(f, "Iterator is not for a memory region. Started with {id}, expected {MEMORY_REGION_IDENTIFIER}"),
476+
LengthTooBig(len) => write!(f, "Iterator specified length too big for declared region: {len}"),
477+
NotEnoughItems => write!(f, "Iterator did not yield enough items to build memory region"),
478+
}
479+
}
480+
}
481+
482+
#[cfg(feature = "std")]
483+
impl std::error::Error for MemoryRegionFromIterError {}
484+
436485
#[cfg(test)]
437486
mod tests {
438487
use super::*;

0 commit comments

Comments
 (0)