1use crate::error::Error;
2use crate::imports::*;
3
4pub trait Linspace {
5 fn linspace(start: f64, stop: f64, n_elements: usize) -> Vec<f64> {
11 let n_steps = n_elements - 1;
12 let step_size = (stop - start) / n_steps as f64;
13 let v_norm: Vec<f64> = (0..=n_steps)
14 .collect::<Vec<usize>>()
15 .iter()
16 .map(|x| *x as f64)
17 .collect();
18 let v = v_norm.iter().map(|x| (x * step_size) + start).collect();
19 v
20 }
21}
22
23impl Linspace for Vec<f64> {}
24
25pub trait Min {
26 fn min(&self) -> anyhow::Result<f64>;
27}
28impl Min for &[f64] {
29 fn min(&self) -> anyhow::Result<f64> {
30 Ok(self.iter().fold(f64::INFINITY, |acc, curr| acc.min(*curr)))
31 }
32}
33impl Min for Vec<f64> {
34 fn min(&self) -> anyhow::Result<f64> {
35 self.as_slice().min()
36 }
37}
38impl Min for &[&f64] {
39 fn min(&self) -> anyhow::Result<f64> {
40 Ok(self.iter().fold(f64::INFINITY, |acc, curr| acc.min(**curr)))
41 }
42}
43impl Min for Vec<&f64> {
44 fn min(&self) -> anyhow::Result<f64> {
45 self.as_slice().min()
46 }
47}
48impl Min for &[Vec<f64>] {
49 fn min(&self) -> anyhow::Result<f64> {
50 self.iter()
51 .map(|v| v.min())
52 .try_fold(f64::INFINITY, |acc, x| Ok(acc.min(x?)))
53 }
54}
55impl Min for Vec<Vec<f64>> {
56 fn min(&self) -> anyhow::Result<f64> {
57 self.as_slice().min()
58 }
59}
60impl Min for &[Vec<Vec<f64>>] {
61 fn min(&self) -> anyhow::Result<f64> {
62 self.iter()
63 .map(|v| v.min())
64 .try_fold(f64::INFINITY, |acc, x| Ok(acc.min(x?)))
65 }
66}
67impl Min for Vec<Vec<Vec<f64>>> {
68 fn min(&self) -> anyhow::Result<f64> {
69 self.as_slice().min()
70 }
71}
72impl Min for Interpolator {
73 fn min(&self) -> anyhow::Result<f64> {
74 match self {
75 Interpolator::Interp0D(value) => Ok(*value),
76 Interpolator::Interp1D(..) => self.f_x()?.min(),
77 Interpolator::Interp2D(..) => self.f_xy()?.min(),
78 Interpolator::Interp3D(..) => self.f_xyz()?.min(),
79 Interpolator::InterpND(..) => Ok(self
80 .values()?
81 .iter()
82 .fold(f64::INFINITY, |acc, x| acc.min(*x))),
83 }
84 }
85}
86
87pub trait Max {
88 fn max(&self) -> anyhow::Result<f64>;
89}
90impl Max for &[f64] {
91 fn max(&self) -> anyhow::Result<f64> {
92 Ok(self
93 .iter()
94 .fold(f64::NEG_INFINITY, |acc, curr| acc.max(*curr)))
95 }
96}
97impl Max for Vec<f64> {
98 fn max(&self) -> anyhow::Result<f64> {
99 self.as_slice().max()
100 }
101}
102impl Max for &[&f64] {
103 fn max(&self) -> anyhow::Result<f64> {
104 Ok(self
105 .iter()
106 .fold(f64::NEG_INFINITY, |acc, curr| acc.max(**curr)))
107 }
108}
109impl Max for Vec<&f64> {
110 fn max(&self) -> anyhow::Result<f64> {
111 self.as_slice().max()
112 }
113}
114impl Max for &[Vec<f64>] {
115 fn max(&self) -> anyhow::Result<f64> {
116 self.iter()
117 .map(|v| v.max())
118 .try_fold(f64::NEG_INFINITY, |acc, x| Ok(acc.max(x?)))
119 }
120}
121impl Max for Vec<Vec<f64>> {
122 fn max(&self) -> anyhow::Result<f64> {
123 self.as_slice().max()
124 }
125}
126impl Max for &[Vec<Vec<f64>>] {
127 fn max(&self) -> anyhow::Result<f64> {
128 self.iter()
129 .map(|v| v.max())
130 .try_fold(f64::NEG_INFINITY, |acc, x| Ok(acc.max(x?)))
131 }
132}
133impl Max for Vec<Vec<Vec<f64>>> {
134 fn max(&self) -> anyhow::Result<f64> {
135 self.as_slice().max()
136 }
137}
138impl Max for Interpolator {
139 fn max(&self) -> anyhow::Result<f64> {
140 match self {
141 Interpolator::Interp0D(value) => Ok(*value),
142 Interpolator::Interp1D(..) => self.f_x()?.max(),
143 Interpolator::Interp2D(..) => self.f_xy()?.max(),
144 Interpolator::Interp3D(..) => self.f_xyz()?.max(),
145 Interpolator::InterpND(..) => Ok(self
146 .values()?
147 .iter()
148 .fold(f64::NEG_INFINITY, |acc, x| acc.max(*x))),
149 }
150 }
151}
152
153pub trait Init {
154 fn init(&mut self) -> Result<(), Error> {
157 Ok(())
158 }
159}
160
161pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> + Init {
162 const ACCEPTED_BYTE_FORMATS: &'static [&'static str] = &[
163 #[cfg(feature = "yaml")]
164 "yaml",
165 #[cfg(feature = "json")]
166 "json",
167 #[cfg(feature = "toml")]
168 "toml",
169 ];
170 const ACCEPTED_STR_FORMATS: &'static [&'static str] = &[
171 #[cfg(feature = "yaml")]
172 "yaml",
173 #[cfg(feature = "json")]
174 "json",
175 #[cfg(feature = "toml")]
176 "toml",
177 ];
178 #[cfg(feature = "resources")]
179 const RESOURCE_PREFIX: &'static str = "";
180
181 #[cfg(feature = "resources")]
187 fn from_resource<P: AsRef<Path>>(filepath: P, skip_init: bool) -> Result<Self, Error> {
188 let filepath = Path::new(Self::RESOURCE_PREFIX).join(filepath);
189 let extension = filepath
190 .extension()
191 .and_then(OsStr::to_str)
192 .ok_or_else(|| {
193 Error::SerdeError(format!("File extension could not be parsed: {filepath:?}"))
194 })?;
195 let file = crate::resources::RESOURCES_DIR
196 .get_file(&filepath)
197 .ok_or_else(|| {
198 Error::SerdeError(format!("File not found in resources: {filepath:?}"))
199 })?;
200 Self::from_reader(&mut file.contents(), extension, skip_init)
201 }
202
203 #[cfg(feature = "web")]
210 fn from_url<S: AsRef<str>>(url: S, skip_init: bool) -> Result<Self, Error> {
211 let url = url::Url::parse(url.as_ref())?;
212 let format = url
213 .path_segments()
214 .and_then(|segments| segments.last())
215 .and_then(|filename| Path::new(filename).extension())
216 .and_then(OsStr::to_str)
217 .with_context(|| "Could not parse file format from URL: {url:?}")?;
218 let mut response = ureq::get(url.as_ref()).call()?.into_reader();
219 Self::from_reader(&mut response, format, skip_init)
220 }
221
222 fn to_file<P: AsRef<Path>>(&self, filepath: P) -> Result<(), Error> {
231 let filepath = filepath.as_ref();
232 let extension = filepath
233 .extension()
234 .and_then(OsStr::to_str)
235 .ok_or_else(|| {
236 Error::SerdeError(format!("File extension could not be parsed: {filepath:?}"))
237 })?;
238 self.to_writer(
239 File::create(filepath).map_err(|err| Error::SerdeError(format!("{err}")))?,
240 extension,
241 )
242 }
243
244 fn from_file<P: AsRef<Path>>(filepath: P, skip_init: bool) -> Result<Self, Error> {
252 let filepath = filepath.as_ref();
253 let extension = filepath
254 .extension()
255 .and_then(OsStr::to_str)
256 .ok_or_else(|| {
257 Error::SerdeError(format!("File extension could not be parsed: {filepath:?}"))
258 })?;
259 let mut file = File::open(filepath)
260 .with_context(|| {
261 if !filepath.exists() {
262 format!("File not found: {filepath:?}")
263 } else {
264 format!("Could not open file: {filepath:?}")
265 }
266 })
267 .map_err(|err| Error::SerdeError(format!("{err}")))?;
268 Self::from_reader(&mut file, extension, skip_init)
269 }
270
271 fn to_writer<W: std::io::Write>(&self, mut wtr: W, format: &str) -> Result<(), Error> {
279 match format.trim_start_matches('.').to_lowercase().as_str() {
280 #[cfg(feature = "yaml")]
281 "yaml" | "yml" => serde_yaml::to_writer(wtr, self)
282 .map_err(|err| Error::SerdeError(format!("{err}")))?,
283 #[cfg(feature = "json")]
284 "json" => serde_json::to_writer(wtr, self)
285 .map_err(|err| Error::SerdeError(format!("{err}")))?,
286 #[cfg(feature = "toml")]
287 "toml" => {
288 let toml_string = self
289 .to_toml()
290 .map_err(|err| Error::SerdeError(format!("{err}")))?;
291 wtr.write_all(toml_string.as_bytes())
292 .map_err(|err| Error::SerdeError(format!("{err}")))?;
293 }
294 _ => Err(Error::SerdeError(format!(
295 "Unsupported format {format:?}, must be one of {:?}",
296 Self::ACCEPTED_BYTE_FORMATS
297 )))?,
298 }
299 Ok(())
300 }
301
302 fn from_reader<R: std::io::Read>(
310 rdr: &mut R,
311 format: &str,
312 skip_init: bool,
313 ) -> Result<Self, Error> {
314 let mut deserialized: Self =
315 match format.trim_start_matches('.').to_lowercase().as_str() {
316 #[cfg(feature = "yaml")]
317 "yaml" | "yml" => serde_yaml::from_reader(rdr)
318 .map_err(|err| Error::SerdeError(format!("{err}")))?,
319 #[cfg(feature = "json")]
320 "json" => serde_json::from_reader(rdr)
321 .map_err(|err| Error::SerdeError(format!("{err}")))?,
322 #[cfg(feature = "msgpack")]
323 "msgpack" => rmp_serde::decode::from_read(rdr)
324 .map_err(|err| Error::SerdeError(format!("{err}")))?,
325 #[cfg(feature = "toml")]
326 "toml" => {
327 let mut buf = String::new();
328 rdr.read_to_string(&mut buf)
329 .map_err(|err| Error::SerdeError(format!("{err}")))?;
330 Self::from_toml(buf, skip_init)
331 .map_err(|err| Error::SerdeError(format!("{err}")))?
332 }
333 _ => Err(Error::SerdeError(format!(
334 "Unsupported format {format:?}, must be one of {:?}",
335 Self::ACCEPTED_BYTE_FORMATS,
336 )))?,
337 };
338 if !skip_init {
339 deserialized.init()?;
340 }
341 Ok(deserialized)
342 }
343
344 fn to_str(&self, format: &str) -> anyhow::Result<String> {
351 match format.trim_start_matches('.').to_lowercase().as_str() {
352 #[cfg(feature = "yaml")]
353 "yaml" | "yml" => self.to_yaml(),
354 #[cfg(feature = "json")]
355 "json" => self.to_json(),
356 #[cfg(feature = "toml")]
357 "toml" => self.to_toml(),
358 _ => bail!(
359 "Unsupported format {format:?}, must be one of {:?}",
360 Self::ACCEPTED_STR_FORMATS
361 ),
362 }
363 }
364
365 fn from_str<S: AsRef<str>>(contents: S, format: &str, skip_init: bool) -> anyhow::Result<Self> {
373 Ok(
374 match format.trim_start_matches('.').to_lowercase().as_str() {
375 #[cfg(feature = "yaml")]
376 "yaml" | "yml" => Self::from_yaml(contents, skip_init)?,
377 #[cfg(feature = "json")]
378 "json" => Self::from_json(contents, skip_init)?,
379 #[cfg(feature = "toml")]
380 "toml" => Self::from_toml(contents, skip_init)?,
381 _ => bail!(
382 "Unsupported format {format:?}, must be one of {:?}",
383 Self::ACCEPTED_STR_FORMATS
384 ),
385 },
386 )
387 }
388
389 #[cfg(feature = "json")]
391 fn to_json(&self) -> anyhow::Result<String> {
392 Ok(serde_json::to_string(&self)?)
393 }
394
395 #[cfg(feature = "json")]
402 fn from_json<S: AsRef<str>>(json_str: S, skip_init: bool) -> anyhow::Result<Self> {
403 let mut json_de: Self = serde_json::from_str(json_str.as_ref())?;
404 if !skip_init {
405 json_de.init()?;
406 }
407 Ok(json_de)
408 }
409
410 #[cfg(feature = "msgpack")]
412 fn to_msg_pack(&self) -> anyhow::Result<Vec<u8>> {
413 Ok(rmp_serde::encode::to_vec_named(&self)?)
414 }
415
416 #[cfg(feature = "msgpack")]
423 fn from_msg_pack(msg_pack: &[u8], skip_init: bool) -> anyhow::Result<Self> {
424 let mut msg_pack_de: Self = rmp_serde::decode::from_slice(msg_pack)?;
425 if !skip_init {
426 msg_pack_de.init()?;
427 }
428 Ok(msg_pack_de)
429 }
430
431 #[cfg(feature = "toml")]
433 fn to_toml(&self) -> anyhow::Result<String> {
434 Ok(toml::to_string(&self)?)
435 }
436
437 #[cfg(feature = "toml")]
444 fn from_toml<S: AsRef<str>>(toml_str: S, skip_init: bool) -> anyhow::Result<Self> {
445 let mut toml_de: Self = toml::from_str(toml_str.as_ref())?;
446 if !skip_init {
447 toml_de.init()?;
448 }
449 Ok(toml_de)
450 }
451
452 #[cfg(feature = "yaml")]
454 fn to_yaml(&self) -> anyhow::Result<String> {
455 Ok(serde_yaml::to_string(&self)?)
456 }
457
458 #[cfg(feature = "yaml")]
465 fn from_yaml<S: AsRef<str>>(yaml_str: S, skip_init: bool) -> anyhow::Result<Self> {
466 let mut yaml_de: Self = serde_yaml::from_str(yaml_str.as_ref())?;
467 if !skip_init {
468 yaml_de.init()?;
469 }
470 Ok(yaml_de)
471 }
472}
473
474impl<T: SerdeAPI> SerdeAPI for Vec<T> {}
475impl<T: Init> Init for Vec<T> {
476 fn init(&mut self) -> Result<(), Error> {
477 for val in self {
478 val.init()?
479 }
480 Ok(())
481 }
482}
483
484pub trait Diff<T> {
485 fn diff(&self) -> Vec<T>;
488}
489
490impl<T: Clone + Sub<T, Output = T> + Default> Diff<T> for Vec<T> {
491 fn diff(&self) -> Vec<T> {
492 let mut v_diff: Vec<T> = vec![Default::default()];
493 v_diff.extend::<Vec<T>>(
494 self.windows(2)
495 .map(|vs| {
496 let x = &vs[0];
497 let y = &vs[1];
498 y.clone() - x.clone()
499 })
500 .collect(),
501 );
502 v_diff
503 }
504}
505
506pub trait SaveState {
509 fn save_state<F: Fn() -> String>(&mut self, loc: F) -> anyhow::Result<()>;
513}
514
515pub trait HistoryMethods: SaveState {
517 fn set_save_interval(&mut self, save_interval: Option<usize>) -> anyhow::Result<()>;
521 fn save_interval(&self) -> anyhow::Result<Option<usize>>;
524 fn clear(&mut self);
526}
527
528pub trait Step {
531 fn step<F: Fn() -> String>(&mut self, loc: F) -> anyhow::Result<()>;
535}
536
537pub trait EqDefault: std::default::Default + PartialEq {
539 fn eq_default(&self) -> bool {
541 *self == Self::default()
542 }
543}
544
545impl<T: Default + PartialEq> EqDefault for T {}
546
547pub trait SetCumulative {
549 fn set_cumulative(&mut self, dt: si::Time) -> anyhow::Result<()>;
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556
557 #[test]
558 fn test_linspace() {
559 assert_eq!(Vec::linspace(0., 2., 3), vec![0., 1., 2.]);
560 }
561
562 #[test]
563 fn test_max_for_vec_f64() {
564 assert_eq!(Vec::linspace(-10., 12., 5).max().unwrap(), 12.);
565 }
566 #[test]
567 fn test_min_for_vec_f64() {
568 assert_eq!(Vec::linspace(-10., 12., 5).min().unwrap(), -10.);
569 }
570
571 #[test]
572 fn test_diff() {
573 let diff = Vec::linspace(0., 2., 3).diff();
574 let ref_diff = vec![0., 1., 1.];
575 assert_eq!(diff, ref_diff);
576 }
577}