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
222impl <'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:")?;
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}