1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
use super::{Align, Base, NumFmt, Sign}; /// Builder for a numeric formatter. #[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct Builder { fill: Option<char>, align: Align, sign: Sign, hash: bool, zero: bool, width: usize, precision: Option<usize>, format: Base, separator: Option<char>, spacing: Option<usize>, decimal_separator: Option<char>, } impl Builder { /// Construct a new `Builder`. pub fn new() -> Builder { Self::default() } /// Build a [`NumFmt`] instance, consuming this builder. pub fn build(self) -> NumFmt { let Builder { fill, align, sign, hash, zero, width, precision, format, separator, spacing, decimal_separator, } = self; NumFmt { fill, align, sign, hash, zero, width, precision, base: format, separator, spacing, decimal_separator, } } /// When `width` is greater than the actual rendered width of the number, the excess is padded /// with this character. /// /// ## Note /// Wide characters are counted according to their quantity, not their bit width. /// /// ```rust /// # use num_runtime_fmt::NumFmt; /// let heart = '🖤'; /// assert_eq!(heart.len_utf8(), 4); /// let fmt = NumFmt::builder().fill(heart).width(3).build(); /// let formatted = fmt.fmt(1).unwrap(); /// assert_eq!(formatted, "🖤🖤1"); /// // Note that even though we requested a width of 3, the binary length is 9. /// assert_eq!(formatted.len(), 9); /// ``` #[inline] pub fn fill(mut self, param: char) -> Self { self.fill = Some(param); self } /// Set the alignment of rendering within allotted `width`. See [`Align`]. #[inline] pub fn align(mut self, param: Align) -> Self { self.align = param; self } /// Set the rendering of the sign. See [`Sign`]. #[inline] pub fn sign(mut self, param: Sign) -> Self { self.sign = param; self } /// If a `set`, print a base specification before the number /// according to its format. /// /// See [`Builder::format`]. /// /// - binary: `0b` /// - octal: `0o` /// - decimal: `0d` /// - hex: `0x` /// /// Corresponds to the `#` format specifier. #[inline] pub fn hash(mut self, set: bool) -> Self { self.hash = set; self } /// If `set`, engage the zero handler. /// /// The zero handler overrides the padding specification to `0`, and /// treats pad characters as part of the number, in contrast /// to the default behavior which treats them as arbitrary spacing. /// /// Only valid with `Align::Right` and `Align::Decimal`. /// /// ## Examples /// /// ```rust /// # use num_runtime_fmt::NumFmt; /// // sign handling /// assert_eq!(NumFmt::from_str("03").unwrap().fmt(-1).unwrap(), "-01"); /// assert_eq!(NumFmt::from_str("0>3").unwrap().fmt(-1).unwrap(), "0-1"); /// ``` /// /// ```rust /// # use num_runtime_fmt::NumFmt; /// // separator handling /// assert_eq!(NumFmt::from_str("0>7,").unwrap().fmt(1).unwrap(), "0000001"); /// assert_eq!(NumFmt::from_str("07,").unwrap().fmt(1).unwrap(), "000,001"); /// ``` #[inline] pub fn zero(mut self, set: bool) -> Self { if set { self.fill = Some('0'); self.zero = true; } else { self.fill = None; self.zero = false; } self } /// Set the `width` parameter. /// /// This is a parameter for the "minimum width" that the format should take up. If /// the value's string does not fill up this many characters, then the padding /// specified by fill/alignment will be used to take up the required space (see /// [`Builder::fill`]). /// /// The width can be set dynamically: /// /// ```rust /// # use num_runtime_fmt::{NumFmt, Dynamic}; /// assert_eq!(NumFmt::from_str("-^").unwrap().fmt_with(1, Dynamic::width(5)).unwrap(), "--1--"); /// ``` /// /// Note: with `Align::Right`, this is the minimum width of the entire rendered field, /// not just the portion before the decimal. To set the width before the decimal, /// use `Align::Decimal`. /// /// ```rust /// # use num_runtime_fmt::{NumFmt, Dynamic}; /// assert_eq!(NumFmt::from_str( "05").unwrap().fmt(1.1).unwrap(), "001.1"); /// assert_eq!(NumFmt::from_str(">05").unwrap().fmt(1.1).unwrap(), "001.1"); /// assert_eq!(NumFmt::from_str("v05").unwrap().fmt(1.1).unwrap(), "00001.1"); /// ``` #[inline] pub fn width(mut self, param: usize) -> Self { self.width = param; self } /// Set the `precision` parameter. /// /// How many digits after the decimal point are printed. Note that integers can be forced /// to emit decimal places with this modifier. /// /// Precision will pad or truncate as required if set. If unset, passes through as many /// digits past the decimal as the underlying type naturally returns. /// /// ```rust /// # use num_runtime_fmt::{NumFmt, Dynamic}; /// assert_eq!(NumFmt::from_str(".2").unwrap().fmt(3.14159).unwrap(), "3.14"); /// assert_eq!(NumFmt::from_str(".7").unwrap().fmt(3.14159).unwrap(), "3.1415900"); /// ``` /// /// If the requested precision exceeds the native precision available to this number, /// the remainder is always filled with `'0'`, even if `fill` is specified: /// /// ```rust /// # use num_runtime_fmt::NumFmt; /// assert_eq!(NumFmt::from_str("-<6.2").unwrap().fmt(1.0_f32).unwrap(), "1.00--"); /// ``` #[inline] pub fn precision(mut self, param: Option<usize>) -> Self { self.precision = param; self } /// Set the output format. /// /// See [`Base`]. #[inline] pub fn base(mut self, param: Base) -> Self { self.format = param; self } /// Set the separator. /// /// A separator is a (typically non-numeric) character inserted between groups of digits to make /// it easier for humans to parse the number when reading. Different separators may /// be desirable in different contexts. #[inline] pub fn separator(mut self, param: Option<char>) -> Self { self.separator = param; self } /// Set the spacing. /// /// Spacing determines the number of characters in each character group. It is only /// of interest when the separator is set. The default spacing is 3. #[inline] pub fn spacing(mut self, param: usize) -> Self { self.spacing = Some(param); self } /// Set the decimal separator. /// /// This can be desirable to i.e. support German number formats, which use a `.` to separate /// numeric groups and a `,` as a decimal separator. #[inline] pub fn decimal_separator(mut self, param: char) -> Self { self.decimal_separator = Some(param); self } } impl From<NumFmt> for Builder { fn from( NumFmt { fill, align, sign, hash, zero, width, precision, base: format, separator, spacing, decimal_separator, }: NumFmt, ) -> Self { Builder { fill, align, sign, hash, zero, width, precision, format, separator, spacing, decimal_separator, } } }