Generalized to any data source and parser.

[?]
CrEcTsRjb1hHQjHuumqRfqdbVV4X58iLEubi4noaDPFa
Aug 1, 2021, 11:52 PM
65C2F32D7BC372KWZGU2DRLAE7BPFOHBXDSN2FTEHWNGB2FO6MBQC

Dependencies

  • [2] R2OU7BE4 Added min and max values to json.
  • [3] YAE43L6A Completed first try at UIData.
  • [4] LVMGQJGH Finished framework for checking series specifications with data.
  • [5] UUD3CJZL Making error handling more comprehensive.
  • [6] UKQAGL5F Checked ts_json toolchain.
  • [7] XPXYFEZM Finished code for building TSJson struct.
  • [8] 4QOTH75I Fixed UI specification code.
  • [9] K4CH53V4 Added GPL2 license, included missing source files.
  • [10] EHEK63WA Cleaning up ts.rs.
  • [11] PK7JY27R Integrate date_range with transforms.
  • [12] BB2T6X3X Improved documentation.
  • [13] CUADTSHQ Save csv data as multiple files.
  • [14] TSY4YBBZ Changed ts Spec datastructures to new format.
  • [15] SAHJYVNB Removed checking functionality.
  • [16] PQKGZNQG Added class field to GraphicJson.
  • [17] UCSU3QE4 Created keytree generator for u and cpi.
  • [18] 5B2HBV3J Completed first try at ts Json data-structure.
  • [19] SPSFTMLR Completed loading ts_data from specification.
  • [20] 77SIQZ3E Separating out spec generation.
  • [21] AIFRDCG2 Split off countries mod into a separate crate.
  • [22] GQVS55HI Finished generate_ts_spec() function.
  • [23] TTR5IFSG Working on building generic TSSpec.
  • [24] XI5ALEH6 Take advantage of keytree FromStr functionality.
  • [25] A6ZAYJNB Debugging DataSelector
  • [26] GUXZCEWW Added Country enum.
  • [27] E2T2A74Y Added class field to GraphicSpec.
  • [28] 5POF332L Working on fn cpi_included().
  • [29] 2SABVMY3 Finished into_json() functionality.
  • [30] 2CCG6KUP Redo time-series spec.
  • [31] U4VCAFXQ Added data_type to TSSpec key.
  • [*] 4MG5JFXT First record.

