I want to be able to write a color as hex in a json object and then deserialize it to an inner value of type u64
of my enum Color
.
At the moment I have an enum looking like this:
#[derive(Deserialize, Serialize)]
pub enum Color {
Red,
Green,
Blue,
Custom(u64)
}
which I then use in a struct looking like this:
pub struct Config {
#[serde(rename = "borderColor", deserialize_with = "color_deserialize")]
pub border_color: Color,
}
Custom deserialize function:
fn color_deserialize<'de, D>(desierializer: D) -> Result<Color, D::Error>
where
D: Deserializer<'de>
{
use serde::de::Error;
let col = match Color::deserialize(desierializer) {
Ok(col) => col,
Err(e) => return Err(format!("Failed to deserilize color: {}", e)).map_err(Error::custom)
};
match col {
Color::Custom(x) => {
let x_str = &x.to_string();
let without_prefix = x_str.trim_start_matches("#");
let res = match u64::from_str_radix(without_prefix, 16) {
Ok(res) => res,
Err(e) => return Err(format!("Failed to deserialize color: {}", e)).map_err(Error::custom)
};
Ok(Color::Custom(res))
},
x => Ok(col)
}
}
My understanding of the problem right now is that the derived Deserialize
first maps the json value according to the type of the enum (which is u64) before I try to convert it to decimal. So because of this it will break if the json representation is a string rather than number.
How can I keep my variant with the inner type of u64
but represent the color as hex in the json?
You can customize the deserialization for Color
itself:
use serde::{de, Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug)]
pub enum Color {
Red,
Green,
Blue,
#[serde(deserialize_with = "color_deserialize")]
Custom(u64),
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Config {
#[serde(rename = "borderColor")]
pub border_color: Color,
}
fn color_deserialize<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: de::Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
let without_prefix = s.trim_start_matches("#");
match u64::from_str_radix(without_prefix, 16) {
Ok(res) => Ok(res),
Err(e) => Err(de::Error::custom(format!(
"Failed to deserialize color: {}",
e
))),
}
}
fn main() {
let c = serde_json::from_str::<Config>(
r##"{ "borderColor": { "Custom": "#bdcebe" }}"##,
);
println!("{:#?}", c);
}
And of course you'll have to implement the other half, ie the serialization, too.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.