1#![cfg_attr(not(feature = "std"), no_std)]
8extern crate alloc;
9
10pub mod centered_average;
11#[cfg(feature = "fetch")]
12pub mod fetch;
13pub mod parsers;
14#[cfg(feature = "python")]
15pub mod python;
16pub mod store;
17
18use alloc::string::String;
19use alloc::vec::Vec;
20use core::fmt;
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub struct Date {
25 pub year: i32,
26 pub month: u8,
27 pub day: u8,
28}
29
30impl Date {
31 pub fn validate(&self) -> Result<(), SpaceWeatherError> {
32 if self.month < 1 || self.month > 12 || self.day < 1 || self.day > 31 {
33 return Err(SpaceWeatherError::InvalidDate);
34 }
35 Ok(())
36 }
37}
38
39#[derive(Clone, Debug)]
44pub struct SpaceWeatherRecord {
45 pub date: Date,
46 pub f10_7_obs: Option<f64>,
47 pub f10_7_adj: Option<f64>,
48 pub f10_7_jb: Option<f64>,
49 pub f10_7_jb_81c: Option<f64>,
50 pub ap_daily: Option<f64>,
51 pub ap_3hr: Option<[f64; 8]>,
52 pub kp_3hr: Option<[f64; 8]>,
53 pub s10_7: Option<f64>,
54 pub m10_7: Option<f64>,
55 pub y10_7: Option<f64>,
56 pub dtc: Option<f64>,
57}
58
59impl SpaceWeatherRecord {
60 pub fn validate(&self) -> Result<(), SpaceWeatherError> {
61 self.date.validate()?;
62 for v in [
63 self.f10_7_obs,
64 self.f10_7_adj,
65 self.f10_7_jb,
66 self.f10_7_jb_81c,
67 self.ap_daily,
68 self.s10_7,
69 self.m10_7,
70 self.y10_7,
71 self.dtc,
72 ]
73 .into_iter()
74 .flatten()
75 {
76 if v < 0.0 {
77 return Err(SpaceWeatherError::InvalidIndex);
78 }
79 }
80 Ok(())
81 }
82}
83
84pub trait SpaceWeatherIndex {
86 fn get(&self, date: Date) -> Option<&SpaceWeatherRecord>;
88
89 fn get_range(&self, start: Date, end: Date) -> Vec<&SpaceWeatherRecord>;
91}
92
93#[derive(Clone, Debug, PartialEq, Eq)]
95pub enum SpaceWeatherError {
96 InvalidDate,
97 InvalidIndex,
98 InvalidHeader,
99 InvalidWindow,
100 ParseError { row: usize, message: String },
101}
102
103impl fmt::Display for SpaceWeatherError {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 match self {
106 Self::InvalidDate => write!(f, "invalid date"),
107 Self::InvalidIndex => write!(f, "invalid index value"),
108 Self::InvalidHeader => write!(f, "invalid or missing CSV header"),
109 Self::InvalidWindow => write!(f, "window must be a positive odd number"),
110 Self::ParseError { row, message } => {
111 write!(f, "parse error at row {}: {}", row, message)
112 }
113 }
114 }
115}