use midiserde::{json, Deserialize, Serialize};
mod string_as_f64 {
use miniserde::de::Visitor;
use miniserde::ser::Fragment;
pub fn begin(out: &mut Option<f64>) -> &mut dyn Visitor {
Place::new(out)
}
pub fn serialize(value: &f64) -> Fragment<'_> {
Fragment::Str(std::borrow::Cow::Owned(value.to_string()))
}
#[repr(C)]
struct Place {
out: Option<f64>,
}
impl Place {
fn new(out: &mut Option<f64>) -> &mut Self {
unsafe { &mut *std::ptr::addr_of_mut!(*out).cast::<Place>() }
}
}
impl Visitor for Place {
fn string(&mut self, s: &str) -> miniserde::Result<()> {
let val: f64 = s.parse().map_err(|_| miniserde::Error)?;
self.out = Some(val);
Ok(())
}
}
}
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Quote {
symbol: String,
#[mini(with = "string_as_f64")]
price: f64,
}
#[test]
fn deserialize() {
let j = r#"{"symbol": "AAPL", "price": "182.63"}"#;
let v: Quote = json::from_str(j).unwrap();
assert_eq!(v.symbol, "AAPL");
assert!((v.price - 182.63).abs() < f64::EPSILON);
}
#[test]
fn serialize() {
let v = Quote {
symbol: "AAPL".into(),
price: 182.63,
};
let j = json::to_string(&v);
assert!(j.contains(r#""price":"182.63""#));
}
#[test]
fn roundtrip() {
let original = Quote {
symbol: "GOOG".into(),
price: 2800.5,
};
let j = json::to_string(&original);
let parsed: Quote = json::from_str(&j).unwrap();
assert_eq!(original, parsed);
}
#[test]
fn invalid_f64_string() {
let j = r#"{"symbol": "AAPL", "price": "not-a-number"}"#;
let result: Result<Quote, _> = json::from_str(j);
assert!(result.is_err());
}