custom-display 0.1.0

A trait for implementing custom formatting logic for types
Documentation
// SPDX-FileCopyrightText: 2026 Marissa (cuddle puddle) <dev@princess.lgbt>
//
// SPDX-License-Identifier: MPL-2.0

use std::fmt::{self, Display, Formatter};
use std::marker::PhantomData;

use super::{CustomDisplay, OwnedDisplayable, PrecisionBehavior};

/**
 * Returns a [`CustomDisplay`] that provides handling of [precision], [width],
 * [fill and alignment] in the way specified by [`std::fmt`] for non-numeric
 * types.
 *
 * For some type that implements [`Display`], returns a [`CustomDisplay`] that,
 * when used by a [`Displayable`], truncates the formatted value based on
 * [precision], pads it based on [width], [fill and alignment], and has a
 * default [`Alignment`] of [`Left`]. This allows one to get the behavior
 * specified by [`std::fmt`] for non-numeric types without having to implement
 * the handling for [precision], [width], [fill and alignment] for their type.
 * The returned [`CustomDisplay`] assumes all characters in formatted values
 * have a monospace width of `1`.
 *
 * See also [`display_non_numeric()`].
 *
 * [precision]: std::fmt#precision
 * [width]: std::fmt#width
 * [fill and alignment]: std::fmt#fillalignment
 * [`Displayable`]: crate::Displayable
 * [`Alignment`]: std::fmt::Alignment
 * [`Left`]: std::fmt::Alignment::Left
 */
#[inline]
pub fn default_non_numeric<T>() -> DefaultNonNumeric<T>
where
    T: Display + ?Sized,
{
    DefaultNonNumeric(PhantomData)
}

/**
 * Returns a wrapper around the given value that handles [precision], [width],
 * [fill and alignment] in the way specified by [`std::fmt`] for non-numeric
 * types.
 *
 * For some type that implements [`Display`], returns a wrapper that truncates
 * the formatted value based on [precision], pads it based on [width],
 * [fill and alignment], and has a default [`Alignment`] of [`Left`]. This
 * allows one to get the behavior specified by [`std::fmt`] for non-numeric
 * types without having to implement the handling for [precision], [width],
 * [fill and alignment] for their type. This method assumes all characters in
 * the formatted value have a monospace width of `1`.
 *
 * See also [`default_non_numeric()`].
 *
 * [precision]: std::fmt#precision
 * [width]: std::fmt#width
 * [fill and alignment]: std::fmt#fillalignment
 * [`Alignment`]: std::fmt::Alignment
 * [`Left`]: std::fmt::Alignment::Left
 */
#[inline]
pub fn display_non_numeric<T>(value: &T) -> OwnedDisplayable<'_, DefaultNonNumeric<T>>
where
    T: Display + ?Sized,
{
    default_non_numeric().into_display(value)
}

/** See [`default_non_numeric()`]. */
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct DefaultNonNumeric<T>(PhantomData<fn(T)>)
where
    T: Display + ?Sized;

impl<T> CustomDisplay for DefaultNonNumeric<T>
where
    T: Display + ?Sized,
{
    type Value = T;
    #[inline]
    fn fmt(&self, value: &Self::Value, f: &mut Formatter<'_>) -> fmt::Result {
        value.fmt(f)
    }
    #[inline]
    fn precision_behavior(&self) -> crate::PrecisionBehavior {
        PrecisionBehavior::AutoTruncate
    }
    #[inline]
    fn width_in_chars(&self, _value: &Self::Value, _f: &Formatter<'_>) -> Option<usize> {
        None
    }
}

impl<T> Display for DefaultNonNumeric<T>
where
    T: Display + ?Sized,
{
    #[inline]
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.pad("DefaultAutoTruncate")
    }
}