use std::collections::HashMap;
use std::sync::Arc;
use crate::calamine::Data as CalamineData;
pub type RowsHandle = Arc<Vec<HashMap<String, Value>>>;
pub type MapHandle = Arc<HashMap<String, Value>>;
pub type ListHandle = Arc<Vec<Value>>;
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Empty,
String(String),
Number(f64),
Bool(bool),
DateNumber(f64),
Rows(RowsHandle),
Map(MapHandle),
List(ListHandle),
}
pub fn canonical_number(n: f64) -> String {
if !n.is_finite() {
return format!("{n}");
}
if n.fract() == 0.0 && n.abs() < 1e16 {
return format!("{}", n as i64);
}
let abs = n.abs();
if abs > 0.0 && abs < 1e-6 {
format!("{n:e}")
} else {
format!("{n}")
}
}
impl Value {
pub fn canonical(&self) -> String {
match self {
Value::Empty => String::new(),
Value::String(s) => s.clone(),
Value::Number(n) => canonical_number(*n),
Value::DateNumber(n) => crate::functions::serial_to_iso_canonical(*n)
.unwrap_or_else(|| canonical_number(*n)),
Value::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
Value::Rows(_) | Value::Map(_) | Value::List(_) => String::new(),
}
}
pub fn from_calamine(d: &CalamineData) -> Value {
match d {
CalamineData::Empty => Value::Empty,
CalamineData::String(s) => Value::String(s.clone()),
CalamineData::Float(f) => Value::Number(*f),
CalamineData::Int(i) => Value::Number(*i as f64),
CalamineData::Bool(b) => Value::Bool(*b),
CalamineData::DateTime(dt) => Value::Number(dt.as_f64()),
CalamineData::DateTimeIso(s) | CalamineData::DurationIso(s) => {
Value::String(s.clone())
}
CalamineData::Error(_) => Value::Empty,
}
}
}