1use crate::{parser, Value};
2use anyhow::{anyhow, Result};
3use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
4use bytes::BytesMut;
5use compact_str::CompactString;
6use escaping::Escape;
7use netidx_core::utils::pack;
8use rust_decimal::Decimal;
9use smallvec::smallvec;
10use std::{
11 cell::RefCell,
12 fmt::{self, Write},
13 ops::Deref,
14};
15
16struct DecimalFmt(Decimal);
17
18impl fmt::Display for DecimalFmt {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 thread_local! {
23 static BUF: RefCell<CompactString> = RefCell::new(CompactString::new(""));
24 }
25 BUF.with_borrow_mut(|buf| {
26 use std::fmt::Write;
27 buf.clear();
28 write!(buf, "{}", self.0)?;
29 if buf.contains('.') {
30 write!(f, "{buf}")
31 } else {
32 write!(f, "{buf}.")
33 }
34 })
35 }
36}
37
38pub struct NakedValue<'a>(pub &'a Value);
40
41impl<'a> Deref for NakedValue<'a> {
42 type Target = Value;
43
44 fn deref(&self) -> &Self::Target {
45 self.0
46 }
47}
48
49impl<'a> fmt::Display for NakedValue<'a> {
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 self.0.fmt_naked(f)
52 }
53}
54
55impl fmt::Display for Value {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 self.fmt_ext(f, &parser::VAL_ESC, true)
58 }
59}
60
61pub fn printf(f: &mut impl Write, fmt: &str, args: &[Value]) -> Result<usize> {
62 use compact_str::{format_compact, CompactString};
63 use fish_printf::{printf_c_locale, Arg, ToArg};
64 use rust_decimal::prelude::ToPrimitive;
65 use smallvec::SmallVec;
66 enum T<'a> {
67 Arg(Arg<'a>),
68 Index(usize),
69 }
70 let mut strings: SmallVec<[CompactString; 4]> = smallvec![];
71 let mut fish_args: SmallVec<[T; 8]> = smallvec![];
72 for v in args {
73 fish_args.push(match v {
74 Value::U8(v) => T::Arg(v.to_arg()),
75 Value::I8(v) => T::Arg(v.to_arg()),
76 Value::U16(v) => T::Arg(v.to_arg()),
77 Value::I16(v) => T::Arg(v.to_arg()),
78 Value::U32(v) | Value::V32(v) => T::Arg(v.to_arg()),
79 Value::I32(v) | Value::Z32(v) => T::Arg(v.to_arg()),
80 Value::U64(v) | Value::V64(v) => T::Arg(v.to_arg()),
81 Value::I64(v) | Value::Z64(v) => T::Arg(v.to_arg()),
82 Value::F32(v) => T::Arg(v.to_arg()),
83 Value::F64(v) => T::Arg(v.to_arg()),
84 Value::Decimal(v) => match v.to_f64() {
85 Some(f) => T::Arg(f.to_arg()),
86 None => {
87 strings.push(format_compact!("{v}"));
88 T::Index(strings.len() - 1)
89 }
90 },
91 Value::DateTime(v) => {
92 strings.push(format_compact!("{v}"));
93 T::Index(strings.len() - 1)
94 }
95 Value::Duration(v) => {
96 strings.push(format_compact!("{v:?}"));
97 T::Index(strings.len() - 1)
98 }
99 Value::String(s) => T::Arg(s.to_arg()),
100 Value::Bytes(b) => {
101 strings.push(format_compact!("{}", BASE64.encode(b)));
102 T::Index(strings.len() - 1)
103 }
104 Value::Bool(true) => T::Arg("true".to_arg()),
105 Value::Bool(false) => T::Arg("false".to_arg()),
106 Value::Null => T::Arg("null".to_arg()),
107 v @ (Value::Error(_)
108 | Value::Array(_)
109 | Value::Map(_)
110 | Value::Abstract(_)) => {
111 strings.push(format_compact!("{v}"));
112 T::Index(strings.len() - 1)
113 }
114 })
115 }
116 let mut fish_args: SmallVec<[Arg; 8]> = fish_args
117 .into_iter()
118 .map(|t| match t {
119 T::Arg(a) => a,
120 T::Index(i) => strings[i].to_arg(),
121 })
122 .collect();
123 printf_c_locale(f, fmt, &mut fish_args).map_err(|e| anyhow!(format!("{e:?}")))
124}
125
126impl Value {
127 pub fn to_string_naked(&self) -> String {
128 format!("{}", NakedValue(self))
129 }
130
131 pub fn fmt_naked(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 match self {
133 Value::U8(v) => write!(f, "{}", v),
134 Value::I8(v) => write!(f, "{}", v),
135 Value::U16(v) => write!(f, "{}", v),
136 Value::I16(v) => write!(f, "{}", v),
137 Value::U32(v) | Value::V32(v) => write!(f, "{}", v),
138 Value::I32(v) | Value::Z32(v) => write!(f, "{}", v),
139 Value::U64(v) | Value::V64(v) => write!(f, "{}", v),
140 Value::I64(v) | Value::Z64(v) => write!(f, "{}", v),
141 Value::F32(v) => write!(f, "{}", v),
142 Value::F64(v) => write!(f, "{}", v),
143 Value::Decimal(v) => write!(f, "{}", DecimalFmt(**v)),
144 Value::DateTime(v) => write!(f, "{}", v),
145 Value::Duration(v) => {
146 let v = v.as_secs_f64();
147 if v.fract() == 0. {
148 write!(f, "{}.s", v)
149 } else {
150 write!(f, "{}s", v)
151 }
152 }
153 Value::String(s) => write!(f, "\"{}\"", parser::VAL_ESC.escape(s)),
154 Value::Bytes(b) => write!(f, "{}", BASE64.encode(b)),
155 Value::Bool(true) => write!(f, "true"),
156 Value::Bool(false) => write!(f, "false"),
157 Value::Null => write!(f, "null"),
158 v @ (Value::Error(_)
159 | Value::Array(_)
160 | Value::Map(_)
161 | Value::Abstract(_)) => write!(f, "{}", v),
162 }
163 }
164
165 pub fn fmt_notyp(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 self.fmt_ext(f, &parser::VAL_ESC, false)
167 }
168
169 pub fn fmt_ext(
170 &self,
171 f: &mut fmt::Formatter<'_>,
172 esc: &Escape,
173 types: bool,
174 ) -> fmt::Result {
175 match self {
176 Value::U8(v) => {
177 if types {
178 write!(f, "u8:{}", v)
179 } else {
180 write!(f, "{}", v)
181 }
182 }
183 Value::I8(v) => {
184 if types {
185 write!(f, "i8:{}", v)
186 } else {
187 write!(f, "{}", v)
188 }
189 }
190 Value::U16(v) => {
191 if types {
192 write!(f, "u16:{}", v)
193 } else {
194 write!(f, "{}", v)
195 }
196 }
197 Value::I16(v) => {
198 if types {
199 write!(f, "i16:{}", v)
200 } else {
201 write!(f, "{}", v)
202 }
203 }
204 Value::U32(v) => {
205 if types {
206 write!(f, "u32:{}", v)
207 } else {
208 write!(f, "{}", v)
209 }
210 }
211 Value::V32(v) => {
212 if types {
213 write!(f, "v32:{}", v)
214 } else {
215 write!(f, "{}", v)
216 }
217 }
218 Value::I32(v) => {
219 if types {
220 write!(f, "i32:{}", v)
221 } else {
222 write!(f, "{}", v)
223 }
224 }
225 Value::Z32(v) => {
226 if types {
227 write!(f, "z32:{}", v)
228 } else {
229 write!(f, "{}", v)
230 }
231 }
232 Value::U64(v) => {
233 if types {
234 write!(f, "u64:{}", v)
235 } else {
236 write!(f, "{}", v)
237 }
238 }
239 Value::V64(v) => {
240 if types {
241 write!(f, "v64:{}", v)
242 } else {
243 write!(f, "{}", v)
244 }
245 }
246 Value::I64(v) => {
247 if types {
248 write!(f, "i64:{}", v)
249 } else {
250 write!(f, "{}", v)
251 }
252 }
253 Value::Z64(v) => {
254 if types {
255 write!(f, "z64:{}", v)
256 } else {
257 write!(f, "{}", v)
258 }
259 }
260 Value::F32(v) => {
261 let pfx = if types { "f32:" } else { "" };
262 if v.fract() == 0. {
263 write!(f, "{}{}.", pfx, v)
264 } else {
265 write!(f, "{}{}", pfx, v)
266 }
267 }
268 Value::F64(v) => {
269 let pfx = if types { "f64:" } else { "" };
270 if v.fract() == 0. {
271 write!(f, "{}{}.", pfx, v)
272 } else {
273 write!(f, "{}{}", pfx, v)
274 }
275 }
276 Value::Decimal(v) => {
277 if types {
278 write!(f, "decimal:{}", DecimalFmt(**v))
279 } else {
280 write!(f, "{}", DecimalFmt(**v))
281 }
282 }
283 Value::DateTime(v) => {
284 if types {
285 write!(f, r#"datetime:"{}""#, v)
286 } else {
287 write!(f, r#""{}""#, v)
288 }
289 }
290 Value::Duration(v) => {
291 let pfx = if types { "duration:" } else { "" };
292 let v = v.as_secs_f64();
293 if v.fract() == 0. {
294 write!(f, r#"{}{}.s"#, pfx, v)
295 } else {
296 write!(f, r#"{}{}s"#, pfx, v)
297 }
298 }
299 Value::String(s) => {
300 write!(f, r#""{}""#, esc.escape(&*s))
301 }
302 Value::Bytes(b) => {
303 let pfx = if types { "bytes:" } else { "" };
304 if b.is_empty() {
305 write!(f, "{}null", pfx)
306 } else {
307 write!(f, "{}{}", pfx, BASE64.encode(&*b))
308 }
309 }
310 Value::Bool(true) => write!(f, "true"),
311 Value::Bool(false) => write!(f, "false"),
312 Value::Null => write!(f, "null"),
313 Value::Error(v) => match &**v {
314 Value::String(s) => {
315 write!(f, r#"error:"{}""#, esc.escape(&*s))
316 }
317 v => {
318 write!(f, r#"error:{v}"#)
319 }
320 },
321 Value::Array(elts) => {
322 write!(f, "[")?;
323 for (i, v) in elts.iter().enumerate() {
324 if i < elts.len() - 1 {
325 v.fmt_ext(f, esc, types)?;
326 write!(f, ", ")?
327 } else {
328 v.fmt_ext(f, esc, types)?
329 }
330 }
331 write!(f, "]")
332 }
333 Value::Map(m) => {
334 write!(f, "{{")?;
335 for (i, (k, v)) in m.into_iter().enumerate() {
336 k.fmt_ext(f, esc, types)?;
337 write!(f, " => ")?;
338 v.fmt_ext(f, esc, types)?;
339 if i < m.len() - 1 {
340 write!(f, ", ")?
341 }
342 }
343 write!(f, "}}")
344 }
345 Value::Abstract(a) => {
346 let bytes = pack(a).unwrap_or_else(|_| BytesMut::new());
347 write!(f, "abstract:{}", BASE64.encode(&bytes))
348 }
349 }
350 }
351}