haystack_types/h_grid/
mod.rs

1use core::{hash, panic};
2use core::slice::SliceIndex;
3use core::ops::Index;
4use std::rc::Rc;
5use std::slice::Iter;
6use num::Float;
7use crate::h_str::HStr;
8use crate::io::HBox;
9use crate::{HType, HVal, NumTrait};
10use std::fmt::{self, write, Display, Write};
11use std::str::FromStr;
12
13use std::collections::HashMap;
14
15pub mod h_col;
16pub use h_col::{Col,HCol};
17
18pub mod h_row;
19pub use h_row::{Row,HRow};
20
21pub enum HGrid<'a, T: NumTrait + 'a> {
22    Grid {
23        meta: HashMap<String, HBox<'a,T>>,
24        col_index: HashMap<String, usize>,
25        cols: Vec<HCol<'a,T>>,
26        rows: Vec<HRow<'a,T>>,
27    },
28    Error {
29        dis: String,
30        errTrace: Option<String>,
31    },
32    Empty { meta: Option<HashMap<String, HBox<'a,T>>> },
33}
34
35impl<'a, T: NumTrait + 'a> fmt::Debug for HGrid<'a, T> {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        match self {
38            HGrid::Grid { .. } => {
39                write!(f, "HGrid::Grid {{}}")
40            }
41            HGrid::Error { dis, errTrace } => {
42                f.debug_struct("HGrid::Error")
43                    .field("dis", dis)
44                    .field("errTrace", errTrace)
45                    .finish()
46            }
47            HGrid::Empty { .. } => write!(f, "HGrid::Empty"),
48        }
49    }
50}
51
52pub type Grid<'a,T> = HGrid<'a,T>;
53
54#[derive(Debug)]
55pub enum HGridErr {
56    NotFound,
57    IndexErr,
58    NotImplemented
59}
60
61const THIS_TYPE: HType = HType::Grid;
62
63impl <'a,T: NumTrait + 'a>HGrid<'a,T> {
64    pub fn new(g_columns: Option<Vec<HCol<'a,T>>>, grid_rows: Vec<HashMap<String, HBox<'a,T>>>) -> HGrid<'a,T> {
65        let meta = HashMap::with_capacity(0);
66        let mut col_index: HashMap<String, _> = HashMap::new();
67        let mut cols = Vec::new();
68
69        if let Some(columns) = g_columns {
70            let mut col_iter = columns.iter();
71            for c in col_iter.by_ref() {
72                let len = col_index.len();
73                let c_name = &c.name;
74                col_index.insert(c_name.clone(),len);
75            }
76            cols = columns;
77        }
78
79        let rows = grid_rows.into_iter().map(|mut r| {
80            for (k,_) in r.iter() {
81                let col_name = k.to_string();
82                if !col_index.contains_key(&col_name) {
83                    let len = col_index.len();
84                    col_index.insert(col_name,len);
85                    cols.push(Col::new(k.to_string(), None));
86                }
87            }
88
89            let row: Vec<Option<HBox<'a,T>>> = cols.iter().map(|c| r.remove(c.name.as_str())).collect();
90            Row::new(row)
91        }).collect();
92
93        let grid = HGrid::Grid {
94            meta,
95            col_index,
96            cols,
97            rows
98        };
99
100        grid
101    }
102
103    pub fn from_row_vec<'b>(columns: Vec<(String,Option<HashMap<String,HBox<'b,T>>>)>, grid_rows: Vec<Vec<Option<HBox<'b,T>>>>) -> Grid<'b,T> {
104        let meta = HashMap::with_capacity(0);
105        let mut col_index: HashMap<String, _> = HashMap::new();
106        let mut cols: Vec<HCol<'_, T>> = Vec::new();
107
108        for (name,meta) in columns.into_iter() {
109            if !col_index.contains_key(name.as_str()) {
110                let len = col_index.len();
111                col_index.insert(name.to_owned(),len);
112                cols.push(Col::new(name.to_owned(), meta));
113            } else {
114                panic!("Attempting to read grid with multiple columns of the same name")
115            }
116        }
117
118        let rows: Vec<HRow<'_, T>> = grid_rows.into_iter().map(|r| {
119            Row::new(r)
120        }).collect();
121
122        HGrid::Grid{ meta, col_index, cols, rows }
123    }
124
125    pub fn add_meta(mut self, meta: HashMap<String, HBox<'a,T>>) -> Result<HGrid<'a,T>,HGridErr> {
126        match &mut self {
127            HGrid::Grid { meta: orig_meta, .. } => {
128                orig_meta.extend(meta);
129            },
130            HGrid::Error { dis, errTrace } => {
131                return Err(HGridErr::NotImplemented);
132            },
133            HGrid::Empty { meta: inner } => {
134                match inner {
135                    Some(inner_meta) => inner_meta.extend(meta),
136                    None => _ = inner.replace(meta),
137                };
138            }
139        }
140        Ok(self)
141    }
142
143    pub fn add_col_meta(mut self, col: &str, meta: HashMap<String, HBox<'a,T>>) -> Result<Self,HGridErr> {
144        match &mut self {
145            HGrid::Grid { col_index, cols, .. } => {
146                let idx = col_index.get(col).ok_or(HGridErr::NotFound)?;
147                cols.get_mut(*idx).ok_or(HGridErr::NotFound)?
148                    .add_meta(meta);
149            },
150            HGrid::Error { dis, errTrace } => {
151                return Err(HGridErr::NotImplemented);
152            },
153            HGrid::Empty { .. } => {
154                return Err(HGridErr::NotFound);
155            }
156        }
157        Ok(self)
158    }
159
160    pub fn get(&'a self, key: usize) -> Result<&'a Row<'a,T>,HGridErr> {
161        match self {
162            HGrid::Grid { rows, .. } => rows.get(key).ok_or(HGridErr::IndexErr),
163            _ => Err(HGridErr::IndexErr),
164        }
165    }
166
167    pub fn first(&'a self) -> Result<&'a Row<'a,T>,HGridErr> {
168        match self {
169            HGrid::Grid { rows, .. } => rows.get(0).ok_or(HGridErr::IndexErr),
170            HGrid::Error { dis, errTrace } => Err(HGridErr::NotImplemented),
171            _ => Err(HGridErr::IndexErr),
172        }
173    }
174
175    pub fn last(&'a self) -> Result<&'a Row<'a,T>,HGridErr> {
176        if let HGrid::Grid { rows, .. } = self {
177            let length = rows.len();
178            rows.get(length - 1).ok_or(HGridErr::IndexErr)
179        } else {
180            Err(HGridErr::IndexErr)
181        }
182    }
183
184    pub fn has(&self, key: &str) -> bool {
185        match self {
186            HGrid::Grid { col_index, .. } => col_index.contains_key(key),
187            HGrid::Error { .. } => key=="err" || key=="errTrace" || key=="dis",
188            _ => false,
189        }
190    }
191
192    pub fn meta(&'a self) -> &'a HashMap<String, HBox<'a, T>> {
193        match self {
194            HGrid::Grid { meta, .. } => meta,
195            HGrid::Error { dis, errTrace } => todo!("Not implemented"),
196            HGrid::Empty { meta } => todo!("Not implemented"),
197        }
198    }
199
200    pub fn iter_cols(&'a self) -> Iter<'a, HCol<'a, T>> {
201        match self {
202            HGrid::Grid { cols, .. } => cols.iter(),
203            _ => panic!("Cannot iterate columns on non-Grid variant"),
204        }
205    }
206
207    pub fn iter(&'a self) -> Iter<'a, HRow<'a, T>> {
208        match self {
209            HGrid::Grid { rows, .. } => rows.iter(),
210            HGrid::Empty { .. } => Iter::default(),
211            HGrid::Error { dis, errTrace } => {
212                panic!("Cannot iterate rows on Error variant: {:?} {:?}", dis, errTrace)
213            }
214        }
215    }
216
217    pub fn as_ref(&self) -> &Self {
218        self
219    }
220}
221
222/*
223impl <'a,T,I>Index<I> for HGrid<'a,T>
224where
225    I: SliceIndex<[HRow<'a, T>]>,
226{
227    type Output = &'a I::Output;
228    // type Output = <I as SliceIndex<[HRow<'a,T>]>>::Output;
229
230    fn index(&self, index: I) -> Self::Output {
231        &self.rows[index]
232    }
233}
234*/
235
236// impl <'g,'a:'g,T:'a + Float + Display + FromStr>IntoIterator for &'g HGrid<'a,T> {
237//     // type Item = &'a HRow<'a,T>;
238//     type Item = &'a HRow<'a,T>;
239//     type IntoIter = HGridIter<'g,'a,T>;
240
241//     fn into_iter(self) -> Self::IntoIter {
242//         HGridIter { index:0, grid:self }
243//     }
244// }
245
246// pub struct HGridIter<'g,'a,T> {
247//     index: usize,
248//     grid: &'g HGrid<'a,T>,
249// }
250
251// impl <'g,'a:'g,T:'a + Float + Display + FromStr>Iterator for HGridIter<'g,'a,T> {
252//     type Item = &'a HRow<'a,T>;
253
254//     fn next(&mut self) -> Option<Self::Item> {
255//         let grid: &'g HGrid<'a, T> = self.grid;
256//         let ret = grid.get(self.index).ok()?;
257//         Some(ret)
258//     }
259// }
260
261impl <'a,T:'a + NumTrait + 'a>HVal<'a,T> for HGrid<'a,T> {
262    fn to_zinc(&self, buf: &mut String) -> fmt::Result {
263        match self {
264            HGrid::Grid { meta, col_index, cols, rows } => {
265                write!(buf,"ver:\"3.0\" ")?;
266                if !meta.is_empty() {
267                    let mut iter = meta.iter().peekable();
268                    while let Some((k,v)) = iter.next() {
269                        write!(buf, " {}", k.as_str())?;
270                        match v.haystack_type() {
271                            HType::Marker => (),
272                            _ => { write!(buf, ":")?; v.to_zinc(buf)?; }
273                        };
274                    }
275                }
276                write!(buf, "\n")?;
277                if !cols.is_empty() {
278                    let mut iter = cols.iter().peekable();
279                    while let Some(c) = iter.next() {
280                        c.to_zinc(buf)?;
281                        if let Some(_) = iter.peek() {
282                            write!(buf, ", ")?;
283                        }
284                    }
285                }
286                write!(buf, "\n")?;
287                if !rows.is_empty() {
288                    let mut iter = rows.iter().peekable();
289                    while let Some(r) = iter.next() {
290                        r.to_zinc(self, buf)?;
291                        write!(buf, "\n")?;
292                    }
293                }
294                Ok(())
295            },
296            HGrid::Error { dis, errTrace } => {
297                //write!(buf,"ver:\"3.0\" err dis:{} errTrace:{}\nempty",dis,HStr(errTrace.toString))?;
298                write!(buf,"ver:\"3.0\" err dis:")?;
299                HVal::<f64>::to_zinc(&HStr(dis.to_string()), buf)?;
300
301                if let Some(errTrace) = errTrace {
302                    write!(buf," errTrace:")?;
303                    HVal::<f64>::to_zinc(&HStr(errTrace.to_string()), buf)?;
304                }
305                write!(buf,"\nempty\n")
306            },
307            HGrid::Empty { meta } => {
308                write!(buf,"ver:\"3.0\"")?;
309                
310                if let Some(meta) = meta {
311                    if !meta.is_empty() {
312                        let mut iter = meta.iter().peekable();
313                        while let Some((k,v)) = iter.next() {
314                            write!(buf, " {}", k.as_str())?;
315                            match v.haystack_type() {
316                                HType::Marker => (),
317                                _ => { write!(buf, ":")?; v.to_zinc(buf)?; }
318                            };
319                        }
320                    }
321                }
322
323                write!(buf,"empty\n")
324            }
325        }
326    }
327    fn to_json(&self, _buf: &mut String) -> fmt::Result {
328        unimplemented!();
329    }
330    fn haystack_type(&self) -> HType { THIS_TYPE }
331
332    fn _eq(&self, other: &dyn HVal<'a,T>) -> bool { false }
333    set_get_method!(get_grid_val, HGrid<'a,T>);
334}
335
336#[cfg(test)]
337mod tests {
338    use std::rc::Rc;
339
340    use super::*;
341    use super::super::{MARKER,REMOVE};
342
343    const EMPTY_GRID: &str = "ver:\"3.0\"\nempty\n";
344    const ERROR_GRID: &str = "ver:\"3.0\" err dis:\"Display message\"\nempty\n";
345    const ERROR_GRID_TRACE: &str = "ver:\"3.0\" err dis:\"Display message\" errTrace:\"Error trace (Optional)\"\nempty\n";
346
347    #[test]
348    fn print_grid() {
349        let mut grid_meta: HashMap<String,HBox<f64>> = HashMap::new();
350        grid_meta.insert("meta1".into(), Rc::new(MARKER));
351        grid_meta.insert("meta2".into(), Rc::new(REMOVE));
352
353        let mut col_meta: HashMap<String,HBox<f64>> = HashMap::new();
354        col_meta.insert("cmeta1".into(), Rc::new(MARKER));
355        col_meta.insert("cmeta2".into(), Rc::new(REMOVE));
356        col_meta.insert("cmeta3".into(), Rc::new(MARKER));
357
358        let mut row_1: HashMap<String,HBox<f64>> = HashMap::new();
359        row_1.insert("col1".into(), Rc::new(MARKER));
360        row_1.insert("col2".into(), Rc::new(MARKER));
361        
362
363        let mut row_2: HashMap<String,HBox<f64>> = HashMap::new();
364        row_2.insert("col1".into(), Rc::new(REMOVE));
365        row_2.insert("col3".into(), Rc::new(REMOVE));
366
367        let mut grid = Grid::new(None,vec![row_1,row_2]);
368        grid = grid.add_meta(grid_meta).unwrap();
369        grid = grid.add_col_meta("col1",col_meta).unwrap();
370
371        let mut buf = String::new();
372        {
373            grid.to_zinc(&mut buf).unwrap();
374        }
375        println!("GRID\n{}", buf);
376    }
377}