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
// DEBUG.rs
// by Lut99
//
// Created:
// 26 Oct 2022, 14:47:11
// Last edited:
// 12 Dec 2022, 13:13:23
// Auto updated?
// Yes
//
// Description:
//! Implements a few debug tools.
//
use std::cell::{RefCell, RefMut};
use std::fmt::{Display, Formatter, Result as FResult};
/***** LIBRARY *****/
/// Defines a struct that capitalizes the first letter of the given string when printing it.
pub struct CapitalizeFormatter<'a> {
s: &'a str,
}
impl<'a> CapitalizeFormatter<'a> {
/// Constructor for the CapitalizeFormatter.
///
/// # Arguments
/// - `s`: The string to print with a capital, initial letter.
///
/// # Returns
/// A new instance of CapitalizeFormatter.
#[inline]
pub fn new(s: &'a (impl ?Sized + AsRef<str>)) -> Self { Self { s: s.as_ref() } }
}
impl<'a> Display for CapitalizeFormatter<'a> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
if !self.s.is_empty() {
let mut chars = self.s.chars();
write!(f, "{}{}", chars.next().unwrap().to_uppercase(), chars.collect::<String>())
} else {
Ok(())
}
}
}
/// Helper trait for the CapitalizeFormatter that implements a convenient capitalize() function for all strings.
pub trait Capitalizeable: AsRef<str> {
/// Returns this str-like object wrapped in a `CapitalizeFormatter` so it may be printed with a capital first letter.
///
/// # Returns
/// A new CapitalizeFormatter that implements `Display` (only).
#[inline]
fn capitalize(&self) -> CapitalizeFormatter { CapitalizeFormatter::new(self) }
}
impl<T> Capitalizeable for T where T: AsRef<str> {}
/// Defines a struct that can format a string of bytes as pairs of hexadecimals.
pub struct HexFormatter<'a> {
/// The bytes to format
bytes: &'a [u8],
}
impl<'a> HexFormatter<'a> {
/// Constructor for the HexFormatter.
///
/// # Arguments
/// - `bytes`: The Bytes-like object to format.
///
/// # Returns
/// A new instance of the HexFormatter that implements Display.
#[inline]
pub fn new(bytes: &'a impl AsRef<[u8]>) -> Self { Self { bytes: bytes.as_ref() } }
}
impl<'a> Display for HexFormatter<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
// Write in pairs of two for as long as we can (i.e., four bits)
let mut first: bool = true;
for b in self.bytes {
if first {
first = false;
} else {
write!(f, " ")?;
}
write!(f, "0x{:X} 0x{:X}", b & 0xF0, b & 0x0F)?;
}
// Done
Ok(())
}
}
/// Defines a struct that can format a large block of text neatly.
pub struct BlockFormatter<S1> {
/// Reference to the thing to format.
to_fmt: S1,
}
impl<S1> BlockFormatter<S1> {
/// Constructor for the BlockFormatter.
///
/// # Arguments
/// - `to_fmt`: The thing to format.
///
/// # Returns
/// A new BlockFormatter instance.
#[inline]
pub fn new(to_fmt: S1) -> Self { Self { to_fmt } }
}
impl<S1> Display for BlockFormatter<S1>
where
S1: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
// Write stdout, with lines to capture it
writeln!(f, "{}\n{}\n{}", (0..80).map(|_| '-').collect::<String>(), self.to_fmt, (0..80).map(|_| '-').collect::<String>(),)?;
// Done
Ok(())
}
}
/// A helper struct that implements Display for a given iterator that prints it like a human-readable list.
pub struct PrettyListFormatter<'a, I> {
/// The list to print.
iter: RefCell<I>,
/// The word to use as a connector word at the end.
word: &'a str,
}
impl<'a, I> PrettyListFormatter<'a, I> {
/// Constructor for the PrettyListFormatter.
///
/// # Arguments
/// - `iter`: The list to prettyprint.
/// - `word`: The word to use at the end of the list (e.g., `and` or `or`).
///
/// # Returns
/// A new instance of the PrettyListFormatter that can be used to show the given iterator as a pretty list.
#[inline]
pub fn new(iter: I, word: &'a str) -> Self { Self { iter: RefCell::new(iter), word } }
}
impl<'a, I> Display for PrettyListFormatter<'a, I>
where
I: Iterator,
<I as Iterator>::Item: Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut list: RefMut<I> = self.iter.borrow_mut();
let mut first: bool = true;
let mut lookahead: Option<<I as Iterator>::Item> = list.next();
while lookahead.is_some() {
// Move the lookahead back
let item: <I as Iterator>::Item = lookahead.take().unwrap();
lookahead = list.next();
// If this isn't the first one, print a thing in between
if first {
first = false;
} else if lookahead.is_some() {
// Just a regular comma
write!(f, ", ")?;
} else {
// The connecting word
write!(f, " {} ", self.word)?;
}
// Print the thing
write!(f, "{item}")?;
}
// Done
Ok(())
}
}