-
-
Notifications
You must be signed in to change notification settings - Fork 872
Closed
Labels
Description
When profiling toml_edit, a hand-written Deserialize for an untagged enum took a benchmark for a common case in cargo from 484us to 181us (for a single Cargo.toml file, using this in the dependency resolving would multiple that by hundreds).
Root Cause
The derive's untagged enum implementation tries each variant, one after another.
#[automatically_derived]
impl <'de> _serde::Deserialize<'de> for Value {
fn deserialize<__D>(__deserializer: __D)
-> _serde::__private::Result<Self, __D::Error> where
__D: _serde::Deserializer<'de> {
let __content =
match <_serde::__private::de::Content as
_serde::Deserialize>::deserialize(__deserializer)
{
_serde::__private::Ok(__val) => __val,
_serde::__private::Err(__err) => {
return _serde::__private::Err(__err);
}
};
if let _serde::__private::Ok(__ok) =
_serde::__private::Result::map(<i64 as
_serde::Deserialize>::deserialize(_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)),
Value::Integer)
{
return _serde::__private::Ok(__ok);
}
if let _serde::__private::Ok(__ok) =
_serde::__private::Result::map(<f64 as
_serde::Deserialize>::deserialize(_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)),
Value::Float) {
return _serde::__private::Ok(__ok);
}
// ...
if let _serde::__private::Ok(__ok) =
_serde::__private::Result::map(<Table as
_serde::Deserialize>::deserialize(_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)),
Value::Table) {
return _serde::__private::Ok(__ok);
}
_serde::__private::Err(_serde::de::Error::custom("data did not match any variant of untagged enum Value"))
}
}For each failure, we generate an error which allocates its message and is adverised as a #[cold]
#[cold]
fn invalid_type(unexp: Unexpected, exp: &Expected) -> Self {
Error::custom(format_args!("invalid type: {}, expected {}", unexp, exp))
}Potential Solutions
- Add a new attribute for suggesting a type to dispatch off of. This can be brittle as it requires knowing the Deserialize implementation of each of the types within the untagged enum.
- Find a backwards-compatible way of checking each variant without a call to
invalid_type - Find a backwards-compatible way of not allocating in
invalid_type - Consider making this error not be
#[cold](I'm assuming this will make little difference)