diff options
Diffstat (limited to 'vendor/powerfmt/src')
-rw-r--r-- | vendor/powerfmt/src/buf.rs | 198 | ||||
-rw-r--r-- | vendor/powerfmt/src/ext.rs | 54 | ||||
-rw-r--r-- | vendor/powerfmt/src/lib.rs | 15 | ||||
-rw-r--r-- | vendor/powerfmt/src/smart_display.rs | 695 | ||||
-rw-r--r-- | vendor/powerfmt/src/smart_display_impls.rs | 303 |
5 files changed, 1265 insertions, 0 deletions
diff --git a/vendor/powerfmt/src/buf.rs b/vendor/powerfmt/src/buf.rs new file mode 100644 index 0000000..5a57a60 --- /dev/null +++ b/vendor/powerfmt/src/buf.rs @@ -0,0 +1,198 @@ +//! A buffer for constructing a string while avoiding heap allocation. + +use core::hash::{Hash, Hasher}; +use core::mem::MaybeUninit; +use core::{fmt, str}; + +use crate::smart_display::{FormatterOptions, Metadata, SmartDisplay}; + +/// A buffer for construct a string while avoiding heap allocation. +/// +/// The only requirement is that the buffer is large enough to hold the formatted string. +pub struct WriteBuffer<const SIZE: usize> { + buf: [MaybeUninit<u8>; SIZE], + len: usize, +} + +impl<const SIZE: usize> fmt::Debug for WriteBuffer<SIZE> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DisplayBuffer") + .field("buf", &self.as_str()) + .field("remaining_capacity", &self.remaining_capacity()) + .finish() + } +} + +impl<const SIZE: usize> WriteBuffer<SIZE> { + /// Creates an empty buffer. + pub const fn new() -> Self { + Self { + buf: maybe_uninit_uninit_array::<_, SIZE>(), + len: 0, + } + } + + /// Obtain the contents of the buffer as a string. + pub fn as_str(&self) -> &str { + self + } + + /// Determine how many bytes are remaining in the buffer. + pub const fn remaining_capacity(&self) -> usize { + SIZE - self.len + } +} + +impl<const SIZE: usize> Default for WriteBuffer<SIZE> { + fn default() -> Self { + Self::new() + } +} + +impl<const LEFT_SIZE: usize, const RIGHT_SIZE: usize> PartialOrd<WriteBuffer<RIGHT_SIZE>> + for WriteBuffer<LEFT_SIZE> +{ + fn partial_cmp(&self, other: &WriteBuffer<RIGHT_SIZE>) -> Option<core::cmp::Ordering> { + self.as_str().partial_cmp(other.as_str()) + } +} + +impl<const LEFT_SIZE: usize, const RIGHT_SIZE: usize> PartialEq<WriteBuffer<RIGHT_SIZE>> + for WriteBuffer<LEFT_SIZE> +{ + fn eq(&self, other: &WriteBuffer<RIGHT_SIZE>) -> bool { + self.as_str() == other.as_str() + } +} + +impl<const SIZE: usize> Eq for WriteBuffer<SIZE> {} + +impl<const SIZE: usize> Ord for WriteBuffer<SIZE> { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} + +impl<const SIZE: usize> Hash for WriteBuffer<SIZE> { + fn hash<H: Hasher>(&self, state: &mut H) { + self.as_str().hash(state) + } +} + +impl<const SIZE: usize> AsRef<str> for WriteBuffer<SIZE> { + fn as_ref(&self) -> &str { + self + } +} + +impl<const SIZE: usize> AsRef<[u8]> for WriteBuffer<SIZE> { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<const SIZE: usize> core::borrow::Borrow<str> for WriteBuffer<SIZE> { + fn borrow(&self) -> &str { + self + } +} + +impl<const SIZE: usize> core::ops::Deref for WriteBuffer<SIZE> { + type Target = str; + + fn deref(&self) -> &Self::Target { + // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation which + // writes a valid UTF-8 string to `buf` and correctly sets `len`. + unsafe { + let s = maybe_uninit_slice_assume_init_ref(&self.buf[..self.len]); + str::from_utf8_unchecked(s) + } + } +} + +impl<const SIZE: usize> fmt::Display for WriteBuffer<SIZE> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self) + } +} + +impl<const SIZE: usize> SmartDisplay for WriteBuffer<SIZE> { + type Metadata = (); + + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + Metadata::new(self.len, self, ()) + } + + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad(self) + } +} + +impl<const SIZE: usize> fmt::Write for WriteBuffer<SIZE> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let bytes = s.as_bytes(); + + if let Some(buf) = self.buf.get_mut(self.len..(self.len + bytes.len())) { + maybe_uninit_write_slice(buf, bytes); + self.len += bytes.len(); + Ok(()) + } else { + Err(fmt::Error) + } + } +} + +/// Equivalent of [`MaybeUninit::uninit_array`] that compiles on stable. +#[must_use] +#[inline(always)] +const fn maybe_uninit_uninit_array<T, const N: usize>() -> [MaybeUninit<T>; N] { + // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. + unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() } +} + +/// Equivalent of [`MaybeUninit::write_slice`] that compiles on stable. +fn maybe_uninit_write_slice<'a, T>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T] +where + T: Copy, +{ + #[allow(trivial_casts)] + // SAFETY: T and MaybeUninit<T> have the same layout + let uninit_src = unsafe { &*(src as *const [T] as *const [MaybeUninit<T>]) }; + + this.copy_from_slice(uninit_src); + + // SAFETY: Valid elements have just been copied into `this` so it is initialized + unsafe { maybe_uninit_slice_assume_init_mut(this) } +} + +/// Equivalent of [`MaybeUninit::slice_assume_init_mut`] that compiles on stable. +/// +/// # Safety +/// +/// See [`MaybeUninit::slice_assume_init_mut`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.slice_assume_init_mut). +#[inline(always)] +unsafe fn maybe_uninit_slice_assume_init_mut<T, U>(slice: &mut [MaybeUninit<T>]) -> &mut [U] { + #[allow(trivial_casts)] + // SAFETY: similar to safety notes for `slice_get_ref`, but we have a mutable reference which is + // also guaranteed to be valid for writes. + unsafe { + &mut *(slice as *mut [MaybeUninit<T>] as *mut [U]) + } +} + +/// Equivalent of [`MaybeUninit::slice_assume_init_ref`] that compiles on stable. +/// +/// # Safety +/// +/// See [`MaybeUninit::slice_assume_init_ref`](https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.slice_assume_init_ref). +#[inline(always)] +const unsafe fn maybe_uninit_slice_assume_init_ref<T>(slice: &[MaybeUninit<T>]) -> &[T] { + #[allow(trivial_casts)] + // SAFETY: casting `slice` to a `*const [T]` is safe since the caller guarantees that `slice` is + // initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`. The pointer + // obtained is valid since it refers to memory owned by `slice` which is a reference and thus + // guaranteed to be valid for reads. + unsafe { + &*(slice as *const [MaybeUninit<T>] as *const [T]) + } +} diff --git a/vendor/powerfmt/src/ext.rs b/vendor/powerfmt/src/ext.rs new file mode 100644 index 0000000..20af7c0 --- /dev/null +++ b/vendor/powerfmt/src/ext.rs @@ -0,0 +1,54 @@ +//! Extension traits. + +use core::fmt::{Alignment, Arguments, Formatter, Result, Write}; + +mod sealed { + pub trait Sealed {} + + impl Sealed for core::fmt::Formatter<'_> {} +} + +/// An extension trait for [`core::fmt::Formatter`]. +pub trait FormatterExt: sealed::Sealed { + /// Writes the given arguments to the formatter, padding them with the given width. If `width` + /// is incorrect, the resulting output will not be the requested width. + fn pad_with_width(&mut self, width: usize, args: Arguments<'_>) -> Result; +} + +impl FormatterExt for Formatter<'_> { + fn pad_with_width(&mut self, args_width: usize, args: Arguments<'_>) -> Result { + let Some(final_width) = self.width() else { + // The caller has not requested a width. Write the arguments as-is. + return self.write_fmt(args); + }; + let Some(fill_width @ 1..) = final_width.checked_sub(args_width) else { + // No padding will be present. Write the arguments as-is. + return self.write_fmt(args); + }; + + let alignment = self.align().unwrap_or(Alignment::Left); + let fill = self.fill(); + + let left_fill_width = match alignment { + Alignment::Left => 0, + Alignment::Right => fill_width, + Alignment::Center => fill_width / 2, + }; + let right_fill_width = match alignment { + Alignment::Left => fill_width, + Alignment::Right => 0, + // When the fill is not even on both sides, the extra fill goes on the right. + Alignment::Center => (fill_width + 1) / 2, + }; + + for _ in 0..left_fill_width { + self.write_char(fill)?; + } + self.write_fmt(args)?; + for _ in 0..right_fill_width { + self.write_char(fill)?; + } + + Ok(()) + } +} diff --git a/vendor/powerfmt/src/lib.rs b/vendor/powerfmt/src/lib.rs new file mode 100644 index 0000000..0cd6f7c --- /dev/null +++ b/vendor/powerfmt/src/lib.rs @@ -0,0 +1,15 @@ +//! `powerfmt` is a library that provides utilities for formatting values. Specifically, it makes it +//! significantly easier to support filling to a minimum width with alignment, avoid heap +//! allocation, and avoid repetitive calculations. + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(__powerfmt_docs, feature(doc_auto_cfg, rustc_attrs))] +#![cfg_attr(__powerfmt_docs, allow(internal_features))] + +#[cfg(feature = "alloc")] +extern crate alloc; + +pub mod buf; +pub mod ext; +pub mod smart_display; +mod smart_display_impls; diff --git a/vendor/powerfmt/src/smart_display.rs b/vendor/powerfmt/src/smart_display.rs new file mode 100644 index 0000000..bb55554 --- /dev/null +++ b/vendor/powerfmt/src/smart_display.rs @@ -0,0 +1,695 @@ +//! Definition of [`SmartDisplay`] and its related items. +//! +//! [`SmartDisplay`] is a trait that allows authors to provide additional information to both the +//! formatter and other users. This information is provided in the form of a metadata type. The only +//! required piece of metadata is the width of the value. This is _before_ it is passed to the +//! formatter (i.e. it does not include any padding added by the formatter). Other information +//! can be stored in a custom metadata type as needed. This information may be made available to +//! downstream users, but it is not required. +//! +//! This module contains the [`SmartDisplay`] and associated items. +//! +//! # Example +//! +//! ```rust +//! use std::fmt; +//! +//! use powerfmt::ext::FormatterExt as _; +//! use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay}; +//! +//! #[derive(Debug)] +//! struct User { +//! id: usize, +//! } +//! +//! // If you try to use `UserMetadata` in the `SmartDisplay` implementation, you will get a +//! // compiler error about a private type being used publicly. To avoid this, use this attribute to +//! // declare a private metadata type. You shouldn't need to worry about how this works, but be +//! // aware that any public fields or methods remain usable by downstream users. +//! #[smart_display::private_metadata] +//! struct UserMetadata { +//! username: String, +//! legal_name: String, +//! } +//! +//! // This attribute can be applied to `SmartDisplay` implementations. It will generate an +//! // implementation of `Display` that delegates to `SmartDisplay`, avoiding the need to write +//! // boilerplate. +//! #[smart_display::delegate] +//! impl SmartDisplay for User { +//! type Metadata = UserMetadata; +//! +//! fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { +//! // This could be obtained from a database, for example. +//! let legal_name = "John Doe".to_owned(); +//! let username = "jdoe".to_owned(); +//! +//! // Note that this must be kept in sync with the implementation of `fmt_with_metadata`. +//! let width = smart_display::padded_width_of!(username, " (", legal_name, ")",); +//! +//! Metadata::new( +//! width, +//! self, +//! UserMetadata { +//! username, +//! legal_name, +//! }, +//! ) +//! } +//! +//! // Use the now-generated metadata to format the value. Here we use the `pad_with_width` +//! // method to use the alignment and desired width from the formatter. +//! fn fmt_with_metadata( +//! &self, +//! f: &mut fmt::Formatter<'_>, +//! metadata: Metadata<Self>, +//! ) -> fmt::Result { +//! f.pad_with_width( +//! metadata.unpadded_width(), +//! format_args!("{} ({})", metadata.username, metadata.legal_name), +//! ) +//! } +//! } +//! +//! let user = User { id: 42 }; +//! assert_eq!(user.to_string(), "jdoe (John Doe)"); +//! assert_eq!(format!("{user:>20}"), " jdoe (John Doe)"); +//! ``` + +use core::cmp; +use core::convert::Infallible; +use core::fmt::{Alignment, Debug, Display, Formatter, Result}; +use core::marker::PhantomData; +use core::mem::MaybeUninit; +use core::ops::Deref; + +/// Compute the width of multiple items while optionally declaring the options for each item. +/// +/// ```rust +/// # use powerfmt::smart_display; +/// let alpha = 0; +/// let beta = 1; +/// let gamma = 100; +/// +/// let width = smart_display::padded_width_of!( +/// alpha, // use the default options +/// beta => width(2), // use the specified options +/// gamma => width(2) sign_plus(true), // use multiple options +/// ); +/// assert_eq!(width, 7); +/// +/// let formatted = format!("{alpha}{beta:2}{gamma:+2}"); +/// assert_eq!(formatted.len(), width); +/// ``` +/// +/// Supported options are: +/// +/// Option | Method called +/// --- | --- +/// `fill(char)` | [`FormatterOptions::with_fill`] +/// `sign_plus(bool)` | [`FormatterOptions::with_sign_plus`] +/// `sign_minus(bool)` | [`FormatterOptions::with_sign_minus`] +/// `align(Alignment)` | [`FormatterOptions::with_align`] +/// `width(usize)` | [`FormatterOptions::with_width`] +/// `precision(usize)` | [`FormatterOptions::with_precision`] +/// `alternate(bool)` | [`FormatterOptions::with_alternate`] +/// `sign_aware_zero_pad(bool)` | [`FormatterOptions::with_sign_aware_zero_pad`] +/// +/// If there are future additions to [`FormatterOptions`], they will be added to this macro as well. +/// +/// Options may be provided in any order and will be called in the order they are provided. The +/// ordering matters if providing both `sign_plus` and `sign_minus`. +#[cfg(doc)] +#[doc(hidden)] // Don't show at crate root. +#[macro_export] +macro_rules! padded_width_of { + ($($t:tt)*) => {}; +} + +#[cfg(not(doc))] +#[allow(missing_docs)] // This is done with `#[cfg(doc)]` to avoid showing the various rules. +#[macro_export] +macro_rules! __not_public_at_root__padded_width_of { + // Base case + (@inner [] [$($output:tt)+]) => { $($output)+ }; + (@inner [$e:expr $(, $($remaining:tt)*)?] [$($expansion:tt)+]) => { + $crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [ + $($expansion)+ + $crate::smart_display::Metadata::padded_width_of( + &$e, + $crate::smart_display::padded_width_of!(@options) + ) + ]) + }; + (@inner + [$e:expr => $($call:ident($call_expr:expr))+ $(, $($remaining:tt)*)?] + [$($expansion:tt)+] + ) => { + $crate::smart_display::padded_width_of!(@inner [$($($remaining)*)?] [ + $($expansion)+ + $crate::smart_display::Metadata::padded_width_of( + &$e, + *$crate::smart_display::padded_width_of!(@options $($call($call_expr))+) + ) + ]) + }; + + // Options base case + (@options_inner [] [$($output:tt)+]) => { $($output)+ }; + (@options_inner [fill($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_fill($e) + ]) + }; + (@options_inner [sign_plus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_sign_plus($e) + ]) + }; + (@options_inner [sign_minus($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_sign_minus($e) + ]) + }; + (@options_inner [align($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_align(Some($e)) + ]) + }; + (@options_inner [width($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_width(Some($e)) + ]) + }; + (@options_inner [precision($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_precision(Some($e)) + ]) + }; + (@options_inner [alternate($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_width($e) + ]) + }; + (@options_inner [sign_aware_zero_pad($e:expr) $($remaining:tt)*] [$($expansion:tt)*]) => { + $crate::smart_display::padded_width_of!(@options_inner [$($remaining)*] [ + $($expansion)*.with_sign_aware_zero_pad($e) + ]) + }; + // Options entry point + (@options $($e:tt)*) => { + $crate::smart_display::padded_width_of!(@options_inner [$($e)*] [ + $crate::smart_display::FormatterOptions::default() + ]) + }; + + // Entry point + ($($t:tt)*) => { + $crate::smart_display::padded_width_of!( + @inner [$($t)*] [0] + ) + }; +} + +#[cfg(not(doc))] +pub use __not_public_at_root__padded_width_of as padded_width_of; +#[cfg(doc)] +#[doc(inline)] // Show in this module. +pub use padded_width_of; +/// Implement [`Display`] for a type by using its implementation of [`SmartDisplay`]. +/// +/// This attribute is applied to the `SmartDisplay` implementation. +/// +/// ```rust,no_run +/// # use powerfmt::smart_display::{self, SmartDisplay, Metadata, FormatterOptions}; +/// # struct Foo; +/// #[smart_display::delegate] +/// impl SmartDisplay for Foo { +/// # type Metadata = (); +/// # fn metadata(&self, f: FormatterOptions) -> Metadata<Self> { +/// # todo!() +/// # } +/// // ... +/// } +/// ``` +#[cfg(feature = "macros")] +pub use powerfmt_macros::smart_display_delegate as delegate; +/// Declare a private metadata type for `SmartDisplay`. +/// +/// Use this attribute if you want to provide metadata for a type that is not public. Doing +/// this will avoid a compiler error about a private type being used publicly. Keep in mind +/// that any public fields, public methods, and trait implementations _will_ be able to be used +/// by downstream users. +/// +/// To avoid accidentally exposing details, such as when all fields are public or if the type +/// is a unit struct, the type is annotated with `#[non_exhaustive]` automatically. +/// +/// ```rust,no_run +/// # use powerfmt::smart_display; +/// /// Metadata for `Foo` +/// #[smart_display::private_metadata] +/// #[derive(Debug)] +/// pub(crate) struct FooMetadata { +/// pub(crate) expensive_to_calculate: usize, +/// } +/// ``` +#[cfg(feature = "macros")] +pub use powerfmt_macros::smart_display_private_metadata as private_metadata; + +#[derive(Debug)] +enum FlagBit { + SignPlus, + SignMinus, + Alternate, + SignAwareZeroPad, + WidthIsInitialized, + PrecisionIsInitialized, +} + +/// Configuration for formatting. +/// +/// This struct is obtained from a [`Formatter`]. It provides the same functionality as that of a +/// reference to a `Formatter`. However, it is not possible to construct a `Formatter`, which is +/// necessary for some use cases of [`SmartDisplay`]. `FormatterOptions` implements [`Default`] and +/// has builder methods to alleviate this. +#[derive(Clone, Copy)] +pub struct FormatterOptions { + flags: u8, + fill: char, + align: Option<Alignment>, + width: MaybeUninit<usize>, + precision: MaybeUninit<usize>, +} + +impl Debug for FormatterOptions { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("FormatterOptions") + .field("fill", &self.fill) + .field("align", &self.align()) + .field("width", &self.width()) + .field("precision", &self.precision()) + .field("sign_plus", &self.sign_plus()) + .field("sign_minus", &self.sign_minus()) + .field("alternate", &self.alternate()) + .field("sign_aware_zero_pad", &self.sign_aware_zero_pad()) + .finish() + } +} + +impl Default for FormatterOptions { + #[inline] + fn default() -> Self { + Self { + flags: 0, + fill: ' ', + align: None, + width: MaybeUninit::uninit(), + precision: MaybeUninit::uninit(), + } + } +} + +impl FormatterOptions { + /// Sets the fill character to use whenever there is alignment. + #[inline] + pub fn with_fill(&mut self, c: char) -> &mut Self { + self.fill = c; + self + } + + /// Set whether the `+` flag is specified. + #[inline] + pub fn with_sign_plus(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::SignPlus as u8; + self.flags &= !(1 << FlagBit::SignMinus as u8); + } else { + self.flags &= !(1 << FlagBit::SignPlus as u8); + } + self + } + + /// Set whether the `-` flag is specified. + #[inline] + pub fn with_sign_minus(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::SignMinus as u8; + self.flags &= !(1 << FlagBit::SignPlus as u8); + } else { + self.flags &= !(1 << FlagBit::SignMinus as u8); + } + self + } + + /// Set the flag indicating what form of alignment is requested, if any. + #[inline] + pub fn with_align(&mut self, align: Option<Alignment>) -> &mut Self { + self.align = align; + self + } + + /// Set the optional integer width that the output should be. + #[inline] + pub fn with_width(&mut self, width: Option<usize>) -> &mut Self { + if let Some(width) = width { + self.flags |= 1 << FlagBit::WidthIsInitialized as u8; + self.width = MaybeUninit::new(width); + } else { + self.flags &= !(1 << FlagBit::WidthIsInitialized as u8); + } + self + } + + /// Set the optional precision for numeric types. Alternatively, the maximum width for string + /// types. + #[inline] + pub fn with_precision(&mut self, precision: Option<usize>) -> &mut Self { + if let Some(precision) = precision { + self.flags |= 1 << FlagBit::PrecisionIsInitialized as u8; + self.precision = MaybeUninit::new(precision); + } else { + self.flags &= !(1 << FlagBit::PrecisionIsInitialized as u8); + } + self + } + + /// Set whether the `#` flag is specified. + #[inline] + pub fn with_alternate(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::Alternate as u8; + } else { + self.flags &= !(1 << FlagBit::Alternate as u8); + } + self + } + + /// Set whether the `0` flag is specified. + #[inline] + pub fn with_sign_aware_zero_pad(&mut self, b: bool) -> &mut Self { + if b { + self.flags |= 1 << FlagBit::SignAwareZeroPad as u8; + } else { + self.flags &= !(1 << FlagBit::SignAwareZeroPad as u8); + } + self + } +} + +impl FormatterOptions { + /// Character used as 'fill' whenever there is alignment. + #[inline] + #[must_use] + pub const fn fill(&self) -> char { + self.fill + } + + /// Flag indicating what form of alignment was requested. + #[inline] + #[must_use] + pub const fn align(&self) -> Option<Alignment> { + self.align + } + + /// Optionally specified integer width that the output should be. + #[inline] + #[must_use] + pub const fn width(&self) -> Option<usize> { + if (self.flags >> FlagBit::WidthIsInitialized as u8) & 1 == 1 { + // Safety: `width` is initialized if the flag is set. + Some(unsafe { self.width.assume_init() }) + } else { + None + } + } + + /// Optionally specified precision for numeric types. Alternatively, the maximum width for + /// string types. + #[inline] + #[must_use] + pub const fn precision(&self) -> Option<usize> { + if (self.flags >> FlagBit::PrecisionIsInitialized as u8) & 1 == 1 { + // Safety: `precision` is initialized if the flag is set. + Some(unsafe { self.precision.assume_init() }) + } else { + None + } + } + + /// Determines if the `+` flag was specified. + #[inline] + #[must_use] + pub const fn sign_plus(&self) -> bool { + (self.flags >> FlagBit::SignPlus as u8) & 1 == 1 + } + + /// Determines if the `-` flag was specified. + #[inline] + #[must_use] + pub const fn sign_minus(&self) -> bool { + (self.flags >> FlagBit::SignMinus as u8) & 1 == 1 + } + + /// Determines if the `#` flag was specified. + #[inline] + #[must_use] + pub const fn alternate(&self) -> bool { + (self.flags >> FlagBit::Alternate as u8) & 1 == 1 + } + + /// Determines if the `0` flag was specified. + #[inline] + #[must_use] + pub const fn sign_aware_zero_pad(&self) -> bool { + (self.flags >> FlagBit::SignAwareZeroPad as u8) & 1 == 1 + } +} + +impl From<&Formatter<'_>> for FormatterOptions { + fn from(value: &Formatter<'_>) -> Self { + *Self::default() + .with_fill(value.fill()) + .with_sign_plus(value.sign_plus()) + .with_sign_minus(value.sign_minus()) + .with_align(value.align()) + .with_width(value.width()) + .with_precision(value.precision()) + .with_alternate(value.alternate()) + .with_sign_aware_zero_pad(value.sign_aware_zero_pad()) + } +} + +impl From<&mut Formatter<'_>> for FormatterOptions { + #[inline] + fn from(value: &mut Formatter<'_>) -> Self { + (&*value).into() + } +} + +/// Information used to format a value. This is returned by [`SmartDisplay::metadata`]. +/// +/// This type is generic over any user-provided type. This allows the author to store any +/// information that is needed. For example, a type's implementation of [`SmartDisplay`] may need +/// to calculate something before knowing its width. This calculation can be performed, with the +/// result being stored in the custom metadata type. +/// +/// Note that `Metadata` _always_ contains the width of the type. Authors do not need to store this +/// information in their custom metadata type. +/// +/// Generally speaking, a type should be able to be formatted using only its metadata, fields, and +/// the formatter. Any other information should be stored in the metadata type. +pub struct Metadata<'a, T> +where + T: SmartDisplay + ?Sized, +{ + unpadded_width: usize, + metadata: T::Metadata, + _value: PhantomData<&'a T>, // variance +} + +// manual impls for bounds +impl<T> Debug for Metadata<'_, T> +where + T: SmartDisplay, + T::Metadata: Debug, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("Metadata") + .field("unpadded_width", &self.unpadded_width) + .field("metadata", &self.metadata) + .finish() + } +} + +impl<T> Clone for Metadata<'_, T> +where + T: SmartDisplay, + T::Metadata: Clone, +{ + fn clone(&self) -> Self { + Self { + unpadded_width: self.unpadded_width, + metadata: self.metadata.clone(), + _value: self._value, + } + } +} + +impl<T> Copy for Metadata<'_, T> +where + T: SmartDisplay, + T::Metadata: Copy, +{ +} + +impl<'a, T> Metadata<'a, T> +where + T: SmartDisplay + ?Sized, +{ + /// Creates a new `Metadata` with the given width and metadata. While the width _should_ be + /// exact, this is not a requirement for soundness. + pub const fn new(unpadded_width: usize, _value: &T, metadata: T::Metadata) -> Self { + Self { + unpadded_width, + metadata, + _value: PhantomData, + } + } + + /// Reuse the metadata for another type. This is useful when implementing [`SmartDisplay`] for a + /// type that wraps another type. Both type's metadata type must be the same. + pub fn reuse<'b, U>(self) -> Metadata<'b, U> + where + 'a: 'b, + U: SmartDisplay<Metadata = T::Metadata> + ?Sized, + { + Metadata { + unpadded_width: self.unpadded_width, + metadata: self.metadata, + _value: PhantomData, + } + } + + /// Obtain the width of the value before padding. + pub const fn unpadded_width(&self) -> usize { + self.unpadded_width + } + + /// Obtain the width of the value after padding. + pub fn padded_width(&self, f: FormatterOptions) -> usize { + match f.width() { + Some(requested_width) => cmp::max(self.unpadded_width(), requested_width), + None => self.unpadded_width(), + } + } +} + +impl Metadata<'_, Infallible> { + /// Obtain the width of the value before padding, given the formatter options. + pub fn unpadded_width_of<T>(value: T, f: FormatterOptions) -> usize + where + T: SmartDisplay, + { + value.metadata(f).unpadded_width + } + + /// Obtain the width of the value after padding, given the formatter options. + pub fn padded_width_of<T>(value: T, f: FormatterOptions) -> usize + where + T: SmartDisplay, + { + value.metadata(f).padded_width(f) + } +} + +/// Permit using `Metadata` as a smart pointer to the user-provided metadata. +impl<T> Deref for Metadata<'_, T> +where + T: SmartDisplay + ?Sized, +{ + type Target = T::Metadata; + + fn deref(&self) -> &T::Metadata { + &self.metadata + } +} + +/// Format trait that allows authors to provide additional information. +/// +/// This trait is similar to [`Display`], but allows the author to provide additional information +/// to the formatter. This information is provided in the form of a custom metadata type. +/// +/// The only required piece of metadata is the width of the value. This is _before_ it is passed to +/// the formatter (i.e. it does not include any padding added by the formatter). Other information +/// can be stored in a custom metadata type as needed. This information may be made available to +/// downstream users, but it is not required. +/// +/// **Note**: While both `fmt_with_metadata` and `fmt` have default implementations, it is strongly +/// recommended to implement only `fmt_with_metadata`. `fmt` should be implemented if and only if +/// the type does not require any of the calculated metadata. In that situation, `fmt_with_metadata` +/// should be omitted. +#[cfg_attr(__powerfmt_docs, rustc_must_implement_one_of(fmt, fmt_with_metadata))] +pub trait SmartDisplay: Display { + /// User-provided metadata type. + type Metadata; + + /// Compute any information needed to format the value. This must, at a minimum, determine the + /// width of the value before any padding is added by the formatter. + /// + /// If the type uses other types that implement `SmartDisplay` verbatim, the inner types should + /// have their metadata calculated and included in the returned value. + /// + /// # Lifetimes + /// + /// This method's return type contains a lifetime to `self`. This ensures that the metadata will + /// neither outlive the value nor be invalidated by a mutation of the value (barring interior + /// mutability). + /// + /// ```rust,compile_fail + /// # use std::fmt; + /// # use std::fmt::Write; + /// # use powerfmt::buf::WriteBuffer; + /// # use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay}; + /// #[derive(Debug)] + /// struct WrappedBuffer(WriteBuffer<128>); + /// + /// #[smart_display::delegate] + /// impl SmartDisplay for WrappedBuffer { + /// type Metadata = (); + /// + /// fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + /// Metadata::new(self.0.len(), self, ()) + /// } + /// + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// f.pad(self.0.as_str()) + /// } + /// } + /// + /// let mut buf = WrappedBuffer(WriteBuffer::new()); + /// let metadata = buf.metadata(FormatterOptions::default()); + /// // We cannot mutate the buffer while it is borrowed and use its previous metadata on the + /// // following line. + /// write!(buf.0, "Hello, world!")?; + /// assert_eq!(metadata.width(), 13); + /// # Ok::<(), Box<dyn std::error::Error>>(()) + /// ``` + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self>; + + /// Format the value using the given formatter and metadata. The formatted output should have + /// the width indicated by the metadata. This is before any padding is added by the + /// formatter. + /// + /// If the metadata is not needed, you should implement the `fmt` method instead. + fn fmt_with_metadata(&self, f: &mut Formatter<'_>, _metadata: Metadata<'_, Self>) -> Result { + SmartDisplay::fmt(self, f) + } + + /// Format the value using the given formatter. This is the same as [`Display::fmt`]. + /// + /// The default implementation of this method calls `fmt_with_metadata` with the result of + /// `metadata`. Generally speaking, this method should not be implemented. You should implement + /// the `fmt_with_metadata` method instead. + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let metadata = self.metadata(f.into()); + self.fmt_with_metadata(f, metadata) + } +} diff --git a/vendor/powerfmt/src/smart_display_impls.rs b/vendor/powerfmt/src/smart_display_impls.rs new file mode 100644 index 0000000..dc82395 --- /dev/null +++ b/vendor/powerfmt/src/smart_display_impls.rs @@ -0,0 +1,303 @@ +//! Implementation of [`SmartDisplay`] for various types. + +#[cfg(feature = "alloc")] +use alloc::borrow::{Cow, ToOwned}; +#[cfg(feature = "alloc")] +use alloc::boxed::Box; +#[cfg(feature = "alloc")] +use alloc::rc::Rc; +#[cfg(feature = "alloc")] +use alloc::string::String; +#[cfg(feature = "alloc")] +use alloc::sync::Arc; +use core::cell::{Ref, RefMut}; +use core::cmp::min; +use core::convert::Infallible; +use core::fmt::{self, Display, Formatter}; +use core::num::Wrapping; +use core::pin::Pin; + +use crate::smart_display::{FormatterOptions, Metadata, SmartDisplay}; + +impl SmartDisplay for Infallible { + type Metadata = Self; + + #[inline] + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + match *self {} + } + + #[inline] + fn fmt(&self, _: &mut Formatter<'_>) -> fmt::Result { + match *self {} + } +} + +impl SmartDisplay for bool { + type Metadata = (); + + #[inline] + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + Metadata::new(if *self { 4 } else { 5 }, self, ()) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +impl SmartDisplay for str { + type Metadata = (); + + #[inline] + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + Metadata::new( + match f.precision() { + Some(max_len) => min(self.len(), max_len), + None => self.len(), + }, + self, + (), + ) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +#[cfg(feature = "alloc")] +impl SmartDisplay for String { + type Metadata = (); + + #[inline] + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +#[cfg(feature = "alloc")] +impl<'a, B, O> SmartDisplay for Cow<'a, B> +where + B: SmartDisplay + ToOwned<Owned = O> + ?Sized, + O: SmartDisplay<Metadata = B::Metadata> + 'a, +{ + type Metadata = B::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + match *self { + Cow::Borrowed(ref b) => b.metadata(f).reuse(), + Cow::Owned(ref o) => o.metadata(f).reuse(), + } + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} + +impl<T> SmartDisplay for Pin<&T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + self.get_ref().metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(self.get_ref(), f) + } +} + +impl<T> SmartDisplay for &T +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(*self, f) + } +} + +impl<T> SmartDisplay for &mut T +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(*self, f) + } +} + +impl<T> SmartDisplay for Ref<'_, T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +impl<T> SmartDisplay for RefMut<'_, T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +impl<T> SmartDisplay for Wrapping<T> +where + T: SmartDisplay, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + self.0.metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&self.0, f) + } +} + +#[cfg(feature = "alloc")] +impl<T> SmartDisplay for Rc<T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +#[cfg(feature = "alloc")] +impl<T> SmartDisplay for Arc<T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +#[cfg(feature = "alloc")] +impl<T> SmartDisplay for Box<T> +where + T: SmartDisplay + ?Sized, +{ + type Metadata = T::Metadata; + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + (**self).metadata(f).reuse() + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + SmartDisplay::fmt(&**self, f) + } +} + +/// Implement [`SmartDisplay`] for unsigned integers. +macro_rules! impl_uint { + ($($t:ty)*) => {$( + impl SmartDisplay for $t { + type Metadata = (); + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + let mut width = self.checked_ilog10().map_or(1, |n| n as usize + 1); + if f.sign_plus() || f.sign_minus() { + width += 1; + } + Metadata::new(width, self, ()) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } + } + )*}; +} + +impl_uint![u8 u16 u32 u64 u128 usize]; + +/// Implement [`SmartDisplay`] for signed integers. +macro_rules! impl_int { + ($($t:ty)*) => {$( + impl SmartDisplay for $t { + type Metadata = (); + + fn metadata(&self, f: FormatterOptions) -> Metadata<'_, Self> { + let mut width = if f.sign_plus() || *self < 0 { 1 } else { 0 }; + width += self.unsigned_abs().checked_ilog10().map_or(1, |n| n as usize + 1); + Metadata::new(width, self, ()) + } + + #[inline] + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } + } + )*}; +} + +impl_int![i8 i16 i32 i64 i128 isize]; + +impl SmartDisplay for char { + type Metadata = (); + + fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> { + let mut buf = [0; 4]; + let c = self.encode_utf8(&mut buf); + + Metadata::new(c.len(), self, ()) + } + + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(self, f) + } +} |