1 use { 2 crate::*, 3 anyhow::*, 4 chrono::{DateTime, FixedOffset, SecondsFormat, Utc}, 5 }; 6 7 #[derive(Debug)] 8 pub struct Seq { 9 pub header: String, 10 pub nature: Nature, 11 pub raw: Vec<Option<String>>, 12 pub ival: Vec<Option<i64>>, 13 pub min: i64, 14 pub max: i64, 15 } 16 impl Seq { from_increasing_times(header: String, times: Vec<DateTime<Utc>>) -> Result<Self>17 pub fn from_increasing_times(header: String, times: Vec<DateTime<Utc>>) -> Result<Self> { 18 if times.is_empty() { 19 bail!("empty column"); 20 } 21 let mut raw = Vec::new(); 22 let mut ival = Vec::new(); 23 for time in times { 24 raw.push(Some(time.to_rfc3339_opts(SecondsFormat::Secs, true))); 25 ival.push(Some(time.timestamp_millis())); 26 } 27 Ok(Self { 28 header, 29 nature: Nature::Date(FixedOffset::east(0)), // should be Utc if I understand chrono 30 raw, 31 min: ival[0].unwrap(), 32 max: ival[ival.len()-1].unwrap(), 33 ival, 34 }) 35 } from_integers(header: String, ival: Vec<Option<i64>>) -> Result<Self>36 pub fn from_integers(header: String, ival: Vec<Option<i64>>) -> Result<Self> { 37 let mut min_max: Option<(i64, i64)> = None; 38 let mut raw = vec![None; ival.len()]; 39 for (idx, val) in ival.iter().enumerate() { 40 if let Some(val) = val { 41 raw[idx] = Some(val.to_string()); 42 min_max = Some(match min_max { 43 Some((min, max)) => (min.min(*val), max.max(*val)), 44 None => (*val, *val), 45 }); 46 } 47 } 48 if let Some((min, max)) = min_max { 49 Ok(Self { 50 header, 51 nature: Nature::Integer, 52 raw, 53 ival, 54 min, 55 max, 56 }) 57 } else { 58 Err(anyhow!("Empty column")) 59 } 60 } new(raw_col: RawCol) -> Result<Self>61 pub fn new(raw_col: RawCol) -> Result<Self> { 62 let RawCol { header, cells: raw } = raw_col; 63 let mut ival = vec![None; raw.len()]; 64 let mut nature = None; 65 let mut min_max: Option<(i64, i64)> = None; 66 for (x, cell) in raw.iter().enumerate() { 67 if let Some(s) = cell { 68 let v = match nature { 69 Some(Nature::Date(_)) => { 70 if let Ok(dt) = DateTime::parse_from_rfc3339(s) { 71 dt.timestamp_millis() 72 } else if let Ok(int) = s.parse::<i64>() { 73 // we change the seq nature 74 nature = Some(Nature::Integer); 75 int 76 } else { 77 bail!("cell can't be used: {:?}", s); 78 } 79 } 80 Some(Nature::Integer) => { 81 if let Ok(int) = s.parse::<i64>() { 82 int 83 } else { 84 bail!("cell can't be used: {:?}", s); 85 } 86 } 87 None => { 88 if let Ok(dt) = DateTime::parse_from_rfc3339(s) { 89 nature = Some(Nature::Date(*dt.offset())); 90 dt.timestamp_millis() 91 } else if let Ok(int) = s.parse::<i64>() { 92 nature = Some(Nature::Integer); 93 int 94 } else { 95 bail!("cell can't be used: {:?}", s); 96 } 97 } 98 }; 99 ival[x] = Some(v); 100 min_max = Some(min_max.map_or((v, v), |mm| (mm.0.min(v), mm.1.max(v)))); 101 } 102 } 103 nature 104 .map(|nature| { 105 let (min, max) = min_max.unwrap(); 106 Self { 107 header, 108 nature, 109 raw, 110 ival, 111 min, 112 max, 113 } 114 }) 115 .ok_or_else(||anyhow!("empty column")) 116 } is_full_and_increasing(&self) -> bool117 pub fn is_full_and_increasing(&self) -> bool { 118 for idx in 1..self.ival.len() { 119 match (self.ival.get(idx - 1), self.ival.get(idx)) { 120 (Some(a), Some(b)) if a < b => {} // ok 121 _ => { 122 return false; 123 } 124 } 125 } 126 true 127 } len(&self) -> usize128 pub fn len(&self) -> usize { 129 self.raw.len() 130 } 131 } 132