mirror of
https://github.com/uutils/coreutils.git
synced 2025-12-23 08:47:37 +00:00
uucore: format: Make Formatter a generic
Using an associated type in Formatter trait was quite nice, but, in a follow-up change, we'd like to pass a _reference_ to the Float Formatter, while just passing i64/u64 as a value to the Int formatters. Associated type doesn't allow for that, so we turn it into a generic instead. This makes Format<> a bit more complicated though, as we need to specify both the Formatter, _and_ the type to be formatted.
This commit is contained in:
parent
2103646ff7
commit
69164688ad
4 changed files with 21 additions and 24 deletions
|
|
@ -12,7 +12,7 @@ use crate::csplit_error::CsplitError;
|
|||
/// format.
|
||||
pub struct SplitName {
|
||||
prefix: Vec<u8>,
|
||||
format: Format<UnsignedInt>,
|
||||
format: Format<UnsignedInt, u64>,
|
||||
}
|
||||
|
||||
impl SplitName {
|
||||
|
|
@ -52,7 +52,7 @@ impl SplitName {
|
|||
None => format!("%0{n_digits}u"),
|
||||
};
|
||||
|
||||
let format = match Format::<UnsignedInt>::parse(format_string) {
|
||||
let format = match Format::<UnsignedInt, u64>::parse(format_string) {
|
||||
Ok(format) => Ok(format),
|
||||
Err(FormatError::TooManySpecs(_)) => Err(CsplitError::SuffixFormatTooManyPercents),
|
||||
Err(_) => Err(CsplitError::SuffixFormatIncorrect),
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
let format = options
|
||||
.format
|
||||
.map(Format::<num_format::Float>::parse)
|
||||
.map(Format::<num_format::Float, f64>::parse)
|
||||
.transpose()?;
|
||||
|
||||
let result = print_seq(
|
||||
|
|
@ -258,7 +258,7 @@ fn print_seq(
|
|||
terminator: &str,
|
||||
pad: bool,
|
||||
padding: usize,
|
||||
format: Option<&Format<num_format::Float>>,
|
||||
format: Option<&Format<num_format::Float, f64>>,
|
||||
) -> std::io::Result<()> {
|
||||
let stdout = stdout().lock();
|
||||
let mut stdout = BufWriter::new(stdout);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
// spell-checker:ignore extendedbigdecimal
|
||||
|
||||
//! `printf`-style formatting
|
||||
//!
|
||||
|
|
@ -45,6 +46,7 @@ use std::{
|
|||
error::Error,
|
||||
fmt::Display,
|
||||
io::{stdout, Write},
|
||||
marker::PhantomData,
|
||||
ops::ControlFlow,
|
||||
};
|
||||
|
||||
|
|
@ -308,20 +310,21 @@ pub fn sprintf<'a>(
|
|||
Ok(writer)
|
||||
}
|
||||
|
||||
/// A parsed format for a single float value
|
||||
/// A parsed format for a single numerical value of type T
|
||||
///
|
||||
/// This is used by `seq`. It can be constructed with [`Format::parse`]
|
||||
/// This is used by `seq` and `csplit`. It can be constructed with [`Format::parse`]
|
||||
/// and can write a value with [`Format::fmt`].
|
||||
///
|
||||
/// It can only accept a single specification without any asterisk parameters.
|
||||
/// If it does get more specifications, it will return an error.
|
||||
pub struct Format<F: Formatter> {
|
||||
pub struct Format<F: Formatter<T>, T> {
|
||||
prefix: Vec<u8>,
|
||||
suffix: Vec<u8>,
|
||||
formatter: F,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<F: Formatter> Format<F> {
|
||||
impl<F: Formatter<T>, T> Format<F, T> {
|
||||
pub fn parse(format_string: impl AsRef<[u8]>) -> Result<Self, FormatError> {
|
||||
let mut iter = parse_spec_only(format_string.as_ref());
|
||||
|
||||
|
|
@ -362,10 +365,11 @@ impl<F: Formatter> Format<F> {
|
|||
prefix,
|
||||
suffix,
|
||||
formatter,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fmt(&self, mut w: impl Write, f: F::Input) -> std::io::Result<()> {
|
||||
pub fn fmt(&self, mut w: impl Write, f: T) -> std::io::Result<()> {
|
||||
w.write_all(&self.prefix)?;
|
||||
self.formatter.fmt(&mut w, f)?;
|
||||
w.write_all(&self.suffix)?;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@ use super::{
|
|||
FormatError,
|
||||
};
|
||||
|
||||
pub trait Formatter {
|
||||
type Input;
|
||||
fn fmt(&self, writer: impl Write, x: Self::Input) -> std::io::Result<()>;
|
||||
pub trait Formatter<T> {
|
||||
fn fmt(&self, writer: impl Write, x: T) -> std::io::Result<()>;
|
||||
fn try_from_spec(s: Spec) -> Result<Self, FormatError>
|
||||
where
|
||||
Self: Sized;
|
||||
|
|
@ -75,10 +74,8 @@ pub struct SignedInt {
|
|||
pub alignment: NumberAlignment,
|
||||
}
|
||||
|
||||
impl Formatter for SignedInt {
|
||||
type Input = i64;
|
||||
|
||||
fn fmt(&self, writer: impl Write, x: Self::Input) -> std::io::Result<()> {
|
||||
impl Formatter<i64> for SignedInt {
|
||||
fn fmt(&self, writer: impl Write, x: i64) -> std::io::Result<()> {
|
||||
let s = if self.precision > 0 {
|
||||
format!("{:0>width$}", x.abs(), width = self.precision)
|
||||
} else {
|
||||
|
|
@ -129,10 +126,8 @@ pub struct UnsignedInt {
|
|||
pub alignment: NumberAlignment,
|
||||
}
|
||||
|
||||
impl Formatter for UnsignedInt {
|
||||
type Input = u64;
|
||||
|
||||
fn fmt(&self, mut writer: impl Write, x: Self::Input) -> std::io::Result<()> {
|
||||
impl Formatter<u64> for UnsignedInt {
|
||||
fn fmt(&self, mut writer: impl Write, x: u64) -> std::io::Result<()> {
|
||||
let mut s = match self.variant {
|
||||
UnsignedIntVariant::Decimal => format!("{x}"),
|
||||
UnsignedIntVariant::Octal(_) => format!("{x:o}"),
|
||||
|
|
@ -236,10 +231,8 @@ impl Default for Float {
|
|||
}
|
||||
}
|
||||
|
||||
impl Formatter for Float {
|
||||
type Input = f64;
|
||||
|
||||
fn fmt(&self, writer: impl Write, f: Self::Input) -> std::io::Result<()> {
|
||||
impl Formatter<f64> for Float {
|
||||
fn fmt(&self, writer: impl Write, f: f64) -> std::io::Result<()> {
|
||||
let x = f.abs();
|
||||
let s = if x.is_finite() {
|
||||
match self.variant {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue