Comments (9)
For the record, I've managed to implement it "the hard way" like this:
impl<'de> Deserialize<'de> for MyEnum {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,
{
struct MyEnumVisitor;
impl<'a> Visitor<'a> for MyEnumVisitor {
type Value = MyEnum;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a or b")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
match v.to_lowercase().as_str() {
"variant_a" => Ok(MyEnum::A),
"variant_b" => Ok(MyEnum::B)
x => Err(de::Error::unknown_variant(x, &["a", "b"])),
}
}
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
self.visit_str(&v)
}
}
deserializer.deserialize_string(MyEnumVisitor)
}
}
from serde-aux.
Thanks for taking your time! In my use-case right now, it is actually for the deserialize_struct_case_insensitive
. I have a simple enum with variants that do not hold any additional data and want it to, well, be deserializable, independent of the string's case :)
Maybe something like deserialize_plain_enum_case_insensitive
is a good fit. Maybe there is even an official name for these enums:
enum E {
A, B, C, D
}
As of know, I just implemented the deserialization myself, the same way as @kornelski did above.
from serde-aux.
@vityafx:
What if an enum
must implement FromStr + Deserialize
, and the FromStr
implementation will be used to do a lowercase comparison. Maybe having the end-user depend on strum_macros
to implement the FromStr
might be a good idea. Not sure if this approach works in serde as I am not familiar with the internals to be honest.
from serde-aux.
Of course, this will work, and I could have implemented it myself, but this is not a generic solution I am looking for. For example, such a way still won't allow such an enum to be deserialized:
enum A {
A,
B(u64)
C(Box<A>),
D(Vector<A>),
// and all other "complex" varieties
}
If you look at the syn parser, the enums are always complex, and such enums will require hell ton of a work to specify all the possible ways of deserialisation. It may work, but then it won't work for the types which aren't just plain enums in C/C++ meaning. Perhaps, it can't be done at all.
As you and other people are looking forward to seeing the support of this macro even for plain enums, I will add it, but under a different name. I might need a couple of weeks, can't return to this project right now, unfortunately. Perhaps, I will take a look at it even sooner. So stay tuned. :)
And thanks for bringing this up, as I don't know how this crate is used, I only see it is a bit popular, but whenever I try to look at its' usage through going each dependent crate, it is quite poor, like only "deserialise_bool_from_anything" is used :) So if you have any other suggestions, please post those! Have a nice day!
from serde-aux.
Yes, I know that. This is intentional. I did not have much time to think how to do this for enums also unfortunately.
from serde-aux.
Awesome! Perhaps we could use it :) I'll look what we can do some time later, not sure when. It looks it is not so difficult though. Thank you for posting your hardcoded solution, it is useful anyway.
from serde-aux.
I've just checked again and I don't think I may come up with a generic solution. Custom deserialisation will always work (at least it should), but can't think of something generic here. Also, enums are different and so the deserialisation must be different for all the types of enums.
from serde-aux.
For info, I've found a more generic way to ignore the case when deserializing enums with variants that do not hold any additional data: https://docs.rs/oauth2/latest/oauth2/helpers/fn.deserialize_untagged_enum_case_insensitive.html#
You can have a look at the source to see how it is implemented:
///
/// Serde case-insensitive deserializer for an untagged `enum`.
///
/// This function converts values to lowercase before deserializing as the `enum`. Requires the
/// `#[serde(rename_all = "lowercase")]` attribute to be set on the `enum`.
///
/// # Example
///
/// In example below, the following JSON values all deserialize to
/// `GroceryBasket { fruit_item: Fruit::Banana }`:
///
/// * `{"fruit_item": "banana"}`
/// * `{"fruit_item": "BANANA"}`
/// * `{"fruit_item": "Banana"}`
///
/// Note: this example does not compile automatically due to
/// [Rust issue #29286](https://github.com/rust-lang/rust/issues/29286).
///
/// ```
/// # /*
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// #[serde(rename_all = "lowercase")]
/// enum Fruit {
/// Apple,
/// Banana,
/// Orange,
/// }
///
/// #[derive(Deserialize)]
/// struct GroceryBasket {
/// #[serde(deserialize_with = "helpers::deserialize_untagged_enum_case_insensitive")]
/// fruit_item: Fruit,
/// }
/// # */
/// ```
///
pub fn deserialize_untagged_enum_case_insensitive<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
use serde::de::Error;
use serde_json::Value;
T::deserialize(Value::String(
String::deserialize(deserializer)?.to_lowercase(),
))
.map_err(Error::custom)
}
What do you think about having this generic function in serde-aux
?
from serde-aux.
I think it is already better to implement a proc-macro for that and use an attribute, and correctly, using the syn
crate, generate the deserializing code. Or, perhaps, just a macro.
from serde-aux.
Related Issues (16)
- Provide a way of serializing and deseriaizing a enum number HOT 6
- deserialize_default_from_empty_object works differently when default tag is set on inner struct HOT 10
- Question: how to apply deserialize_struct_case_insensitive to a struct? HOT 7
- deserialize_struct_case_insensitive + serde::rename HOT 5
- deserialize_default_from_empty_object with null value HOT 6
- Cannot deserialize null HOT 2
- Feature Request: Get the field names of a struct HOT 9
- RUSTSEC-2020-0071 and 'chrono' dependency HOT 7
- Proposal: `deserialize_with_tilde` and `deserialize_optional_with_tilde` HOT 3
- `StringOrVecToVec` with trailing separator. HOT 7
- Please add deserialize_datetime_utc_from_seconds HOT 4
- Question: deserialize_option_number_from_string is not compatible with serde_json::Value::String HOT 8
- deserialize_option_number_from_string does not seem to allow non-existent values HOT 1
- [Bug] Introspect not working with `flatten` and (possibly) `serde_with` HOT 7
- "deserialize_option_number_from_string" fails when property does not exist. HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from serde-aux.