diff --git a/src/serde/de.rs b/src/serde/de.rs index 2ce664d..f35d0c9 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -163,7 +163,8 @@ impl<'de> de::Deserialize<'de> for Ipld { where V: de::SeqAccess<'de>, { - let mut vec = Vec::with_capacity(visitor.size_hint().unwrap_or(0)); + let capacity = super::size_hint_cautious::(visitor.size_hint().unwrap_or(0)); + let mut vec = Vec::with_capacity(capacity); while let Some(elem) = visitor.next_element()? { vec.push(elem); diff --git a/src/serde/mod.rs b/src/serde/mod.rs index f108014..f24e5f1 100644 --- a/src/serde/mod.rs +++ b/src/serde/mod.rs @@ -7,7 +7,7 @@ mod extract_links; mod ser; use alloc::string::{String, ToString}; -use core::fmt; +use core::{fmt, mem}; pub use de::from_ipld; pub use extract_links::ExtractLinks; @@ -37,6 +37,13 @@ impl serde::ser::Error for SerdeError { impl serde::ser::StdError for SerdeError {} +// Limit the the number of bytes that are used for preallocating `Vec`s. This follows what Serde is +// doing internally with `serde::private::size_hint::cautious()`. +fn size_hint_cautious(size_hint: usize) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + size_hint.min(MAX_PREALLOC_BYTES / mem::size_of::()) +} + #[cfg(test)] mod tests { use alloc::{collections::BTreeMap, string::String, vec, vec::Vec}; diff --git a/src/serde/ser.rs b/src/serde/ser.rs index f31a2ea..67a98b9 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -254,8 +254,9 @@ impl serde::Serializer for Serializer { } fn serialize_seq(self, len: Option) -> Result { + let capacity = super::size_hint_cautious::(len.unwrap_or(0)); Ok(SerializeVec { - vec: Vec::with_capacity(len.unwrap_or(0)), + vec: Vec::with_capacity(capacity), }) } @@ -278,9 +279,10 @@ impl serde::Serializer for Serializer { variant: &'static str, len: usize, ) -> Result { + let capacity = super::size_hint_cautious::(len); Ok(SerializeTupleVariant { name: String::from(variant), - vec: Vec::with_capacity(len), + vec: Vec::with_capacity(capacity), }) }