-
-
Save matdexir/8b0285a63ec744f55d76131de643149a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use serde::de::{self, Deserialize, Visitor}; | |
use std::fmt; | |
pub struct Quantity(u64); | |
impl fmt::Display for Quantity { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "{}", self.0) | |
} | |
} | |
impl From<u64> for Quantity { | |
fn from(value: u64) -> Self { | |
Quantity(value) | |
} | |
} | |
impl From<Quantity> for u64 { | |
fn from(value: Quantity) -> u64 { | |
value.0 | |
} | |
} | |
struct QuantityVisitor; | |
impl<'de> Visitor<'de> for QuantityVisitor { | |
type Value = Quantity; | |
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
formatter.write_str("str of form `5kB` or `10MiB`") | |
} | |
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> | |
where | |
E: de::Error, | |
{ | |
if let Some((number, unit)) = split_unit(v) { | |
let parsed_value: u64 = number.parse().expect("Failed to parse number"); | |
let true_value = match_true_value(parsed_value, unit.as_str()); | |
Ok(Quantity(true_value as u64)) | |
} else { | |
Err(E::custom(format!("Unable to parse the true quantity"))) | |
} | |
} | |
} | |
impl<'de> Deserialize<'de> for Quantity { | |
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |
where | |
D: de::Deserializer<'de>, | |
{ | |
deserializer.deserialize_str(QuantityVisitor) | |
} | |
} | |
fn match_true_value(value: u64, unit: &str) -> u64 { | |
match unit { | |
"kB" => value * 1000, | |
"KiB" => value * 1024, | |
"mB" => value * 1000 * 1000, | |
_ => value, | |
} | |
} | |
fn split_unit(text: &str) -> Option<(String, String)> { | |
let chars = text.chars(); | |
let mut split_idx = None; | |
for (i, c) in chars.enumerate() { | |
if c.is_alphabetic() { | |
split_idx = Some(i); | |
break; | |
} | |
} | |
if let Some(i) = split_idx { | |
let number = text[..i].to_string(); | |
let unit = text[i..].to_string(); | |
Some((number, unit)) | |
} else { | |
None | |
} | |
} | |
fn main() { | |
println!("Hello, world!"); | |
const VALUE: &str = "\"10KiB\""; | |
let deserialized: Quantity = serde_json::from_str(&VALUE).unwrap(); | |
// let deser: i32 = serde_json::from_str("5").unwrap(); | |
println!("{}", deserialized); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment