use std::collections::HashMap; use std::str::FromStr; use chrono::{NaiveDate, NaiveDateTime}; mod tokenizer; mod parser; pub use parser::Parser; pub trait GetValue<'a, R: 'a> { fn get(&'a self, key: &'_ str) -> Option; } pub type Props = Vec<(String, String)>; #[derive(Debug, PartialEq)] pub struct Object { pub name: String, pub content: HashMap, pub children: Vec>, } impl<'a> GetValue<'a, &'a str> for Object { fn get(&'a self, key: &'_ str) -> Option<&'a str> { self.content.get(key) .map(|(_props, value)| value.as_ref()) } } impl<'a> GetValue<'a, String> for Object { fn get(&self, key: &'_ str) -> Option { self.content.get(key) .map(|(_props, value)| value.clone()) } } // TODO: TZID, offset impl<'a> GetValue<'a, Timestamp> for Object { fn get(&self, key: &'_ str) -> Option { let s = self.get(key)?; Timestamp::from_str(s) .map_err(|e| println!("Cannot parse date: {:?}", e)) .ok() } } #[derive(Debug, Clone)] pub enum Timestamp { Date(NaiveDate), DateTime(NaiveDateTime), } impl FromStr for Timestamp { type Err = String; fn from_str(s: &'_ str) -> Result { NaiveDateTime::parse_from_str(s, "%Y%m%dT%H%M%SZ") .or_else(|_| NaiveDateTime::parse_from_str(s, "%Y%m%dT%H%M%S")) .map(Timestamp::DateTime) .or_else(|_| NaiveDate::parse_from_str(s, "%Y%m%d") .map(Timestamp::Date) ) .map_err(|e| format!("Cannot parse date: {:?}", e)) } } impl Timestamp { pub fn or_hms(self, hour: u32, min: u32, sec: u32) -> NaiveDateTime { match self { Timestamp::Date(date) => date.and_hms(hour, min, sec), Timestamp::DateTime(date_time) => date_time, } } }