Skip to content

Commit 54aa1e5

Browse files
committed
PR feedback: don't implement infallibly allocating traits for TryVec
Also, add some doc comments to make the approach clear and warn against implementing such traits in the future.
1 parent 317ad5d commit 54aa1e5

File tree

1 file changed

+39
-20
lines changed

1 file changed

+39
-20
lines changed

mp4parse/src/lib.rs

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ mod fallible {
174174
use std::convert::TryInto as _;
175175
use std::io::Read;
176176
use std::io::Take;
177-
use std::iter::FromIterator;
178177
use std::iter::IntoIterator;
179178
use vec_push;
180179
use vec_with_capacity;
@@ -229,6 +228,25 @@ mod fallible {
229228
inner: Vec<T>,
230229
}
231230

231+
/// TryVec is a thin wrapper around std::vec::Vec to provide support for
232+
/// fallible allocation. Though the fallible allocator is only enabled
233+
/// with the mp4parse_fallible feature, the API differences from stdlib
234+
/// Vec ensure that all operations which allocate return a Result. For the
235+
/// most part, this simply means adding a Result return value to Vec
236+
/// functions which return nothing or a non-Result value. However, Vec
237+
/// implements some traits whose API cannot communicate failure, but which
238+
/// do require allocation, so it is important that TryVec does not
239+
/// implement these traits.
240+
///
241+
/// Specifically, do not implement any of the following traits:
242+
/// - Clone
243+
/// - Extend
244+
/// - From
245+
/// - FromIterator
246+
///
247+
/// This list may not be exhaustive. Exercise caution when implementing
248+
/// any new traits to ensure they won't potentially allocate in a way that
249+
/// can't return a Result to indicate allocation failure.
232250
impl<T> TryVec<T> {
233251
pub fn new() -> Self {
234252
Self { inner: Vec::new() }
@@ -282,12 +300,20 @@ mod fallible {
282300
Ok(())
283301
}
284302
}
303+
304+
pub fn resize_with<F>(&mut self, new_len: usize, f: F) -> Result<(), ()>
305+
where F: FnMut() -> T
306+
{
307+
self.reserve(new_len)?;
308+
self.inner.resize_with(new_len, f);
309+
Ok(())
310+
}
285311
}
286312

287313
impl<T: Clone> TryVec<TryVec<T>> {
288314
pub fn concat(&self) -> Result<TryVec<T>, ()> {
289315
let size = self.iter().map(|v| v.inner.len()).sum();
290-
let mut result: TryVec<T> = TryVec::with_capacity(size)?;
316+
let mut result = TryVec::with_capacity(size)?;
291317
for v in self.iter() {
292318
result.extend_from_slice(&v.inner)?;
293319
}
@@ -297,18 +323,11 @@ mod fallible {
297323

298324
impl<T: Clone> TryVec<T> {
299325
pub fn extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> {
326+
self.reserve(other.len())?;
300327
extend_from_slice(&mut self.inner, other)
301328
}
302329
}
303330

304-
impl<T: Clone> Clone for TryVec<T> {
305-
fn clone(&self) -> Self {
306-
Self {
307-
inner: self.inner.clone(),
308-
}
309-
}
310-
}
311-
312331
impl<T> std::ops::Deref for TryVec<T> {
313332
type Target = [T];
314333

@@ -317,11 +336,12 @@ mod fallible {
317336
}
318337
}
319338

320-
impl<T> FromIterator<T> for TryVec<T> {
321-
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
322-
Self {
323-
inner: Vec::from_iter(iter),
324-
}
339+
impl<T> IntoIterator for TryVec<T> {
340+
type Item = T;
341+
type IntoIter = std::vec::IntoIter<T>;
342+
343+
fn into_iter(self) -> Self::IntoIter {
344+
self.inner.into_iter()
325345
}
326346
}
327347

@@ -1089,7 +1109,7 @@ impl TryFrom<u8> for IlocVersion {
10891109
/// See ISO 14496-12:2015 § 8.11.3
10901110
/// `base_offset` is omitted since it is integrated into the ranges in `extents`
10911111
/// `data_reference_index` is omitted, since only 0 (i.e., this file) is supported
1092-
#[derive(Clone, Debug)]
1112+
#[derive(Debug)]
10931113
struct ItemLocationBoxItem {
10941114
item_id: u32,
10951115
construction_method: ConstructionMethod,
@@ -1464,9 +1484,8 @@ pub fn read_avif<T: Read>(f: &mut T, context: &mut AvifContext) -> Result<()> {
14641484
let primary_item_loc = read_avif_meta(&mut b)?;
14651485
match primary_item_loc.construction_method {
14661486
ConstructionMethod::File => {
1487+
primary_item_extents_data.resize_with(primary_item_loc.extents.len(), Default::default)?;
14671488
primary_item_extents = Some(primary_item_loc.extents);
1468-
primary_item_extents_data =
1469-
primary_item_extents.iter().map(|_| TryVec::new()).collect();
14701489
}
14711490
_ => return Err(Error::Unsupported("unsupported construction_method")),
14721491
}
@@ -1591,11 +1610,11 @@ fn read_avif_meta<T: Read + Offset>(src: &mut BMFFBox<T>) -> Result<ItemLocation
15911610
}
15921611

15931612
if let Some(loc) = iloc_items
1594-
.iter()
1613+
.into_iter()
15951614
.flatten()
15961615
.find(|loc| loc.item_id == primary_item_id)
15971616
{
1598-
Ok(loc.clone())
1617+
Ok(loc)
15991618
} else {
16001619
Err(Error::InvalidData(
16011620
"primary_item_id not present in iloc box",

0 commit comments

Comments
 (0)