printf: support precision for integers

This commit is contained in:
Terts Diepraam 2023-11-17 14:42:52 +01:00
parent f83e0d1b04
commit f3da0817a5
2 changed files with 38 additions and 4 deletions

View file

@ -63,6 +63,7 @@ pub enum NumberAlignment {
pub struct SignedInt { pub struct SignedInt {
pub width: usize, pub width: usize,
pub precision: usize,
pub positive_sign: PositiveSign, pub positive_sign: PositiveSign,
pub alignment: NumberAlignment, pub alignment: NumberAlignment,
} }
@ -79,16 +80,19 @@ impl Formatter for SignedInt {
}?; }?;
} }
let s = format!("{:0width$}", x, width = self.precision);
match self.alignment { match self.alignment {
NumberAlignment::Left => write!(writer, "{x:<width$}", width = self.width), NumberAlignment::Left => write!(writer, "{s:<width$}", width = self.width),
NumberAlignment::RightSpace => write!(writer, "{x:>width$}", width = self.width), NumberAlignment::RightSpace => write!(writer, "{s:>width$}", width = self.width),
NumberAlignment::RightZero => write!(writer, "{x:0>width$}", width = self.width), NumberAlignment::RightZero => write!(writer, "{s:0>width$}", width = self.width),
} }
} }
fn try_from_spec(s: Spec) -> Result<Self, FormatError> { fn try_from_spec(s: Spec) -> Result<Self, FormatError> {
let Spec::SignedInt { let Spec::SignedInt {
width, width,
precision,
positive_sign, positive_sign,
alignment, alignment,
} = s } = s
@ -102,8 +106,15 @@ impl Formatter for SignedInt {
Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError), Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError),
}; };
let precision = match precision {
Some(CanAsterisk::Fixed(x)) => x,
None => 0,
Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError),
};
Ok(Self { Ok(Self {
width, width,
precision,
positive_sign, positive_sign,
alignment, alignment,
}) })
@ -113,6 +124,7 @@ impl Formatter for SignedInt {
pub struct UnsignedInt { pub struct UnsignedInt {
pub variant: UnsignedIntVariant, pub variant: UnsignedIntVariant,
pub width: usize, pub width: usize,
pub precision: usize,
pub alignment: NumberAlignment, pub alignment: NumberAlignment,
} }
@ -120,7 +132,7 @@ impl Formatter for UnsignedInt {
type Input = u64; type Input = u64;
fn fmt(&self, mut writer: impl Write, x: Self::Input) -> std::io::Result<()> { fn fmt(&self, mut writer: impl Write, x: Self::Input) -> std::io::Result<()> {
let s = match self.variant { let mut s = match self.variant {
UnsignedIntVariant::Decimal => format!("{x}"), UnsignedIntVariant::Decimal => format!("{x}"),
UnsignedIntVariant::Octal(Prefix::No) => format!("{x:o}"), UnsignedIntVariant::Octal(Prefix::No) => format!("{x:o}"),
UnsignedIntVariant::Octal(Prefix::Yes) => format!("{x:#o}"), UnsignedIntVariant::Octal(Prefix::Yes) => format!("{x:#o}"),
@ -138,6 +150,10 @@ impl Formatter for UnsignedInt {
} }
}; };
if self.precision > s.len() {
s = format!("{:0width$}", s, width = self.precision)
}
match self.alignment { match self.alignment {
NumberAlignment::Left => write!(writer, "{s:<width$}", width = self.width), NumberAlignment::Left => write!(writer, "{s:<width$}", width = self.width),
NumberAlignment::RightSpace => write!(writer, "{s:>width$}", width = self.width), NumberAlignment::RightSpace => write!(writer, "{s:>width$}", width = self.width),
@ -149,6 +165,7 @@ impl Formatter for UnsignedInt {
let Spec::UnsignedInt { let Spec::UnsignedInt {
variant, variant,
width, width,
precision,
alignment, alignment,
} = s } = s
else { else {
@ -161,8 +178,15 @@ impl Formatter for UnsignedInt {
Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError), Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError),
}; };
let precision = match precision {
Some(CanAsterisk::Fixed(x)) => x,
None => 0,
Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError),
};
Ok(Self { Ok(Self {
width, width,
precision,
variant, variant,
alignment, alignment,
}) })

View file

@ -22,12 +22,14 @@ pub enum Spec {
}, },
SignedInt { SignedInt {
width: Option<CanAsterisk<usize>>, width: Option<CanAsterisk<usize>>,
precision: Option<CanAsterisk<usize>>,
positive_sign: PositiveSign, positive_sign: PositiveSign,
alignment: NumberAlignment, alignment: NumberAlignment,
}, },
UnsignedInt { UnsignedInt {
variant: UnsignedIntVariant, variant: UnsignedIntVariant,
width: Option<CanAsterisk<usize>>, width: Option<CanAsterisk<usize>>,
precision: Option<CanAsterisk<usize>>,
alignment: NumberAlignment, alignment: NumberAlignment,
}, },
Float { Float {
@ -167,6 +169,7 @@ impl Spec {
}, },
b'd' | b'i' => Spec::SignedInt { b'd' | b'i' => Spec::SignedInt {
width, width,
precision,
alignment: match (minus, zero) { alignment: match (minus, zero) {
(true, _) => NumberAlignment::Left, (true, _) => NumberAlignment::Left,
(false, true) => NumberAlignment::RightZero, (false, true) => NumberAlignment::RightZero,
@ -197,6 +200,7 @@ impl Spec {
}; };
Spec::UnsignedInt { Spec::UnsignedInt {
variant, variant,
precision,
width, width,
alignment, alignment,
} }
@ -282,10 +286,12 @@ impl Spec {
} }
&Spec::SignedInt { &Spec::SignedInt {
width, width,
precision,
positive_sign, positive_sign,
alignment, alignment,
} => { } => {
let width = resolve_asterisk(width, &mut args)?.unwrap_or(0); let width = resolve_asterisk(width, &mut args)?.unwrap_or(0);
let precision = resolve_asterisk(precision, &mut args)?.unwrap_or(0);
let arg = next_arg(&mut args)?; let arg = next_arg(&mut args)?;
let Some(i) = arg.get_i64() else { let Some(i) = arg.get_i64() else {
@ -294,6 +300,7 @@ impl Spec {
num_format::SignedInt { num_format::SignedInt {
width, width,
precision,
positive_sign, positive_sign,
alignment, alignment,
} }
@ -303,9 +310,11 @@ impl Spec {
&Spec::UnsignedInt { &Spec::UnsignedInt {
variant, variant,
width, width,
precision,
alignment, alignment,
} => { } => {
let width = resolve_asterisk(width, &mut args)?.unwrap_or(0); let width = resolve_asterisk(width, &mut args)?.unwrap_or(0);
let precision = resolve_asterisk(precision, &mut args)?.unwrap_or(0);
let arg = next_arg(args)?; let arg = next_arg(args)?;
let Some(i) = arg.get_u64() else { let Some(i) = arg.get_u64() else {
@ -314,6 +323,7 @@ impl Spec {
num_format::UnsignedInt { num_format::UnsignedInt {
variant, variant,
precision,
width, width,
alignment, alignment,
} }