1use crate::pyjson::Shape;
2use crate::{ProjectError, PyJson};
3pub use secs_types::target::TargetCurve;
4
5pub(crate) static TARGET_SHAPE: Shape = Shape::Record {
7 optional: &[],
8 nested: &[],
9};
10
11pub trait TargetJson: Sized {
14 fn to_json(&self) -> PyJson;
16 fn from_json(value: PyJson) -> Result<Self, ProjectError>;
18}
19
20impl TargetJson for TargetCurve {
21 fn to_json(&self) -> PyJson {
22 PyJson::Object(vec![(
23 "points".into(),
24 PyJson::Array(
25 self.points
26 .iter()
27 .map(|(frequency, level)| {
28 PyJson::Array(vec![PyJson::Float(*frequency), PyJson::Float(*level)])
29 })
30 .collect(),
31 ),
32 )])
33 }
34
35 fn from_json(value: PyJson) -> Result<Self, ProjectError> {
36 let points = match &value {
37 PyJson::Null => &[][..],
38 PyJson::Array(points) => points.as_slice(),
39 PyJson::Object(_) => value
40 .get("points")
41 .map_or(&[][..], |value| value.array().unwrap_or(&[])),
42 _ => {
43 return Err(ProjectError::Invalid(
44 "target must be an object or array".into(),
45 ));
46 }
47 };
48 Ok(Self::new(
49 points
50 .iter()
51 .map(|point| {
52 let pair = point.array().ok_or_else(|| {
53 ProjectError::Invalid("target point must be a pair".into())
54 })?;
55 if pair.len() != 2 {
56 return Err(ProjectError::Invalid(
57 "target point must contain two numbers".into(),
58 ));
59 }
60 Ok((
61 crate::project::float(&pair[0])?,
62 crate::project::float(&pair[1])?,
63 ))
64 })
65 .collect::<Result<Vec<_>, ProjectError>>()?,
66 ))
67 }
68}