powerfmt/smart_display.rs
1//! Definition of [`SmartDisplay`] and its related items.
2//!
3//! [`SmartDisplay`] is a trait that allows authors to provide additional information to both the
4//! formatter and other users. This information is provided in the form of a metadata type. The only
5//! required piece of metadata is the width of the value. This is _before_ it is passed to the
6//! formatter (i.e. it does not include any padding added by the formatter). Other information
7//! can be stored in a custom metadata type as needed. This information may be made available to
8//! downstream users, but it is not required.
9//!
10//! This module contains the [`SmartDisplay`] and associated items.
11//!
12//! # Example
13//!
14//! ```rust
15//! use std::fmt;
16//!
17//! use powerfmt::ext::FormatterExt as _;
18//! use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
19//!
20//! #[derive(Debug)]
21//! struct User {
22//! id: usize,
23//! }
24//!
25//! // If you try to use `UserMetadata` in the `SmartDisplay` implementation, you will get a
26//! // compiler error about a private type being used publicly. To avoid this, use this attribute to
27//! // declare a private metadata type. You shouldn't need to worry about how this works, but be
28//! // aware that any public fields or methods remain usable by downstream users.
29//! #[smart_display::private_metadata]
30//! struct UserMetadata {
31//! username: String,
32//! legal_name: String,
33//! }
34//!
35//! // This attribute can be applied to `SmartDisplay` implementations. It will generate an
36//! // implementation of `Display` that delegates to `SmartDisplay`, avoiding the need to write
37//! // boilerplate.
38//! #[smart_display::delegate]
39//! impl SmartDisplay for User {
40//! type Metadata = UserMetadata;
41//!
42//! fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
43//! // This could be obtained from a database, for example.
44//! let legal_name = "John Doe".to_owned();
45//! let username = "jdoe".to_owned();
46//!
47//! // Note that this must be kept in sync with the implementation of `fmt_with_metadata`.
48//! let width = smart_display::padded_width_of!(username, " (", legal_name, ")",);
49//!
50//! Metadata::new(
51//! width,
52//! self,
53//! UserMetadata {
54//! username,
55//! legal_name,
56//! },
57//! )
58//! }
59//!
60//! // Use the now-generated metadata to format the value. Here we use the `pad_with_width`
61//! // method to use the alignment and desired width from the formatter.
62//! fn fmt_with_metadata(
63//! &self,
64//! f: &mut fmt::Formatter<'_>,
65//! metadata: Metadata<Self>,
66//! ) -> fmt::Result {
67//! f.pad_with_width(
68//! metadata.unpadded_width(),
69//! format_args!("{} ({})", metadata.username, metadata.legal_name),
70//! )
71//! }
72//! }
73//!
74//! let user = User { id: 42 };
75//! assert_eq!(user.to_string(), "jdoe (John Doe)");
76//! assert_eq!(format!("{user:>20}"), " jdoe (John Doe)");
77//! ```
78
79use core::cmp;
80use core::convert::Infallible;
81use core::fmt::{Alignment, Debug, Display, Formatter, Result};
82use core::marker::PhantomData;
83use core::mem::MaybeUninit;
84use core::ops::Deref;
85
86/// Compute the width of multiple items while optionally declaring the options for each item.
87///
88/// ```rust
89/// # use powerfmt::smart_display;
90/// let alpha = 0;
91/// let beta = 1;
92/// let gamma = 100;
93///
94/// let width = smart_display::padded_width_of!(
95/// alpha, // use the default options
96/// beta => width(2), // use the specified options
97/// gamma => width(2) sign_plus(true), // use multiple options
98/// );
99/// assert_eq!(width, 7);
100///
101/// let formatted = format!("{alpha}{beta:2}{gamma:+2}");
102/// assert_eq!(formatted.len(), width);
103/// ```
104///
105/// Supported options are:
106///
107/// Option | Method called
108/// --- | ---
109/// `fill(char)` | [`FormatterOptions::with_fill`]
110/// `sign_plus(bool)` | [`FormatterOptions::with_sign_plus`]
111/// `sign_minus(bool)` | [`FormatterOptions::with_sign_minus`]
112/// `align(Alignment)` | [`FormatterOptions::with_align`]
113/// `width(usize)` | [`FormatterOptions::with_width`]
114/// `precision(usize)` | [`FormatterOptions::with_precision`]
115/// `alternate(bool)` | [`FormatterOptions::with_alternate`]
116/// `sign_aware_zero_pad(bool)` | [`FormatterOptions::with_sign_aware_zero_pad`]
117///
118/// If there are future additions to [`FormatterOptions`], they will be added to this macro as well.
119///
120/// Options may be provided in any order and will be called in the order they are provided. The
121/// ordering matters if providing both `sign_plus` and `sign_minus`.
122#[cfg(doc)]
123#[doc(hidden)] // Don't show at crate root.
124#[macro_export]
125macro_rules! padded_width_of {
126 ($($t:tt)*) => {};
127}
128
129#[cfg(not(doc))]
130#[allow(missing_docs)] // This is done with `#[cfg(doc)]` to avoid showing the various rules.
131#[macro_export]
132macro_rules! __not_public_at_root__padded_width_of {
133 // Base case
134 (@inner [] [$($output:tt)+]) => { $($output)+ };
135 (@inner [$e:expr $(, $($remaining:tt)*)?] [$($expansion:tt)+]) => {
136 $crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [
137 $($expansion)+ + $crate::smart_display::Metadata::padded_width_of(
138 &$e,
139 $crate::smart_display::padded_width_of!(@options)
140 )
141 ])
142 };
143 (@inner
144 [$e:expr => $($call:ident($call_expr:expr))+ $(, $($remaining:tt)*)?]
145 [$($expansion:tt)+]
146 ) => {
147 $crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [
148 $($expansion)+ + $crate::smart_display::Metadata::padded_width_of(
149 &$e,
150 *$crate::smart_display::padded_width_of!(@options $($call($call_expr))+)
151 )
152 ])
153 };
154
155 // Options base case
156 (@options_inner [] [$($output:tt)+]) => { $($output)+ };
157 (@options_inner [fill($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
158 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
159 $($expansion)*.with_fill($e)
160 ])
161 };
162 (@options_inner [sign_plus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
163 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
164 $($expansion)*.with_sign_plus($e)
165 ])
166 };
167 (@options_inner [sign_minus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
168 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
169 $($expansion)*.with_sign_minus($e)
170 ])
171 };
172 (@options_inner [align($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
173 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
174 $($expansion)*.with_align(Some($e))
175 ])
176 };
177 (@options_inner [width($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
178 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
179 $($expansion)*.with_width(Some($e))
180 ])
181 };
182 (@options_inner [precision($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
183 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
184 $($expansion)*.with_precision(Some($e))
185 ])
186 };
187 (@options_inner [alternate($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
188 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
189 $($expansion)*.with_width($e)
190 ])
191 };
192 (@options_inner [sign_aware_zero_pad($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => {
193 $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [
194 $($expansion)*.with_sign_aware_zero_pad($e)
195 ])
196 };
197 // Options entry point
198 (@options $($e:tt)*) => {
199 $crate::smart_display::padded_width_of!(@options_inner [$($e)*] [
200 $crate::smart_display::FormatterOptions::default()
201 ])
202 };
203
204 // Entry point
205 ($($t:tt)*) => {
206 $crate::smart_display::padded_width_of!(
207 @inner [$($t)*] [0]
208 )
209 };
210}
211
212#[cfg(not(doc))]
213pub use __not_public_at_root__padded_width_of as padded_width_of;
214#[cfg(doc)]
215#[doc(inline)] // Show in this module.
216pub use padded_width_of;
217/// Implement [`Display`] for a type by using its implementation of [`SmartDisplay`].
218///
219/// This attribute is applied to the `SmartDisplay` implementation.
220///
221/// ```rust,no_run
222/// # use powerfmt::smart_display::{self, SmartDisplay, Metadata, FormatterOptions};
223/// # struct Foo;
224/// #[smart_display::delegate]
225/// impl SmartDisplay for Foo {
226/// # type Metadata = ();
227/// # fn metadata(&self, f: FormatterOptions) -> Metadata<Self> {
228/// # todo!()
229/// # }
230/// // ...
231/// }
232/// ```
233#[cfg(feature = "macros")]
234pub use powerfmt_macros::smart_display_delegate as delegate;
235/// Declare a private metadata type for `SmartDisplay`.
236///
237/// Use this attribute if you want to provide metadata for a type that is not public. Doing
238/// this will avoid a compiler error about a private type being used publicly. Keep in mind
239/// that any public fields, public methods, and trait implementations _will_ be able to be used
240/// by downstream users.
241///
242/// To avoid accidentally exposing details, such as when all fields are public or if the type
243/// is a unit struct, the type is annotated with `#[non_exhaustive]` automatically.
244///
245/// ```rust,no_run
246/// # use powerfmt::smart_display;
247/// /// Metadata for `Foo`
248/// #[smart_display::private_metadata]
249/// #[derive(Debug)]
250/// pub(crate) struct FooMetadata {
251/// pub(crate) expensive_to_calculate: usize,
252/// }
253/// ```
254#[cfg(feature = "macros")]
255pub use powerfmt_macros::smart_display_private_metadata as private_metadata;
256
257#[derive(Debug)]
258enum FlagBit {
259 SignPlus,
260 SignMinus,
261 Alternate,
262 SignAwareZeroPad,
263 WidthIsInitialized,
264 PrecisionIsInitialized,
265}
266
267/// Configuration for formatting.
268///
269/// This struct is obtained from a [`Formatter`]. It provides the same functionality as that of a
270/// reference to a `Formatter`. However, it is not possible to construct a `Formatter`, which is
271/// necessary for some use cases of [`SmartDisplay`]. `FormatterOptions` implements [`Default`] and
272/// has builder methods to alleviate this.
273#[derive(Clone, Copy)]
274pub struct FormatterOptions {
275 flags: u8,
276 fill: char,
277 align: Option<Alignment>,
278 width: MaybeUninit<usize>,
279 precision: MaybeUninit<usize>,
280}
281
282impl Debug for FormatterOptions {
283 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
284 f.debug_struct("FormatterOptions")
285 .field("fill", &self.fill)
286 .field("align", &self.align())
287 .field("width", &self.width())
288 .field("precision", &self.precision())
289 .field("sign_plus", &self.sign_plus())
290 .field("sign_minus", &self.sign_minus())
291 .field("alternate", &self.alternate())
292 .field("sign_aware_zero_pad", &self.sign_aware_zero_pad())
293 .finish()
294 }
295}
296
297impl Default for FormatterOptions {
298 #[inline]
299 fn default() -> Self {
300 Self {
301 flags: 0,
302 fill: ' ',
303 align: None,
304 width: MaybeUninit::uninit(),
305 precision: MaybeUninit::uninit(),
306 }
307 }
308}
309
310impl FormatterOptions {
311 /// Sets the fill character to use whenever there is alignment.
312 #[inline]
313 pub fn with_fill(&mut self, c: char) -> &mut Self {
314 self.fill = c;
315 self
316 }
317
318 /// Set whether the `+` flag is specified.
319 #[inline]
320 pub fn with_sign_plus(&mut self, b: bool) -> &mut Self {
321 if b {
322 self.flags |= 1 << FlagBit::SignPlus as u8;
323 self.flags &= !(1 << FlagBit::SignMinus as u8);
324 } else {
325 self.flags &= !(1 << FlagBit::SignPlus as u8);
326 }
327 self
328 }
329
330 /// Set whether the `-` flag is specified.
331 #[inline]
332 pub fn with_sign_minus(&mut self, b: bool) -> &mut Self {
333 if b {
334 self.flags |= 1 << FlagBit::SignMinus as u8;
335 self.flags &= !(1 << FlagBit::SignPlus as u8);
336 } else {
337 self.flags &= !(1 << FlagBit::SignMinus as u8);
338 }
339 self
340 }
341
342 /// Set the flag indicating what form of alignment is requested, if any.
343 #[inline]
344 pub fn with_align(&mut self, align: Option<Alignment>) -> &mut Self {
345 self.align = align;
346 self
347 }
348
349 /// Set the optional integer width that the output should be.
350 #[inline]
351 pub fn with_width(&mut self, width: Option<usize>) -> &mut Self {
352 if let Some(width) = width {
353 self.flags |= 1 << FlagBit::WidthIsInitialized as u8;
354 self.width = MaybeUninit::new(width);
355 } else {
356 self.flags &= !(1 << FlagBit::WidthIsInitialized as u8);
357 }
358 self
359 }
360
361 /// Set the optional precision for numeric types. Alternatively, the maximum width for string
362 /// types.
363 #[inline]
364 pub fn with_precision(&mut self, precision: Option<usize>) -> &mut Self {
365 if let Some(precision) = precision {
366 self.flags |= 1 << FlagBit::PrecisionIsInitialized as u8;
367 self.precision = MaybeUninit::new(precision);
368 } else {
369 self.flags &= !(1 << FlagBit::PrecisionIsInitialized as u8);
370 }
371 self
372 }
373
374 /// Set whether the `#` flag is specified.
375 #[inline]
376 pub fn with_alternate(&mut self, b: bool) -> &mut Self {
377 if b {
378 self.flags |= 1 << FlagBit::Alternate as u8;
379 } else {
380 self.flags &= !(1 << FlagBit::Alternate as u8);
381 }
382 self
383 }
384
385 /// Set whether the `0` flag is specified.
386 #[inline]
387 pub fn with_sign_aware_zero_pad(&mut self, b: bool) -> &mut Self {
388 if b {
389 self.flags |= 1 << FlagBit::SignAwareZeroPad as u8;
390 } else {
391 self.flags &= !(1 << FlagBit::SignAwareZeroPad as u8);
392 }
393 self
394 }
395}
396
397impl FormatterOptions {
398 /// Character used as 'fill' whenever there is alignment.
399 #[inline]
400 #[must_use]
401 pub const fn fill(&self) -> char {
402 self.fill
403 }
404
405 /// Flag indicating what form of alignment was requested.
406 #[inline]
407 #[must_use]
408 pub const fn align(&self) -> Option<Alignment> {
409 self.align
410 }
411
412 /// Optionally specified integer width that the output should be.
413 #[inline]
414 #[must_use]
415 pub const fn width(&self) -> Option<usize> {
416 if (self.flags >> FlagBit::WidthIsInitialized as u8) & 1 == 1 {
417 // Safety: `width` is initialized if the flag is set.
418 Some(unsafe { self.width.assume_init() })
419 } else {
420 None
421 }
422 }
423
424 /// Optionally specified precision for numeric types. Alternatively, the maximum width for
425 /// string types.
426 #[inline]
427 #[must_use]
428 pub const fn precision(&self) -> Option<usize> {
429 if (self.flags >> FlagBit::PrecisionIsInitialized as u8) & 1 == 1 {
430 // Safety: `precision` is initialized if the flag is set.
431 Some(unsafe { self.precision.assume_init() })
432 } else {
433 None
434 }
435 }
436
437 /// Determines if the `+` flag was specified.
438 #[inline]
439 #[must_use]
440 pub const fn sign_plus(&self) -> bool {
441 (self.flags >> FlagBit::SignPlus as u8) & 1 == 1
442 }
443
444 /// Determines if the `-` flag was specified.
445 #[inline]
446 #[must_use]
447 pub const fn sign_minus(&self) -> bool {
448 (self.flags >> FlagBit::SignMinus as u8) & 1 == 1
449 }
450
451 /// Determines if the `#` flag was specified.
452 #[inline]
453 #[must_use]
454 pub const fn alternate(&self) -> bool {
455 (self.flags >> FlagBit::Alternate as u8) & 1 == 1
456 }
457
458 /// Determines if the `0` flag was specified.
459 #[inline]
460 #[must_use]
461 pub const fn sign_aware_zero_pad(&self) -> bool {
462 (self.flags >> FlagBit::SignAwareZeroPad as u8) & 1 == 1
463 }
464}
465
466impl From<&Formatter<'_>> for FormatterOptions {
467 fn from(value: &Formatter<'_>) -> Self {
468 *Self::default()
469 .with_fill(value.fill())
470 .with_sign_plus(value.sign_plus())
471 .with_sign_minus(value.sign_minus())
472 .with_align(value.align())
473 .with_width(value.width())
474 .with_precision(value.precision())
475 .with_alternate(value.alternate())
476 .with_sign_aware_zero_pad(value.sign_aware_zero_pad())
477 }
478}
479
480impl From<&mut Formatter<'_>> for FormatterOptions {
481 #[inline]
482 fn from(value: &mut Formatter<'_>) -> Self {
483 (&*value).into()
484 }
485}
486
487/// Information used to format a value. This is returned by [`SmartDisplay::metadata`].
488///
489/// This type is generic over any user-provided type. This allows the author to store any
490/// information that is needed. For example, a type's implementation of [`SmartDisplay`] may need
491/// to calculate something before knowing its width. This calculation can be performed, with the
492/// result being stored in the custom metadata type.
493///
494/// Note that `Metadata` _always_ contains the width of the type. Authors do not need to store this
495/// information in their custom metadata type.
496///
497/// Generally speaking, a type should be able to be formatted using only its metadata, fields, and
498/// the formatter. Any other information should be stored in the metadata type.
499pub struct Metadata<'a, T>
500where
501 T: SmartDisplay + ?Sized,
502{
503 unpadded_width: usize,
504 metadata: T::Metadata,
505 _value: PhantomData<&'a T>, // variance
506}
507
508// manual impls for bounds
509impl<T> Debug for Metadata<'_, T>
510where
511 T: SmartDisplay,
512 T::Metadata: Debug,
513{
514 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
515 f.debug_struct("Metadata")
516 .field("unpadded_width", &self.unpadded_width)
517 .field("metadata", &self.metadata)
518 .finish()
519 }
520}
521
522impl<T> Clone for Metadata<'_, T>
523where
524 T: SmartDisplay,
525 T::Metadata: Clone,
526{
527 fn clone(&self) -> Self {
528 Self {
529 unpadded_width: self.unpadded_width,
530 metadata: self.metadata.clone(),
531 _value: self._value,
532 }
533 }
534}
535
536impl<T> Copy for Metadata<'_, T>
537where
538 T: SmartDisplay,
539 T::Metadata: Copy,
540{
541}
542
543impl<'a, T> Metadata<'a, T>
544where
545 T: SmartDisplay + ?Sized,
546{
547 /// Creates a new `Metadata` with the given width and metadata. While the width _should_ be
548 /// exact, this is not a requirement for soundness.
549 pub const fn new(unpadded_width: usize, _value: &T, metadata: T::Metadata) -> Self {
550 Self {
551 unpadded_width,
552 metadata,
553 _value: PhantomData,
554 }
555 }
556
557 /// Reuse the metadata for another type. This is useful when implementing [`SmartDisplay`] for a
558 /// type that wraps another type. Both type's metadata type must be the same.
559 pub fn reuse<'b, U>(self) -> Metadata<'b, U>
560 where
561 'a: 'b,
562 U: SmartDisplay<Metadata = T::Metadata> + ?Sized,
563 {
564 Metadata {
565 unpadded_width: self.unpadded_width,
566 metadata: self.metadata,
567 _value: PhantomData,
568 }
569 }
570
571 /// Obtain the width of the value before padding.
572 pub const fn unpadded_width(&self) -> usize {
573 self.unpadded_width
574 }
575
576 /// Obtain the width of the value after padding.
577 pub fn padded_width(&self, f: FormatterOptions) -> usize {
578 match f.width() {
579 Some(requested_width) => cmp::max(self.unpadded_width(), requested_width),
580 None => self.unpadded_width(),
581 }
582 }
583}
584
585impl Metadata<'_, Infallible> {
586 /// Obtain the width of the value before padding, given the formatter options.
587 pub fn unpadded_width_of<T>(value: T, f: FormatterOptions) -> usize
588 where
589 T: SmartDisplay,
590 {
591 value.metadata(f).unpadded_width
592 }
593
594 /// Obtain the width of the value after padding, given the formatter options.
595 pub fn padded_width_of<T>(value: T, f: FormatterOptions) -> usize
596 where
597 T: SmartDisplay,
598 {
599 value.metadata(f).padded_width(f)
600 }
601}
602
603/// Permit using `Metadata` as a smart pointer to the user-provided metadata.
604impl<T> Deref for Metadata<'_, T>
605where
606 T: SmartDisplay + ?Sized,
607{
608 type Target = T::Metadata;
609
610 fn deref(&self) -> &T::Metadata {
611 &self.metadata
612 }
613}
614
615/// Format trait that allows authors to provide additional information.
616///
617/// This trait is similar to [`Display`], but allows the author to provide additional information
618/// to the formatter. This information is provided in the form of a custom metadata type.
619///
620/// The only required piece of metadata is the width of the value. This is _before_ it is passed to
621/// the formatter (i.e. it does not include any padding added by the formatter). Other information
622/// can be stored in a custom metadata type as needed. This information may be made available to
623/// downstream users, but it is not required.
624///
625/// **Note**: While both `fmt_with_metadata` and `fmt` have default implementations, it is strongly
626/// recommended to implement only `fmt_with_metadata`. `fmt` should be implemented if and only if
627/// the type does not require any of the calculated metadata. In that situation, `fmt_with_metadata`
628/// should be omitted.
629#[cfg_attr(__powerfmt_docs, rustc_must_implement_one_of(fmt, fmt_with_metadata))]
630pub trait SmartDisplay: Display {
631 /// User-provided metadata type.
632 type Metadata;
633
634 /// Compute any information needed to format the value. This must, at a minimum, determine the
635 /// width of the value before any padding is added by the formatter.
636 ///
637 /// If the type uses other types that implement `SmartDisplay` verbatim, the inner types should
638 /// have their metadata calculated and included in the returned value.
639 ///
640 /// # Lifetimes
641 ///
642 /// This method's return type contains a lifetime to `self`. This ensures that the metadata will
643 /// neither outlive the value nor be invalidated by a mutation of the value (barring interior
644 /// mutability).
645 ///
646 /// ```rust,compile_fail
647 /// # use std::fmt;
648 /// # use std::fmt::Write;
649 /// # use powerfmt::buf::WriteBuffer;
650 /// # use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
651 /// #[derive(Debug)]
652 /// struct WrappedBuffer(WriteBuffer<128>);
653 ///
654 /// #[smart_display::delegate]
655 /// impl SmartDisplay for WrappedBuffer {
656 /// type Metadata = ();
657 ///
658 /// fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
659 /// Metadata::new(self.0.len(), self, ())
660 /// }
661 ///
662 /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
663 /// f.pad(self.0.as_str())
664 /// }
665 /// }
666 ///
667 /// let mut buf = WrappedBuffer(WriteBuffer::new());
668 /// let metadata = buf.metadata(FormatterOptions::default());
669 /// // We cannot mutate the buffer while it is borrowed and use its previous metadata on the
670 /// // following line.
671 /// write!(buf.0, "Hello, world!")?;
672 /// assert_eq!(metadata.width(), 13);
673 /// # Ok::<(), Box<dyn std::error::Error>>(())
674 /// ```
675 fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self>;
676
677 /// Format the value using the given formatter and metadata. The formatted output should have
678 /// the width indicated by the metadata. This is before any padding is added by the
679 /// formatter.
680 ///
681 /// If the metadata is not needed, you should implement the `fmt` method instead.
682 fn fmt_with_metadata(&self, f: &mut Formatter<'_>, _metadata: Metadata<'_, Self>) -> Result {
683 SmartDisplay::fmt(self, f)
684 }
685
686 /// Format the value using the given formatter. This is the same as [`Display::fmt`].
687 ///
688 /// The default implementation of this method calls `fmt_with_metadata` with the result of
689 /// `metadata`. Generally speaking, this method should not be implemented. You should implement
690 /// the `fmt_with_metadata` method instead.
691 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
692 let metadata = self.metadata(f.into());
693 self.fmt_with_metadata(f, metadata)
694 }
695}