1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use {
    crate::*,
    anyhow::{anyhow, bail, Result},
    chrono::{DateTime, FixedOffset, SecondsFormat, Utc},
};

#[derive(Debug)]
pub struct Seq {
    pub header: String,
    pub nature: Nature,
    pub raw: Vec<Option<String>>,
    pub ival: Vec<Option<i64>>,
    pub min: i64,
    pub max: i64,
}
impl Seq {
    pub fn from_increasing_times(header: String, times: Vec<DateTime<Utc>>) -> Result<Self> {
        if times.is_empty() {
            bail!("empty column");
        }
        let mut raw = Vec::new();
        let mut ival = Vec::new();
        for time in times {
            raw.push(Some(time.to_rfc3339_opts(SecondsFormat::Secs, true)));
            ival.push(Some(time.timestamp_millis()));
        }
        Ok(Self {
            header,
            nature: Nature::Date(FixedOffset::east_opt(0).unwrap()), // should be Utc if I understand chrono
            raw,
            min: ival[0].unwrap(),
            max: ival[ival.len() - 1].unwrap(),
            ival,
        })
    }
    pub fn from_integers(header: String, ival: Vec<Option<i64>>) -> Result<Self> {
        let mut min_max: Option<(i64, i64)> = None;
        let mut raw = vec![None; ival.len()];
        for (idx, val) in ival.iter().enumerate() {
            if let Some(val) = val {
                raw[idx] = Some(val.to_string());
                min_max = Some(match min_max {
                    Some((min, max)) => (min.min(*val), max.max(*val)),
                    None => (*val, *val),
                });
            }
        }
        if let Some((min, max)) = min_max {
            Ok(Self {
                header,
                nature: Nature::Integer,
                raw,
                ival,
                min,
                max,
            })
        } else {
            Err(anyhow!("Empty column"))
        }
    }
    pub fn new(raw_col: RawCol) -> Result<Self> {
        let RawCol { header, cells: raw } = raw_col;
        let mut ival = vec![None; raw.len()];
        let mut nature = None;
        let mut min_max: Option<(i64, i64)> = None;
        for (x, cell) in raw.iter().enumerate() {
            if let Some(s) = cell {
                let v = match nature {
                    Some(Nature::Date(_)) => {
                        if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
                            dt.timestamp_millis()
                        } else if let Ok(int) = s.parse::<i64>() {
                            // we change the seq nature
                            nature = Some(Nature::Integer);
                            int
                        } else {
                            bail!("cell can't be used: {:?}", s);
                        }
                    }
                    Some(Nature::Integer) => {
                        if let Ok(int) = s.parse::<i64>() {
                            int
                        } else {
                            bail!("cell can't be used: {:?}", s);
                        }
                    }
                    None => {
                        if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
                            nature = Some(Nature::Date(*dt.offset()));
                            dt.timestamp_millis()
                        } else if let Ok(int) = s.parse::<i64>() {
                            nature = Some(Nature::Integer);
                            int
                        } else {
                            bail!("cell can't be used: {:?}", s);
                        }
                    }
                };
                ival[x] = Some(v);
                min_max = Some(min_max.map_or((v, v), |mm| (mm.0.min(v), mm.1.max(v))));
            }
        }
        nature
            .map(|nature| {
                let (min, max) = min_max.unwrap();
                Self {
                    header,
                    nature,
                    raw,
                    ival,
                    min,
                    max,
                }
            })
            .ok_or_else(|| anyhow!("empty column"))
    }
    pub fn is_full_and_increasing(&self) -> bool {
        for idx in 1..self.ival.len() {
            match (self.ival.get(idx - 1), self.ival.get(idx)) {
                (Some(a), Some(b)) if a < b => {} // ok
                _ => {
                    return false;
                }
            }
        }
        true
    }
    pub fn len(&self) -> usize {
        self.raw.len()
    }
    pub fn is_empty(&self) -> bool {
        self.raw.is_empty()
    }
}