use std::fmt::Display;
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
use serde_path_to_error::Segment;
use crate::{Error, Path, Result, Step};
pub fn from_json<T: DeserializeOwned>(text: &str) -> Result<T> {
let mut deserializer = serde_json::Deserializer::from_str(text);
let value = read(&mut deserializer)?;
deserializer.end().map_err(|e| Error::invalid(e.to_string()))?;
Ok(value)
}
pub(crate) fn read<'de, T: Deserialize<'de>, D: Deserializer<'de>>(deserializer: D) -> Result<T>
where
D::Error: Display,
{
serde_path_to_error::deserialize(deserializer).map_err(|error| {
let steps = error.path().iter().filter_map(|segment| match segment {
Segment::Seq { index } => Some(Step::Index(*index)),
Segment::Map { key } => Some(Step::Name(key.as_str().into())),
Segment::Enum { variant } => Some(Step::Name(variant.as_str().into())),
Segment::Unknown => None,
});
Error::Invalid { path: Path(steps.collect()), reason: error.into_inner().to_string().into() }
})
}
#[cfg(all(test, feature = "gpu"))]
mod tests {
use crate::{Scene, from_json};
#[test]
fn errors_name_the_path_through_presets_and_marks() {
let at = |json: &str| from_json::<Scene>(json).unwrap_err().to_string();
let grid = at(r#"{"space": {"plane": {"grid": "bogus"}}, "marks": []}"#);
assert!(grid.starts_with("space.plane.grid:"), "{grid}");
let mark = at(r#"{"space": "plane", "marks": [{"vertices": {"of": ["d", "t"], "colour": "x"}}]}"#);
assert!(mark.starts_with("marks[0].vertices"), "{mark}");
assert!(from_json::<Scene>(r#"{"space": "plane", "marks": []} trailing"#).is_err());
}
}