use crate::dict;
use crate::haystack::val::Value;
use crate::haystack::val::dict::*;
use std::collections::HashSet;
use std::iter::Iterator;
use std::ops::Index;
#[derive(Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Debug, Default)]
pub struct Column {
pub name: String,
pub meta: Option<Dict>,
}
pub const GRID_FORMAT_VERSION: &str = "3.0";
pub const VER: &str = "ver";
#[derive(Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Debug)]
pub struct Grid {
pub meta: Option<Dict>,
pub columns: Vec<Column>,
pub rows: Vec<Dict>,
pub ver: String,
}
impl Grid {
pub fn make_empty() -> Self {
Grid {
meta: None,
columns: vec![Column {
name: String::from("empty"),
meta: None,
}],
rows: Vec::default(),
ver: GRID_FORMAT_VERSION.to_string(),
}
}
pub fn make_from_dicts(rows: Vec<Dict>) -> Self {
let mut col_names = HashSet::<String>::new();
rows.iter().for_each(|el| {
el.keys().for_each(|col_name| {
col_names.insert(col_name.clone());
})
});
let mut columns: Vec<Column> = col_names
.iter()
.map(|col_name| Column {
name: col_name.clone(),
meta: None,
})
.collect();
columns.sort_by(|a, b| a.name.cmp(&b.name));
Grid {
meta: None,
columns,
rows,
ver: GRID_FORMAT_VERSION.to_string(),
}
}
pub fn make_from_dicts_with_meta(rows: Vec<Dict>, meta: Dict) -> Self {
let mut grid = Grid::make_from_dicts(rows);
grid.meta = if meta.is_empty() { None } else { Some(meta) };
grid
}
pub fn make_err(dis: &str) -> Self {
Grid {
meta: Some(dict! {"err" => Value::Marker, "dis" => dis}),
columns: vec![Column {
name: String::from("empty"),
meta: None,
}],
rows: Vec::default(),
ver: GRID_FORMAT_VERSION.to_string(),
}
}
pub fn is_empty(&self) -> bool {
self.rows.is_empty()
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn is_err(&self) -> bool {
if let Some(meta) = &self.meta {
meta.has_marker("err")
} else {
false
}
}
}
impl Default for Grid {
fn default() -> Self {
Grid {
columns: Vec::default(),
meta: None,
rows: Vec::default(),
ver: GRID_FORMAT_VERSION.to_string(),
}
}
}
impl Index<usize> for Grid {
type Output = Dict;
fn index(&self, index: usize) -> &Self::Output {
&self.rows[index]
}
}
pub struct IterHelper<'a> {
iter: ::std::slice::Iter<'a, Dict>,
}
impl<'a> Iterator for IterHelper<'a> {
type Item = &'a Dict;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
}
impl<'a> IntoIterator for &'a Grid {
type Item = &'a Dict;
type IntoIter = IterHelper<'a>;
fn into_iter(self) -> Self::IntoIter {
IterHelper {
iter: self.rows.iter(),
}
}
}
impl From<Grid> for Value {
fn from(value: Grid) -> Self {
Value::Grid(value)
}
}
impl TryFrom<&Value> for Grid {
type Error = &'static str;
fn try_from(value: &Value) -> Result<Self, Self::Error> {
match value {
Value::Grid(v) => Ok(v.clone()),
_ => Err("Value is not an `Grid`"),
}
}
}