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 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Formatting {
Debug,
Display,
}
impl Formatting {
/// Whether the current variant is `Display`
#[inline(always)]
pub const fn is_display(self) -> bool {
matches!(self, Formatting::Display)
}
}
/// How numbers are formatted in debug formatters.
///
/// Hexadecimal or binary formatting in the formatting string from this crate imply
/// debug formatting.
///
///
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum NumberFormatting {
/// Formats numbers as decimal
Decimal,
/// Formats numbers as hexadecimal
Hexadecimal,
/// Formats numbers as binary
Binary,
}
#[doc(hidden)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum HexFormatting {
// micro-optimization
// by having these values for the discriminants,
// going from a number greater than 9 and smaller than 16
// to their ascii digits is as simple as `number + (hex_fmt as u8)`
Upper = b'A' - 10,
Lower = b'a' - 10,
}
impl NumberFormatting {
#[cfg(test)]
#[cfg(feature = "fmt")]
pub(crate) const ALL: &'static [Self; 3] = &[
NumberFormatting::Decimal,
NumberFormatting::Hexadecimal,
NumberFormatting::Binary,
];
}
////////////////////////////////////////////////////////////////////////////////
/// This type bundles configuration for how to format data into strings, including.
///
/// # Number formatting
///
/// How numbers are formatted in debug formatters,
/// It can be accessed with the `num_fmt` method, and set with the `set_num_fmt` method.
///
/// Each type of number formatting corresponds to a [`NumberFormatting`] variant:
///
/// - `NumberFormatting::Decimal` (eg: `formatc!("{:?}", FOO)`):
/// formats numbers as decimal.
///
/// - `NumberFormatting::Hexadecimal` (eg: `formatc!("{:x}", FOO)`):
/// formats numbers as hexadecimal.
///
/// - `NumberFormatting::Binary` (eg: `formatc!("{:b}", FOO)`):
/// formats numbers as binary.
///
/// Hexadecimal or binary formatting in the formatting string from this crate imply
/// debug formatting,
/// and can be used to for example print an array of binary numbers.
///
/// Note: Lowercase hexadecimal formatting requires calling the
/// [`set_lower_hexadecimal`](#method.set_lower_hexadecimal) method.
///
/// # Alternate flag
///
/// A flag that types can use to be formatted differently when it's enabled,
/// checked with the `.is_alternate()` method.
///
/// The default behavior when it is enabled is this:
///
/// - The Debug formater (eg: `formatc!("{:#?}", FOO)`):
/// pretty print structs and enums.
///
/// - The hexadecimal formater (eg: `formatc!("{:#x}", FOO)`):
/// prefixes numbers with `0x`.
///
/// - The binary formater (eg: `formatc!("{:#b}", FOO)`):
/// prefixes numbers with `0b`.`
///
/// [`Formatter`]: ./struct.Formatter.html
///
#[must_use]
#[derive(Debug, Copy, Clone)]
pub struct FormattingFlags {
num_fmt: NumberFormatting,
// Whether the `NumberFormatting` prints hexadecimal digits in lowercase
// (e.g: 0xf00, 0xF00)
//
// move this in 0.3.0 to `NumberFormatting`.
hex_fmt: HexFormatting,
is_alternate: bool,
}
#[doc(hidden)]
impl FormattingFlags {
pub const __REG: Self = Self::NEW.set_alternate(false).set_decimal();
pub const __HEX: Self = Self::NEW.set_alternate(false).set_hexadecimal();
pub const __LOWHEX: Self = Self::NEW.set_alternate(false).set_lower_hexadecimal();
pub const __BIN: Self = Self::NEW.set_alternate(false).set_binary();
pub const __A_REG: Self = Self::NEW.set_alternate(true).set_decimal();
pub const __A_HEX: Self = Self::NEW.set_alternate(true).set_hexadecimal();
pub const __A_LOWHEX: Self = Self::NEW.set_alternate(true).set_lower_hexadecimal();
pub const __A_BIN: Self = Self::NEW.set_alternate(true).set_binary();
}
impl FormattingFlags {
#[doc(hidden)]
pub const DEFAULT: Self = Self {
num_fmt: NumberFormatting::Decimal,
hex_fmt: HexFormatting::Upper,
is_alternate: false,
};
/// Constructs a `FormattingFlags` with these values:
///
/// - number formatting: NumberFormatting::Decimal
///
/// - is alternate: false
///
pub const NEW: Self = Self {
num_fmt: NumberFormatting::Decimal,
hex_fmt: HexFormatting::Upper,
is_alternate: false,
};
/// Constructs a `FormattingFlags` with these values:
///
/// - number formatting: NumberFormatting::Decimal
///
/// - is alternate: false
///
#[inline]
pub const fn new() -> Self {
Self::NEW
}
/// Sets the integer formatting,
///
/// This usually doesn't affect the outputted text in display formatting.
#[inline]
pub const fn set_num_fmt(mut self, num_fmt: NumberFormatting) -> Self {
self.num_fmt = num_fmt;
self
}
/// Sets the number formatting to `NumberFormatting::Decimal`.
///
/// This means that numbers are written as decimal.
#[inline]
pub const fn set_decimal(mut self) -> Self {
self.num_fmt = NumberFormatting::Decimal;
self
}
/// Sets the number formatting to `NumberFormatting::Hexadecimal`.
///
/// This means that numbers are written as uppercase hexadecimal.
#[inline]
pub const fn set_hexadecimal(mut self) -> Self {
self.num_fmt = NumberFormatting::Hexadecimal;
self.hex_fmt = HexFormatting::Upper;
self
}
/// Sets the number formatting to `NumberFormatting::Hexadecimal`,
/// and uses lowercase for alphabetic hexadecimal digits.
///
/// This means that numbers are written as lowercase hexadecimal.
#[inline]
pub const fn set_lower_hexadecimal(mut self) -> Self {
self.num_fmt = NumberFormatting::Hexadecimal;
self.hex_fmt = HexFormatting::Lower;
self
}
/// Sets the number formatting to `NumberFormatting::Binary`.
///
/// This means that numbers are written as binary.
#[inline]
pub const fn set_binary(mut self) -> Self {
self.num_fmt = NumberFormatting::Binary;
self
}
/// Sets whether the formatting flag is enabled.
#[inline]
pub const fn set_alternate(mut self, is_alternate: bool) -> Self {
self.is_alternate = is_alternate;
self
}
/// Gets the current `NumberFormatting`.
#[inline]
pub const fn num_fmt(self) -> NumberFormatting {
self.num_fmt
}
/// Gets whether the alternate flag is enabled
#[inline]
pub const fn is_alternate(self) -> bool {
self.is_alternate
}
pub(crate) const fn hex_fmt(self) -> HexFormatting {
self.hex_fmt
}
}
////////////////////////////////////////////////////////////////////////////////
#[doc(hidden)]
/// For writing into an array from the start
pub struct LenAndArray<T: ?Sized> {
/// The amount of elements written in `array`
pub len: usize,
pub array: T,
}
#[doc(hidden)]
/// For writing into an array from the end
pub struct StartAndArray<T: ?Sized> {
/// The first element in `array`
pub start: usize,
pub array: T,
}
////////////////////////////////////////////////////////////////////////////////
#[doc(hidden)]
pub struct ForEscaping {
pub is_escaped: u128,
pub is_backslash_escaped: u128,
pub escape_char: [u8; 16],
}
impl ForEscaping {
/// Gets the backslash escape for a character that is kwown to be escaped with a backslash.
#[inline(always)]
pub const fn get_backslash_escape(b: u8) -> u8 {
FOR_ESCAPING.escape_char[(b & 0b1111) as usize]
}
}
#[doc(hidden)]
/// Converts 0..=0xF to its ascii representation of '0'..='9' and 'A'..='F'
#[inline(always)]
pub const fn hex_as_ascii(n: u8, hex_fmt: HexFormatting) -> u8 {
if n < 10 {
n + b'0'
} else {
n + (hex_fmt as u8)
}
}
#[doc(hidden)]
// Really clippy? Array indexing can panic you know.
#[allow(clippy::no_effect)]
pub const FOR_ESCAPING: &ForEscaping = {
let mut is_backslash_escaped = 0;
let escaped = [
(b'\t', b't'),
(b'\n', b'n'),
(b'\r', b'r'),
(b'\'', b'\''),
(b'"', b'"'),
(b'\\', b'\\'),
];
// Using the fact that the characters above all have different bit patterns for
// the lowest 4 bits.
let mut escape_char = [0u8; 16];
__for_range! {i in 0..escaped.len() =>
let (code, escape) = escaped[i];
is_backslash_escaped |= 1 << code;
let ei = (code & 0b1111) as usize;
let prev_escape = escape_char[ei] as usize;
["Oh no, some escaped character uses the same 4 lower bits as another"][prev_escape];
escape_char[ei] = escape;
}
// Setting all the control characters as being escaped.
let is_escaped = is_backslash_escaped | 0xFFFF_FFFF;
&ForEscaping {
escape_char,
is_backslash_escaped,
is_escaped,
}
};