zero_copy_pads/
pad.rs

1use crate::{Unit, Width};
2use core::fmt::{Display, Error, Formatter};
3use fmt_iter::repeat;
4
5/// Pad a value knowing the number of blocks.
6///
7/// Values that implement this trait are to be passed
8/// to `pad` field of [`PaddedValue`](crate::PaddedValue)
9/// or [`PaddedColumn`](crate::PaddedColumn).
10pub trait Pad<Value: Width, PadBlock: Display> {
11    /// Pad a value knowing the number of blocks.
12    fn fmt(
13        &self,
14        formatter: &mut Formatter<'_>,
15        value: &Value,
16        pad_block: &PadBlock,
17        pad_width: usize,
18    ) -> Result<(), Error>;
19}
20
21impl<Value, PadBlock, X> Pad<Value, PadBlock> for &X
22where
23    Value: Width,
24    PadBlock: Display,
25    X: Pad<Value, PadBlock> + Sized,
26{
27    fn fmt(
28        &self,
29        formatter: &mut Formatter<'_>,
30        value: &Value,
31        pad_block: &PadBlock,
32        pad_width: usize,
33    ) -> Result<(), Error> {
34        X::fmt(*self, formatter, value, pad_block, pad_width)
35    }
36}
37
38/// All pre-defined zero-sized [`Pad`] types in this [crate] implement this trait.
39pub trait UnitPad<Value: Width, PadBlock: Display>: Unit + Pad<Value, PadBlock> {}
40
41macro_rules! unit_pad {
42    ($name:ident) => {
43        impl Unit for $name {
44            const VALUE: Self = $name;
45        }
46
47        impl<Value: Width, PadBlock: Display> UnitPad<Value, PadBlock> for $name {}
48    };
49}
50
51/// Pad to the right, content to the left.
52///
53/// **Example:**
54///
55/// ```
56/// # use pretty_assertions::assert_eq;
57/// use zero_copy_pads::{AlignLeft, PaddedValue, PanicOnExcess};
58/// let padded_value = PaddedValue {
59///     pad: AlignLeft,
60///     value: "abcdef",
61///     pad_block: '-',
62///     total_width: 9,
63///     handle_excess: PanicOnExcess,
64/// };
65/// assert_eq!(padded_value.to_string(), "abcdef---");
66/// ```
67#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
68pub struct AlignLeft;
69unit_pad!(AlignLeft);
70
71impl<Value: Width, PadBlock: Display> Pad<Value, PadBlock> for AlignLeft {
72    fn fmt(
73        &self,
74        formatter: &mut Formatter<'_>,
75        value: &Value,
76        pad_block: &PadBlock,
77        pad_width: usize,
78    ) -> Result<(), Error> {
79        let pad = repeat(pad_block, pad_width);
80        write!(formatter, "{}{}", value, pad)
81    }
82}
83
84/// Pad to the left, content to the right.
85///
86/// **Example:**
87///
88/// ```
89/// # use pretty_assertions::assert_eq;
90/// use zero_copy_pads::{AlignRight, PaddedValue, PanicOnExcess};
91/// let padded_value = PaddedValue {
92///     pad: AlignRight,
93///     value: "abcdef",
94///     pad_block: '-',
95///     total_width: 9,
96///     handle_excess: PanicOnExcess,
97/// };
98/// assert_eq!(padded_value.to_string(), "---abcdef");
99/// ```
100#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
101pub struct AlignRight;
102unit_pad!(AlignRight);
103
104impl<Value: Width, PadBlock: Display> Pad<Value, PadBlock> for AlignRight {
105    fn fmt(
106        &self,
107        formatter: &mut Formatter<'_>,
108        value: &Value,
109        pad_block: &PadBlock,
110        pad_width: usize,
111    ) -> Result<(), Error> {
112        let pad = repeat(pad_block, pad_width);
113        write!(formatter, "{}{}", pad, value)
114    }
115}
116
117/// Pad to both sides, place content in the middle, but shift to the left one
118/// block if it can't be exactly central.
119///
120/// **Example:**
121///
122/// ```
123/// # #[cfg(feature = "std")] fn main() {
124/// # use pretty_assertions::assert_eq;
125/// use zero_copy_pads::{AlignCenterLeft, PaddedColumn, PanicOnExcess};
126/// let values = [
127///     "Rust", "C", "C++", "C#", "JavaScript",
128///     "TypeScript", "Java", "Kotlin", "Go",
129/// ];
130/// let padded_column = PaddedColumn {
131///     pad: AlignCenterLeft,
132///     values: values.iter(),
133///     pad_block: '-',
134/// };
135/// let padded_values: Vec<_> = padded_column
136///     .into_iter()
137///     .map(|x| x.to_string())
138///     .collect();
139/// let expected = [
140///     "---Rust---", "----C-----", "---C++----",
141///     "----C#----", "JavaScript", "TypeScript",
142///     "---Java---", "--Kotlin--", "----Go----",
143/// ];
144/// assert_eq!(padded_values, expected);
145/// # }
146/// # #[cfg(not(feature = "std"))] fn main() {}
147/// ```
148#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
149pub struct AlignCenterLeft;
150unit_pad!(AlignCenterLeft);
151
152impl<Value: Width, PadBlock: Display> Pad<Value, PadBlock> for AlignCenterLeft {
153    fn fmt(
154        &self,
155        formatter: &mut Formatter<'_>,
156        value: &Value,
157        pad_block: &PadBlock,
158        pad_width: usize,
159    ) -> Result<(), Error> {
160        let pad = repeat(pad_block, pad_width >> 1);
161        let remainder = repeat(pad_block, pad_width & 1);
162        write!(formatter, "{}{}{}{}", pad, value, pad, remainder)
163    }
164}
165
166/// Pad to both sides, place content in the middle, but shift to the right one
167/// block if it can't be exactly central.
168///
169/// **Example:**
170///
171/// ```
172/// # #[cfg(feature = "std")] fn main() {
173/// # use pretty_assertions::assert_eq;
174/// use zero_copy_pads::{AlignCenterRight, PaddedColumn, PanicOnExcess};
175/// let values = [
176///     "Rust", "C", "C++", "C#", "JavaScript",
177///     "TypeScript", "Java", "Kotlin", "Go",
178/// ];
179/// let padded_column = PaddedColumn {
180///     pad: AlignCenterRight,
181///     values: values.iter(),
182///     pad_block: '-',
183/// };
184/// let padded_values: Vec<_> = padded_column
185///     .into_iter()
186///     .map(|x| x.to_string())
187///     .collect();
188/// let expected = [
189///     "---Rust---", "-----C----", "----C++---",
190///     "----C#----", "JavaScript", "TypeScript",
191///     "---Java---", "--Kotlin--", "----Go----",
192/// ];
193/// assert_eq!(padded_values, expected);
194/// # }
195/// # #[cfg(not(feature = "std"))] fn main() {}
196/// ```
197#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
198pub struct AlignCenterRight;
199unit_pad!(AlignCenterRight);
200
201impl<Value: Width, PadBlock: Display> Pad<Value, PadBlock> for AlignCenterRight {
202    fn fmt(
203        &self,
204        formatter: &mut Formatter<'_>,
205        value: &Value,
206        pad_block: &PadBlock,
207        pad_width: usize,
208    ) -> Result<(), Error> {
209        let pad = repeat(pad_block, pad_width >> 1);
210        let remainder = repeat(pad_block, pad_width & 1);
211        write!(formatter, "{}{}{}{}", pad, remainder, value, pad)
212    }
213}