Skip to main content

value_bag/internal/
fmt.rs

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
6use crate::{
7    fill::Slot,
8    std::{any::Any, fmt},
9    Error, ValueBag,
10};
11
12use super::{Internal, InternalVisitor};
13
14impl<'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
78pub(crate) trait DowncastDisplay {
79    fn as_any(&self) -> &dyn Any;
80    fn as_super(&self) -> &dyn fmt::Display;
81}
82
83impl<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
93impl<'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
99pub(crate) trait DowncastDebug {
100    fn as_any(&self) -> &dyn Any;
101    fn as_super(&self) -> &dyn fmt::Debug;
102}
103
104impl<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
114impl<'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
120impl<'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| 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| visitor.display(&value))
139    }
140}
141
142pub use self::fmt::{Debug, Display};
143
144impl<'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(
219                &mut self,
220                v: &(dyn crate::internal::error::Error + 'static),
221            ) -> Result<(), Error> {
222                Debug::fmt(v, self.0)?;
223
224                Ok(())
225            }
226
227            #[cfg(feature = "sval2")]
228            fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> {
229                crate::internal::sval::v2::fmt(self.0, v)
230            }
231
232            #[cfg(feature = "serde1")]
233            fn serde1(
234                &mut self,
235                v: &dyn crate::internal::serde::v1::Serialize,
236            ) -> Result<(), Error> {
237                crate::internal::serde::v1::fmt(self.0, v)
238            }
239
240            #[cfg(feature = "seq")]
241            fn seq(&mut self, seq: &dyn crate::internal::seq::Seq) -> Result<(), Error> {
242                let mut visitor = seq::FmtSeq(self.0.debug_list());
243                seq.visit(&mut visitor);
244                visitor.0.finish()?;
245
246                Ok(())
247            }
248
249            fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> {
250                write!(self.0, "<{msg}>")?;
251
252                Ok(())
253            }
254        }
255
256        self.internal_visit(&mut DebugVisitor(f))
257            .map_err(|_| fmt::Error)?;
258
259        Ok(())
260    }
261}
262
263impl<'v> Display for ValueBag<'v> {
264    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
265        struct DisplayVisitor<'a, 'b: 'a>(&'a mut fmt::Formatter<'b>);
266
267        impl<'a, 'b: 'a, 'v> InternalVisitor<'v> for DisplayVisitor<'a, 'b> {
268            fn fill(&mut self, v: &dyn crate::fill::Fill) -> Result<(), Error> {
269                v.fill(crate::fill::Slot::new(self))
270            }
271
272            fn debug(&mut self, v: &dyn Debug) -> Result<(), Error> {
273                Debug::fmt(v, self.0)?;
274
275                Ok(())
276            }
277
278            fn display(&mut self, v: &dyn Display) -> Result<(), Error> {
279                Display::fmt(v, self.0)?;
280
281                Ok(())
282            }
283
284            fn u64(&mut self, v: u64) -> Result<(), Error> {
285                Display::fmt(&v, self.0)?;
286
287                Ok(())
288            }
289
290            fn i64(&mut self, v: i64) -> Result<(), Error> {
291                Display::fmt(&v, self.0)?;
292
293                Ok(())
294            }
295
296            fn u128(&mut self, v: &u128) -> Result<(), Error> {
297                Display::fmt(&v, self.0)?;
298
299                Ok(())
300            }
301
302            fn i128(&mut self, v: &i128) -> Result<(), Error> {
303                Display::fmt(&v, self.0)?;
304
305                Ok(())
306            }
307
308            fn f64(&mut self, v: f64) -> Result<(), Error> {
309                Display::fmt(&v, self.0)?;
310
311                Ok(())
312            }
313
314            fn bool(&mut self, v: bool) -> Result<(), Error> {
315                Display::fmt(&v, self.0)?;
316
317                Ok(())
318            }
319
320            fn char(&mut self, v: char) -> Result<(), Error> {
321                Display::fmt(&v, self.0)?;
322
323                Ok(())
324            }
325
326            fn str(&mut self, v: &str) -> Result<(), Error> {
327                Display::fmt(&v, self.0)?;
328
329                Ok(())
330            }
331
332            fn none(&mut self) -> Result<(), Error> {
333                self.debug(&format_args!("None"))
334            }
335
336            #[cfg(feature = "error")]
337            fn error(
338                &mut self,
339                v: &(dyn crate::internal::error::Error + 'static),
340            ) -> Result<(), Error> {
341                Display::fmt(v, self.0)?;
342
343                Ok(())
344            }
345
346            #[cfg(feature = "sval2")]
347            fn sval2(&mut self, v: &dyn crate::internal::sval::v2::Value) -> Result<(), Error> {
348                crate::internal::sval::v2::fmt(self.0, v)
349            }
350
351            #[cfg(feature = "serde1")]
352            fn serde1(
353                &mut self,
354                v: &dyn crate::internal::serde::v1::Serialize,
355            ) -> Result<(), Error> {
356                crate::internal::serde::v1::fmt(self.0, v)
357            }
358
359            #[cfg(feature = "seq")]
360            fn seq(&mut self, seq: &dyn crate::internal::seq::Seq) -> Result<(), Error> {
361                let mut visitor = seq::FmtSeq(self.0.debug_list());
362                seq.visit(&mut visitor);
363                visitor.0.finish()?;
364
365                Ok(())
366            }
367
368            fn poisoned(&mut self, msg: &'static str) -> Result<(), Error> {
369                write!(self.0, "<{msg}>")?;
370
371                Ok(())
372            }
373        }
374
375        self.internal_visit(&mut DisplayVisitor(f))
376            .map_err(|_| fmt::Error)?;
377
378        Ok(())
379    }
380}
381
382#[cfg(feature = "seq")]
383mod seq {
384    use super::*;
385    use core::ops::ControlFlow;
386
387    pub(super) struct FmtSeq<'a, 'b>(pub(super) fmt::DebugList<'b, 'a>);
388
389    impl<'a, 'b, 'c> crate::internal::seq::Visitor<'c> for FmtSeq<'a, 'b> {
390        fn element(&mut self, inner: ValueBag) -> ControlFlow<()> {
391            self.0.entry(&inner);
392            ControlFlow::Continue(())
393        }
394    }
395}
396
397#[cfg(feature = "owned")]
398pub(crate) mod owned {
399    use crate::std::{boxed::Box, fmt};
400
401    #[cfg(feature = "inline-str")]
402    use crate::internal::owned::inline_str::{self, InlineStr};
403
404    impl fmt::Debug for crate::OwnedValueBag {
405        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
406            fmt::Debug::fmt(&self.by_ref(), f)
407        }
408    }
409
410    impl fmt::Display for crate::OwnedValueBag {
411        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
412            fmt::Display::fmt(&self.by_ref(), f)
413        }
414    }
415
416    #[cfg(not(feature = "inline-str"))]
417    pub(crate) enum InlineFmt {}
418
419    #[derive(Clone)]
420    pub(crate) struct OwnedFmt(Box<str>);
421
422    pub(crate) fn buffer_debug(v: impl fmt::Debug) -> Result<InlineFmt, OwnedFmt> {
423        #[cfg(feature = "inline-str")]
424        {
425            buffer_inline(format_args!("{v:?}"))
426        }
427        #[cfg(not(feature = "inline-str"))]
428        {
429            Err(OwnedFmt(format!("{v:?}").into()))
430        }
431    }
432
433    pub(crate) fn buffer_display(v: impl fmt::Display) -> Result<InlineFmt, OwnedFmt> {
434        #[cfg(feature = "inline-str")]
435        {
436            buffer_inline(v)
437        }
438        #[cfg(not(feature = "inline-str"))]
439        {
440            use crate::std::string::ToString as _;
441
442            Err(OwnedFmt(v.to_string().into()))
443        }
444    }
445
446    impl fmt::Debug for OwnedFmt {
447        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
448            fmt::Display::fmt(self, f)
449        }
450    }
451
452    impl fmt::Display for OwnedFmt {
453        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
454            fmt::Display::fmt(&self.0, f)
455        }
456    }
457
458    #[cfg(feature = "inline-str")]
459    #[inline]
460    fn buffer_inline(v: impl fmt::Display) -> Result<InlineFmt, OwnedFmt> {
461        // Use a slightly larger buffer in case we can compress the resulting buffer down to 22 bytes
462        // This can also save a few extra bounds checks and re-allocations
463        match InlineStr::<64>::buffer(v) {
464            Ok(inline) => {
465                if inline.len() <= inline_str::MAX_INLINE_LEN {
466                    // SAFETY: The condition above guarantees `inline` will fit in `MAX_INLINE_LEN` bytes
467                    let inline = unsafe {
468                        InlineStr::<{ inline_str::MAX_INLINE_LEN }>::copy_from_unchecked(
469                            inline.get(),
470                        )
471                    };
472
473                    Ok(InlineFmt(inline))
474                } else {
475                    Err(OwnedFmt(Box::from(inline.get())))
476                }
477            }
478            Err(spilled) => Err(OwnedFmt(spilled)),
479        }
480    }
481
482    #[cfg(feature = "inline-str")]
483    #[derive(Clone, Copy)]
484    pub(crate) struct InlineFmt(InlineStr<{ inline_str::MAX_INLINE_LEN }>);
485
486    #[cfg(feature = "inline-str")]
487    impl fmt::Debug for InlineFmt {
488        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
489            fmt::Display::fmt(self, f)
490        }
491    }
492
493    #[cfg(feature = "inline-str")]
494    impl fmt::Display for InlineFmt {
495        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
496            fmt::Display::fmt(&self.0, f)
497        }
498    }
499}
500
501impl<'v> From<&'v dyn Debug> for ValueBag<'v> {
502    #[inline]
503    fn from(v: &'v dyn Debug) -> Self {
504        ValueBag::from_dyn_debug(v)
505    }
506}
507
508impl<'v> From<Option<&'v dyn Debug>> for ValueBag<'v> {
509    #[inline]
510    fn from(v: Option<&'v dyn Debug>) -> Self {
511        ValueBag::from_option(v)
512    }
513}
514
515impl<'v, 'u> From<&'v &'u dyn Debug> for ValueBag<'v>
516where
517    'u: 'v,
518{
519    #[inline]
520    fn from(v: &'v &'u dyn Debug) -> Self {
521        ValueBag::from_dyn_debug(*v)
522    }
523}
524
525impl<'v> From<&'v dyn Display> for ValueBag<'v> {
526    #[inline]
527    fn from(v: &'v dyn Display) -> Self {
528        ValueBag::from_dyn_display(v)
529    }
530}
531
532impl<'v> From<Option<&'v dyn Display>> for ValueBag<'v> {
533    #[inline]
534    fn from(v: Option<&'v dyn Display>) -> Self {
535        ValueBag::from_option(v)
536    }
537}
538
539impl<'v, 'u> From<&'v &'u dyn Display> for ValueBag<'v>
540where
541    'u: 'v,
542{
543    #[inline]
544    fn from(v: &'v &'u dyn Display) -> Self {
545        ValueBag::from_dyn_display(*v)
546    }
547}
548
549#[cfg(test)]
550mod tests {
551    #[cfg(target_arch = "wasm32")]
552    use wasm_bindgen_test::*;
553
554    use super::*;
555    use crate::{
556        std::string::ToString,
557        test::{IntoValueBag, TestToken},
558    };
559
560    #[test]
561    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
562    fn fmt_capture() {
563        assert_eq!(
564            ValueBag::capture_debug(&1u16).to_test_token(),
565            TestToken::U64(1)
566        );
567        assert_eq!(
568            ValueBag::capture_display(&1u16).to_test_token(),
569            TestToken::U64(1)
570        );
571
572        assert_eq!(
573            ValueBag::capture_debug(&Some(1u16)).to_test_token(),
574            TestToken::U64(1)
575        );
576    }
577
578    #[test]
579    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
580    fn fmt_fill() {
581        assert_eq!(
582            ValueBag::from_fill(&|slot: Slot| slot.fill_debug(1u16)).to_test_token(),
583            TestToken::Str("1".into())
584        );
585        assert_eq!(
586            ValueBag::from_fill(&|slot: Slot| slot.fill_display(1u16)).to_test_token(),
587            TestToken::Str("1".into())
588        );
589    }
590
591    #[test]
592    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
593    fn fmt_capture_args() {
594        assert_eq!(
595            ValueBag::from_debug(&format_args!("a {}", "value")).to_string(),
596            "a value"
597        );
598    }
599
600    #[test]
601    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
602    fn fmt_cast() {
603        assert_eq!(
604            42u64,
605            ValueBag::capture_debug(&42u64)
606                .to_u64()
607                .expect("invalid value")
608        );
609
610        assert_eq!(
611            "a string",
612            ValueBag::capture_display(&"a string")
613                .to_borrowed_str()
614                .expect("invalid value")
615        );
616    }
617
618    #[test]
619    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
620    fn fmt_downcast() {
621        #[derive(Debug, PartialEq, Eq)]
622        struct Timestamp(usize);
623
624        impl Display for Timestamp {
625            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
626                write!(f, "time is {}", self.0)
627            }
628        }
629
630        let ts = Timestamp(42);
631
632        assert_eq!(
633            &ts,
634            ValueBag::capture_debug(&ts)
635                .downcast_ref::<Timestamp>()
636                .expect("invalid value")
637        );
638
639        assert_eq!(
640            &ts,
641            ValueBag::capture_display(&ts)
642                .downcast_ref::<Timestamp>()
643                .expect("invalid value")
644        );
645    }
646
647    #[test]
648    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
649    fn fmt_debug() {
650        assert_eq!(
651            format!("{:?}", "a string"),
652            format!("{:?}", "a string".into_value_bag().by_ref()),
653        );
654
655        assert_eq!(
656            format!("{:04?}", 42u64),
657            format!("{:04?}", 42u64.into_value_bag().by_ref()),
658        );
659    }
660
661    #[test]
662    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
663    fn fmt_display() {
664        assert_eq!(
665            format!("{}", "a string"),
666            format!("{}", "a string".into_value_bag().by_ref()),
667        );
668
669        assert_eq!(
670            format!("{:04}", 42u64),
671            format!("{:04}", 42u64.into_value_bag().by_ref()),
672        );
673    }
674
675    #[cfg(feature = "seq")]
676    mod seq_support {
677        use super::*;
678
679        #[test]
680        #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
681        fn fmt_debug_seq() {
682            assert_eq!(
683                "[01, 02, 03]",
684                format!("{:>02?}", ValueBag::from_seq_slice(&[1, 2, 3]))
685            );
686        }
687
688        #[test]
689        #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
690        fn fmt_display_seq() {
691            assert_eq!(
692                "[1, 2, 3]",
693                format!("{}", ValueBag::from_seq_slice(&[1, 2, 3]))
694            );
695        }
696    }
697}