3

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
harmic
  • 28,606
  • 5
  • 67
  • 91
  • See also [How to call a method when a trait and struct use the same method name?](https://stackoverflow.com/q/44445730/155423). – Shepmaster Feb 01 '21 at 21:49

2 Answers2

5

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.

Masklinn
  • 34,759
  • 3
  • 38
  • 57
2

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)?;
harmic
  • 28,606
  • 5
  • 67
  • 91