Skip to main content

padder/
lib.rs

1//!
2//! A highly efficient Rust crate for padding data during runtime.
3//!
4//! padder is a lightweight Rust crate for padding and formatting data structures at runtime
5//! efficiently. It provides fine-grained control over alignment, truncating strategies, padding,
6//! and memory allocation - making it ideal for performance-critical applications.
7//!
8//! Unlike the builtin `format!` macro, padder avoids unneccessary repeated heap allocations and
9//! lets you pad and format directly into preallocated buffers, or modify buffers in-place.
10//!
11//! **Fully UTF-8 compatible** - padder works seamlessly with any Unicode characters like emojis (πŸ‰),
12//! Japanese kana/kanji (こんにけは), or other multibyte symbols, when operating on String types.
13//!
14//! # Features
15//! - Pad strings, slices, and vectors with custom alignment and width.
16//! - Zero-cost abstractions via the `Source` and `MutableSource` traits.
17//! - Pad directly into buffers for fine-grained heap allocation control.
18//! - Highly extensible to custom types through the provided traits.
19//!
20//! # Usage
21//! ```
22//! use padder::*;
23//!
24//! let mut string = String::from("kratos");
25//! (&mut string).pad(10, Alignment::Right, '$');  // "$$$$kratos"
26//! pad_mut(&mut string, 14, Alignment::Center, '-');  // "--$$$$kratos--"
27//!
28//! let s = "dragon";
29//! let padded = pad(s, 11, Alignment::Left, 'πŸ‰');
30//! assert_eq!("dragonπŸ‰πŸ‰πŸ‰πŸ‰πŸ‰", padded);
31//!
32//! let vec: Vec<u8> = Vec::from(&[0u8, 2, 5]);
33//! let mut buffer: Vec<u8> = Vec::with_capacity(5);
34//! pad_to_buffer(vec, 5, Alignment::Right, 128u8, &mut buffer);
35//! assert_eq!(Vec::from(&[128u8, 128, 0, 2, 5]), buffer);
36//! ```
37//!
38
39mod alignment;
40mod mutable_source;
41mod source;
42
43pub use alignment::{Alignment, Pads};
44pub use mutable_source::MutableSource;
45pub use source::Source;
46
47/// Pads the given source buffer to the specified `width` using the provided `symbol` and alignment `mode`.
48///
49/// This is a convenience wrapper around the [`Source::pad`] method. It consumes the source buffer
50/// and produces a new, owned, and padded buffer.
51///
52/// # Examples
53/// ```
54/// use padder::*;
55///
56/// let string = String::from("this is a string");
57/// let padded = pad(string, 20, Alignment::Right, '_');
58/// assert_eq!("____this is a string", padded);
59///
60/// let string = String::from("sackboy");
61/// let padded = pad(string, 4, Alignment::Left, ' ');
62/// assert_eq!("sack", padded);  // 4 < string.chars.count() so it will be truncated
63///
64/// let vec: Vec<usize> = Vec::from(&[200, 10, 23]);
65/// let padded = pad(vec, 6, Alignment::Center, 0usize);
66/// assert_eq!(Vec::from(&[0usize, 200, 10, 23, 0, 0]), padded);
67/// ```
68pub fn pad<S: Source>(source: S, width: usize, mode: Alignment, symbol: S::Symbol) -> S::Output {
69    source.pad(width, mode, symbol)
70}
71
72/// Pad the given mutable source buffer in-place to the specified `width` using the provided `symbol` and `alignment` mode.
73///
74/// This is a convenience wrapper around the [`MutableSource::pad`] method. It modifies the source
75/// buffer directly and does not consume it.
76///
77/// # Examples
78/// ```
79/// use padder::*;
80///
81/// let mut string = String::from("elden ring");
82/// pad_mut(&mut string, 14, Alignment::Left, 'πŸ’');
83/// assert_eq!("elden ringπŸ’πŸ’πŸ’πŸ’", string);
84///
85/// let mut string = String::from("dark souls");
86/// pad_mut(&mut string, 14, Alignment::Center, 'πŸŒ‘');
87/// assert_eq!("πŸŒ‘πŸŒ‘dark soulsπŸŒ‘πŸŒ‘", string);
88/// ```
89pub fn pad_mut<S: MutableSource>(mut source: S, width: usize, mode: Alignment, symbol: S::Symbol) {
90    source.pad(width, mode, symbol);
91}
92
93/// Pad the given source to match the specified `width` according to the specified alignment
94/// `mode` by writing into the provided `buffer`.
95///
96/// This is a convenience wrapper around the [`Source::pad_to_buffer`] method. It does not modify
97/// the source buffer and instead directly writes in the the `buffer`.
98///
99/// # Examples
100/// ```
101/// use padder::*;
102///
103/// let slice: &[&str] = &[
104///     "liurnia",
105///     "of",
106///     "the",
107///     "lakes",
108/// ];
109/// let width = 6;
110/// let mut buf: Vec<&str> = Vec::with_capacity(width);
111/// pad_to_buffer(slice, width, Alignment::Right, "tarnished", &mut buf);
112/// let expected: Vec<&str> = Vec::from(&[
113///     "tarnished",
114///     "tarnished",
115///     "liurnia",
116///     "of",
117///     "the",
118///     "lakes",
119/// ]);
120/// assert_eq!(expected, buf);
121/// ```
122pub fn pad_to_buffer<S: Source>(
123    source: S,
124    width: usize,
125    mode: Alignment,
126    symbol: S::Symbol,
127    buffer: &mut S::Buffer,
128) {
129    source.pad_to_buffer(width, mode, symbol, buffer);
130}
131
132#[cfg(test)]
133mod tests_wrappers {
134    use super::*;
135
136    #[test]
137    fn str_pad() {
138        let output = pad("little big planet", 20, Alignment::Center, '!');
139        assert_eq!("!little big planet!!", output);
140        assert_eq!(20, output.len());
141    }
142
143    #[test]
144    fn string_pad() {
145        let output = pad("uh oh", 8, Alignment::Right, 'πŸ’£');
146        assert_eq!("πŸ’£πŸ’£πŸ’£uh oh", output);
147        assert_eq!(17, output.len());
148    }
149
150    #[test]
151    fn mut_string_pad() {
152        let mut s = String::from("def fn(xd: str) -> None: ...");
153        pad_mut(&mut s, 30, Alignment::Left, 'Γ¦');
154        assert_eq!("def fn(xd: str) -> None: ...ææ", s);
155        assert_eq!(32, s.len());
156        assert_eq!(30, s.chars().count());
157    }
158
159    #[test]
160    fn vec_pad_to_buffer() {
161        let mut buffer: Vec<u8> = Vec::new();
162        let v: Vec<u8> = Vec::from(&[1u8, 2]);
163        assert_eq!(2, v.len());
164        pad_to_buffer(v, 4, Alignment::Right, 89u8, &mut buffer);
165        assert_eq!(Vec::from(&[89u8, 89, 1, 2]), buffer);
166        assert_eq!(4, buffer.len());
167    }
168
169    #[test]
170    fn slice_pad() {
171        let source: &[bool] = &[true, false, true, true];
172        let s = source.pad(6, Alignment::Center, false);
173        assert_eq!(Vec::from(&[false, true, false, true, true, false]), s);
174        assert_eq!(6, s.len());
175    }
176}