databend_driver_core/value/format/
display.rs1use crate::_macro_internal::Value;
16use crate::value::base::{DAYS_FROM_CE, TIMESTAMP_FORMAT, TIMESTAMP_TIMEZONE_FORMAT};
17use crate::value::NumberValue;
18use chrono::NaiveDate;
19use ethnum::i256;
20use std::fmt::Write;
21
22impl std::fmt::Display for Value {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 self.display_value(f, true)
25 }
26}
27
28impl std::fmt::Display for NumberValue {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 NumberValue::Int8(i) => write!(f, "{i}"),
32 NumberValue::Int16(i) => write!(f, "{i}"),
33 NumberValue::Int32(i) => write!(f, "{i}"),
34 NumberValue::Int64(i) => write!(f, "{i}"),
35 NumberValue::UInt8(i) => write!(f, "{i}"),
36 NumberValue::UInt16(i) => write!(f, "{i}"),
37 NumberValue::UInt32(i) => write!(f, "{i}"),
38 NumberValue::UInt64(i) => write!(f, "{i}"),
39 NumberValue::Float32(i) => display_float(*i, f),
40 NumberValue::Float64(i) => display_float(*i, f),
41 NumberValue::Decimal64(v, s) => {
42 write!(f, "{}", display_decimal_128(*v as i128, s.scale))
43 }
44 NumberValue::Decimal128(v, s) => write!(f, "{}", display_decimal_128(*v, s.scale)),
45 NumberValue::Decimal256(v, s) => write!(f, "{}", display_decimal_256(*v, s.scale)),
46 }
47 }
48}
49
50impl Value {
51 pub fn display_value(&self, f: &mut std::fmt::Formatter<'_>, raw: bool) -> std::fmt::Result {
54 match self {
55 Value::Null => write!(f, "NULL"),
56 Value::EmptyArray => write!(f, "[]"),
57 Value::EmptyMap => write!(f, "{{}}"),
58 Value::Boolean(b) => {
59 if *b {
60 write!(f, "true")
61 } else {
62 write!(f, "false")
63 }
64 }
65 Value::Number(n) => write!(f, "{n}"),
66 Value::Binary(s) => write!(f, "{}", hex::encode_upper(s)),
67 Value::String(s) | Value::Bitmap(s) | Value::Interval(s) => {
68 if raw {
69 write!(f, "{s}")
70 } else {
71 write!(f, "\"{s}\"")
72 }
73 }
74 Value::Variant(s) => {
75 write!(f, "{s}")
76 }
77 Value::Geometry(s) | Value::Geography(s) => {
78 if raw || s.starts_with('{') {
79 write!(f, "{s}")
80 } else {
81 write!(f, "\"{s}\"")
82 }
83 }
84 Value::Timestamp(dt) => {
85 let formatted = dt.strftime(TIMESTAMP_FORMAT);
86 if raw {
87 write!(f, "{formatted}")
88 } else {
89 write!(f, "\"{formatted}\"")
90 }
91 }
92 Value::TimestampTz(dt) => {
93 let formatted = dt.strftime(TIMESTAMP_TIMEZONE_FORMAT);
94 if raw {
95 write!(f, "{formatted}")
96 } else {
97 write!(f, "\"{formatted}\"")
98 }
99 }
100 Value::Date(i) => {
101 let days = i + DAYS_FROM_CE;
102 let d = NaiveDate::from_num_days_from_ce_opt(days).unwrap_or_default();
103 if raw {
104 write!(f, "{d}")
105 } else {
106 write!(f, "\"{d}\"")
107 }
108 }
109 Value::Array(vals) => {
110 write!(f, "[")?;
111 for (i, val) in vals.iter().enumerate() {
112 if i > 0 {
113 write!(f, ",")?;
114 }
115 val.display_value(f, false)?;
116 }
117 write!(f, "]")?;
118 Ok(())
119 }
120 Value::Map(kvs) => {
121 write!(f, "{{")?;
122 for (i, (key, val)) in kvs.iter().enumerate() {
123 if i > 0 {
124 write!(f, ",")?;
125 }
126 key.display_value(f, false)?;
127 write!(f, ":")?;
128 val.display_value(f, false)?;
129 }
130 write!(f, "}}")?;
131 Ok(())
132 }
133 Value::Tuple(vals) => {
134 write!(f, "(")?;
135 for (i, val) in vals.iter().enumerate() {
136 if i > 0 {
137 write!(f, ",")?;
138 }
139 val.display_value(f, false)?;
140 }
141 write!(f, ")")?;
142 Ok(())
143 }
144 Value::Vector(vals) => {
145 write!(f, "[")?;
146 let mut buffer = zmij::Buffer::new();
147 for (i, val) in vals.iter().enumerate() {
148 if i > 0 {
149 write!(f, ",")?;
150 }
151 let s = buffer.format_finite(*val);
152 write!(f, "{s}")?;
153 }
154 write!(f, "]")?;
155 Ok(())
156 }
157 }
158 }
159}
160
161trait FloatForDisplay: Copy {
162 fn is_nan(self) -> bool;
163 fn is_infinite(self) -> bool;
164 fn is_sign_negative(self) -> bool;
165 fn write_with(self, buf: &mut zmij::Buffer) -> &str;
166}
167
168impl FloatForDisplay for f32 {
169 fn is_nan(self) -> bool {
170 f32::is_nan(self)
171 }
172 fn is_infinite(self) -> bool {
173 f32::is_infinite(self)
174 }
175 fn is_sign_negative(self) -> bool {
176 f32::is_sign_negative(self)
177 }
178 fn write_with(self, buf: &mut zmij::Buffer) -> &str {
179 buf.format_finite(self)
180 }
181}
182
183impl FloatForDisplay for f64 {
184 fn is_nan(self) -> bool {
185 f64::is_nan(self)
186 }
187 fn is_infinite(self) -> bool {
188 f64::is_infinite(self)
189 }
190 fn is_sign_negative(self) -> bool {
191 f64::is_sign_negative(self)
192 }
193 fn write_with(self, buf: &mut zmij::Buffer) -> &str {
194 buf.format_finite(self)
195 }
196}
197
198fn display_float<T: FloatForDisplay>(num: T, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 if num.is_nan() {
200 write!(f, "NaN")
201 } else if num.is_infinite() {
202 if num.is_sign_negative() {
203 write!(f, "-inf")
204 } else {
205 write!(f, "inf")
206 }
207 } else {
208 let mut buffer = zmij::Buffer::new();
209 write!(f, "{}", num.write_with(&mut buffer))
210 }
211}
212
213pub fn display_decimal_128(num: i128, scale: u8) -> String {
214 let mut buf = String::new();
215 if scale == 0 {
216 write!(buf, "{num}").unwrap();
217 } else {
218 let pow_scale = 10_i128.pow(scale as u32);
219 if num >= 0 {
220 write!(
221 buf,
222 "{}.{:0>width$}",
223 num / pow_scale,
224 (num % pow_scale).abs(),
225 width = scale as usize
226 )
227 .unwrap();
228 } else {
229 write!(
230 buf,
231 "-{}.{:0>width$}",
232 -num / pow_scale,
233 (num % pow_scale).abs(),
234 width = scale as usize
235 )
236 .unwrap();
237 }
238 }
239 buf
240}
241
242pub fn display_decimal_256(num: i256, scale: u8) -> String {
243 let mut buf = String::new();
244 if scale == 0 {
245 write!(buf, "{}", num).unwrap();
246 } else {
247 let pow_scale = i256::from(10).pow(scale as u32);
248 if !num.is_negative() {
250 write!(
251 buf,
252 "{}.{:0>width$}",
253 num / pow_scale,
254 (num % pow_scale).wrapping_abs(),
255 width = scale as usize
256 )
257 } else {
258 write!(
259 buf,
260 "-{}.{:0>width$}",
261 -num / pow_scale,
262 (num % pow_scale).wrapping_abs(),
263 width = scale as usize
264 )
265 }
266 .expect("display_decimal_256 should not fail");
267 }
268 String::from_utf8_lossy(buf.as_bytes()).to_string()
269}