Skip to main content

geello/
magic_value.rs

1use std::{collections::HashMap, convert::From};
2
3use peniko::Brush;
4use serde::{Deserialize, Serialize};
5use vello::kurbo::Stroke;
6
7pub trait MagicConverter {
8    fn convert(&mut self, props: &HashMap<String, PropValue>) -> Result<(), String>;
9}
10
11impl MagicConverter for Brush {
12    fn convert(&mut self, _: &HashMap<String, PropValue>) -> Result<(), String> {
13        Ok(())
14    }
15}
16
17impl MagicConverter for Stroke {
18    fn convert(&mut self, _: &HashMap<String, PropValue>) -> Result<(), String> {
19        Ok(())
20    }
21}
22
23pub trait MagicFetcher {
24    fn fetch(&mut self) -> Result<(), String>;
25}
26
27impl MagicFetcher for Brush {
28    fn fetch(&mut self) -> Result<(), String> {
29        Ok(())
30    }
31}
32
33impl MagicFetcher for Stroke {
34    fn fetch(&mut self) -> Result<(), String> {
35        Ok(())
36    }
37}
38
39#[derive(Debug, Default, PartialEq, Eq, Clone, Serialize, Deserialize)]
40pub enum StrEncoding {
41    #[default]
42    Ron,
43    #[cfg(feature = "from_json")]
44    Json,
45}
46
47#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)]
48pub enum MagicValueKind {
49    #[default]
50    Fixed,
51    Prop(String, StrEncoding),
52    Ron(String),
53    #[cfg(feature = "from_json")]
54    Json(String),
55    #[cfg(feature = "from_http")]
56    Http(String, StrEncoding),
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct MagicValue<T> {
61    #[serde(flatten)]
62    #[serde(default)]
63    inner: T,
64    #[serde(default)]
65    #[serde(skip_serializing_if = "crate::utils::is_default")]
66    kind: MagicValueKind,
67    #[serde(default)]
68    #[serde(skip_serializing_if = "crate::utils::is_default")]
69    need_scale: bool,
70}
71
72impl<T> MagicValue<T>
73where
74    T: Default,
75{
76    pub fn new_ron(path: String) -> Self {
77        Self {
78            inner: Default::default(),
79            kind: MagicValueKind::Ron(path),
80            need_scale: false,
81        }
82    }
83}
84
85impl<T> MagicValue<T> {
86    pub fn new(inner: T) -> Self {
87        Self {
88            inner,
89            kind: MagicValueKind::Fixed,
90            need_scale: false,
91        }
92    }
93    pub fn unwrap(self) -> T {
94        self.inner
95    }
96    pub fn as_ref(&self) -> &T {
97        &self.inner
98    }
99    pub fn as_mut(&mut self) -> &mut T {
100        &mut self.inner
101    }
102}
103
104impl<T> Default for MagicValue<T>
105where
106    T: Default,
107{
108    fn default() -> Self {
109        Self {
110            inner: Default::default(),
111            kind: MagicValueKind::Fixed,
112            need_scale: false,
113        }
114    }
115}
116
117impl<T> From<T> for MagicValue<T> {
118    fn from(value: T) -> Self {
119        MagicValue::new(value)
120    }
121}
122
123impl MagicValue<PropValue> {
124    pub fn inner_try_into<T: TryFrom<PropValue, Error = std::string::String>>(
125        &self,
126    ) -> Result<T, String> {
127        self.inner.clone().try_into()
128    }
129    pub fn to_string(&self) -> String {
130        self.inner.clone().to_string()
131    }
132    pub fn wrap<D: Into<PropValue>>(value: D) -> Self {
133        Self {
134            inner: Into::<PropValue>::into(value),
135            kind: MagicValueKind::Fixed,
136            need_scale: false,
137        }
138    }
139}
140
141impl<T> MagicValue<T>
142where
143    T: for<'de> Deserialize<'de> + Default + MagicFetcher + MagicConverter,
144{
145    pub fn convert(&mut self, props: &HashMap<String, PropValue>) -> Result<(), String> {
146        match &self.kind {
147            MagicValueKind::Prop(name, encoding) => {
148                if let Some(value) = props.get(name) {
149                    let mut v: MagicValue<T> = match encoding {
150                        StrEncoding::Ron => ron::from_str(&value.to_string()).map_err(|e| {
151                            format!("Deserializing value from Prop:{} error: {}", name, e)
152                        })?,
153                        #[cfg(feature = "from_json")]
154                        StrEncoding::Json => {
155                            serde_json::from_str(&value.to_string()).map_err(|e| {
156                                format!("Deserializing value from Prop:{} error: {}", name, e)
157                            })?
158                        }
159                    };
160                    v.fetch()?;
161                    v.convert(props)?;
162                    self.inner = v.unwrap();
163                } else {
164                    return Err(format!("No {} found in props", name));
165                }
166            }
167            _ => {}
168        }
169        self.inner.fetch()?;
170        self.inner.convert(props)?;
171        Ok(())
172    }
173}
174
175impl<T> MagicValue<T>
176where
177    T: for<'de> Deserialize<'de> + Default + MagicFetcher,
178{
179    pub fn fetch(&mut self) -> Result<(), String> {
180        let inner = match &self.kind {
181            MagicValueKind::Ron(path) => {
182                let content = std::fs::read_to_string(path)
183                    .map_err(|e| format!("Read value from File:{} error: {}", path, e))?;
184                let mut value: MagicValue<T> = ron::from_str(&content)
185                    .map_err(|e| format!("Deserializing value from File:{} error: {}", path, e))?;
186                value.fetch()?;
187                Some(value.unwrap())
188            }
189            #[cfg(feature = "from_json")]
190            MagicValueKind::Json(path) => {
191                let content = std::fs::read_to_string(path)
192                    .map_err(|e| format!("Read value from File:{} error: {}", path, e))?;
193                let mut value: MagicValue<T> = serde_json::from_str(&content)
194                    .map_err(|e| format!("Deserializing value from File:{} error: {}", path, e))?;
195                value.fetch()?;
196                Some(value.unwrap())
197            }
198            #[cfg(feature = "from_http")]
199            MagicValueKind::Http(url, encoding) => {
200                let res = reqwest::blocking::get(url)
201                    .map_err(|e| format!("Get value from Url:{} error: {}", url, e))?;
202                let text = res
203                    .text()
204                    .map_err(|e| format!("Get text from Url:{} error: {}", url, e))?;
205                let mut value: MagicValue<T> = match encoding {
206                    StrEncoding::Ron => ron::from_str(&text).map_err(|e| {
207                        format!("Deserializing value from Url:{} error: {}", url, e)
208                    })?,
209                    #[cfg(feature = "from_json")]
210                    StrEncoding::Json => serde_json::from_str(&text).map_err(|e| {
211                        format!("Deserializing value from Url:{} error: {}", url, e)
212                    })?,
213                };
214                value.fetch()?;
215                Some(value.unwrap())
216            }
217            _ => None,
218        };
219        if inner.is_some() {
220            self.inner = inner.unwrap();
221        }
222        self.inner.fetch()?;
223        Ok(())
224    }
225}
226
227#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
228pub enum PropValue {
229    #[default]
230    None,
231    String(String),
232    Float64(f64),
233    Float32(f32),
234    Int32(i32),
235    Int64(i64),
236    Boolean(bool),
237}
238
239impl MagicFetcher for PropValue {
240    fn fetch(&mut self) -> Result<(), String> {
241        Ok(())
242    }
243}
244
245impl MagicConverter for PropValue {
246    fn convert(&mut self, _: &HashMap<String, PropValue>) -> Result<(), String> {
247        Ok(())
248    }
249}
250
251impl From<&str> for PropValue {
252    fn from(value: &str) -> Self {
253        PropValue::String(value.to_string())
254    }
255}
256
257impl From<String> for PropValue {
258    fn from(value: String) -> Self {
259        PropValue::String(value)
260    }
261}
262
263impl From<f32> for PropValue {
264    fn from(value: f32) -> Self {
265        PropValue::Float32(value)
266    }
267}
268
269impl From<f64> for PropValue {
270    fn from(value: f64) -> Self {
271        PropValue::Float64(value)
272    }
273}
274
275impl From<bool> for PropValue {
276    fn from(value: bool) -> Self {
277        PropValue::Boolean(value)
278    }
279}
280
281impl ToString for PropValue {
282    fn to_string(&self) -> String {
283        match self {
284            PropValue::String(v) => v.clone(),
285            PropValue::Float64(v) => v.to_string(),
286            PropValue::Float32(v) => v.to_string(),
287            PropValue::Int32(v) => v.to_string(),
288            PropValue::Int64(v) => v.to_string(),
289            PropValue::Boolean(v) => v.to_string(),
290            PropValue::None => "None".to_string(),
291        }
292    }
293}
294
295impl TryFrom<PropValue> for String {
296    type Error = String;
297
298    fn try_from(value: PropValue) -> Result<Self, Self::Error> {
299        match value {
300            PropValue::String(v) => Ok(v),
301            PropValue::Float64(v) => Ok(v.to_string()),
302            PropValue::Float32(v) => Ok(v.to_string()),
303            PropValue::Int32(v) => Ok(v.to_string()),
304            PropValue::Int64(v) => Ok(v.to_string()),
305            PropValue::Boolean(v) => Ok(v.to_string()),
306            PropValue::None => Err("Cannot convert None to String".to_string()),
307        }
308    }
309}
310
311impl TryFrom<PropValue> for f32 {
312    type Error = String;
313    fn try_from(value: PropValue) -> Result<Self, Self::Error> {
314        match value {
315            PropValue::String(v) => v.parse().map_err(|e: std::num::ParseFloatError| {
316                format!("Convert from string error: {}", e.to_string())
317            }),
318            PropValue::Float64(v) => Ok(v as f32),
319            PropValue::Float32(v) => Ok(v),
320            PropValue::Int32(v) => Ok(v as f32),
321            PropValue::Int64(v) => Ok(v as f32),
322            PropValue::Boolean(v) => {
323                if v {
324                    Ok(1.0)
325                } else {
326                    Ok(0.0)
327                }
328            }
329            PropValue::None => Err("Cannot convert None to f32".to_string()),
330        }
331    }
332}
333
334impl TryFrom<PropValue> for f64 {
335    type Error = String;
336
337    fn try_from(value: PropValue) -> Result<Self, Self::Error> {
338        match value {
339            PropValue::String(v) => v.parse().map_err(|e: std::num::ParseFloatError| {
340                format!("Convert from string error: {}", e.to_string())
341            }),
342            PropValue::Float64(v) => Ok(v),
343            PropValue::Float32(v) => Ok(v as f64),
344            PropValue::Int32(v) => Ok(v as f64),
345            PropValue::Int64(v) => Ok(v as f64),
346            PropValue::Boolean(v) => {
347                if v {
348                    Ok(1.0)
349                } else {
350                    Ok(0.0)
351                }
352            }
353            PropValue::None => Err("Cannot convert None to f64".to_string()),
354        }
355    }
356}
357
358impl TryFrom<PropValue> for bool {
359    type Error = String;
360
361    fn try_from(value: PropValue) -> Result<Self, Self::Error> {
362        match value {
363            PropValue::String(v) => v.parse().map_err(|e: std::str::ParseBoolError| {
364                format!("Convert from string error: {}", e.to_string())
365            }),
366            PropValue::Float64(v) => Ok(v != 0.0),
367            PropValue::Float32(v) => Ok(v != 0.0),
368            PropValue::Int32(v) => Ok(v != 0),
369            PropValue::Int64(v) => Ok(v != 0),
370            PropValue::Boolean(v) => Ok(v),
371            PropValue::None => Err("Cannot convert None to bool".to_string()),
372        }
373    }
374}