1 | //! Integration between `Value` and `std::fmt`. |
2 | //! |
3 | //! This module allows any `Value` to implement the `Debug` and `Display` traits, |
4 | //! and for any `Debug` or `Display` to be captured as a `Value`. |
5 | |
6 | use crate::{ |
7 | fill::Slot, |
8 | std::{any::Any, fmt}, |
9 | Error, ValueBag, |
10 | }; |
11 | |
12 | use super::{Internal, InternalVisitor}; |
13 | |
14 | impl<'v> ValueBag<'v> { |
15 | /// Get a value from a debuggable type. |
16 | /// |
17 | /// This method will attempt to capture the given value as a well-known primitive |
18 | /// before resorting to using its `Debug` implementation. |
19 | pub fn capture_debug<T>(value: &'v T) -> Self |
20 | where |
21 | T: Debug + 'static, |
22 | { |
23 | Self::try_capture(value).unwrap_or(ValueBag { |
24 | inner: Internal::Debug(value), |
25 | }) |
26 | } |
27 | |
28 | /// Get a value from a displayable type. |
29 | /// |
30 | /// This method will attempt to capture the given value as a well-known primitive |
31 | /// before resorting to using its `Display` implementation. |
32 | pub fn capture_display<T>(value: &'v T) -> Self |
33 | where |
34 | T: Display + 'static, |
35 | { |
36 | Self::try_capture(value).unwrap_or(ValueBag { |
37 | inner: Internal::Display(value), |
38 | }) |
39 | } |
40 | |
41 | /// Get a value from a debuggable type without capturing support. |
42 | pub const fn from_debug<T>(value: &'v T) -> Self |
43 | where |
44 | T: Debug, |
45 | { |
46 | ValueBag { |
47 | inner: Internal::AnonDebug(value), |
48 | } |
49 | } |
50 | |
51 | /// Get a value from a displayable type without capturing support. |
52 | pub const fn from_display<T>(value: &'v T) -> Self |
53 | where |
54 | T: Display, |
55 | { |
56 | ValueBag { |
57 | inner: Internal::AnonDisplay(value), |
58 | } |
59 | } |
60 | |
61 | /// Get a value from a debuggable type without capturing support. |
62 | #[inline ] |
63 | pub const fn from_dyn_debug(value: &'v dyn Debug) -> Self { |
64 | ValueBag { |
65 | inner: Internal::AnonDebug(value), |
66 | } |
67 | } |
68 | |
69 | /// Get a value from a displayable type without capturing support. |
70 | #[inline ] |
71 | pub const fn from_dyn_display(value: &'v dyn Display) -> Self { |
72 | ValueBag { |
73 | inner: Internal::AnonDisplay(value), |
74 | } |
75 | } |
76 | } |
77 | |
78 | pub(crate) trait DowncastDisplay { |
79 | fn as_any(&self) -> &dyn Any; |
80 | fn as_super(&self) -> &dyn fmt::Display; |
81 | } |
82 | |
83 | impl<T: fmt::Display + 'static> DowncastDisplay for T { |
84 | fn as_any(&self) -> &dyn Any { |
85 | self |
86 | } |
87 | |
88 | fn as_super(&self) -> &dyn fmt::Display { |
89 | self |
90 | } |
91 | } |
92 | |
93 | impl<'a> fmt::Display for dyn DowncastDisplay + Send + Sync + 'a { |
94 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
95 | self.as_super().fmt(f) |
96 | } |
97 | } |
98 | |
99 | pub(crate) trait DowncastDebug { |
100 | fn as_any(&self) -> &dyn Any; |
101 | fn as_super(&self) -> &dyn fmt::Debug; |
102 | } |
103 | |
104 | impl<T: fmt::Debug + 'static> DowncastDebug for T { |
105 | fn as_any(&self) -> &dyn Any { |
106 | self |
107 | } |
108 | |
109 | fn as_super(&self) -> &dyn fmt::Debug { |
110 | self |
111 | } |
112 | } |
113 | |
114 | impl<'a> fmt::Debug for dyn DowncastDebug + Send + Sync + 'a { |
115 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
116 | self.as_super().fmt(f) |
117 | } |
118 | } |
119 | |
120 | impl<'s, 'f> Slot<'s, 'f> { |
121 | /// Fill the slot with a debuggable value. |
122 | /// |
123 | /// The given value doesn't need to satisfy any particular lifetime constraints. |
124 | pub fn fill_debug<T>(self, value: T) -> Result<(), Error> |
125 | where |
126 | T: Debug, |
127 | { |
128 | self.fill(|visitor: &mut (dyn InternalVisitor<'f> + 'static)| visitor.debug(&value)) |
129 | } |
130 | |
131 | /// Fill the slot with a displayable value. |
132 | /// |
133 | /// The given value doesn't need to satisfy any particular lifetime constraints. |
134 | pub fn fill_display<T>(self, value: T) -> Result<(), Error> |
135 | where |
136 | T: Display, |
137 | { |
138 | self.fill(|visitor: &mut (dyn InternalVisitor<'f> + 'static)| visitor.display(&value)) |
139 | } |
140 | } |
141 | |
142 | pub use self::fmt::{Debug, Display}; |
143 | |
144 | impl<'v> Debug for ValueBag<'v> { |
145 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
146 | struct DebugVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>); |
147 | |
148 | impl<'a, 'b: 'a, 'v> InternalVisitor<'v> for DebugVisitor<'a, 'b> { |
149 | fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { |
150 | v.fill(crate::fill::Slot::new(self)) |
151 | } |
152 | |
153 | fn debug(&mut self, v: &dyn Debug) -> Result<(), Error> { |
154 | Debug::fmt(v, self.0)?; |
155 | |
156 | Ok(()) |
157 | } |
158 | |
159 | fn display(&mut self, v: &dyn Display) -> Result<(), Error> { |
160 | Display::fmt(v, self.0)?; |
161 | |
162 | Ok(()) |
163 | } |
164 | |
165 | fn u64(&mut self, v: u64) -> Result<(), Error> { |
166 | Debug::fmt(&v, self.0)?; |
167 | |
168 | Ok(()) |
169 | } |
170 | |
171 | fn i64(&mut self, v: i64) -> Result<(), Error> { |
172 | Debug::fmt(&v, self.0)?; |
173 | |
174 | Ok(()) |
175 | } |
176 | |
177 | fn u128(&mut self, v: &u128) -> Result<(), Error> { |
178 | Debug::fmt(&v, self.0)?; |
179 | |
180 | Ok(()) |
181 | } |
182 | |
183 | fn i128(&mut self, v: &i128) -> Result<(), Error> { |
184 | Debug::fmt(&v, self.0)?; |
185 | |
186 | Ok(()) |
187 | } |
188 | |
189 | fn f64(&mut self, v: f64) -> Result<(), Error> { |
190 | Debug::fmt(&v, self.0)?; |
191 | |
192 | Ok(()) |
193 | } |
194 | |
195 | fn bool(&mut self, v: bool) -> Result<(), Error> { |
196 | Debug::fmt(&v, self.0)?; |
197 | |
198 | Ok(()) |
199 | } |
200 | |
201 | fn char(&mut self, v: char) -> Result<(), Error> { |
202 | Debug::fmt(&v, self.0)?; |
203 | |
204 | Ok(()) |
205 | } |
206 | |
207 | fn str(&mut self, v: &str) -> Result<(), Error> { |
208 | Debug::fmt(&v, self.0)?; |
209 | |
210 | Ok(()) |
211 | } |
212 | |
213 | fn none(&mut self) -> Result<(), Error> { |
214 | self.debug(&format_args!("None" )) |
215 | } |
216 | |
217 | #[cfg (feature = "error" )] |
218 | fn error(&mut self, v: &(dyn std::error::Error + 'static)) -> Result<(), Error> { |
219 | Debug::fmt(v, self.0)?; |
220 | |
221 | Ok(()) |
222 | } |
223 | |
224 | #[cfg (feature = "sval2" )] |
225 | fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> { |
226 | crate::internal::sval::v2::fmt(self.0, v) |
227 | } |
228 | |
229 | #[cfg (feature = "serde1" )] |
230 | fn serde1( |
231 | &mut self, |
232 | v: &dyn crate::internal::serde::v1::Serialize, |
233 | ) -> Result<(), Error> { |
234 | crate::internal::serde::v1::fmt(self.0, v) |
235 | } |
236 | |
237 | #[cfg (feature = "seq" )] |
238 | fn seq(&mut self, seq: &dyn crate::internal::seq::Seq) -> Result<(), Error> { |
239 | let mut visitor = seq::FmtSeq(self.0.debug_list()); |
240 | seq.visit(&mut visitor); |
241 | visitor.0.finish()?; |
242 | |
243 | Ok(()) |
244 | } |
245 | |
246 | fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { |
247 | write!(self.0, "< {msg}>" )?; |
248 | |
249 | Ok(()) |
250 | } |
251 | } |
252 | |
253 | self.internal_visit(&mut DebugVisitor(f)) |
254 | .map_err(|_| fmt::Error)?; |
255 | |
256 | Ok(()) |
257 | } |
258 | } |
259 | |
260 | impl<'v> Display for ValueBag<'v> { |
261 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
262 | struct DisplayVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>); |
263 | |
264 | impl<'a, 'b: 'a, 'v> InternalVisitor<'v> for DisplayVisitor<'a, 'b> { |
265 | fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> { |
266 | v.fill(crate::fill::Slot::new(self)) |
267 | } |
268 | |
269 | fn debug(&mut self, v: &dyn Debug) -> Result<(), Error> { |
270 | Debug::fmt(v, self.0)?; |
271 | |
272 | Ok(()) |
273 | } |
274 | |
275 | fn display(&mut self, v: &dyn Display) -> Result<(), Error> { |
276 | Display::fmt(v, self.0)?; |
277 | |
278 | Ok(()) |
279 | } |
280 | |
281 | fn u64(&mut self, v: u64) -> Result<(), Error> { |
282 | Display::fmt(&v, self.0)?; |
283 | |
284 | Ok(()) |
285 | } |
286 | |
287 | fn i64(&mut self, v: i64) -> Result<(), Error> { |
288 | Display::fmt(&v, self.0)?; |
289 | |
290 | Ok(()) |
291 | } |
292 | |
293 | fn u128(&mut self, v: &u128) -> Result<(), Error> { |
294 | Display::fmt(&v, self.0)?; |
295 | |
296 | Ok(()) |
297 | } |
298 | |
299 | fn i128(&mut self, v: &i128) -> Result<(), Error> { |
300 | Display::fmt(&v, self.0)?; |
301 | |
302 | Ok(()) |
303 | } |
304 | |
305 | fn f64(&mut self, v: f64) -> Result<(), Error> { |
306 | Display::fmt(&v, self.0)?; |
307 | |
308 | Ok(()) |
309 | } |
310 | |
311 | fn bool(&mut self, v: bool) -> Result<(), Error> { |
312 | Display::fmt(&v, self.0)?; |
313 | |
314 | Ok(()) |
315 | } |
316 | |
317 | fn char(&mut self, v: char) -> Result<(), Error> { |
318 | Display::fmt(&v, self.0)?; |
319 | |
320 | Ok(()) |
321 | } |
322 | |
323 | fn str(&mut self, v: &str) -> Result<(), Error> { |
324 | Display::fmt(&v, self.0)?; |
325 | |
326 | Ok(()) |
327 | } |
328 | |
329 | fn none(&mut self) -> Result<(), Error> { |
330 | self.debug(&format_args!("None" )) |
331 | } |
332 | |
333 | #[cfg (feature = "error" )] |
334 | fn error(&mut self, v: &(dyn std::error::Error + 'static)) -> Result<(), Error> { |
335 | Display::fmt(v, self.0)?; |
336 | |
337 | Ok(()) |
338 | } |
339 | |
340 | #[cfg (feature = "sval2" )] |
341 | fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> { |
342 | crate::internal::sval::v2::fmt(self.0, v) |
343 | } |
344 | |
345 | #[cfg (feature = "serde1" )] |
346 | fn serde1( |
347 | &mut self, |
348 | v: &dyn crate::internal::serde::v1::Serialize, |
349 | ) -> Result<(), Error> { |
350 | crate::internal::serde::v1::fmt(self.0, v) |
351 | } |
352 | |
353 | #[cfg (feature = "seq" )] |
354 | fn seq(&mut self, seq: &dyn crate::internal::seq::Seq) -> Result<(), Error> { |
355 | let mut visitor = seq::FmtSeq(self.0.debug_list()); |
356 | seq.visit(&mut visitor); |
357 | visitor.0.finish()?; |
358 | |
359 | Ok(()) |
360 | } |
361 | |
362 | fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> { |
363 | write!(self.0, "< {msg}>" )?; |
364 | |
365 | Ok(()) |
366 | } |
367 | } |
368 | |
369 | self.internal_visit(&mut DisplayVisitor(f)) |
370 | .map_err(|_| fmt::Error)?; |
371 | |
372 | Ok(()) |
373 | } |
374 | } |
375 | |
376 | #[cfg (feature = "seq" )] |
377 | mod seq { |
378 | use super::*; |
379 | use core::ops::ControlFlow; |
380 | |
381 | pub(super) struct FmtSeq<'a, 'b>(pub(super) fmt::DebugList<'b, 'a>); |
382 | |
383 | impl<'a, 'b, 'c> crate::internal::seq::Visitor<'c> for FmtSeq<'a, 'b> { |
384 | fn element(&mut self, inner: ValueBag) -> ControlFlow<()> { |
385 | self.0.entry(&inner); |
386 | ControlFlow::Continue(()) |
387 | } |
388 | } |
389 | } |
390 | |
391 | #[cfg (feature = "owned" )] |
392 | pub(crate) mod owned { |
393 | use crate::std::{boxed::Box, fmt, string::ToString}; |
394 | |
395 | impl fmt::Debug for crate::OwnedValueBag { |
396 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
397 | fmt::Debug::fmt(&self.by_ref(), f) |
398 | } |
399 | } |
400 | |
401 | impl fmt::Display for crate::OwnedValueBag { |
402 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
403 | fmt::Display::fmt(&self.by_ref(), f) |
404 | } |
405 | } |
406 | |
407 | #[derive (Clone)] |
408 | pub(crate) struct OwnedFmt(Box<str>); |
409 | |
410 | pub(crate) fn buffer_debug(v: impl fmt::Debug) -> OwnedFmt { |
411 | OwnedFmt(format!("{:?}" , v).into()) |
412 | } |
413 | |
414 | pub(crate) fn buffer_display(v: impl fmt::Display) -> OwnedFmt { |
415 | OwnedFmt(v.to_string().into()) |
416 | } |
417 | |
418 | impl fmt::Debug for OwnedFmt { |
419 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
420 | fmt::Display::fmt(self, f) |
421 | } |
422 | } |
423 | |
424 | impl fmt::Display for OwnedFmt { |
425 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
426 | fmt::Display::fmt(&self.0, f) |
427 | } |
428 | } |
429 | } |
430 | |
431 | impl<'v> From<&'v dyn Debug> for ValueBag<'v> { |
432 | #[inline ] |
433 | fn from(v: &'v dyn Debug) -> Self { |
434 | ValueBag::from_dyn_debug(v) |
435 | } |
436 | } |
437 | |
438 | impl<'v> From<Option<&'v dyn Debug>> for ValueBag<'v> { |
439 | #[inline ] |
440 | fn from(v: Option<&'v dyn Debug>) -> Self { |
441 | ValueBag::from_option(v) |
442 | } |
443 | } |
444 | |
445 | impl<'v, 'u> From<&'v &'u dyn Debug> for ValueBag<'v> |
446 | where |
447 | 'u: 'v, |
448 | { |
449 | #[inline ] |
450 | fn from(v: &'v &'u dyn Debug) -> Self { |
451 | ValueBag::from_dyn_debug(*v) |
452 | } |
453 | } |
454 | |
455 | impl<'v> From<&'v dyn Display> for ValueBag<'v> { |
456 | #[inline ] |
457 | fn from(v: &'v dyn Display) -> Self { |
458 | ValueBag::from_dyn_display(v) |
459 | } |
460 | } |
461 | |
462 | impl<'v> From<Option<&'v dyn Display>> for ValueBag<'v> { |
463 | #[inline ] |
464 | fn from(v: Option<&'v dyn Display>) -> Self { |
465 | ValueBag::from_option(v) |
466 | } |
467 | } |
468 | |
469 | impl<'v, 'u> From<&'v &'u dyn Display> for ValueBag<'v> |
470 | where |
471 | 'u: 'v, |
472 | { |
473 | #[inline ] |
474 | fn from(v: &'v &'u dyn Display) -> Self { |
475 | ValueBag::from_dyn_display(*v) |
476 | } |
477 | } |
478 | |
479 | #[cfg (test)] |
480 | mod tests { |
481 | #[cfg (target_arch = "wasm32" )] |
482 | use wasm_bindgen_test::*; |
483 | |
484 | use super::*; |
485 | use crate::{ |
486 | std::string::ToString, |
487 | test::{IntoValueBag, TestToken}, |
488 | }; |
489 | |
490 | #[test ] |
491 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
492 | fn fmt_capture() { |
493 | assert_eq!( |
494 | ValueBag::capture_debug(&1u16).to_test_token(), |
495 | TestToken::U64(1) |
496 | ); |
497 | assert_eq!( |
498 | ValueBag::capture_display(&1u16).to_test_token(), |
499 | TestToken::U64(1) |
500 | ); |
501 | |
502 | assert_eq!( |
503 | ValueBag::capture_debug(&Some(1u16)).to_test_token(), |
504 | TestToken::U64(1) |
505 | ); |
506 | } |
507 | |
508 | #[test ] |
509 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
510 | fn fmt_fill() { |
511 | assert_eq!( |
512 | ValueBag::from_fill(&|slot: Slot| slot.fill_debug(1u16)).to_test_token(), |
513 | TestToken::Str("1" .into()) |
514 | ); |
515 | assert_eq!( |
516 | ValueBag::from_fill(&|slot: Slot| slot.fill_display(1u16)).to_test_token(), |
517 | TestToken::Str("1" .into()) |
518 | ); |
519 | } |
520 | |
521 | #[test ] |
522 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
523 | fn fmt_capture_args() { |
524 | assert_eq!( |
525 | ValueBag::from_debug(&format_args!("a {}" , "value" )).to_string(), |
526 | "a value" |
527 | ); |
528 | } |
529 | |
530 | #[test ] |
531 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
532 | fn fmt_cast() { |
533 | assert_eq!( |
534 | 42u64, |
535 | ValueBag::capture_debug(&42u64) |
536 | .to_u64() |
537 | .expect("invalid value" ) |
538 | ); |
539 | |
540 | assert_eq!( |
541 | "a string" , |
542 | ValueBag::capture_display(&"a string" ) |
543 | .to_borrowed_str() |
544 | .expect("invalid value" ) |
545 | ); |
546 | } |
547 | |
548 | #[test ] |
549 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
550 | fn fmt_downcast() { |
551 | #[derive (Debug, PartialEq, Eq)] |
552 | struct Timestamp(usize); |
553 | |
554 | impl Display for Timestamp { |
555 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
556 | write!(f, "time is {}" , self.0) |
557 | } |
558 | } |
559 | |
560 | let ts = Timestamp(42); |
561 | |
562 | assert_eq!( |
563 | &ts, |
564 | ValueBag::capture_debug(&ts) |
565 | .downcast_ref::<Timestamp>() |
566 | .expect("invalid value" ) |
567 | ); |
568 | |
569 | assert_eq!( |
570 | &ts, |
571 | ValueBag::capture_display(&ts) |
572 | .downcast_ref::<Timestamp>() |
573 | .expect("invalid value" ) |
574 | ); |
575 | } |
576 | |
577 | #[test ] |
578 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
579 | fn fmt_debug() { |
580 | assert_eq!( |
581 | format!("{:?}" , "a string" ), |
582 | format!("{:?}" , "a string" .into_value_bag().by_ref()), |
583 | ); |
584 | |
585 | assert_eq!( |
586 | format!("{:04?}" , 42u64), |
587 | format!("{:04?}" , 42u64.into_value_bag().by_ref()), |
588 | ); |
589 | } |
590 | |
591 | #[test ] |
592 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
593 | fn fmt_display() { |
594 | assert_eq!( |
595 | format!("{}" , "a string" ), |
596 | format!("{}" , "a string" .into_value_bag().by_ref()), |
597 | ); |
598 | |
599 | assert_eq!( |
600 | format!("{:04}" , 42u64), |
601 | format!("{:04}" , 42u64.into_value_bag().by_ref()), |
602 | ); |
603 | } |
604 | |
605 | #[cfg (feature = "seq" )] |
606 | mod seq_support { |
607 | use super::*; |
608 | |
609 | #[test ] |
610 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
611 | fn fmt_debug_seq() { |
612 | assert_eq!( |
613 | "[01, 02, 03]" , |
614 | format!("{:>02?}" , ValueBag::from_seq_slice(&[1, 2, 3])) |
615 | ); |
616 | } |
617 | |
618 | #[test ] |
619 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen_test)] |
620 | fn fmt_display_seq() { |
621 | assert_eq!( |
622 | "[1, 2, 3]" , |
623 | format!("{}" , ValueBag::from_seq_slice(&[1, 2, 3])) |
624 | ); |
625 | } |
626 | } |
627 | } |
628 | |