2CCG6KUP6VL2Q7WQKLVNIPPGZWHSWIOWETRCS3APZTV4WSF5GLWAC AZQVIGSM6OJHNHTTWY3X5D6YEYWQ5IXNJ2OM7DDVP2MPJ3R37MTAC K4CH53V4MO5KCCJOOQUQKI3LEFSUSCNAJS24VUWOZISXTCQD4FZQC 4MG5JFXTKAE3SOVKGGNKEUTNCKOWEBHTGKVZHJWLWE3PTZTQKHPAC SAHJYVNBUBBIUBI4ZMAXK4QJFOT54M5UA3W2HQMTNDSP3GGCRX7QC GQVS55HIQLU7KPJNRMF57QUM4EATSWFQRCS7ZEJMJPUXFX2NHSYAC 4QOTH75I2VINLY52J75OR3E3B5CN5ITHJGOAKQYXI6PH3XLJ6DBQC SPSFTMLRZE2R4EBAAQKWBUZDRYZ36S2VFTBIJRE6XS7JMKELV4AQC TTR5IFSG25VNBQ2F2FNOLUMTEIHVBHFOEXYB2ZWEHWOURUV4GJMQC XI5ALEH6NPTQWB6O62QV62EP4H3K7WSNTHCOGT3LZIIU6I2YDGIQC YJXKWWM6TQLANMJZ2KGCLYUPSHYQXBD6JGZZLGF4BHAPL57YFNAQC UKQAGL5F5LWZZR7RWFJI3H2MW6LXPRGPXAIGNBZI5IVJLWUFHLGAC U4VCAFXQNTKC7KWWE3B2JJMZMFRGLBOHSZIOXCE6EEXW7WE2Q5NAC 2SABVMY3A2RZDF3KJXZSMJ2UQ4Q5EW422G4DVBJRKK26S2ESGVQAC GUXZCEWWPBCHXO26JVWZ74CTSDFDDO775YR7FKY7UGVZCA7GCSYAC A6ZAYJNBYFXPUTCHTQDGAWUZIYOXNO3IJBN73ZX6PEJ3T4NMNOGQC fn from_str(s: &str) -> Result<Self, Self::Err> {match s {"ident" => Ok(Transform1::Ident),_ => Err(parse_transform1(file!(), line!(), s)),}}}/// Transforms from two TimeSeries<1> to a TimeSeries<2>.pub enum Transform2 {///Zip,}impl FromStr for Transform2 {type Err = Error;fn from_str(s: &str) -> Result<Self, Self::Err> {match s {"zip" => Ok(Transform2::Zip),_ => {Err(parse_transform2(file!(), line!(), s))},}}}
// --- Client-facing data-structures --------------------------------------------------------------/// `(DataType, Country)` key to lookup data or spec.#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub struct PageKey {///pub country: Country,///pub data_type: DataType,///pub index: usize,}impl PageKey {/// Return a new `PageKey`.pub fn new(country: Country, data_type: DataType, index: usize) -> Self {PageKey { country, data_type, index }}}impl<'a> TryInto<PageKey> for KeyTreeRef<'a> {type Error = keytree::Error;fn try_into(self) -> Result<PageKey, Self::Error> {Ok(PageKey {index: self.value("key::index")?,data_type: self.value("key::data_type")?,country: self.value("key::country")?,})}}/// Represents a series of graphics to be plotted on one page. A `PageKey` is a combination of/// `Country` and `DataType`. It is served to the client as one chunk of JSON.// GraphicJson. Json holds the JSON serialization as a String. PageJson is the largest component// that is serializable into JSON.#[derive(Debug)]pub struct TSData(pub HashMap<PageKey, String>);impl TSData {/// Build time-series data from a time-series specification.pub fn from_spec(spec: &Spec, root_path: &str) -> Result<Self, Error> {spec.into_data(root_path)}pub (crate) fn new() -> TSData {TSData(HashMap::new())}pub (crate) fn insert(&mut self, key: &PageKey, value: String) {match self.0.get_mut(key) {Some(_) => {println!("Tried to insert page_key: {:?} twice.", key);panic!();},None => {self.0.insert(*key, value);},}}}/// Converts specification data into `TSData`.pub struct Json(Vec<PageJson>);impl Json {pub (crate) fn into_data(&self) -> Result<TSData, Error> {let mut ts_data = TSData::new();for page_json in &self.0 {let key = PageKey::new(page_json.country,page_json.data_type,page_json.index);let value = match serde_json::to_string(&page_json) {Ok(s) => s,Err(err) => {eprintln!("{}", err.to_string());panic!();},};ts_data.insert(&key, value);}Ok(ts_data)}pub (crate) fn new() -> Self {Json(Vec::new())}pub (crate) fn push(&mut self, page_json: PageJson) {self.0.push(page_json);}}#[derive(Debug)]/// Serializable into JSON data for a time-series HTML page.pub struct PageJson {country: Country,data_type: DataType,index: usize,graphics: Vec<GraphicJson>,}impl PageJson {pub (crate) fn new(country: Country, data_type: DataType, index: usize) -> Self {PageJson {country, data_type, index, graphics: Vec::new()}}pub (crate) fn push(&mut self, graphic_json: GraphicJson) {self.graphics.push(graphic_json);}pub (crate) fn max(&self) -> f32 {self.graphics.iter().map(|graphic| graphic.max()).fold(f32::NEG_INFINITY, |a, b| a.max(b))}pub (crate) fn min(&self) -> f32 {self.graphics.iter().map(|graphic| graphic.min()).fold(f32::INFINITY, |a, b| a.min(b))}pub (crate) fn first_date(&self) -> MonthlyDate {match self.graphics.iter().map(|graphic| graphic.first_date().0).min(){Some(date) => MonthlyDate(date),None => {// No data in series?eprintln!("Could not calculate first date.");panic!()},}}pub (crate) fn last_date(&self) -> MonthlyDate {match self.graphics.iter().map(|graphic| graphic.last_date().0).max(){Some(date) => MonthlyDate(date),None => {// No data in series?eprintln!("Could not calculate last date.");panic!()},}}}impl Serialize for PageJson {fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>whereS: Serializer,{let mut page_json = serializer.serialize_struct("Json", 6)?;page_json.serialize_field("country", &self.country)?;page_json.serialize_field("data_type", &self.data_type)?;page_json.serialize_field("index", &self.index)?;page_json.serialize_field("max", &self.max())?;page_json.serialize_field("min", &self.min())?;page_json.serialize_field("first_date", &self.first_date())?;page_json.serialize_field("last_date", &self.last_date())?;page_json.serialize_field("graphics", &self.graphics)?;page_json.serialize_field("height", &GRAPHIC_HEIGHT)?;page_json.end()}}
/// GraphicJson is the largest component that is serializable into JSON.#[derive(Debug)]pub struct GraphicJson {///pub height: Option<f32>,///pub series: Vec<(RegularTimeSeries<1>, SeriesMetaData)>,}impl GraphicJson {pub (crate) fn new() -> Self {GraphicJson {height: None,series: Vec::new(),}}pub (crate) fn push(&mut self, time_series: RegularTimeSeries<1>, meta: SeriesMetaData) {self.series.push((time_series, meta))}/// Calculate the maximum value of all series in `Self`.pub (crate) fn max(&self) -> f32 {self.series.iter().map(|(ts, _)| ts.max(0)).fold(f32::NEG_INFINITY, |a, b| a.max(b))}/// Calculate the minimum value of all series in `Self`.pub (crate) fn min(&self) -> f32 {self.series.iter().map(|(ts, _)| ts.min(0)).fold(f32::INFINITY, |a, b| a.min(b))}/// Return first date in all series.pub (crate) fn first_date(&self) -> MonthlyDate {match self.series.iter().map(|(ts, _)| ts.first_date()).min(){Some(date) => MonthlyDate(date),None => {// No data in series?eprintln!("Could not calculate first date.");panic!()}}}/// Return last date of in all series.pub (crate) fn last_date(&self) -> MonthlyDate {match self.series.iter().map(|(ts, _)| ts.last_date()).max(){Some(date) => MonthlyDate(date),None => {// No data in series?eprintln!("Could not calculate first date.");panic!()}}}pub (crate) fn height(&self) -> f32 {match self.height {Some(h) => h,None => GRAPHIC_HEIGHT,}}}impl Serialize for GraphicJson {fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>whereS: Serializer,{let mut graphic_json = serializer.serialize_struct("GraphicJson", 6)?;graphic_json.serialize_field("height", &self.height())?;graphic_json.serialize_field("series", &self.series)?;graphic_json.serialize_field("max", &self.max())?;graphic_json.serialize_field("min", &self.min())?;graphic_json.serialize_field("first_date", &self.first_date())?;graphic_json.serialize_field("last_date", &self.last_date())?;graphic_json.end()}}
// The Spec components do not map well to Json components.// 1. Json is not serializable - it is a HashMap which maps PageKeys to Strings to serve.// 2. PageJson does not exists. PageSpec.into_json creates a Vec<GraphicJson>.pub (crate) fn into_data(&self, root_path: &str) -> Result<TSData, Error> {let mut json = Json::new();for page_spec in &self.0 {let mut page_json = PageJson::new(page_spec.country,page_spec.data_type,page_spec.index,);for graphic_spec in &page_spec.graphics {let mut graphic_json = GraphicJson::new();for series_spec in &graphic_spec.seriess {let rts = data_from_file(page_spec.country,series_spec.data_type,series_spec.series_id.clone(),root_path,)?;let meta = meta_from_file(page_spec.country,series_spec.data_type,series_spec.series_id.clone(),root_path,);
graphic_json.push(rts, meta);}page_json.push(graphic_json);}json.push(page_json);}// Now we have a Json datastructure which we can iterate over the pages, serialize, generate// keys, and build a TSData Hashmap.json.into_data()}
}}/// Specifies what text a graphic displays.pub enum TextSpec {/// Specifies that graphic displays Links to series.Link,/// Specifies that graphics displays metadata.Meta,/// Specifies that graphics do not display text.None,}impl FromStr for TextSpec {type Err = Error;fn from_str(s: &str) -> Result<Self, Self::Err> {match s {"link" => Ok(TextSpec::Link),"meta" => Ok(TextSpec::Meta),_ => Err(keytree_error(file!(), line!(), "Failed to parse to Text")),}
pub (crate) fn push(&mut self, series_spec: self::SeriesSpec) {self.seriess.push(series_spec)}
// pub (crate) fn push(// &mut self,// title: Option<Title>,// height: Option<f32>,// transform_spec: Vec<TransformSpec>)// {// let graph_spec = GraphSpec {// title,// height,// transform_spec,// };// self.seriess.push(series_spec)// }
GraphicSpec{height: self.opt_value("graphic::height")?,seriess: self.vec_at("graphic::series")?,
GraphicSpec {title: self.opt_value("graphic::title")?,height: self.opt_value("graphic::height")?,series_id: self.vec_value("graphic::series_id")?,fid: self.vec_value("graphic::fid")?,text: self.value("graphic::text")?,
SeriesSpec{data_type: self.value("series::data_type")?,series_id: self.value("series::series_id")?,
SeriesSpec {data_type: self.value("series::data_type")?,series_id: self.value("series::series_id")?,date_range,transforms: self.vec_value("series::transform")?,fid: self.opt_value("series::fid")?,
fn from_str(s: &str) -> Result<Self, Self::Err> {match s {"to_monthly" => Ok(Transform::ToMonthly),"to_quarterly" => Ok(Transform::ToQuarterly),"yoy" => Ok(Transform::YearOnYear),_ => Err(parse_transform1(file!(), line!(), s)),}}}/// SeriesIdentifierAfterTransform#[derive(Debug)]pub struct FID(String);
impl FID {pub (crate) fn new(series_id: &SeriesId, f: Vec<Transform>) -> Self {let mut s = format!("{}_",series_id,);for transform in f {match transform {Transform::ToMonthly => { s.push('m') },Transform::ToQuarterly => { s.push('q') },Transform::YearOnYear => { s.push('y') },}}FID(s)}}
fn from_str(s: &str) -> Result<Self, Self::Err> {Ok(FID(String::from(s)))}}
impl MonthlyDate {/// Create a time_series::DateRange.pub fn range(date_opt1: &Option<MonthlyDate>,date_opt2: &Option<MonthlyDate>) -> time_series::DateRange{time_series::DateRange::new(date_opt1.as_ref().map(|date| date.0),date_opt2.as_ref().map(|date| date.0),)}}
/// Create a time_series::DateRange.pub fn new(first_date: &Option<MonthlyDate>,last_date: &Option<MonthlyDate>) -> DateRange{DateRange(time_series::DateRange::new(&first_date.clone().map(|d| d.0),&last_date.clone().map(|d| d.0),))}///pub fn first_date(&self) -> Option<MonthlyDate> {self.0.first_date().map(|date| MonthlyDate(date))}///pub fn last_date(&self) -> Option<MonthlyDate> {self.0.last_date().map(|date| MonthlyDate(date))}}
for series_spec in series_specs {let ts_series_spec = ts::SeriesSpec::new(series_spec.data_type,series_spec.series_id.clone());ts_graphic_spec.push(ts_series_spec);};
// let series_id = series_spec.series_id;// let f = Vec::new();// for series_spec in series_specs {// let series_spec = ts::SeriesSpec::new(// series_spec.data_type,// series_id,// DateRange::new(&None, &None),// f,// FID::new(series_id, f),// );// graphic_spec.push(series_spec);// };