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}