Skip to content

Commit dfb5601

Browse files
committed
alloc: Add fallible Vec::with_capacity
1 parent 5661d18 commit dfb5601

File tree

5 files changed

+45
-11
lines changed

5 files changed

+45
-11
lines changed

lofty/src/id3/v2/frame/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,13 @@ impl<'a> Frame<'a> {
212212

213213
attached_picture.as_bytes(version)?
214214
},
215-
Frame::Popularimeter(popularimeter) => popularimeter.as_bytes(),
215+
Frame::Popularimeter(popularimeter) => popularimeter.as_bytes()?,
216216
Frame::KeyValue(content) => content.as_bytes(is_id3v23),
217217
Frame::RelativeVolumeAdjustment(frame) => frame.as_bytes(),
218218
Frame::UniqueFileIdentifier(frame) => frame.as_bytes(),
219219
Frame::Ownership(frame) => frame.as_bytes(is_id3v23)?,
220220
Frame::EventTimingCodes(frame) => frame.as_bytes(),
221-
Frame::Private(frame) => frame.as_bytes(),
221+
Frame::Private(frame) => frame.as_bytes()?,
222222
Frame::Timestamp(frame) => frame.as_bytes(is_id3v23)?,
223223
Frame::Binary(frame) => frame.as_bytes(),
224224
})

lofty/src/id3/v2/items/popularimeter.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::error::Result;
22
use crate::id3::v2::{FrameFlags, FrameHeader, FrameId};
3+
use crate::util::alloc::VecFallibleCapacity;
34
use crate::util::text::{decode_text, encode_text, TextDecodeOptions, TextEncoding};
45

56
use std::borrow::Cow;
@@ -114,8 +115,12 @@ impl<'a> PopularimeterFrame<'a> {
114115
/// Convert a [`PopularimeterFrame`] into an ID3v2 POPM frame byte Vec
115116
///
116117
/// NOTE: This does not include a frame header
117-
pub fn as_bytes(&self) -> Vec<u8> {
118-
let mut content = Vec::with_capacity(self.email.len() + 9);
118+
///
119+
/// # Errors
120+
///
121+
/// * The resulting [`Vec`] exceeds [`GlobalOptions::allocation_limit`](crate::config::GlobalOptions::allocation_limit)
122+
pub fn as_bytes(&self) -> Result<Vec<u8>> {
123+
let mut content = Vec::try_with_capacity_stable(self.email.len() + 9)?;
119124
content.extend(encode_text(self.email.as_str(), TextEncoding::Latin1, true));
120125
content.push(self.rating);
121126

@@ -132,7 +137,7 @@ impl<'a> PopularimeterFrame<'a> {
132137
content.extend(&counter_bytes[i..]);
133138
}
134139

135-
content
140+
Ok(content)
136141
}
137142
}
138143

@@ -146,7 +151,7 @@ mod tests {
146151
let rating = popm.rating;
147152
let counter = popm.counter;
148153

149-
let popm_bytes = popm.as_bytes();
154+
let popm_bytes = popm.as_bytes().unwrap();
150155
assert_eq!(&popm_bytes[..email.len()], email.as_bytes());
151156
assert_eq!(popm_bytes[email.len()], 0);
152157
assert_eq!(popm_bytes[email.len() + 1], rating);

lofty/src/id3/v2/items/private_frame.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::error::Result;
22
use crate::id3::v2::{FrameFlags, FrameHeader, FrameId};
3+
use crate::util::alloc::VecFallibleCapacity;
34
use crate::util::text::{decode_text, encode_text, TextDecodeOptions, TextEncoding};
45

56
use std::borrow::Cow;
@@ -81,18 +82,22 @@ impl<'a> PrivateFrame<'a> {
8182
}
8283

8384
/// Convert an [`PrivateFrame`] to a byte vec
84-
pub fn as_bytes(&self) -> Vec<u8> {
85+
///
86+
/// # Errors
87+
///
88+
/// * The resulting [`Vec`] exceeds [`GlobalOptions::allocation_limit`](crate::config::GlobalOptions::allocation_limit)
89+
pub fn as_bytes(&self) -> Result<Vec<u8>> {
8590
let Self {
8691
owner,
8792
private_data,
8893
..
8994
} = self;
9095

91-
let mut content = Vec::with_capacity(owner.len() + private_data.len());
96+
let mut content = Vec::try_with_capacity_stable(owner.len() + private_data.len())?;
9297
content.extend(encode_text(owner.as_str(), TextEncoding::Latin1, true));
9398
content.extend_from_slice(private_data);
9499

95-
content
100+
Ok(content)
96101
}
97102
}
98103

@@ -121,7 +126,7 @@ mod tests {
121126

122127
#[test]
123128
fn priv_encode() {
124-
let encoded = expected().as_bytes();
129+
let encoded = expected().as_bytes().unwrap();
125130

126131
let expected_bytes =
127132
crate::tag::utils::test_utils::read_path("tests/tags/assets/id3v2/test.priv");

lofty/src/mp4/ilst/write.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::mp4::read::{atom_tree, meta_is_full, nested_atom, verify_mp4, AtomRea
99
use crate::mp4::write::{AtomWriter, AtomWriterCompanion, ContextualAtom};
1010
use crate::mp4::AtomData;
1111
use crate::picture::{MimeType, Picture};
12+
use crate::util::alloc::VecFallibleCapacity;
1213
use crate::util::io::{FileLike, Length, Truncate};
1314

1415
use std::io::{Cursor, Seek, SeekFrom, Write};
@@ -540,7 +541,7 @@ fn create_udta(ilst: &[u8]) -> Result<Vec<u8>> {
540541

541542
// `udta` + `meta` + `hdlr` + `ilst`
542543
let capacity = ATOM_HEADER_LEN + FULL_ATOM_SIZE + HDLR_SIZE + ilst.len() as u64;
543-
let mut buf = Vec::with_capacity(capacity as usize);
544+
let mut buf = Vec::try_with_capacity_stable(capacity as usize)?;
544545

545546
buf.write_all(&UDTA_HEADER)?;
546547

lofty/src/util/alloc.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,29 @@ where
5656
Vec::new().fallible_repeat(element, expected_size)
5757
}
5858

59+
/// Provides the `try_with_capacity` method on `Vec`
60+
///
61+
/// This can be used directly.
62+
pub(crate) trait VecFallibleCapacity<T>: Sized {
63+
/// Same as `Vec::with_capacity`, but takes `GlobalOptions::allocation_limit` into account.
64+
///
65+
/// Named `try_with_capacity_stable` to avoid conflicts with the nightly `Vec::try_with_capacity`.
66+
fn try_with_capacity_stable(capacity: usize) -> Result<Self>;
67+
}
68+
69+
impl<T> VecFallibleCapacity<T> for Vec<T> {
70+
fn try_with_capacity_stable(capacity: usize) -> Result<Self> {
71+
if capacity > unsafe { global_options().allocation_limit } {
72+
err!(TooMuchData);
73+
}
74+
75+
let mut v = Vec::new();
76+
v.try_reserve(capacity)?;
77+
78+
Ok(v)
79+
}
80+
}
81+
5982
#[cfg(test)]
6083
mod tests {
6184
use crate::util::alloc::fallible_vec_from_element;

0 commit comments

Comments
 (0)