use crate::_macro_internal::Value;
use crate::value::base::{DAYS_FROM_CE, TIMESTAMP_FORMAT, TIMESTAMP_TIMEZONE_FORMAT};
use crate::value::format::display::{display_decimal_128, display_decimal_256};
use crate::value::NumberValue;
use chrono::NaiveDate;
use hex;
use lexical_core::{ToLexical, ToLexicalWithOptions, WriteFloatOptions};
pub struct FormatOptions {
pub true_string: &'static [u8],
pub false_string: &'static [u8],
pub float_options: WriteFloatOptions,
}
impl Value {
pub fn to_string_with_options(&self, format_options: &FormatOptions) -> String {
let mut buf = Vec::<u8>::with_capacity(100);
self.write_with_option(&mut buf, true, format_options);
String::from_utf8_lossy(&buf).into_owned()
}
fn write_with_option(&self, bytes: &mut Vec<u8>, raw: bool, format_options: &FormatOptions) {
match self {
Value::Null => bytes.extend_from_slice("NULL".as_bytes()),
Value::EmptyArray => bytes.extend_from_slice("[]".as_bytes()),
Value::EmptyMap => bytes.extend_from_slice("{}".as_bytes()),
Value::Boolean(b) => {
if *b {
bytes.extend_from_slice(format_options.true_string)
} else {
bytes.extend_from_slice(format_options.false_string)
}
}
Value::Number(n) => match n {
NumberValue::Int8(v) => Self::write_int(bytes, *v),
NumberValue::Int16(v) => Self::write_int(bytes, *v),
NumberValue::Int32(v) => Self::write_int(bytes, *v),
NumberValue::Int64(v) => Self::write_int(bytes, *v),
NumberValue::UInt8(v) => Self::write_int(bytes, *v),
NumberValue::UInt16(v) => Self::write_int(bytes, *v),
NumberValue::UInt32(v) => Self::write_int(bytes, *v),
NumberValue::UInt64(v) => Self::write_int(bytes, *v),
NumberValue::Float32(v) => Self::write_float(bytes, *v, format_options),
NumberValue::Float64(v) => Self::write_float(bytes, *v, format_options),
NumberValue::Decimal64(v, size) => {
let s = display_decimal_128(*v as i128, size.scale);
Self::write_string(bytes, &s, true);
}
NumberValue::Decimal128(v, size) => {
let s = display_decimal_128(*v, size.scale);
Self::write_string(bytes, &s, true);
}
NumberValue::Decimal256(v, size) => {
let s = display_decimal_256(*v, size.scale);
Self::write_string(bytes, &s, true);
}
},
Value::Binary(s) => bytes.extend_from_slice(hex::encode_upper(s).as_bytes()),
Value::String(s) | Value::Bitmap(s) | Value::Interval(s) => {
Self::write_string(bytes, s, raw);
}
Value::Variant(s) => {
bytes.extend_from_slice(s.as_bytes());
}
Value::Geometry(s) | Value::Geography(s) => {
if s.starts_with('{') {
bytes.extend_from_slice(s.as_bytes());
} else {
Self::write_string(bytes, s, raw);
}
}
Value::Timestamp(dt) => {
let s = dt.strftime(TIMESTAMP_FORMAT).to_string();
Self::write_string(bytes, &s, raw);
}
Value::TimestampTz(dt) => {
let s = dt.strftime(TIMESTAMP_TIMEZONE_FORMAT).to_string();
Self::write_string(bytes, &s, raw);
}
Value::Date(i) => {
let days = i + DAYS_FROM_CE;
let d = NaiveDate::from_num_days_from_ce_opt(days).unwrap_or_default();
let s = format!("{}", d);
Self::write_string(bytes, &s, raw);
}
Value::Array(vals) => {
bytes.push(b'[');
for (i, val) in vals.iter().enumerate() {
if i > 0 {
bytes.push(b',');
}
val.write_with_option(bytes, false, format_options);
}
bytes.push(b']');
}
Value::Map(kvs) => {
bytes.push(b'{');
for (i, (key, val)) in kvs.iter().enumerate() {
if i > 0 {
bytes.push(b',');
}
key.write_with_option(bytes, false, format_options);
bytes.push(b':');
val.write_with_option(bytes, false, format_options);
}
bytes.push(b'}');
}
Value::Tuple(vals) => {
bytes.push(b'(');
for (i, val) in vals.iter().enumerate() {
if i > 0 {
bytes.push(b',');
}
val.write_with_option(bytes, false, format_options);
}
bytes.push(b')');
}
Value::Vector(vals) => {
bytes.push(b'[');
for (i, val) in vals.iter().enumerate() {
if i > 0 {
bytes.push(b',');
}
Self::write_float(bytes, *val, format_options);
}
bytes.push(b']');
}
}
}
fn write_string(bytes: &mut Vec<u8>, string: &String, raw: bool) {
if !raw {
bytes.push(b'"');
write_quoted_string_min_escape(string.as_bytes(), bytes, b'"');
bytes.push(b'"');
} else {
bytes.extend_from_slice(string.as_bytes());
}
}
fn write_float<T: ToLexicalWithOptions<Options = WriteFloatOptions>>(
out_buf: &mut Vec<u8>,
v: T,
options: &FormatOptions,
) {
out_buf.reserve(T::FORMATTED_SIZE_DECIMAL);
let len0 = out_buf.len();
unsafe {
let slice = std::slice::from_raw_parts_mut(
out_buf.as_mut_ptr().add(len0),
out_buf.capacity() - len0,
);
let len = v
.to_lexical_with_options::<{ lexical_core::format::STANDARD }>(
slice,
&options.float_options,
)
.len();
out_buf.set_len(len0 + len);
}
}
fn write_int<T: ToLexical>(out_buf: &mut Vec<u8>, v: T) {
out_buf.reserve(T::FORMATTED_SIZE_DECIMAL);
let len0 = out_buf.len();
unsafe {
let slice = std::slice::from_raw_parts_mut(
out_buf.as_mut_ptr().add(len0),
out_buf.capacity() - len0,
);
let len = v.to_lexical(slice).len();
out_buf.set_len(len0 + len);
}
}
}
fn write_quoted_string_min_escape(bytes: &[u8], buf: &mut Vec<u8>, quote: u8) {
let mut start = 0;
for (i, &byte) in bytes.iter().enumerate() {
if byte == quote {
if start < i {
buf.extend_from_slice(&bytes[start..i]);
}
buf.push(b'\\');
buf.push(quote);
start = i + 1;
}
}
if start != bytes.len() {
buf.extend_from_slice(&bytes[start..]);
}
}