Reputation: 30577
I am trying to write a custom Deserialize
implementation that can perform a case insensitive deserialization of my enum:
use serde::{Deserialize, Deserializer}; // 1.0.120
use serde_json; // 1.0.61
#[derive(Debug, PartialEq)]
enum MyEnum {
Foo,
Bar,
}
// Implements case-insensitive deserialization of node types using from_str above
impl<'de> Deserialize<'de> for MyEnum {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let v = String::deserialize(deserializer)?;
match v.to_ascii_lowercase().as_ref() {
"foo" => Ok(MyEnum::Foo),
"bar" => Ok(MyEnum::Bar),
_ => Err(serde::de::Error::custom("invalid value")),
}
}
}
This works, but results in two allocations: one to place the input value into a String
and another to convert that String
to uppercase. I don't need the first one because serde provides an implementation of Deserialize for &str
. How do I call that?
This does not work:
let v: &str = &str::deserialize(deserializer)?
because:
error[E0277]: the trait bound `str: Deserialize<'_>` is not satisfied
--> src/lib.rs:16:24
|
16 | let v: &str = &str::deserialize(deserializer)?;
| ^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `str`
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.120/src/de/mod.rs:540:12
|
540 | D: Deserializer<'de>;
| ----------------- required by this bound in `serde::Deserialize::deserialize`
|
= help: the following implementations were found:
<&'a str as Deserialize<'de>>
(in addition to other errors about the size of str not being known).
It even tells me there is an implementation for &'a str
, but I am unsure what syntax to use to call it.
Upvotes: 3
Views: 203
Reputation: 42227
harmic provided a "dispatch" via the output type, you can invoke the method on the trait itself as long as the result is disambiguated.
Alternatively, you can use a "turbofish" in order to force a type-evaluation: as the error tells you, &str::deserialize(deserializer)?
really parses as &(str::deserialize(deserializer)?)
. <&str>::deserialize(deserializer)?
will force the call to happen on &str
instead, and obviate the need for explicitly typing the result.
Upvotes: 5
Reputation: 30577
The solution I eventually found (and I am not sure it is the only one) is to call the method on the trait, and use a type annotation to ensure the correct one is chosen.
let v : &str = Deserialize::deserialize(deserializer)?;
Upvotes: 2