use std::fmt;
use crate::attributes::Map;
use crate::attributes::scalar::Scalar;
#[derive(Clone, Debug, PartialEq)]
pub enum Value<'e> {
Scalar(Scalar),
List(&'e [Scalar]),
Map(&'e [Scalar], &'e [Scalar]),
}
impl<'i> fmt::Display for Value<'i> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::Scalar(s) => write!(f, "{}", s),
Self::List(ss) => {
write!(f, "[")?;
for i in 0..ss.len() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}", ss[i])?;
}
write!(f, "]")
}
Self::Map(keys, ss) => {
write!(f, "{{")?;
for i in 0..keys.len() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", keys[i], ss[i])?;
}
write!(f, "}}")
}
}
}
}
impl<'i> Value<'i> {
pub fn write_fmt<T: fmt::Write>(&self, out: &mut T, attrs: &Map) -> fmt::Result {
match &self {
Self::Scalar(s) => s.write_fmt(out, attrs),
Self::List(ss) => {
write!(out, "[")?;
for i in 0..ss.len() {
if i != 0 {
write!(out, ", ")?;
}
ss[i].write_fmt(out, attrs)?;
}
write!(out, "]")
}
Self::Map(keys, ss) => {
write!(out, "{{")?;
for i in 0..keys.len() {
if i != 0 {
write!(out, ", ")?;
}
keys[i].write_fmt(out, attrs)?;
write!(out, ": ")?;
ss[i].write_fmt(out, attrs)?;
}
write!(out, "}}")
}
}
}
}
impl<'i, T: Into<Scalar>> From<T> for Value<'i> {
fn from(t: T) -> Self {
Self::Scalar(t.into())
}
}
impl<'i> From<&'i Vec<Scalar>> for Value<'i> {
fn from(v: &'i Vec<Scalar>) -> Self {
Self::List(v.as_slice())
}
}
impl<'i> From<&'i [Scalar]> for Value<'i> {
fn from(ss: &'i [Scalar]) -> Self {
match ss.len() {
1 => Self::Scalar(ss[0].clone()),
_ => Self::List(ss),
}
}
}
impl<'i, const N: usize> From<&'i [Scalar; N]> for Value<'i> {
fn from(l: &'i [Scalar; N]) -> Self {
Self::List(l.as_slice())
}
}
impl<'i> From<(&'i Vec<Scalar>, &'i Vec<Scalar>)> for Value<'i> {
fn from(m: (&'i Vec<Scalar>, &'i Vec<Scalar>)) -> Self {
Self::Map(m.0.as_slice(), m.1.as_slice())
}
}
impl<'i> From<(&'i [Scalar], &'i [Scalar])> for Value<'i> {
fn from(m: (&'i [Scalar], &'i [Scalar])) -> Self {
Self::Map(m.0, m.1)
}
}
impl<'i, const N: usize> From<(&'i [Scalar; N], &'i [Scalar; N])> for Value<'i> {
fn from(m: (&'i [Scalar; N], &'i [Scalar; N])) -> Self {
Self::Map(m.0.as_slice(), m.1.as_slice())
}
}
impl<'i> From<[&'i [Scalar]; 2]> for Value<'i> {
fn from(m: [&'i [Scalar]; 2]) -> Self {
Self::Map(m[0], m[1])
}
}
impl<'i, const N: usize> From<[&'i [Scalar; N]; 2]> for Value<'i> {
fn from(m: [&'i [Scalar; N]; 2]) -> Self {
Self::Map(m[0].as_slice(), m[1].as_slice())
}
}
impl<'i, const N: usize> From<&'i [&'i [Scalar; N]; 2]> for Value<'i> {
fn from(m: &'i [&'i [Scalar; N]; 2]) -> Self {
Self::Map(m[0].as_slice(), m[1].as_slice())
}
}
#[cfg(test)]
mod tests {
use super::*;
use ntime::{Duration, Timestamp};
#[test]
fn from_scalar() {
assert_eq!(Value::from(true), Value::Scalar(Scalar::Bool(true)));
assert_eq!(Value::from("lalala"), Value::Scalar(Scalar::StringSlice("lalala", false)));
assert_eq!(Value::from("declaró\nen\tcontra"), Value::Scalar(Scalar::StringSlice("declaró\nen\tcontra", true)));
assert_eq!(Value::from(String::from("lalala")), Value::Scalar(Scalar::String(String::from("lalala"), false)));
assert_eq!(
Value::from(String::from("declaró\nen\tcontra")),
Value::Scalar(Scalar::String(String::from("declaró\nen\tcontra"), true))
);
assert_eq!(Value::from(-12 as i8), Value::Scalar(Scalar::Int(-12)));
assert_eq!(Value::from(345 as i16), Value::Scalar(Scalar::Int(345)));
assert_eq!(Value::from(-678 as i32), Value::Scalar(Scalar::Int(-678)));
assert_eq!(Value::from(9012 as i64), Value::Scalar(Scalar::Int(9012)));
assert_eq!(Value::from(-3456 as i128), Value::Scalar(Scalar::LongInt(-3456)));
assert_eq!(Value::from(7890 as isize), Value::Scalar(Scalar::Size(7890)));
assert_eq!(Value::from(12 as u8), Value::Scalar(Scalar::Uint(12)));
assert_eq!(Value::from(345 as u16), Value::Scalar(Scalar::Uint(345)));
assert_eq!(Value::from(678 as u32), Value::Scalar(Scalar::Uint(678)));
assert_eq!(Value::from(9012 as u64), Value::Scalar(Scalar::Uint(9012)));
assert_eq!(Value::from(3456 as u128), Value::Scalar(Scalar::LongUint(3456)));
assert_eq!(Value::from(7890 as usize), Value::Scalar(Scalar::Usize(7890)));
assert_eq!(Value::from(-123.456 as f32), Value::Scalar(Scalar::Float(-123.45600128173828)));
assert_eq!(Value::from(789.012 as f64), Value::Scalar(Scalar::Float(789.012)));
assert_eq!(Value::from(Duration::from_millis(12345)), Value::Scalar(Scalar::Uint(12)));
assert_eq!(Value::from(&Duration::from_millis(67890)), Value::Scalar(Scalar::Uint(67)));
assert_eq!(Value::from(Timestamp::from_millis(12345)), Value::Scalar(Scalar::Uint(12)));
assert_eq!(Value::from(&Timestamp::from_millis(67890)), Value::Scalar(Scalar::Uint(67)));
}
#[test]
fn from_scalar_vec() {
let v: Vec<Scalar> = vec![Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-12345678901234567)];
assert_eq!(Value::from(&v), Value::List(&[Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-12345678901234567)]));
}
#[test]
fn from_collection() {
let arr = [Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-12345678901234567)];
let slice = &[Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-12345678901234567)];
assert_eq!(Value::from(&arr), Value::List(&[Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-12345678901234567)]));
assert_eq!(Value::from(slice), Value::List(&[Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-12345678901234567)]));
}
#[test]
fn from_map_vecs() {
let keys = vec![Scalar::from("key_a"), Scalar::from("key_b"), Scalar::from("key_c")];
let vals = vec![Scalar::Bool(false), Scalar::Int(-123), Scalar::Float(456.789)];
assert_eq!(
Value::from((&keys, &vals)),
Value::Map(
&[Scalar::from("key_a"), Scalar::from("key_b"), Scalar::from("key_c")],
&[Scalar::Bool(false), Scalar::Int(-123), Scalar::Float(456.789)]
)
);
}
#[test]
fn from_map_collections() {
let arrays = [
&[Scalar::from("key_a"), Scalar::from("key_b"), Scalar::from("key_c")],
&[Scalar::Bool(false), Scalar::Int(-123), Scalar::Float(456.789)],
];
let slices = &[&[Scalar::from("key_c"), Scalar::from("key_d")], &[Scalar::Bool(true), Scalar::Int(456)]];
assert_eq!(
Value::from(&arrays),
Value::Map(
&[Scalar::from("key_a"), Scalar::from("key_b"), Scalar::from("key_c")],
&[Scalar::Bool(false), Scalar::Int(-123), Scalar::Float(456.789)]
)
);
assert_eq!(
Value::from(slices),
Value::Map(&[Scalar::from("key_c"), Scalar::from("key_d")], &[Scalar::Bool(true), Scalar::Int(456)])
);
}
#[test]
fn to_string() {
for tc in [
(Value::Scalar(Scalar::Bool(true)), "true"),
(Value::Scalar(Scalar::from("boo")), "\"boo\""),
(Value::Scalar(Scalar::from(String::from("abcd 1234"))), "\"abcd 1234\""),
(Value::Scalar(Scalar::Size(-12345678901234567)), "-0x2bdc545d6b4b87"),
(Value::Scalar(Scalar::Uint(123456)), "123456"),
(
Value::List(&[
Scalar::Bool(true),
Scalar::from("boo"),
Scalar::from("abcd 1234"),
Scalar::Size(-12345678901234567),
Scalar::Uint(123456),
]),
"[true, \"boo\", \"abcd 1234\", -0x2bdc545d6b4b87, 123456]",
),
(
Value::Map(&[Scalar::Int(123), Scalar::Int(456), Scalar::Int(-789)], &[Scalar::Bool(true), Scalar::from("boo"), Scalar::Size(-111)]),
"{123: true, 456: \"boo\", -789: -0x6f}",
),
] {
let (v, want): (Value, &str) = tc;
assert_eq!(v.to_string(), want);
}
}
}