scratch_test_model/scopes/
target_data.rs1use std::collections::HashMap;
2
3use svalue::SValue;
4
5use crate::{
6 Id,
7 attrs::data::{List, ListKind, Variable, VariableKind},
8 error::TargetDataError,
9};
10
11pub type TargetVariables = TargetData<VariableKind, (Variable, SValue)>;
12pub type TargetLists = TargetData<ListKind, (List, Vec<SValue>)>;
13
14#[derive(Debug, PartialEq)]
23pub struct TargetData<Kind, Data> {
24 map: HashMap<Id, Data>,
28 phantom: std::marker::PhantomData<Kind>,
29}
30
31impl<Kind, Data> TargetData<Kind, Data> {
32 pub fn values(&self) -> impl Iterator<Item = &Data> {
33 self.map.values()
34 }
35 pub fn ids(&self) -> impl Iterator<Item = &Id> {
36 self.map.keys()
37 }
38 pub fn iter(&self) -> impl Iterator<Item = (&Id, &Data)> {
39 self.map.iter()
40 }
41 pub fn get<'a>(&'a self, id: &Id) -> Option<&'a Data> {
42 self.map.get(id)
43 }
44}
45
46impl<Kind: DataEntry> TargetData<Kind, Kind::Data> {
47 pub(crate) fn from_json(value: &serde_json::Value) -> Result<Self, TargetDataError<Kind>> {
48 let dict = value
49 .as_object()
50 .ok_or(TargetDataError::ExpectedObject {})?;
51 let map: Result<_, _> = dict
52 .into_iter()
53 .map(|(id, def)| {
54 let id: Id = id.clone().into();
55 if let Some(parsed) = Kind::parse_entry(id.clone(), def) {
56 Ok((id, parsed))
57 } else {
58 Err(TargetDataError::AtLeastOneInvalid(id))
59 }
60 })
61 .collect();
62 Ok(Self {
63 map: map?,
64 phantom: std::marker::PhantomData {},
65 })
66 }
67}
68
69impl DataEntry for VariableKind {
70 type Data = (Variable, SValue);
71 fn parse_entry(id: Id, def: &serde_json::Value) -> Option<(Variable, SValue)> {
72 let name = def.get(0)?.as_str()?.into();
73 let Ok(initial) = SValue::try_from(def.get(1)?.clone()) else {
79 log::warn!("failed to parse value of variable {name:?}: definition is {def:?}");
80 return None;
81 };
82 Some((Variable::new(name, id), initial))
83 }
84}
85
86impl DataEntry for ListKind {
87 type Data = (List, Vec<SValue>);
88 fn parse_entry(id: Id, def: &serde_json::Value) -> Option<(List, Vec<SValue>)> {
89 let name = def[0].as_str()?.into();
90 let initial = if let Some(arr) = def[1].as_array() {
91 arr.iter()
92 .map(|element| {
93 if let Some(number) = element.as_number().cloned().map(SValue::from) {
94 return number;
95 }
96 let text = element
97 .as_str()
98 .map(|s| s.into())
99 .unwrap_or_else(|| element.to_string().into());
100 SValue::Text(text)
101 })
102 .collect()
103 } else {
104 return None;
105 };
106 Some((List::new(name, id), initial))
107 }
108}
109pub trait DataEntry {
110 type Data;
111 fn parse_entry(id: Id, value: &serde_json::Value) -> Option<Self::Data>
112 where
113 Self: Sized;
114}