From c23a457e72abe608715ac76f076f47dc42af07a5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 20:31:44 +0200 Subject: Merging upstream version 1.74.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/pad/src/lib.rs | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 vendor/pad/src/lib.rs (limited to 'vendor/pad/src') diff --git a/vendor/pad/src/lib.rs b/vendor/pad/src/lib.rs new file mode 100644 index 000000000..1eda86837 --- /dev/null +++ b/vendor/pad/src/lib.rs @@ -0,0 +1,261 @@ +#![deny(unsafe_code)] + +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] +#![warn(missing_docs)] +#![warn(trivial_numeric_casts)] +#![warn(unreachable_pub)] +#![warn(unused_results)] + + +//! This is a library for padding strings at runtime. +//! +//! It provides four helper functions for the most common use cases, and one +//! main function (`pad`) to cover the other cases. +//! +//! String length is determined with the +//! [width](http://doc.rust-lang.org/nightly/std/str/trait.StrExt.html#tymethod.width) +//! function, without assuming CJK. +//! +//! Padding in the stdlib +//! --------------------- +//! +//! **You do not need this crate for simple padding!** +//! It’s possible to pad strings using the Rust standard library. +//! +//! For example, to pad a number with zeroes: +//! +//! ``` +//! // Padding using std::fmt +//! assert_eq!("0000012345", format!("{:0>10}", 12345)); +//! ``` +//! +//! You can even use a variable for the padding width: +//! +//! ``` +//! // Padding using std::fmt +//! assert_eq!("hello ", format!("{:width$}", "hello", width=12)); +//! ``` +//! +//! The [Rust documentation for `std::fmt`](https://doc.rust-lang.org/std/fmt/) +//! contains more examples. The rest of the examples will use the `pad` crate. +//! +//! Examples +//! -------- +//! +//! You can pad a string to have a minimum width with the `pad_to_width` +//! method: +//! +//! ``` +//! use pad::PadStr; +//! +//! println!("{}", "Hi there!".pad_to_width(16)); +//! ``` +//! +//! This will print out “Hi there!” followed by seven spaces, which is the +//! number of spaces necessary to bring it up to a total of sixteen characters +//! wide. +//! +//! +//! Alignment +//! --------- +//! +//! By default, strings are left-aligned: any extra characters are added on +//! the right. To change this, pass in an `Alignment` value: +//! +//! ``` +//! use pad::{PadStr, Alignment}; +//! +//! let s = "I'm over here".pad_to_width_with_alignment(20, Alignment::Right); +//! ``` +//! +//! There are four of these in total: +//! +//! - **Left**, which puts the text on the left and spaces on the right; +//! - **Right**, which puts the text on the right and spaces on the left; +//! - **Middle**, which centres the text evenly, putting it slightly to the +//! left if it can’t be exactly centered; +//! - **MiddleRight**, as above, but to the right. +//! +//! +//! Characters +//! ---------- +//! +//! Another thing that’s set by default is the character that’s used to pad +//! the strings — by default, it’s space, but you can change it: +//! +//! ``` +//! use pad::PadStr; +//! +//! let s = "Example".pad_to_width_with_char(10, '_'); +//! ``` +//! +//! +//! Truncation +//! ---------- +//! +//! Finally, you can override what happens when a value exceeds the width you +//! give. By default, the width parameter indicates a *minimum width*: any +//! string less will be padded, but any string greater will still be returned +//! in its entirety. +//! +//! You can instead tell it to pad with a maximum value, which will truncate +//! the input when a string longer than the width is passed in. +//! +//! ``` +//! use pad::PadStr; +//! +//! let short = "short".with_exact_width(10); // "short " +//! let long = "this string is long".with_exact_width(10); // "this strin" +//! ``` +//! +//! +//! A Full Example +//! -------------- +//! +//! All of the above functions delegate to the `pad` function, which you can +//! use in special cases. Here, in order to **right**-pad a number with +//! **zeroes**, pass in all the arguments: +//! +//! ``` +//! use pad::{PadStr, Alignment}; +//! +//! let s = "12345".pad(10, '0', Alignment::Right, true); +//! ``` +//! +//! (The `true` at the end governs whether to truncate or not.) +//! +//! +//! Note on Debugging +//! ----------------- +//! +//! One very last point: the width function takes a `usize`, rather than a +//! signed number type. This means that if you try to pass in a negative size, +//! it’ll wrap around to a positive size, and produce a massive string and +//! possibly crash your program. So if your padding calls are failing for some +//! reason, this is probably why. + + +extern crate unicode_width; +use unicode_width::UnicodeWidthStr; + + +/// An **alignment** tells the padder where to put the spaces. +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +pub enum Alignment { + + /// Text on the left, spaces on the right. + Left, + + /// Text on the right, spaces on the left. + Right, + + /// Text in the middle, spaces around it, but **shifted to the left** if it can’t be exactly central. + Middle, + + /// Text in the middle, spaces around it, but **shifted to the right** if it can’t be exactly central. + MiddleRight, +} + +/// Functions to do with string padding. +pub trait PadStr { + + /// Pad a string to be at least the given width by adding spaces on the + /// right. + fn pad_to_width(&self, width: usize) -> String { + self.pad(width, ' ', Alignment::Left, false) + } + + /// Pad a string to be at least the given width by adding the given + /// character on the right. + fn pad_to_width_with_char(&self, width: usize, pad_char: char) -> String { + self.pad(width, pad_char, Alignment::Left, false) + } + + /// Pad a string to be at least the given with by adding spaces around it. + fn pad_to_width_with_alignment(&self, width: usize, alignment: Alignment) -> String { + self.pad(width, ' ', alignment, false) + } + + /// Pad a string to be *exactly* the given width by either adding spaces + /// on the right, or by truncating it to that width. + fn with_exact_width(&self, width: usize) -> String { + self.pad(width, ' ', Alignment::Left, true) + } + + /// Pad a string to the given width somehow. + fn pad(&self, width: usize, pad_char: char, alignment: Alignment, truncate: bool) -> String; +} + +impl PadStr for str { + fn pad(&self, width: usize, pad_char: char, alignment: Alignment, truncate: bool) -> String { + // Use width instead of len for graphical display + let cols = UnicodeWidthStr::width(self); + + if cols >= width { + if truncate { + return self[..width].to_string(); + } + else { + return self.to_string(); + } + } + + let diff = width - cols; + + let (left_pad, right_pad) = match alignment { + Alignment::Left => (0, diff), + Alignment::Right => (diff, 0), + Alignment::Middle => (diff / 2, diff - diff / 2), + Alignment::MiddleRight => (diff - diff / 2, diff / 2), + }; + + let mut s = String::new(); + for _ in 0..left_pad { s.push(pad_char) } + s.push_str(self); + for _ in 0..right_pad { s.push(pad_char) } + s + } +} + + +#[cfg(test)] +mod test { + use super::PadStr; + use super::Alignment::*; + + macro_rules! test { + ($name: ident: $input: expr => $result: expr) => { + #[test] + fn $name() { + assert_eq!($result.to_string(), $input) + } + }; + } + + test!(zero: "".pad_to_width(0) => ""); + + test!(simple: "hello".pad_to_width(10) => "hello "); + test!(spaces: "".pad_to_width(6) => " "); + + test!(too_long: "hello".pad_to_width(2) => "hello"); + test!(still_to_long: "hi there".pad_to_width(0) => "hi there"); + test!(exact_length: "greetings".pad_to_width(9) => "greetings"); + test!(one_more: "greetings".pad_to_width(10) => "greetings "); + test!(one_less: "greetings".pad_to_width(8) => "greetings"); + + test!(left: "left align".pad_to_width_with_alignment(13, Left) => "left align "); + test!(right: "right align".pad_to_width_with_alignment(13, Right) => " right align"); + + test!(centre_even: "good day".pad_to_width_with_alignment(12, Middle) => " good day "); + test!(centre_odd: "salutations".pad_to_width_with_alignment(13, Middle) => " salutations "); + test!(centre_offset: "odd".pad_to_width_with_alignment(6, Middle) => " odd "); + test!(centre_offset_2: "odd".pad_to_width_with_alignment(6, MiddleRight) => " odd "); + + test!(character: "testing".pad_to_width_with_char(10, '_') => "testing___"); + + test!(accent: "pâté".pad_to_width(6) => "pâté "); + + test!(truncate: "this song is just six words long".with_exact_width(7) => "this so"); + test!(too_short: "stormclouds".with_exact_width(15) => "stormclouds "); +} -- cgit v1.2.3