使用 serde_json 将内部枚举值从 &str 反序列化为 u64
Deserialize inner enum value from &str to u64 with serde_json
我希望能够在 json 对象中以十六进制形式写入颜色,然后将其反序列化为我的枚举 Color
类型 u64
的内部值。
目前我有一个如下所示的枚举:
#[derive(Deserialize, Serialize)]
pub enum Color {
Red,
Green,
Blue,
Custom(u64)
}
然后我在结构中使用它,如下所示:
pub struct Config {
#[serde(rename = "borderColor", deserialize_with = "color_deserialize")]
pub border_color: Color,
}
自定义反序列化函数:
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)
}
}
我现在对问题的理解是派生的 Deserialize
首先根据枚举类型(即 u64)映射 json 值,然后再尝试将其转换为十进制.因此,如果 json 表示是字符串而不是数字,它将中断。
如何让我的变体保持 u64
的内部类型,但在 json 中将颜色表示为十六进制?
您可以为 Color
本身自定义反序列化:
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);
}
当然,您还必须实现另一半,即序列化。
我希望能够在 json 对象中以十六进制形式写入颜色,然后将其反序列化为我的枚举 Color
类型 u64
的内部值。
目前我有一个如下所示的枚举:
#[derive(Deserialize, Serialize)]
pub enum Color {
Red,
Green,
Blue,
Custom(u64)
}
然后我在结构中使用它,如下所示:
pub struct Config {
#[serde(rename = "borderColor", deserialize_with = "color_deserialize")]
pub border_color: Color,
}
自定义反序列化函数:
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)
}
}
我现在对问题的理解是派生的 Deserialize
首先根据枚举类型(即 u64)映射 json 值,然后再尝试将其转换为十进制.因此,如果 json 表示是字符串而不是数字,它将中断。
如何让我的变体保持 u64
的内部类型,但在 json 中将颜色表示为十六进制?
您可以为 Color
本身自定义反序列化:
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);
}
当然,您还必须实现另一半,即序列化。