use crate::_macro_internal::Value;
use crate::value::base::{DAYS_FROM_CE, TIMESTAMP_FORMAT, TIMESTAMP_TIMEZONE_FORMAT};
use crate::value::NumberValue;
use chrono::NaiveDate;
use ethnum::i256;
use std::fmt::Write;
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.display_value(f, true)
}
}
impl std::fmt::Display for NumberValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NumberValue::Int8(i) => write!(f, "{i}"),
NumberValue::Int16(i) => write!(f, "{i}"),
NumberValue::Int32(i) => write!(f, "{i}"),
NumberValue::Int64(i) => write!(f, "{i}"),
NumberValue::UInt8(i) => write!(f, "{i}"),
NumberValue::UInt16(i) => write!(f, "{i}"),
NumberValue::UInt32(i) => write!(f, "{i}"),
NumberValue::UInt64(i) => write!(f, "{i}"),
NumberValue::Float32(i) => display_float(*i, f),
NumberValue::Float64(i) => display_float(*i, f),
NumberValue::Decimal64(v, s) => {
write!(f, "{}", display_decimal_128(*v as i128, s.scale))
}
NumberValue::Decimal128(v, s) => write!(f, "{}", display_decimal_128(*v, s.scale)),
NumberValue::Decimal256(v, s) => write!(f, "{}", display_decimal_256(*v, s.scale)),
}
}
}
impl Value {
pub fn display_value(&self, f: &mut std::fmt::Formatter<'_>, raw: bool) -> std::fmt::Result {
match self {
Value::Null => write!(f, "NULL"),
Value::EmptyArray => write!(f, "[]"),
Value::EmptyMap => write!(f, "{{}}"),
Value::Boolean(b) => {
if *b {
write!(f, "true")
} else {
write!(f, "false")
}
}
Value::Number(n) => write!(f, "{n}"),
Value::Binary(s) => write!(f, "{}", hex::encode_upper(s)),
Value::String(s) | Value::Bitmap(s) | Value::Interval(s) => {
if raw {
write!(f, "{s}")
} else {
write!(f, "\"{s}\"")
}
}
Value::Variant(s) => {
write!(f, "{s}")
}
Value::Geometry(s) | Value::Geography(s) => {
if raw || s.starts_with('{') {
write!(f, "{s}")
} else {
write!(f, "\"{s}\"")
}
}
Value::Timestamp(dt) => {
let formatted = dt.strftime(TIMESTAMP_FORMAT);
if raw {
write!(f, "{formatted}")
} else {
write!(f, "\"{formatted}\"")
}
}
Value::TimestampTz(dt) => {
let formatted = dt.strftime(TIMESTAMP_TIMEZONE_FORMAT);
if raw {
write!(f, "{formatted}")
} else {
write!(f, "\"{formatted}\"")
}
}
Value::Date(i) => {
let days = i + DAYS_FROM_CE;
let d = NaiveDate::from_num_days_from_ce_opt(days).unwrap_or_default();
if raw {
write!(f, "{d}")
} else {
write!(f, "\"{d}\"")
}
}
Value::Array(vals) => {
write!(f, "[")?;
for (i, val) in vals.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
val.display_value(f, false)?;
}
write!(f, "]")?;
Ok(())
}
Value::Map(kvs) => {
write!(f, "{{")?;
for (i, (key, val)) in kvs.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
key.display_value(f, false)?;
write!(f, ":")?;
val.display_value(f, false)?;
}
write!(f, "}}")?;
Ok(())
}
Value::Tuple(vals) => {
write!(f, "(")?;
for (i, val) in vals.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
val.display_value(f, false)?;
}
write!(f, ")")?;
Ok(())
}
Value::Vector(vals) => {
write!(f, "[")?;
let mut buffer = zmij::Buffer::new();
for (i, val) in vals.iter().enumerate() {
if i > 0 {
write!(f, ",")?;
}
let s = buffer.format_finite(*val);
write!(f, "{s}")?;
}
write!(f, "]")?;
Ok(())
}
}
}
}
trait FloatForDisplay: Copy {
fn is_nan(self) -> bool;
fn is_infinite(self) -> bool;
fn is_sign_negative(self) -> bool;
fn write_with(self, buf: &mut zmij::Buffer) -> &str;
}
impl FloatForDisplay for f32 {
fn is_nan(self) -> bool {
f32::is_nan(self)
}
fn is_infinite(self) -> bool {
f32::is_infinite(self)
}
fn is_sign_negative(self) -> bool {
f32::is_sign_negative(self)
}
fn write_with(self, buf: &mut zmij::Buffer) -> &str {
buf.format_finite(self)
}
}
impl FloatForDisplay for f64 {
fn is_nan(self) -> bool {
f64::is_nan(self)
}
fn is_infinite(self) -> bool {
f64::is_infinite(self)
}
fn is_sign_negative(self) -> bool {
f64::is_sign_negative(self)
}
fn write_with(self, buf: &mut zmij::Buffer) -> &str {
buf.format_finite(self)
}
}
fn display_float<T: FloatForDisplay>(num: T, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if num.is_nan() {
write!(f, "NaN")
} else if num.is_infinite() {
if num.is_sign_negative() {
write!(f, "-inf")
} else {
write!(f, "inf")
}
} else {
let mut buffer = zmij::Buffer::new();
write!(f, "{}", num.write_with(&mut buffer))
}
}
pub fn display_decimal_128(num: i128, scale: u8) -> String {
let mut buf = String::new();
if scale == 0 {
write!(buf, "{num}").unwrap();
} else {
let pow_scale = 10_i128.pow(scale as u32);
if num >= 0 {
write!(
buf,
"{}.{:0>width$}",
num / pow_scale,
(num % pow_scale).abs(),
width = scale as usize
)
.unwrap();
} else {
write!(
buf,
"-{}.{:0>width$}",
-num / pow_scale,
(num % pow_scale).abs(),
width = scale as usize
)
.unwrap();
}
}
buf
}
pub fn display_decimal_256(num: i256, scale: u8) -> String {
let mut buf = String::new();
if scale == 0 {
write!(buf, "{}", num).unwrap();
} else {
let pow_scale = i256::from(10).pow(scale as u32);
if !num.is_negative() {
write!(
buf,
"{}.{:0>width$}",
num / pow_scale,
(num % pow_scale).wrapping_abs(),
width = scale as usize
)
} else {
write!(
buf,
"-{}.{:0>width$}",
-num / pow_scale,
(num % pow_scale).wrapping_abs(),
width = scale as usize
)
}
.expect("display_decimal_256 should not fail");
}
String::from_utf8_lossy(buf.as_bytes()).to_string()
}