Change contents

  • replacement in src/ui.rs at line 18
    [3.351][3.351:364](),[3.364][3.110:203](),[3.203][3.17:31](),[3.17][3.17:31](),[3.31][3.204:251](),[3.31][3.426:429](),[3.134][3.426:429](),[3.251][3.426:429](),[3.426][3.426:429]()
    use crate::{
    // DataSpec,
    DataType,
    // DateRange,
    // data_from_file,
    // MonthlyDate,
    SeriesId,
    SeriesJson,
    SeriesSpec,
    Transform,
    };
    [3.351]
    [3.32]
    use crate::{ GraphicRange, SeriesId, SeriesSpec, Transform };
  • replacement in src/ui.rs at line 48
    [3.800][3.800:849]()
    failed_to_serialize_to_json(
    [3.800]
    [3.849]
    serialize_to_json_failed(
  • edit in src/ui.rs at line 66
    [2.322]
    [3.988]
    // Describes the plotted range
    x_range: Option<GraphicRange>,
    y_range: Option<GraphicRange>,
  • replacement in src/ui.rs at line 100
    [2.809][2.809:858]()
    None => self.x_min = Some(x),
    [2.809]
    [2.858]
    None => self.x_max = Some(x),
  • replacement in src/ui.rs at line 116
    [2.1243][2.1243:1292]()
    None => self.y_min = Some(y),
    [2.1243]
    [2.1292]
    None => self.y_max = Some(y),
  • replacement in src/ui.rs at line 146
    [3.1798][3.1798:1835]()
    failed_to_read_file(
    [3.1798]
    [3.1835]
    read_file_failed(
  • edit in src/ui.rs at line 154
    [3.2031][2.1628:1647]()
    dbg!(&kt);
  • replacement in src/ui.rs at line 155
    [2.1727][3.2101:2163](),[3.2101][3.2101:2163]()
    keytree_error(file!(), line!(), &err.to_string())
    [2.1727]
    [2.1728]
    external(file!(), line!(), &err.to_string())
  • edit in src/ui.rs at line 169
    [3.2400]
    [3.2400]
    x_range,
    y_range,
  • edit in src/ui.rs at line 172
    [3.146][3.1070:1071](),[3.2423][3.1070:1071](),[3.1070][3.1070:1071](),[3.1071][2.1753:1789]()
    dbg!((country, index));
  • replacement in src/ui.rs at line 186
    [3.2814][3.2814:2896]()
    Some(s) => s.read_data_with_transforms(*country, root_path)?,
    [3.2814]
    [3.2896]
    Some(s) => s.read_data_with_transforms(root_path)?,
  • replacement in src/ui.rs at line 188
    [3.2926][3.2926:2989]()
    return Err(failed_to_reference_series(
    [3.2926]
    [3.2989]
    return Err(series_lookup_failed(
  • replacement in src/ui.rs at line 199
    [3.3228][3.3228:3330]()
    Some(series_json) => series_json.read_data_with_transforms(*country, root_path)?,
    [3.3228]
    [3.3330]
    Some(series_json) => series_json.read_data_with_transforms(root_path)?,
  • replacement in src/ui.rs at line 201
    [3.3360][3.3360:3423]()
    return Err(failed_to_reference_series(
    [3.3360]
    [3.3423]
    return Err(series_lookup_failed(
  • replacement in src/ui.rs at line 211
    [3.1898][3.3611:3663]()
    let rts = x_rts.zip_one_one(y_rts);
    [3.1898]
    [3.2120]
    let rts = x_rts.zip_one_one(y_rts)
    .map_err(|err| external(file!(), line!(), &err.to_string()))?;
  • edit in src/ui.rs at line 234
    [2.2676]
    [2.2676]
    x_range: *x_range,
    y_range: *y_range,
  • edit in src/ui.rs at line 261
    [3.4508]
    [3.2808]
    pub x_range: Option<GraphicRange>,
    pub y_range: Option<GraphicRange>,
  • edit in src/ui.rs at line 282
    [3.5098]
    [3.3645]
    x_range: self.opt_value("graphic::x_range")?,
    y_range: self.opt_value("graphic::y_range")?,
  • edit in src/ts.rs at line 13
    [3.185][3.185:225]()
    use time_series::{ RegularTimeSeries };
  • replacement in src/ts.rs at line 14
    [3.7908][3.5391:5490]()
    use crate::{ DataType, DateRange, MonthlyDate, SeriesId, SeriesJson, SeriesMetaData, SeriesSpec };
    [3.7908]
    [3.1114]
    use crate::{ DataType, DateRange, GraphicRange, MonthlyDate, SeriesId, SeriesJson, SeriesSpec };
  • replacement in src/ts.rs at line 32
    [3.351][3.351:400]()
    failed_to_serialize_to_json(
    [3.351]
    [3.400]
    serialize_to_json_failed(
  • replacement in src/ts.rs at line 64
    [3.321][3.88:121]()
    category: GraphicCategory,
    [3.321]
    [3.169]
    category: GraphicCategory,
  • replacement in src/ts.rs at line 66
    [3.202][3.202:230]()
    series_ref: Vec<usize>,
    [3.202]
    [3.230]
    series_ref: Vec<usize>,
  • replacement in src/ts.rs at line 68
    [3.292][3.386:412](),[3.386][3.386:412]()
    text_spec: TextSpec,
    [3.292]
    [3.412]
    caption_spec: CaptionSpec,
    graphic_range: Option<GraphicRange>,
    note: Option<String>,
  • edit in src/ts.rs at line 80
    [3.6617]
    [3.6960]
    pub (crate) fn empty() -> Self {
    Spec(Vec::new())
    }
    // This has to be the sole initialization method for Spec, because we need to specifically
    // downcast counties to series specifications.
  • replacement in src/ts.rs at line 94
    [3.7271][3.7271:7308]()
    failed_to_read_file(
    [3.7271]
    [3.7308]
    read_file_failed(
  • edit in src/ts.rs at line 101
    [3.7448]
    [3.7448]
  • replacement in src/ts.rs at line 103
    [3.7504][3.7504:7648]()
    kt.to_ref().try_into().map_err(|err: keytree::error::Error| {
    keytree_error(file!(), line!(), &err.to_string())
    })
    [3.7504]
    [3.599]
    let mut spec: Spec = kt.to_ref().try_into().map_err(|err: keytree::error::Error| {
    external(file!(), line!(), &err.to_string())
    })?;
    // We need to do some post-processing to
    // Iterate over PageSpecs and
    spec.0.iter_mut().for_each(|page_spec| page_spec.downcast_countries());
    Ok(spec)
  • replacement in src/ts.rs at line 150
    [3.1430][3.1430:1515]()
    page_spec.into_series_json(series_id, *country, root_path)?,
    [3.1430]
    [3.1515]
    page_spec.into_series_json(series_id, root_path)?,
  • replacement in src/ts.rs at line 162
    [3.1260][3.1260:1283]()
    ..
    [3.1229]
    [3.1283]
    graphic_range,
    note,
  • replacement in src/ts.rs at line 192
    [3.796][3.1213:1353](),[3.1353][3.5799:5873](),[3.5873][3.1427:1501](),[3.1427][3.1427:1501]()
    let text_spec = match graphic_spec.category_opt {
    Some(GraphicCategory::Cleaned) => TextSpec::Link,
    Some(GraphicCategory::Collation) => TextSpec::Link,
    Some(GraphicCategory::Source) => TextSpec::Meta,
    [3.796]
    [3.308]
    let caption_spec = match graphic_spec.category_opt {
    Some(GraphicCategory::Cleaned) => CaptionSpec::Link,
    Some(GraphicCategory::Collation) => CaptionSpec::Link,
    Some(GraphicCategory::Source) => CaptionSpec::Meta,
  • replacement in src/ts.rs at line 197
    [3.389][3.389:460]()
    None => TextSpec::Meta,
    [3.389]
    [3.460]
    None => CaptionSpec::Meta,
  • replacement in src/ts.rs at line 201
    [3.1577][3.1502:1544](),[3.1617][3.1331:1375](),[3.1375][3.481:525]()
    category: category,
    series_ref: Vec::new(),
    text_spec: text_spec,
    [3.1577]
    [3.1717]
    category: category,
    series_ref: Vec::new(),
    caption_spec: caption_spec,
    graphic_range: *graphic_range,
    note: note.clone(),
  • replacement in src/ts.rs at line 212
    [3.1540][3.1540:1607]()
    return Err(failed_to_reference_series(
    [3.1540]
    [3.1607]
    return Err(series_lookup_failed(
  • replacement in src/ts.rs at line 300
    [3.8076][3.8076:8104]()
    // 2. PageJason.into_data()
    [3.8076]
    [3.8104]
    // 2. PageJson.into_data()
  • replacement in src/ts.rs at line 318
    [3.540][3.540:569](),[3.577][3.577:607](),[3.8607][3.608:635](),[3.635][3.3336:3369]()
    pub country: Country,
    pub data_type: DataType,
    pub index: usize,
    pub height_opt: Option<f32>,
    [3.8473]
    [3.2183]
    country: Country,
    data_type: DataType,
    index: usize,
    height_opt: Option<f32>,
  • edit in src/ts.rs at line 328
    [3.2253]
    [3.2253]
    pub fn new(
    country: Country,
    data_type: DataType,
    index: usize,
    height_opt: Option<f32>) -> Self
    {
    PageSpec {
    country,
    data_type,
    index,
    height_opt,
    seriess: BTreeMap::new(),
    graphics: Vec::new(),
    }
    }
    // Because country is specified in the PageSpec level of a specification, on initialization of a
    // PageSpec, we need to set the country in series. The only way to initialize is through the
    // Spec::from_file() function.
    pub (crate) fn downcast_countries(&mut self) {
    for mut country in self.seriess.iter().map(|(_, series_spec)| series_spec.country) {
    country = Some(self.country);
    }
    }
  • edit in src/ts.rs at line 357
    [3.2335][3.2335:2361]()
    country: Country,
  • replacement in src/ts.rs at line 364
    [3.2570][3.2570:2618]()
    failed_to_reference_series(
    [3.2570]
    [3.2618]
    series_lookup_failed(
  • replacement in src/ts.rs at line 372
    [3.2798][3.2530:2680]()
    let rts = series_spec.read_data_with_transforms(country, root_path)?;
    let meta = series_spec.read_meta_from_file(country, root_path);
    [3.2798]
    [3.2910]
    let rts = series_spec.read_data_with_transforms(root_path)?;
    let meta = series_spec.read_meta_from_file(root_path);
  • replacement in src/ts.rs at line 431
    [3.3478][3.604:624](),[3.604][3.604:624]()
    pub enum TextSpec {
    [3.3478]
    [3.681]
    pub enum CaptionSpec {
  • replacement in src/ts.rs at line 437
    [3.818][3.818:846]()
    impl FromStr for TextSpec {
    [3.818]
    [3.846]
    impl FromStr for CaptionSpec {
  • replacement in src/ts.rs at line 442
    [3.941][3.941:1107]()
    "link" => Ok(TextSpec::Link),
    "meta" => Ok(TextSpec::Meta),
    _ => Err(keytree_error(file!(), line!(), "Failed to parse to Text")),
    [3.941]
    [3.1247]
    "link" => Ok(CaptionSpec::Link),
    "meta" => Ok(CaptionSpec::Meta),
    _ => Err(external(file!(), line!(), "Failed to parse to Text")),
  • replacement in src/ts.rs at line 449
    [3.1266][3.1266:1299]()
    impl fmt::Display for TextSpec {
    [3.1266]
    [3.1299]
    impl fmt::Display for CaptionSpec {
  • replacement in src/ts.rs at line 452
    [3.1383][3.1383:1530]()
    TextSpec::Link => write!(f, "link"),
    TextSpec::Meta => write!(f, "meta"),
    TextSpec::None => write!(f, "none"),
    [3.1383]
    [3.1107]
    CaptionSpec::Link => write!(f, "link"),
    CaptionSpec::Meta => write!(f, "meta"),
    CaptionSpec::None => write!(f, "none"),
  • replacement in src/ts.rs at line 459
    [3.10307][3.1531:1563]()
    impl IntoKeyTree for TextSpec {
    [3.10307]
    [3.1563]
    impl IntoKeyTree for CaptionSpec {
  • replacement in src/ts.rs at line 463
    [3.1668][3.1668:1830]()
    TextSpec::Link => kt.push_value(0, "text", "link"),
    TextSpec::Meta => kt.push_value(0, "text", "meta"),
    TextSpec::None => {},
    [3.1668]
    [3.1830]
    CaptionSpec::Link => kt.push_value(0, "caption", "link"),
    CaptionSpec::Meta => kt.push_value(0, "caption", "meta"),
    CaptionSpec::None => {},
  • replacement in src/ts.rs at line 491
    [3.1840][3.1111:1208](),[3.1111][3.1111:1208]()
    _ => Err(keytree_error(file!(), line!(), "Failed to parse GraphicClass")),
    [3.1840]
    [3.1208]
    _ => Err(external(file!(), line!(), "Failed to parse GraphicClass")),
  • edit in src/ts.rs at line 521
    [3.2171]
    [3.978]
    pub graphic_range: Option<GraphicRange>,
    pub note: Option<String>,
  • edit in src/ts.rs at line 539
    [3.3808]
    [3.7030]
    graphic_range: self.opt_value("graphic::range")?,
    note: self.opt_value("graphic::note")?,
  • edit in src/ts.rs at line 553
    [3.1750]
    [3.1750]
    }
    if let Some(range) = &self.graphic_range {
    kt.push_value(1, "graphic", range);
  • edit in src/ts.rs at line 559
    [3.1761]
    [3.3902]
    if let Some(note) = &self.note {
    kt.push_value(1, "note", note);
    }
  • edit in src/ts.rs at line 573
    [3.3254][3.3254:3262]()
    ///
  • edit in src/ts.rs at line 574
    [3.3277][3.3277:3285]()
    ///
  • edit in src/ts.rs at line 577
    [3.3358][3.2388:2393]()
  • replacement in src/ts.rs at line 588
    [3.3657][3.3657:3732]()
    _ => Err(parse_transform1(file!(), line!(), s)),
    [3.3657]
    [3.3732]
    _ => Err(parse_transform1_failed(file!(), line!(), s)),
  • file addition: parser.rs (----------)
    [33.6]
    use std::convert::TryInto;
    use fred_api::Fred;
    use keytree::{ KeyTreeRef };
    use time_series::{ DatePoint, RegularTimeSeries, TimeSeries };
    use crate::SeriesSpec;
    use crate::error::*;
    // --- Specifications -----------------------------------------------------------------------------
    #[derive(Clone, Copy, Debug)]
    pub enum ParserSpec {
    FredSpec(FredSpec),
    FredDailySpec(FredDailySpec),
    }
    #[derive(Clone, Copy, Debug)]
    pub struct FredSpec {
    drop_first: usize
    }
    impl FredSpec {
    pub fn empty() -> Self {
    FredSpec { drop_first: 0 }
    }
    }
    #[derive(Clone, Copy, Debug)]
    pub struct FredDailySpec;
    impl FredDailySpec {
    pub fn empty() -> Self {
    FredDailySpec
    }
    }
    impl<'a> TryInto<FredSpec> for KeyTreeRef<'a> {
    type Error = keytree::Error;
    fn try_into(self) -> Result<FredSpec, Self::Error> {
    let drop_first: usize = self.opt_value("parser::drop_first")?
    .unwrap_or(0);
    Ok(FredSpec { drop_first })
    }
    }
    pub struct FredLineParser;
    impl FredLineParser {
    pub fn default() -> Self {
    FredLineParser
    }
    }
    pub enum FredLine {
    Ok(DatePoint::<1>),
    Dot(time_series::MonthlyDate),
    }
    impl FredLine {
    fn to_datepoint(&self) -> Option<DatePoint::<1>> {
    match self {
    FredLine::Ok(dp) => Some(*dp),
    FredLine::Dot(_) => None,
    }
    }
    fn new(obs: &fred_api::Observation, line: usize) -> Result<FredLine, Error> {
    let year = obs.date[..4].parse()
    .map_err(|_| {
    parse_datepoint_failed(
    file!(),
    line!(),
    &line.to_string(),
    &format!("{}, {}", obs.date, obs.value),
    )
    })?;
    let month = obs.date[5..7].parse()
    .map_err(|_| {
    parse_datepoint_failed(
    file!(),
    line!(),
    &line.to_string(),
    &format!("{}, {}", obs.date, obs.value),
    )
    })?;
    let date = time_series::MonthlyDate::ym(year, month);
    match obs.value.as_str() {
    "." => Ok(FredLine::Dot(date)),
    _ => {
    let value = obs.value[12..].parse::<f32>()
    .map_err(|_| {
    parse_datepoint_failed(
    file!(),
    line!(),
    &line.to_string(),
    &format!("{}, {}", obs.date, obs.value),
    )
    })?;
    Ok(FredLine::Ok(
    DatePoint::new(date, [value])
    ))
    },
    }
    }
    }
    // I'm not sure if its necessary to separate out FredParser from its specification, but it 'feels
    // right' at this point. Maybe fix in future?
    pub struct FredParser(pub FredSpec);
    impl FredParser {
    /// Given the series specification and the parser type, fetch the data and build it into a
    /// `RegularTimeSeries`.
    pub (crate) fn to_data(&self, spec: &SeriesSpec) -> Result<RegularTimeSeries::<1>, Error> {
    // First fetch the data
    let observations = match Fred::series_observations(&spec.series_id.to_string()) {
    Ok(series_obs) => series_obs.observations,
    Err(err) => {
    return Err(fred_error(
    file!(),
    line!(),
    &err.to_string(),
    ))
    },
    };
    // Iterate through observations to build time_series.
    let mut ts = TimeSeries::<1>::new(Vec::new());
    for (line_num, obs) in observations.iter()
    .enumerate()
    .skip(self.0.drop_first)
    {
    let dp = FredLine::new(obs, line_num + 1)?.to_datepoint().ok_or_else(|| {
    expected_datapoint_found_dot(
    file!(),
    line!(),
    &format!("{}, {}", obs.date, obs.value),
    &(line_num + 1).to_string(),
    )
    })?;
    ts.push(dp);
    }
    // Convert time-series to regular time-series.
    ts.try_into()
    .map_err(|err: time_series::error::Error| external(file!(), line!(), &err.to_string()))
    }
    // /// Parse observations into string for debugging and exit.
    // pub fn soft_parse(&self, observations: fred_api::Observations, err: Error) {
    // for (i, obs) in observations.iter().enumerate() {
    // eprintln!(
    // "{} {}, {}",
    // i + 1,
    // obs.date,
    // obs.value,
    // )
    // }
    // eprintln!("{}", err);
    // std::process::exit(1);
    // }
    }
    // --- Parsers ------------------------------------------------------------------------------------
    pub enum Parser {
    FredParser,
    FredDailyParser,
    }
    pub struct FredDailyParser(pub FredDailySpec);
    impl FredDailyParser {
    pub (crate) fn to_data(&self, series_spec: &SeriesSpec) -> Result<RegularTimeSeries::<1>, Error> {
    let observations = match Fred::series_observations(&series_spec.series_id.to_string()) {
    Ok(series_obs) => series_obs.observations,
    Err(err) => { return Err(fred_error(file!(), line!(), &err.to_string())) },
    };
    let mut ts = TimeSeries::<1>::new(Vec::new());
    let mut month_data = Vec::new();
    let mut current_date = time_series::MonthlyDate::ym(0,0);
    for (i, obs) in observations.iter().enumerate() {
    // Get the Datapoint or else continue.
    match FredLine::new(obs, i + 1)?.to_datepoint() {
    Some(dp) => {
    if dp.date() != current_date {
    let value = month_data.iter().sum::<f32>() / month_data.len() as f32;
    ts.push(DatePoint::<1>::new(current_date, [value]));
    current_date = dp.date();
    } else { month_data.push(dp.value(0)); }
    },
    None => {}, // Ignore dot line.
    }
    }
    ts.try_into()
    .map_err(|err| {
    expected_regular_time_series(
    file!(),
    line!(),
    &series_spec.country().to_string(),
    &series_spec.data_type.to_string(),
    &series_spec.series_id.to_string(),
    )
    })
    }
    }
  • replacement in src/main.rs at line 22
    [3.127][3.8881:8935]()
    let root_dir = shellexpand::tilde("~/test_data");
    [3.127]
    [3.10584]
    let root_dir = shellexpand::tilde("~/currency.engineering/contents/data");
  • replacement in src/main.rs at line 26
    [3.10602][3.10602:10679]()
    // println!("{}", DataSelector::from_file("series_selector.keytree")
    [3.10602]
    [3.10679]
    // println!("{}", DataSelector::from_file("interest_rate_selector.keytree")
  • replacement in src/main.rs at line 45
    [3.11132][3.2744:2825]()
    // let data_spec = DataSpec::from_file("source_data.keytree").unwrap();
    [3.11132]
    [3.11210]
    let data_spec = DataSpec::from_file(&format!("{}/source_data.keytree", root_dir)).unwrap();
  • edit in src/main.rs at line 47
    [3.11265]
    [3.1755]
    data_spec
    .update_write(&root_dir)
    .unwrap();
  • replacement in src/main.rs at line 79
    [3.11847][3.6175:6246]()
    let ui_spec = ui::Spec::from_file("ui_spec.keytree").unwrap();
    [3.11847]
    [3.6246]
    // let ui_spec = ui::Spec::from_file("ui_spec.keytree").unwrap();
  • replacement in src/lib.rs at line 166
    [3.799][3.7798:7802]()
    ///
    [3.799]
    [3.2200]
    pub mod error;
  • replacement in src/lib.rs at line 168
    [3.2214][3.7810:7829](),[3.7810][3.7810:7829](),[3.7829][3.2215:2219]()
    ///
    pub mod error;
    ///
    [3.2214]
    [3.2219]
    pub mod parser;
  • edit in src/lib.rs at line 170
    [3.2231][3.7830:7834](),[3.7830][3.7830:7834]()
    ///
  • replacement in src/lib.rs at line 174
    [3.2304][3.12162:12177](),[3.2304][3.10718:10732](),[3.12177][3.10718:10732](),[3.10718][3.10718:10732](),[3.10732][3.2305:2318](),[3.2318][3.12178:12193]()
    use std::file;
    use std::fmt;
    use std::fs;
    use std::line;
    [3.2304]
    [3.12193]
    use std::{ file, fmt, fs, line };
  • replacement in src/lib.rs at line 182
    [3.175][3.478:498](),[3.368][3.478:498](),[3.2343][3.478:498](),[3.478][3.478:498](),[3.498][3.2344:2475](),[3.2475][3.12238:12253](),[3.12268][3.2475:2517](),[3.2475][3.2475:2517]()
    use fred_api::Fred;
    use keytree::{
    KeyTree,
    KeyTreeRef,
    };
    use keytree::serialize::{
    IntoKeyTree,
    KeyTreeString,
    };
    use time_series::{
    DatePoint,
    RegularTimeSeries,
    TimeSeries,
    };
    [3.2343]
    [3.2377]
    use fred_api::{ Fred };
    use keytree::{ KeyTree, KeyTreeRef };
    use keytree::error::keytree_selection_failed;
    use keytree::serialize::{ IntoKeyTree, KeyTreeString };
    use time_series::{ RegularTimeSeries, TimeSeries };
  • replacement in src/lib.rs at line 189
    [3.2424][3.4266:4283](),[3.4283][3.2546:2567](),[3.1780][3.4177:4191](),[3.2567][3.4177:4191](),[3.4283][3.4177:4191](),[3.4297][3.4192:4207](),[3.4207][3.4297:4300](),[3.4297][3.4297:4300]()
    use crate::ts::{
    GraphicCategory,
    PageSpec,
    Transform,
    };
    [3.2424]
    [3.12294]
    use crate::parser::*;
    use crate::ts::{ GraphicCategory, Transform };
  • edit in src/lib.rs at line 192
    [3.12295][3.12295:12630](),[3.2616][3.2424:2425](),[3.12630][3.2424:2425](),[3.2424][3.2424:2425]()
    /// Return the pathname of a data file.
    pub fn data_path(
    root_path: &str,
    data_type: DataType,
    country: Country,
    series_id: SeriesId,
    extension: &str) -> String
    {
    format!(
    "{}/{}/{}/{}.{}",
    root_path,
    data_type,
    country.as_path(),
    series_id,
    extension,
    )
    }
  • replacement in src/lib.rs at line 200
    [3.2651][3.12631:12809]()
    let year = s[..4].parse().map_err(|_| parse_date(file!(), line!(), "failed"))?;
    let month = s[5..7].parse().map_err(|_| parse_date(file!(), line!(), "failed"))?;
    [3.2651]
    [3.2793]
    let year = s[..4].parse().map_err(|_| {
    parse_datepoint_failed(
    file!(),
    line!(),
    "?",
    s,
    )
    })?;
    let month = s[5..7].parse().map_err(|_| {
    parse_datepoint_failed(
    file!(),
    line!(),
    "?",
    s,
    )
    })?;
  • edit in src/lib.rs at line 247
    [3.5168][3.5168:5176]()
    ///
  • edit in src/lib.rs at line 251
    [3.5295][3.5295:5303]()
    ///
  • replacement in src/lib.rs at line 348
    [3.3347][3.12810:12875]()
    _ => Err(parse_datatype(file!(), line!(), s)),
    [3.3347]
    [3.15738]
    _ => Err(parse_datatype_failed(file!(), line!(), s)),
  • edit in src/lib.rs at line 413
    [3.3201]
    [3.3201]
    /// Used to build a generic specification.
    pub fn empty() -> Self {
    DataSpec {
    map: BTreeMap::new(),
    reverse: BTreeMap::new(),
    }
    }
  • edit in src/lib.rs at line 437
    [3.13603][3.1425:1432](),[3.1425][3.1425:1432](),[3.1432][3.3524:3675](),[3.3524][3.3524:3675]()
    }
    ///
    pub fn append(&mut self, other: &mut DataSpec) {
    self.map.append(&mut other.map);
    self.reverse.append(&mut other.reverse);
  • replacement in src/lib.rs at line 439
    [3.3682][3.3682:3717]()
    ///
    pub fn new() -> Self {
    [3.3682]
    [3.3717]
    pub (crate) fn new() -> Self {
  • replacement in src/lib.rs at line 447
    [3.3894][3.3894:3944]()
    pub fn from_vec(v: Vec<SeriesSpec>) -> Self {
    [3.3894]
    [3.3944]
    pub (crate) fn from_vec(v: Vec<SeriesSpec>) -> Self {
  • replacement in src/lib.rs at line 488
    [3.5020][3.4564:4609]()
    let mut spec = ts::Spec(Vec::new());
    [3.5020]
    [3.5061]
    let mut spec = ts::Spec::empty();
  • replacement in src/lib.rs at line 492
    [3.5133][3.4827:4870](),[3.4870][3.4728:4837](),[3.4728][3.4728:4837](),[3.4837][3.3533:3568](),[3.3568][3.4871:4916](),[3.4837][3.4871:4916](),[3.4916][3.4877:4932](),[3.4877][3.4877:4932]()
    let mut page_spec = PageSpec {
    country: *country,
    data_type: *data_type,
    index: 0,
    height_opt: None,
    seriess: BTreeMap::new(),
    graphics: Vec::new(),
    };
    [3.5133]
    [3.5193]
    let mut page_spec = ts::PageSpec::new(
    *country, // country
    *data_type, // data_type
    0, // index
    None, // height
    );
  • edit in src/lib.rs at line 502
    [3.3740]
    [3.5182]
    graphic_range: None,
    note: None,
  • edit in src/lib.rs at line 516
    [3.5179]
    [3.5632]
    parser: ParserSpec::FredSpec(FredSpec::empty()),
  • edit in src/lib.rs at line 528
    [3.3924]
    [3.6078]
    graphic_range: None,
    note: None,
  • replacement in src/lib.rs at line 562
    [3.14081][3.14081:14118]()
    failed_to_read_file(
    [3.14081]
    [3.14118]
    read_file_failed(
  • replacement in src/lib.rs at line 571
    [3.14318][3.14318:14380]()
    keytree_error(file!(), line!(), &err.to_string())
    [3.14318]
    [3.14380]
    external(file!(), line!(), &err.to_string())
  • edit in src/lib.rs at line 604
    [3.15173]
    [3.3536]
    dbg!(&series_spec);
  • edit in src/lib.rs at line 616
    [3.15541]
    [3.15541]
  • edit in src/lib.rs at line 618
    [3.15588]
    [3.15588]
  • replacement in src/lib.rs at line 621
    [3.15629][3.15629:15730]()
    if entry.file_type().is_dir() { continue };
    let pathbuf = entry.path();
    [3.15629]
    [3.15730]
    if !entry.file_type().is_dir() {
    let pathbuf = entry.path();
    let mut path_iter = pathbuf
    .iter()
    .rev()
    .map(|os_str| os_str.to_str()
    .unwrap());
  • replacement in src/lib.rs at line 631
    [3.15731][3.15731:15824]()
    let mut path_iter = pathbuf.iter().rev().map(|os_str| os_str.to_str().unwrap());
    [3.15731]
    [3.15824]
    let mut file_parts = path_iter
    .next()
    .unwrap()
    .split('.');
  • replacement in src/lib.rs at line 636
    [3.15825][3.15825:16007]()
    let mut file_parts = path_iter.next().unwrap().split('.');
    let file_stem = file_parts.next().unwrap();
    let file_ext = file_parts.next().unwrap();
    [3.15825]
    [3.16007]
    let file_stem = file_parts.next().unwrap();
    let file_ext = file_parts.next().unwrap();
  • replacement in src/lib.rs at line 639
    [3.16008][3.16008:16169](),[3.16169][3.1072:1086](),[3.1072][3.1072:1086]()
    if (file_ext != "csv") && (file_ext != "meta") {
    println!("Unknown file [{}]", pathbuf.to_str().unwrap());
    panic!();
    }
    [3.16008]
    [3.16170]
    if file_ext == "csv" || file_ext == "meta" {
  • replacement in src/lib.rs at line 641
    [3.16171][3.16171:16225]()
    let series_id = SeriesId::new(file_stem);
    [3.16171]
    [3.16225]
    let series_id = SeriesId::new(file_stem);
  • replacement in src/lib.rs at line 643
    [3.16226][3.16226:16564]()
    match self.get_series_spec(&series_id) {
    Some(_) => {},
    None => {
    match fs::remove_file(entry.path()) {
    Ok(_) => {},
    Err(_) => {
    return Err(file_error(file!(), line!()))
    },
    [3.16226]
    [3.16564]
    match self.get_series_spec(&series_id) {
    Some(_) => {},
    None => {
    println!("remove file: {}", entry.path().display());
    // match fs::remove_file(entry.path()) {
    // Ok(_) => {},
    // Err(_) => {
    // return Err(file_error(file!(), line!()))
    // },
    // }
    },
  • replacement in src/lib.rs at line 655
    [3.16586][3.16586:16605]()
    },
    [3.16586]
    [3.16605]
    }
  • replacement in src/lib.rs at line 706
    [3.7852][3.5499:5848]()
    // We conflate both FRED-facing series and client-facing series. The reason for this is so that
    // the time_series() functionality is in one place. The down-side is that we need to make
    // the transforms optional, as they are not used in FRED-facing functionality, and
    // the country field optional as it is specified at a higher level in JsonSpec.
    [3.7852]
    [3.17073]
    // The country field is always `Some`. The `Option` is used in initialization from a keytree file.
    // The transforms field is set is the time-series and ui specifications, and so is empty when a
    // SeriesSpec is initialized from a source specification.
  • replacement in src/lib.rs at line 711
    [3.7898][3.5849:5890]()
    pub country: Option<Country>,
    [3.7898]
    [3.7906]
    country: Option<Country>,
  • edit in src/lib.rs at line 716
    [3.8070]
    [3.8070]
    pub parser: ParserSpec,
  • replacement in src/lib.rs at line 721
    [3.5968][3.3786:3910](),[3.3910][3.6155:6191](),[3.6155][3.6155:6191]()
    /// Read metadata from file.
    pub fn read_meta_from_file(&self, country: Country, root_path: &str) -> SeriesMetaData
    {
    let path = data_path(
    [3.5968]
    [3.6191]
    pub fn country(&self) -> Country {
    self.country.unwrap()
    }
    pub fn data_path(&self, root_path: &str, extension: &str) -> String {
    format!(
    "{}/{}/{}/{}.{}",
  • replacement in src/lib.rs at line 730
    [3.6242][3.6242:6263]()
    country,
    [3.6242]
    [3.3911]
    self.country().as_path(),
  • replacement in src/lib.rs at line 732
    [3.3946][3.6299:6401](),[3.6299][3.6299:6401]()
    "meta"
    );
    let meta_str = fs::read_to_string(path).unwrap();
    [3.3946]
    [3.6401]
    extension,
    )
    }
    pub fn dir_path(&self, root_path: &str) -> String {
    format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    self.country().as_path(),
    )
    }
    /// Read metadata from file.
    pub fn read_meta_from_file(&self, root_path: &str) -> SeriesMetaData
    {
    let meta_str = fs::read_to_string(
    &self.data_path(root_path, "meta")
    ).unwrap();
  • edit in src/lib.rs at line 756
    [3.1253][3.6501:6502]()
  • edit in src/lib.rs at line 759
    [3.17207][3.17207:17292](),[3.17292][3.6503:6602](),[3.6602][3.17318:17471](),[3.17318][3.17318:17471](),[3.17471][3.6603:6702](),[3.6702][3.17497:17565](),[3.17497][3.17497:17565]()
    let csv_path = data_path(
    root_path,
    self.data_type,
    // Expect country to be Some while building source.
    self.country.unwrap(),
    self.series_id.clone(),
    "csv",
    );
    let meta_path = data_path(
    root_path,
    self.data_type,
    // Expect country to be Some while building source.
    self.country.unwrap(),
    self.series_id.clone(),
    "meta",
    );
  • replacement in src/lib.rs at line 760
    [3.17577][3.17577:17665]()
    Path::new(&csv_path).exists() &&
    Path::new(&meta_path).exists()
    [3.17577]
    [3.17665]
    Path::new(&self.data_path(root_path, "csv")).exists() &&
    Path::new(&self.data_path(root_path, "meta")).exists()
  • edit in src/lib.rs at line 767
    [3.5048][3.5048:5074]()
    country: Country,
  • replacement in src/lib.rs at line 769
    [3.5144][3.6403:6480]()
    let mut rts = self.read_data_without_transform(country, root_path)?;
    [3.5144]
    [3.6855]
    let mut rts = self.read_data_without_transform(root_path)?;
  • replacement in src/lib.rs at line 784
    [3.7325][3.7325:7372]()
    keytree_error(
    [3.7325]
    [3.7372]
    external(
  • edit in src/lib.rs at line 801
    [3.5278][3.5278:5304]()
    country: Country,
  • replacement in src/lib.rs at line 803
    [3.5374][3.5374:5427](),[3.2043][3.8091:8092](),[3.5427][3.8091:8092](),[3.7733][3.8091:8092](),[3.8091][3.8091:8092](),[3.8092][3.5428:5648]()
    let series_id_stem = self.series_id.stem();
    let csv_path = data_path(
    root_path,
    self.data_type,
    country,
    series_id_stem,
    "csv",
    );
    let ts = TimeSeries::<1>::from_csv(&csv_path)
    [3.5374]
    [3.5648]
    let ts = TimeSeries::<1>::from_csv(&self.data_path(root_path, "csv"))
  • replacement in src/lib.rs at line 816
    [3.5946][3.5946:5973]()
    pub fn data_from_fred(
    [3.5946]
    [3.5973]
    pub fn to_data(
  • replacement in src/lib.rs at line 818
    [3.5988][3.5988:6053]()
    country: Country) -> Result<RegularTimeSeries<1>, Error>
    [3.5988]
    [3.6053]
    parser: ParserSpec) -> Result<RegularTimeSeries<1>, Error>
  • replacement in src/lib.rs at line 820
    [3.6059][3.18065:18373](),[3.7816][3.18065:18373](),[3.18065][3.18065:18373](),[3.18373][3.8201:8202](),[3.8201][3.8201:8202](),[3.8202][3.18374:18545](),[3.18545][3.8389:8390](),[3.8389][3.8389:8390](),[3.8390][3.18546:18582](),[3.18582][3.8547:8548](),[3.8547][3.8547:8548](),[3.8548][3.18583:18615](),[3.18615][3.8695:8696](),[3.8695][3.8695:8696](),[3.8696][3.18616:19169](),[3.19169][3.7817:7893](),[3.7893][3.6060:6106](),[3.6106][3.19220:19629](),[3.7953][3.19220:19629](),[3.19220][3.19220:19629](),[3.19629][3.8882:8883](),[3.8882][3.8882:8883](),[3.8883][3.19630:19729]()
    // Select the observation data from the FRED data.
    let observations = match Fred::series_observations(&self.series_id.to_string()) {
    Ok(series_obs) => series_obs.observations,
    Err(err) => { return Err(fred_error(file!(), line!(), &err.to_string())) },
    };
    // We need to build a RegularTimeSeries here, and then use RegularTimeSeries here
    // to build csv file.
    // Data is parsed into a RegularTimeSeries
    // Want power to drop_first
    let mut v = Vec::new();
    // Drop the first n items
    let skip = match self.drop_first {
    None => 0,
    Some(n) => n,
    };
    for (i, obs) in observations.iter().enumerate().skip(skip) {
    let date = MonthlyDate::from_str(&obs.date)?;
    let value: f32 = match obs.value.parse() {
    Ok(n) => n,
    Err(_) => {
    let err = parse_fred_value_failed(
    file!(),
    line!(),
    &self.data_type.to_string(),
    // Expect country to be Some while building source.
    &country.to_string(),
    &self.series_id.to_string(),
    &format!(
    "{}, {}",
    obs.date,
    obs.value,
    ),
    i + 1,
    );
    self.soft_parse(observations, err);
    unreachable!();
    },
    };
    let date_point = DatePoint::<1>::new(date.0, [value]);
    v.push(date_point)
    [3.6059]
    [3.19729]
    // We want to handle data fetching and parsing in the Parser implementation, so make the
    // Parser the receiver.
    match self.parser {
    ParserSpec::FredSpec(fred_spec) => FredParser(fred_spec).to_data(self),
    ParserSpec::FredDailySpec(fred_daily_spec) => FredDailyParser(fred_daily_spec).to_data(self),
  • edit in src/lib.rs at line 826
    [3.19739][3.19739:20015](),[3.20015][3.6107:6149](),[3.6149][3.20015:20064](),[3.20015][3.20015:20064](),[3.8082][3.20111:20263](),[3.20111][3.20111:20263](),[3.20263][3.9125:9140](),[3.9125][3.9125:9140](),[3.9140][3.20264:20291]()
    let ts = TimeSeries::new(v);
    let rts = match ts.try_into() {
    Ok(rts) => {
    rts
    },
    Err(_) => {
    let err = expected_regular_time_series(
    file!(),
    line!(),
    &country.to_string(),
    &self.data_type.to_string(),
    &self.series_id.to_string(),
    );
    self.soft_parse(observations, err);
    unreachable!();
    },
    };
    Ok(rts)
  • edit in src/lib.rs at line 827
    [3.20297][3.20297:20298](),[3.20298][3.6150:6637]()
    // pub fn data_without_transform(
    // &self,
    // country: Country,
    // root_path: &str) -> Result<RegularTimeSeries<1>, Error>
    // {
    // // Select the observation data from the FRED data.
    //
    // let observations = match Fred::series_observations(&self.series_id.to_string()) {
    // Ok(series_obs) => series_obs.observations,
    // Err(err) => { return Err(fred_error(file!(), line!(), &err.to_string())) },
    // };
  • edit in src/lib.rs at line 828
    [3.6638][3.6638:8807](),[3.8807][3.20298:20642](),[3.20298][3.20298:20642](),[3.20642][3.9205:9215](),[3.9205][3.9205:9215](),[3.9215][3.20643:20704](),[3.20704][3.9215:9222](),[3.9215][3.9215:9222]()
    // // We need to build a RegularTimeSeries here, and then use RegularTimeSeries here
    // // to build csv file.
    // // Data is parsed into a RegularTimeSeries
    // // Want power to drop_first
    // let mut v = Vec::new();
    // // Drop the first n items
    // let skip = match self.drop_first {
    // None => 0,
    // Some(n) => n,
    // };
    // for (i, obs) in observations.iter().enumerate().skip(skip) {
    // let date = MonthlyDate::from_str(&obs.date)?;
    // let value: f32 = match obs.value.parse() {
    // Ok(n) => n,
    // Err(_) => {
    // let err = parse_fred_value_failed(
    // file!(),
    // line!(),
    // &self.data_type.to_string(),
    // // Expect country to be Some while building source.
    // &country.to_string(),
    // &self.series_id.to_string(),
    // &format!(
    // "{}, {}",
    // obs.date,
    // obs.value,
    // ),
    // i + 1,
    // );
    // self.soft_parse(observations, err);
    // unreachable!();
    // },
    // };
    // let date_point = DatePoint::<1>::new(date.0, [value]);
    // v.push(date_point)
    // }
    // let ts = TimeSeries::new(v);
    // let rts = match ts.try_into() {
    // Ok(rts) => {
    // rts
    // },
    // Err(_) => {
    // let err = expected_regular_time_series(
    // file!(),
    // line!(),
    // &country.to_string(),
    // &self.data_type.to_string(),
    // &self.series_id.to_string(),
    // );
    // self.soft_parse(observations, err);
    // unreachable!();
    // },
    // };
    // Ok(rts)
    // }
    /// Parse observations into string for debugging and exit.
    pub fn soft_parse(&self, observations: fred_api::Observations, err: Error) {
    for (i, obs) in observations.iter().enumerate() {
    eprintln!(
    "{} {}, {}",
    i + 1,
    obs.date,
    obs.value,
    )
    }
    eprintln!("{}", err);
    std::process::exit(1);
    }
  • edit in src/lib.rs at line 830
    [3.8885][3.8885:9017]()
    // When this function is used, Self.country should be Some.
    let rts = self.data_from_fred(self.country.unwrap())?;
  • replacement in src/lib.rs at line 831
    [3.9223][3.9018:9089]()
    // There should be a function here to get the data from Fred.
    [3.9223]
    [3.2044]
    let rts = self.to_data(self.parser)?;
  • replacement in src/lib.rs at line 833
    [3.2045][3.20898:20935](),[3.20935][3.6506:6575](),[3.6575][3.21000:21183](),[3.21000][3.21000:21183]()
    let mut csv = String::new();
    for date_point in rts.iter(DateRange::new(&None, &None).0) {
    let date = date_point.date();
    let date_str = format!(
    "{}-{:02}-01",
    date.year(),
    date.month(),
    );
    [3.2045]
    [3.9350]
    // Build csv manually
  • replacement in src/lib.rs at line 835
    [3.9351][3.21184:21356]()
    let line = format!(
    "{}, {}\n",
    date_str,
    date_point.value(0),
    );
    csv.push_str(&line);
    [3.9351]
    [3.9840]
    let mut s = String::new();
    for dp in rts.iter(time_series::DateRange::new(&None, &None)) {
    s.push_str(&format!(
    "{}-{}-01, {}",
    dp.date().year(),
    dp.date().month(),
    dp.value(0).to_string()
    ))
  • replacement in src/lib.rs at line 845
    [3.9851][3.9851:9959](),[3.8198][3.8198:8243](),[3.8243][3.9995:10006](),[3.9995][3.9995:10006]()
    let dir_path = &format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    self.country.unwrap().as_path(),
    );
    [3.9851]
    [3.10006]
    fs::create_dir_all(&self.dir_path(root_path))
    .map_err(|err| create_dir_failed( file!(), line!(), &err.to_string()))?;
  • replacement in src/lib.rs at line 848
    [3.10007][3.10007:10152](),[3.10152][3.21357:21614]()
    let filename = &format!(
    "{}/{}.csv",
    dir_path,
    self.series_id,
    );
    if let Err(err) = fs::create_dir_all(&dir_path) {
    return Err(
    failed_to_create_dir(
    file!(),
    line!(),
    &err.to_string()
    )
    )
    }
    [3.10007]
    [3.10200]
    fs::write(self.data_path(root_path, "csv"), s)
    .map_err(|err| external(file!(), line!(), &err.to_string()))?;
  • edit in src/lib.rs at line 851
    [3.10201][3.21615:21915]()
    println!(
    "Writing {}", filename);
    if let Err(_) = fs::write(filename, &csv) {
    return Err(
    failed_to_write_file(
    file!(),
    line!(),
    filename,
    )
    )
    };
  • replacement in src/lib.rs at line 857
    [3.10433][3.10433:10530]()
    let meta = match Fred::series(&self.series_id.to_string()) {
    Ok(series) => {
    [3.10433]
    [3.10530]
    let series = Fred::series(&self.series_id.to_string())
    .map_err(|err| external(file!(), line!(), &err.to_string()))?;
    let series_item = series.seriess.iter().next().ok_or_else(|| {
    expected_series_data(file!(), line!(), &self.series_id.to_string())
    })?;
  • replacement in src/lib.rs at line 864
    [3.10531][3.10531:11208](),[3.11208][3.22089:22284]()
    let series_item = series.seriess.iter().next().unwrap();
    SeriesMetaData {
    realtime: series.realtime_start.clone(),
    series_id: self.series_id.clone(),
    title: series_item.title.clone(),
    observation_start: series_item.observation_start.clone(),
    observation_end: series_item.observation_end.clone(),
    frequency: series_item.frequency.clone(),
    seasonal_adjustment: series_item.seasonal_adjustment.clone(),
    }
    },
    Err(err) => { return Err(
    fred_error(
    file!(),
    line!(),
    &err.to_string()
    )
    )},
    [3.10531]
    [3.11313]
    let meta = SeriesMetaData {
    realtime: series.realtime_start.clone(),
    series_id: self.series_id.clone(),
    title: series_item.title.clone(),
    observation_start: series_item.observation_start.clone(),
    observation_end: series_item.observation_end.clone(),
    frequency: series_item.frequency.clone(),
    seasonal_adjustment: series_item.seasonal_adjustment.clone(),
  • edit in src/lib.rs at line 873
    [3.11324]
    [3.11324]
    let json = serde_json::to_string(&meta)
    .map_err(|err| external(file!(), line!(), &err.to_string()))?;
  • replacement in src/lib.rs at line 876
    [3.11325][3.11325:11433](),[3.11433][3.8244:8354](),[3.8354][3.11469:11480](),[3.11469][3.11469:11480]()
    let dir_path = &format!(
    "{}/{}/{}",
    root_path,
    self.data_type,
    // Expect country to be Some while building source.
    self.country.unwrap().as_path(),
    );
    [3.11325]
    [3.11480]
    fs::create_dir_all(self.dir_path(root_path))
    .map_err(|err| create_dir_failed( file!(), line!(), &err.to_string()))?;
    let path = self.data_path(root_path, "meta");
  • replacement in src/lib.rs at line 881
    [3.11481][3.11481:11601]()
    let filename = &format!(
    "{}/{}.meta",
    dir_path,
    self.series_id,
    );
    [3.11481]
    [3.11601]
    println!("Writing {}", path);
    fs::write(path, json)
    .map_err(|err| external(file!(), line!(), &err.to_string()))?;
  • edit in src/lib.rs at line 885
    [3.11602][3.11602:11759]()
    fs::create_dir_all(&dir_path).unwrap();
    println!("Writing {}", filename);
    fs::write(filename, &meta.keytree().to_string()).unwrap();
  • replacement in src/lib.rs at line 925
    [3.4154][3.6518:6601]()
    let mut transforms: Vec<Transform> = self.vec_value("series::transform")?;
    [3.4154]
    [3.4238]
    let mut transforms: Vec<Transform> = self.opt_vec_value("series::transform")?;
  • edit in src/lib.rs at line 930
    [3.4372]
    [3.4372]
    // let parser_str_opt: Option<String> = self.opt_value("series::parser")?;
    // let parser = match parser_str_opt {
    // None => Parser::Fred,
    // Some(parser_str) => {
    // Parser::from_str(&parser_str)
    // .map_err(|err| keytree::error::external(file!(), line!(), &err.to_string()))?
    // },
    // };
    let a_parser: Option<String> = self.opt_value("series::parse_cat::fred_daily")?;
    let b_parser: Option<String> = self.opt_value("series::parse_cat::fred")?;
  • edit in src/lib.rs at line 943
    [3.4373]
    [3.12311]
    let parser = match (a_parser.is_some(), b_parser.is_some()) {
    (false, false) => ParserSpec::FredDailySpec(FredDailySpec::empty()),
    (true, false) => ParserSpec::FredDailySpec(FredDailySpec::empty()),
    (false, true) => ParserSpec::FredSpec(self.at("series::parser")?),
    (true, true) => Err(keytree_selection_failed(file!(), line!()))?,
    };
  • replacement in src/lib.rs at line 956
    [3.12532][3.4374:4415]()
    transforms: transforms,
    [3.12532]
    [3.12532]
    transforms,
  • edit in src/lib.rs at line 958
    [3.12599]
    [3.12599]
    parser,
  • edit in src/lib.rs at line 1059
    [3.6994]
    [3.15544]
    }
    #[derive(Clone, Copy, Debug, Serialize)]
    /// Specifies the range of a graphic
    pub struct GraphicRange {
    min: f32,
    max: f32,
    }
    impl FromStr for GraphicRange {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
    let segment: Vec<&str> = s.split(" to ").collect();
    if segment[0].is_empty() || segment[1].is_empty() {
    return Err(
    parse_graphic_range_failed(
    file!(),
    line!(),
    s
    ))
    };
    let min = segment[0].parse()
    .map_err(|_| parse_graphic_range_failed(file!(), line!(), s))?;
    let max = segment[1].parse()
    .map_err(|_| parse_graphic_range_failed(file!(), line!(), s))?;
    Ok(GraphicRange { min, max })
    }
  • edit in src/lib.rs at line 1092
    [3.15547]
    impl fmt::Display for GraphicRange {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "{} to {}", self.min, self.max)
    }
    }
    // /// The United States prime interest rate data is daily. To buid a monthly time-series, we read
    // /// through raw csv data, calculate a monthly value and add to to the time-series. The data include
    // /// missing days, so we need the mechanism to ignore datepoints with value ".".
    //
    // ts.try_into().map_err(|err: time_series::error::Error| {
    // external(
    // file!(),
    // line!(),
    // &err.to_string(),
    // )
    // })
    // }
  • edit in src/fred.rs at line 20
    [3.6429]
    [3.6429]
    use crate::parser::{ FredSpec, ParserSpec };
  • edit in src/fred.rs at line 22
    [3.6430][3.6430:6455]()
    use crate::error::Error;
  • replacement in src/fred.rs at line 97
    [3.8663][3.8663:8708]()
    failed_fred_request(
    [3.8663]
    [3.8708]
    fred_request_failed(
  • edit in src/fred.rs at line 118
    [3.9435]
    [3.9435]
    parser: ParserSpec::FredSpec(FredSpec::empty()),
  • replacement in src/fred.rs at line 151
    [3.10502][3.10502:10547]()
    failed_fred_request(
    [3.10502]
    [3.10547]
    fred_request_failed(
  • edit in src/fred.rs at line 172
    [3.11272]
    [3.11272]
    parser: ParserSpec::FredSpec(FredSpec::empty()),
  • replacement in src/fred.rs at line 280
    [3.14268][3.14268:14522]()
    tags: self.vec_value("series::tag")?,
    enumerate: self.vec_value("series::enumerate")?,
    exclude: self.vec_value("series::exclude")?,
    require: self.vec_value("series::require")?,
    [3.14268]
    [3.14522]
    tags: self.opt_vec_value("series::tag")?,
    enumerate: self.opt_vec_value("series::enumerate")?,
    exclude: self.opt_vec_value("series::exclude")?,
    require: self.opt_vec_value("series::require")?,
  • edit in src/error.rs at line 3
    [3.14582][3.14582:14603]()
    /// A ui_data error.
  • replacement in src/error.rs at line 12
    [3.14781][3.14781:14785]()
    ///
    [3.14781]
    [3.14785]
    pub fn create_dir_failed(
    code_file: &str,
    code_line: u32,
    msg: &str) -> Error
    {
    Error(format!(
    "[ui_data::{}:{}] Failed to create dir with msg: [{}].",
    code_file,
    code_line,
    msg,
    ))
    }
  • replacement in src/error.rs at line 32
    [3.14927][3.14927:14995]()
    "[ui_data:01:{}:{}] Datatypes [{}] and [{}] do not match.",
    [3.14927]
    [3.14995]
    "[ui_data:{}:{}] Datatypes [{}] and [{}] do not match.",
  • edit in src/error.rs at line 37
    [3.15073]
    [3.1350]
    ))
    }
    pub fn expected_datapoint_found_dot(
    code_file: &str,
    code_line: u32,
    line_num: &str,
    line_str: &str) -> Error
    {
    Error(format!(
    "[ui*date:{}:{}] Line [{}] is [{}] but expected datapoint.]",
    code_file,
    code_line,
    line_num,
    line_str,
  • replacement in src/error.rs at line 63
    [3.1471][3.4504:4597]()
    "[ui_date:02:{}:{}] [{} {} {}] Expected source graphic to have exactly one series.",
    [3.1471]
    [3.1553]
    "[ui_data:{}:{}] [{} {} {}] Expected source graphic to have exactly one series.",
  • edit in src/error.rs at line 69
    [3.4649]
    [3.15073]
    ))
    }
    pub fn expected_series_data(
    code_file: &str,
    code_line: u32,
    series_id: &str) -> Error
    {
    Error(format!(
    "[ui_data:{}:{}] Expected series data from series [{}] but was empty.",
    code_file,
    code_line,
    series_id,
  • replacement in src/error.rs at line 94
    [3.15287][3.1592:1669]()
    "[ui_data:03:{}:{}] Expected regular time-series from [{} {} {}].",
    [3.15287]
    [3.15364]
    "[ui_data:{}:{}] Expected regular time-series from [{} {} {}].",
  • replacement in src/error.rs at line 109
    [3.9321][3.1670:1713]()
    "[ui_data:04:{}:{}] External: {}",
    [3.9321]
    [3.9364]
    "[ui_data:{}:{}] External: {}",
  • replacement in src/error.rs at line 116
    [3.15467][3.15467:15499]()
    ///
    pub fn failed_fred_request(
    [3.15467]
    [3.15499]
    pub fn file_error(
  • replacement in src/error.rs at line 118
    [3.15520][3.15520:15564]()
    code_line: u32,
    msg: &str) -> Error
    [3.15520]
    [3.15564]
    code_line: u32) -> Error
  • replacement in src/error.rs at line 121
    [3.15585][3.1714:1771]()
    "[ui_data:05:{}]{}] Fred request failed: [{}].",
    [3.15585]
    [3.15642]
    "[ui_data:{}:{}] File error.",
  • edit in src/error.rs at line 124
    [3.15680][3.15680:15693]()
    msg,
  • replacement in src/error.rs at line 127
    [3.15703][3.15703:15736]()
    ///
    pub fn failed_to_create_dir(
    [3.15703]
    [3.15736]
    pub fn fred_request_failed(
  • replacement in src/error.rs at line 133
    [3.15822][3.1772:1840]()
    "[ui_data::06:{}:{}] Failed to create dir with msg: [{}].",
    [3.15822]
    [3.15890]
    "[ui_data:{}]{}] Fred request failed: [{}].",
  • replacement in src/error.rs at line 140
    [3.15951][3.15951:15983]()
    ///
    pub fn failed_to_read_file(
    [3.15951]
    [3.15983]
    pub fn into_keytree_failed(
  • replacement in src/error.rs at line 142
    [3.16004][3.16004:16053]()
    code_line: u32,
    filename: &str) -> Error
    [3.16004]
    [3.16053]
    code_line: u32) -> Error
  • replacement in src/error.rs at line 145
    [3.16074][3.1841:1897]()
    "[ui_data:07:{}:{}] Failed to read file [{}].",
    [3.16074]
    [3.16130]
    "[ui_data:{}:{}] Into keytree failed.",
  • edit in src/error.rs at line 148
    [3.16168][3.16168:16187]()
    filename,
  • replacement in src/error.rs at line 151
    [3.16197][3.9635:9670]()
    pub fn failed_to_reference_series(
    [3.16197]
    [3.9670]
    pub fn series_lookup_failed(
  • replacement in src/error.rs at line 157
    [3.9762][3.1898:1977]()
    "[ui_data:08:{}:{}] Could not find graphic reference [{}] in series.",
    [3.9762]
    [3.9841]
    "[ui_data:{}:{}] Could not find graphic reference [{}] in series.",
  • edit in src/error.rs at line 161
    [3.9898][3.9898:9908](),[3.9908][3.3649:3756](),[3.3756][3.1978:2037](),[3.2037][3.3815:3853](),[3.3815][3.3815:3853]()
    ))
    }
    pub fn failed_to_serialize_to_json(
    code_file: &str,
    code_line: u32) -> Error
    {
    Error(format!(
    "[ui_data:09:{}:{}] Failed to serialize to json.",
    code_file,
    code_line,
  • replacement in src/error.rs at line 164
    [3.3863][3.16201:16230](),[3.9908][3.16201:16230](),[3.16201][3.16201:16230]()
    pub fn failed_to_write_file(
    [3.3863]
    [3.16230]
    pub fn read_file_failed(
  • replacement in src/error.rs at line 170
    [3.16321][3.2038:2095]()
    "[ui_data:10:{}:{}] Failed to write file [{}].",
    [3.16321]
    [3.16378]
    "[ui_data:{}:{}] Failed to read file [{}].",
  • replacement in src/error.rs at line 173
    [3.16416][3.16416:16434]()
    filename,
    [3.16416]
    [3.16434]
    filename,
  • replacement in src/error.rs at line 177
    [3.16444][3.16444:16467]()
    ///
    pub fn file_error(
    [3.16444]
    [3.16467]
    pub fn serialize_to_json_failed(
  • replacement in src/error.rs at line 183
    [3.16538][3.2096:2138]()
    "[ui_data:11:{}:{}] File error.",
    [3.16538]
    [3.16580]
    "[ui_data:{}:{}] Failed to serialize to json.",
  • replacement in src/error.rs at line 195
    [3.16737][3.2139:2185]()
    "ui_data:12:{}:{}] Fred error [{}].",
    [3.16737]
    [3.16783]
    "ui_data:{}:{}] Fred error [{}].",
  • replacement in src/error.rs at line 209
    [3.16987][3.2186:2248]()
    "[ui_data:13:{}:{}] Key [({}, {})] not in dataspec.",
    [3.16987]
    [3.17049]
    "[ui_data:{}:{}] Key [({}, {})] not in dataspec.",
  • replacement in src/error.rs at line 218
    [3.17137][3.17137:17159]()
    pub fn keytree_error(
    [3.17137]
    [3.17159]
    pub fn parse_datatype_failed(
  • replacement in src/error.rs at line 221
    [3.17200][3.17200:17224]()
    msg: &str) -> Error
    [3.17200]
    [3.17224]
    s: &str) -> Error
  • replacement in src/error.rs at line 224
    [3.17245][3.2249:2297]()
    "[ui_data:14:{}:{}] Keytree error: {}",
    [3.17245]
    [3.17293]
    "[ui_data:{}:{}] Failed to parse datatype from string [{}].",
  • replacement in src/error.rs at line 227
    [3.17331][3.17331:17343]()
    msg
    [3.17331]
    [3.17343]
    s,
  • replacement in src/error.rs at line 231
    [3.17353][3.17353:17380]()
    ///
    pub fn parse_datatype(
    [3.17353]
    [3.17380]
    pub fn parse_datepoint_failed(
  • replacement in src/error.rs at line 234
    [3.17421][3.17421:17445]()
    s: &str) -> Error
    {
    [3.17421]
    [3.17445]
    line: &str,
    obs_str: &str) -> Error
    {
  • replacement in src/error.rs at line 238
    [3.17464][3.2298:2371]()
    "[ui_data:15:{}:{}] Failed to parse datatype from string [{}].",
    [3.17464]
    [3.17537]
    "[ui_data:{}:{}] Failed to parse datepoint at line [{}] from string [{}].",
  • replacement in src/error.rs at line 241
    [3.17575][3.17575:17586]()
    s,
    [3.17575]
    [3.17586]
    line,
    obs_str,
  • edit in src/error.rs at line 246
    [3.17596][3.17596:17600]()
    ///
  • replacement in src/error.rs at line 256
    [3.17798][3.2372:2454]()
    "[ui_data:16:{}:{}] [{} {} {}] Parse Fred value [{}] failed on line {}.",
    [3.17798]
    [3.17880]
    "[ui_data:{}:{}] [{} {} {}] Parse Fred value [{}] failed on line {}.",
  • replacement in src/error.rs at line 267
    [3.18012][3.18012:18035]()
    ///
    pub fn parse_date(
    [3.18012]
    [3.18035]
    pub fn parse_graphic_range_failed(
  • replacement in src/error.rs at line 271
    [3.18098][3.18098:18101]()
    {
    [3.18098]
    [3.18101]
    {
  • replacement in src/error.rs at line 273
    [3.18120][3.2455:2524]()
    "[ui_data:17:{}:{}] Failed to parse date from string [{}].",
    [3.18120]
    [3.18189]
    "[ui_data:{}:{}] Parse graphic range [{}] failed.",
  • replacement in src/error.rs at line 280
    [3.18248][3.18248:18276]()
    ///
    pub fn parse_timestamp(
    [3.18248]
    [3.18276]
    pub fn parse_parser_failed(
  • replacement in src/error.rs at line 286
    [3.18360][3.2525:2599]()
    "[ui_data:18:{}:{}] Failed to parse timestamp from string [{}].",
    [3.18360]
    [3.18434]
    "[ui_data::{}:{}] Parse parser type [{}] failed.",
  • replacement in src/error.rs at line 289
    [3.18472][3.18472:18483]()
    s,
    [3.18472]
    [3.18483]
    s
  • replacement in src/error.rs at line 293
    [3.18493][3.18493:18522]()
    ///
    pub fn parse_transform1(
    [3.18493]
    [3.18522]
    pub fn parse_timestamp_failed(
  • replacement in src/error.rs at line 299
    [3.18606][3.2600:2675]()
    "[ui_data:19:{}:{}] Failed to parse transform1 from string [{}].",
    [3.18606]
    [3.18681]
    "[ui_data:{}:{}] Failed to parse timestamp from string [{}].",
  • replacement in src/error.rs at line 306
    [3.18740][3.18740:18769]()
    ///
    pub fn parse_transform2(
    [3.18740]
    [3.18769]
    pub fn parse_transform1_failed(
  • replacement in src/error.rs at line 312
    [3.18853][3.2676:2751]()
    "[ui_data:20:{}:{}] Failed to parse transform2 from string [{}].",
    [3.18853]
    [3.18928]
    "[ui_data:{}:{}] Failed to parse transform1 from string [{}].",
  • replacement in src/error.rs at line 319
    [3.18987][3.18987:19025]()
    ///
    pub fn series_id_not_in_dataspec(
    [3.18987]
    [3.19025]
    pub fn parse_transform2_failed(
  • replacement in src/error.rs at line 322
    [3.19066][3.19066:19096]()
    series_id: &str) -> Error
    [3.19066]
    [3.19096]
    s: &str) -> Error
  • replacement in src/error.rs at line 325
    [3.19117][3.2752:2813]()
    "[ui_data:21:{}:{}] SeriesId [{}] not in DataSpec.",
    [3.19117]
    [3.19178]
    "[ui_data:{}:{}] Failed to parse transform2 from string [{}].",
  • replacement in src/error.rs at line 328
    [3.19216][3.19216:19235]()
    series_id,
    [3.19216]
    [3.19235]
    s,
  • replacement in src/error.rs at line 332
    [3.19245][3.19245:19279]()
    ///
    pub fn spec_has_error_status(
    [3.19245]
    [3.19279]
    pub fn series_id_not_in_dataspec(
  • replacement in src/error.rs at line 335
    [3.19320][3.19320:19368]()
    series_id: &str,
    status: &str) -> Error
    [3.19320]
    [3.19368]
    series_id: &str) -> Error
  • replacement in src/error.rs at line 338
    [3.19389][3.2814:2924]()
    "[ui_data:22:{}:{}] Cannot access data because specification for series [{}] has error status [{}].",
    [3.19389]
    [3.19499]
    "[ui_data:{}:{}] SeriesId [{}] not in DataSpec.",
  • edit in src/error.rs at line 342
    [3.19556][3.19556:19572]()
    status,
  • edit in src/error.rs at line 345
    [3.19582][3.19582:19586]()
    ///
  • replacement in src/error.rs at line 352
    [3.19722][3.2925:2980]()
    "[ui_data:23:{}:{}] Series [{} {}] is empty.",
    [3.19722]
    [3.19777]
    "[ui_data:{}:{}] Series [{} {}] is empty.",
  • edit in src/error.rs at line 359
    [3.19860][3.19860:19861]()
  • edit in src/error.rs at line 360
    [3.9417][3.19861:19866](),[3.19861][3.19861:19866]()
    ///
  • replacement in src/error.rs at line 369
    [3.20049][3.2981:3075]()
    "[ui_data:24:{}:{}] Failed to parse time-series from csv [{} {} {}] with msg: [{}].",
    [3.20049]
    [3.20143]
    "[ui_data:{}:{}] Failed to parse time-series from csv [{} {} {}] with msg: [{}].",
  • replacement in src/error.rs at line 379
    [3.20259][3.9418:9419]()
    [3.20259]
    [3.9419]
    pub fn write_file_failed(
    code_file: &str,
    code_line: u32,
    filename: &str) -> Error
    {
    Error(format!(
    "[ui_data:{}:{}] Failed to write file [{}].",
    code_file,
    code_line,
    filename,
    ))
    }