-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The way to serialize enum as number and duration #163
Comments
I figured out that the better choice is that we de/serialize use serde::{de, Deserialize, Serialize, Serializer};
use std::{fmt, time::Duration};
struct DurationVisitor;
impl<'de> de::Visitor<'de> for DurationVisitor {
type Value = Duration;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a milliseconds represents std::time::Duration")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Duration::from_millis(v))
}
}
fn from_duration_ms<'de, D>(d: D) -> Result<Duration, D::Error>
where
D: de::Deserializer<'de>,
{
d.deserialize_u64(DurationVisitor)
}
fn to_duration_ms<S>(x: &Duration, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_u64(x.as_millis() as u64)
}
#[derive(Deserialize, Serialize, Debug)]
struct Track {
#[serde(
deserialize_with = "from_duration_ms",
serialize_with = "to_duration_ms",
rename = "duration_ms"
)]
duration: Duration,
}
fn main() {
let json = r#"
{
"duration_ms": 31231232
}
"#;
let track: Track = serde_json::from_str(json).unwrap();
println!("{:?}", serde_json::to_string(&track).unwrap());
} |
I think manually deserializing |
The the |
Ah I was confused because rather than |
Yep, I have to confess it's a design mistake,
Agree! we should avoid to introduce any unnecessary dependency as well. |
My solution to manually deserialize #[derive(Debug, PartialEq)]
enum Mode {
Minor,
Major,
NoResult,
}
struct ModeVisitor;
impl<'de> de::Visitor<'de> for ModeVisitor {
type Value = Mode;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "valid number: 0, 1, -1")
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
match v {
0 => Ok(Mode::Minor),
1 => Ok(Mode::Major),
value @ _ => {
println!("invalid value: {:?}", value);
Err(de::Error::invalid_value(de::Unexpected::Unsigned(v), &self))
}
}
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: de::Error,
{
match v {
0 => Ok(Mode::Minor),
1 => Ok(Mode::Major),
-1 => Ok(Mode::NoResult),
value @ _ => {
println!("invalid value: {:?}", value);
Err(de::Error::invalid_value(de::Unexpected::Signed(v), &self))
}
}
}
}
fn from_integer<'de, D>(d: D) -> Result<Mode, D::Error>
where
D: de::Deserializer<'de>,
{
d.deserialize_any(ModeVisitor)
}
fn to_integer<S>(x: &Mode, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match x {
Mode::Minor => s.serialize_i8(0),
Mode::Major => s.serialize_i8(1),
Mode::NoResult => s.serialize_i8(-1),
}
}
#[derive(Deserialize, Serialize, Debug)]
struct Track {
#[serde(deserialize_with = "from_integer", serialize_with = "to_integer")]
mode: Mode,
}
fn main() {
let json = r#"
{
"mode": 1
}
"#;
let track: Track = serde_json::from_str(json).unwrap();
assert_eq!(track.mode, Mode::Major);
println!("{:?}", serde_json::to_string(&track).unwrap());
} You may be curious about the |
Is your feature request related to a problem? Please describe.
As #127 pointing out that
AudioAnalysisSection::mode
andAudioFeatures::mode
aref32
s but should beOption<Mode>
s whereenum Mode { Major, Minor }
as it is more useful, it needs to serialize enum to number and deserialize number to enum.Describe the solution you'd like
The
serde
official documentation provides a recommended way to serialize enum to number, but this solution needs an external crate namedserde_repr
, and I think we should be cautious to introduce a new dependency since it will increase the compile time.Describe alternatives you've considered
there is another solution to convert enum value to an integer, but needs unsafe operation, check this link for more details
Additional context
I am trying to figure out that is there a more lightweight way to do so, if you have any suggestion, feel free to help :)
PS:
I am still looking for a way to serialize/deserialize
Duration
, and I find some tracking issues:The text was updated successfully, but these errors were encountered: