use crate::{
ibig::IBig,
radix::{self, Digit, DigitCase},
sign::Sign::{self, *},
ubig::UBig,
};
use core::fmt::{
self, Alignment, Binary, Debug, Display, Formatter, LowerHex, Octal, UpperHex, Write,
};
use digit_writer::DigitWriter;
mod digit_writer;
mod non_power_two;
mod power_two;
impl Display for UBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: Positive,
magnitude: self,
radix: 10,
prefix: "",
digit_case: DigitCase::NoLetters,
}
.fmt(f)
}
}
impl Debug for UBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl Binary for UBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: Positive,
magnitude: self,
radix: 2,
prefix: if f.alternate() { "0b" } else { "" },
digit_case: DigitCase::NoLetters,
}
.fmt(f)
}
}
impl Octal for UBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: Positive,
magnitude: self,
radix: 8,
prefix: if f.alternate() { "0o" } else { "" },
digit_case: DigitCase::NoLetters,
}
.fmt(f)
}
}
impl LowerHex for UBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: Positive,
magnitude: self,
radix: 16,
prefix: if f.alternate() { "0x" } else { "" },
digit_case: DigitCase::Lower,
}
.fmt(f)
}
}
impl UpperHex for UBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: Positive,
magnitude: self,
radix: 16,
prefix: if f.alternate() { "0x" } else { "" },
digit_case: DigitCase::Upper,
}
.fmt(f)
}
}
impl Display for IBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: self.sign(),
magnitude: self.magnitude(),
radix: 10,
prefix: "",
digit_case: DigitCase::NoLetters,
}
.fmt(f)
}
}
impl Debug for IBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl Binary for IBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: self.sign(),
magnitude: self.magnitude(),
radix: 2,
prefix: if f.alternate() { "0b" } else { "" },
digit_case: DigitCase::NoLetters,
}
.fmt(f)
}
}
impl Octal for IBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: self.sign(),
magnitude: self.magnitude(),
radix: 8,
prefix: if f.alternate() { "0o" } else { "" },
digit_case: DigitCase::NoLetters,
}
.fmt(f)
}
}
impl LowerHex for IBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: self.sign(),
magnitude: self.magnitude(),
radix: 16,
prefix: if f.alternate() { "0x" } else { "" },
digit_case: DigitCase::Lower,
}
.fmt(f)
}
}
impl UpperHex for IBig {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
InRadixFull {
sign: self.sign(),
magnitude: self.magnitude(),
radix: 16,
prefix: if f.alternate() { "0x" } else { "" },
digit_case: DigitCase::Upper,
}
.fmt(f)
}
}
impl UBig {
pub fn in_radix(&self, radix: u32) -> InRadix {
radix::check_radix_valid(radix);
InRadix {
sign: Positive,
magnitude: self,
radix,
}
}
}
impl IBig {
pub fn in_radix(&self, radix: u32) -> InRadix {
radix::check_radix_valid(radix);
InRadix {
sign: self.sign(),
magnitude: self.magnitude(),
radix,
}
}
}
pub struct InRadix<'a> {
sign: Sign,
magnitude: &'a UBig,
radix: Digit,
}
struct InRadixFull<'a> {
sign: Sign,
magnitude: &'a UBig,
radix: Digit,
prefix: &'static str,
digit_case: DigitCase,
}
impl Display for InRadix<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let digit_case = if self.radix <= 10 {
DigitCase::NoLetters
} else if f.alternate() {
DigitCase::Upper
} else {
DigitCase::Lower
};
InRadixFull {
sign: self.sign,
magnitude: self.magnitude,
radix: self.radix,
prefix: "",
digit_case,
}
.fmt(f)
}
}
impl InRadixFull<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.radix.is_power_of_two() {
self.fmt_power_two(f)
} else {
self.fmt_non_power_two(f)
}
}
fn format_prepared(
&self,
f: &mut Formatter,
prepared: &mut dyn PreparedForFormatting,
) -> fmt::Result {
let mut width = prepared.width();
let sign = if self.sign == Negative {
"-"
} else if f.sign_plus() {
"+"
} else {
""
};
width += sign.len() + self.prefix.len();
let mut write_digits = |f| {
let mut digit_writer = DigitWriter::new(f, self.digit_case);
prepared.write(&mut digit_writer)?;
digit_writer.flush()
};
match f.width() {
None => {
f.write_str(sign)?;
f.write_str(self.prefix)?;
write_digits(f)?
}
Some(min_width) => {
if width >= min_width {
f.write_str(sign)?;
f.write_str(self.prefix)?;
write_digits(f)?;
} else if f.sign_aware_zero_pad() {
f.write_str(sign)?;
f.write_str(self.prefix)?;
for _ in 0..min_width - width {
f.write_str("0")?;
}
write_digits(f)?;
} else {
let left = match f.align() {
Some(Alignment::Left) => 0,
Some(Alignment::Right) | None => min_width - width,
Some(Alignment::Center) => (min_width - width) / 2,
};
let fill = f.fill();
for _ in 0..left {
f.write_char(fill)?;
}
f.write_str(sign)?;
f.write_str(self.prefix)?;
write_digits(f)?;
for _ in left..min_width - width {
f.write_char(fill)?;
}
}
}
}
Ok(())
}
}
trait PreparedForFormatting {
fn width(&self) -> usize;
fn write(&mut self, digit_writer: &mut DigitWriter) -> fmt::Result;
}