Remove unused runtime string formatting logic (#6624)

In https://github.com/astral-sh/ruff/pull/6616 we are adding support for
nested replacements in format specifiers which makes actually formatting
strings infeasible without a great deal of complexity. Since we're not
using these functions (they just exist for runtime use in RustPython),
we can just remove them.
This commit is contained in:
Zanie Blue 2023-08-16 12:38:33 -05:00 committed by GitHub
parent 0a5be74be3
commit 6253d8e2c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 4 additions and 949 deletions

View file

@ -1,15 +1,13 @@
//! Implementation of Printf-Style string formatting
//! as per the [Python Docs](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting).
use bitflags::bitflags;
use num_traits::Signed;
use std::{
cmp, fmt,
fmt,
iter::{Enumerate, Peekable},
str::FromStr,
};
use crate::{float, Case};
use num_bigint::{BigInt, Sign};
use crate::Case;
#[derive(Debug, PartialEq)]
pub enum CFormatErrorType {
@ -165,249 +163,6 @@ impl CFormatSpec {
format_char,
})
}
fn compute_fill_string(fill_char: char, fill_chars_needed: usize) -> String {
(0..fill_chars_needed)
.map(|_| fill_char)
.collect::<String>()
}
fn fill_string(
&self,
string: String,
fill_char: char,
num_prefix_chars: Option<usize>,
) -> String {
let mut num_chars = string.chars().count();
if let Some(num_prefix_chars) = num_prefix_chars {
num_chars += num_prefix_chars;
}
let num_chars = num_chars;
let width = match &self.min_field_width {
Some(CFormatQuantity::Amount(width)) => cmp::max(width, &num_chars),
_ => &num_chars,
};
let fill_chars_needed = width.saturating_sub(num_chars);
let fill_string = CFormatSpec::compute_fill_string(fill_char, fill_chars_needed);
if fill_string.is_empty() {
string
} else {
if self.flags.contains(CConversionFlags::LEFT_ADJUST) {
format!("{string}{fill_string}")
} else {
format!("{fill_string}{string}")
}
}
}
fn fill_string_with_precision(&self, string: String, fill_char: char) -> String {
let num_chars = string.chars().count();
let width = match &self.precision {
Some(CFormatPrecision::Quantity(CFormatQuantity::Amount(width))) => {
cmp::max(width, &num_chars)
}
_ => &num_chars,
};
let fill_chars_needed = width.saturating_sub(num_chars);
let fill_string = CFormatSpec::compute_fill_string(fill_char, fill_chars_needed);
if fill_string.is_empty() {
string
} else {
// Don't left-adjust if precision-filling: that will always be prepending 0s to %d
// arguments, the LEFT_ADJUST flag will be used by a later call to fill_string with
// the 0-filled string as the string param.
format!("{fill_string}{string}")
}
}
fn format_string_with_precision(
&self,
string: String,
precision: Option<&CFormatPrecision>,
) -> String {
// truncate if needed
let string = match precision {
Some(CFormatPrecision::Quantity(CFormatQuantity::Amount(precision)))
if string.chars().count() > *precision =>
{
string.chars().take(*precision).collect::<String>()
}
Some(CFormatPrecision::Dot) => {
// truncate to 0
String::new()
}
_ => string,
};
self.fill_string(string, ' ', None)
}
#[inline]
pub fn format_string(&self, string: String) -> String {
self.format_string_with_precision(string, self.precision.as_ref())
}
#[inline]
pub fn format_char(&self, ch: char) -> String {
self.format_string_with_precision(
ch.to_string(),
Some(&(CFormatQuantity::Amount(1).into())),
)
}
pub fn format_bytes(&self, bytes: &[u8]) -> Vec<u8> {
let bytes = if let Some(CFormatPrecision::Quantity(CFormatQuantity::Amount(precision))) =
self.precision
{
&bytes[..cmp::min(bytes.len(), precision)]
} else {
bytes
};
if let Some(CFormatQuantity::Amount(width)) = self.min_field_width {
let fill = cmp::max(0, width - bytes.len());
let mut v = Vec::with_capacity(bytes.len() + fill);
if self.flags.contains(CConversionFlags::LEFT_ADJUST) {
v.extend_from_slice(bytes);
v.append(&mut vec![b' '; fill]);
} else {
v.append(&mut vec![b' '; fill]);
v.extend_from_slice(bytes);
}
v
} else {
bytes.to_vec()
}
}
pub fn format_number(&self, num: &BigInt) -> String {
use CNumberType::{Decimal, Hex, Octal};
let magnitude = num.abs();
let prefix = if self.flags.contains(CConversionFlags::ALTERNATE_FORM) {
match self.format_type {
CFormatType::Number(Octal) => "0o",
CFormatType::Number(Hex(Case::Lower)) => "0x",
CFormatType::Number(Hex(Case::Upper)) => "0X",
_ => "",
}
} else {
""
};
let magnitude_string: String = match self.format_type {
CFormatType::Number(Decimal) => magnitude.to_str_radix(10),
CFormatType::Number(Octal) => magnitude.to_str_radix(8),
CFormatType::Number(Hex(Case::Lower)) => magnitude.to_str_radix(16),
CFormatType::Number(Hex(Case::Upper)) => {
let mut result = magnitude.to_str_radix(16);
result.make_ascii_uppercase();
result
}
_ => unreachable!(), // Should not happen because caller has to make sure that this is a number
};
let sign_string = match num.sign() {
Sign::Minus => "-",
_ => self.flags.sign_string(),
};
let padded_magnitude_string = self.fill_string_with_precision(magnitude_string, '0');
if self.flags.contains(CConversionFlags::ZERO_PAD) {
let fill_char = if self.flags.contains(CConversionFlags::LEFT_ADJUST) {
' ' // '-' overrides the '0' conversion if both are given
} else {
'0'
};
let signed_prefix = format!("{sign_string}{prefix}");
format!(
"{}{}",
signed_prefix,
self.fill_string(
padded_magnitude_string,
fill_char,
Some(signed_prefix.chars().count()),
),
)
} else {
self.fill_string(
format!("{sign_string}{prefix}{padded_magnitude_string}"),
' ',
None,
)
}
}
pub fn format_float(&self, num: f64) -> String {
let sign_string = if num.is_sign_negative() && !num.is_nan() {
"-"
} else {
self.flags.sign_string()
};
let precision = match &self.precision {
Some(CFormatPrecision::Quantity(quantity)) => match quantity {
CFormatQuantity::Amount(amount) => *amount,
CFormatQuantity::FromValuesTuple => 6,
},
Some(CFormatPrecision::Dot) => 0,
None => 6,
};
let magnitude_string = match &self.format_type {
CFormatType::Float(CFloatType::PointDecimal(case)) => {
let magnitude = num.abs();
float::format_fixed(
precision,
magnitude,
*case,
self.flags.contains(CConversionFlags::ALTERNATE_FORM),
)
}
CFormatType::Float(CFloatType::Exponent(case)) => {
let magnitude = num.abs();
float::format_exponent(
precision,
magnitude,
*case,
self.flags.contains(CConversionFlags::ALTERNATE_FORM),
)
}
CFormatType::Float(CFloatType::General(case)) => {
let precision = if precision == 0 { 1 } else { precision };
let magnitude = num.abs();
float::format_general(
precision,
magnitude,
*case,
self.flags.contains(CConversionFlags::ALTERNATE_FORM),
false,
)
}
_ => unreachable!(),
};
if self.flags.contains(CConversionFlags::ZERO_PAD) {
let fill_char = if self.flags.contains(CConversionFlags::LEFT_ADJUST) {
' '
} else {
'0'
};
format!(
"{}{}",
sign_string,
self.fill_string(
magnitude_string,
fill_char,
Some(sign_string.chars().count()),
)
)
} else {
self.fill_string(format!("{sign_string}{magnitude_string}"), ' ', None)
}
}
}
fn parse_spec_mapping_key<T, I>(iter: &mut ParseIter<I>) -> Result<Option<String>, ParsingError>
@ -741,38 +496,6 @@ impl CFormatString {
mod tests {
use super::*;
#[test]
fn test_fill_and_align() {
assert_eq!(
"%10s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("test".to_owned()),
" test".to_owned()
);
assert_eq!(
"%-10s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("test".to_owned()),
"test ".to_owned()
);
assert_eq!(
"%#10x"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(0x1337)),
" 0x1337".to_owned()
);
assert_eq!(
"%-#10x"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(0x1337)),
"0x1337 ".to_owned()
);
}
#[test]
fn test_parse_key() {
let expected = Ok(CFormatSpec {
@ -844,165 +567,6 @@ mod tests {
});
let parsed = "% 0 -+++###10d".parse::<CFormatSpec>();
assert_eq!(parsed, expected);
assert_eq!(
parsed.unwrap().format_number(&BigInt::from(12)),
"+12 ".to_owned()
);
}
#[test]
fn test_parse_and_format_string() {
assert_eq!(
"%5.4s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("Hello, World!".to_owned()),
" Hell".to_owned()
);
assert_eq!(
"%-5.4s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("Hello, World!".to_owned()),
"Hell ".to_owned()
);
assert_eq!(
"%.s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("Hello, World!".to_owned()),
String::new()
);
assert_eq!(
"%5.s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("Hello, World!".to_owned()),
" ".to_owned()
);
}
#[test]
fn test_parse_and_format_unicode_string() {
assert_eq!(
"%.2s"
.parse::<CFormatSpec>()
.unwrap()
.format_string("❤❤❤❤❤❤❤❤".to_owned()),
"❤❤".to_owned()
);
}
#[test]
fn test_parse_and_format_number() {
assert_eq!(
"%5d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(27)),
" 27".to_owned()
);
assert_eq!(
"%05d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(27)),
"00027".to_owned()
);
assert_eq!(
"%.5d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(27)),
"00027".to_owned()
);
assert_eq!(
"%+05d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(27)),
"+0027".to_owned()
);
assert_eq!(
"%-d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(-27)),
"-27".to_owned()
);
assert_eq!(
"% d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(27)),
" 27".to_owned()
);
assert_eq!(
"% d"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(-27)),
"-27".to_owned()
);
assert_eq!(
"%08x"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(0x1337)),
"00001337".to_owned()
);
assert_eq!(
"%#010x"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(0x1337)),
"0x00001337".to_owned()
);
assert_eq!(
"%-#010x"
.parse::<CFormatSpec>()
.unwrap()
.format_number(&BigInt::from(0x1337)),
"0x1337 ".to_owned()
);
}
#[test]
fn test_parse_and_format_float() {
assert_eq!(
"%f".parse::<CFormatSpec>().unwrap().format_float(1.2345),
"1.234500"
);
assert_eq!(
"%.2f".parse::<CFormatSpec>().unwrap().format_float(1.2345),
"1.23"
);
assert_eq!(
"%.f".parse::<CFormatSpec>().unwrap().format_float(1.2345),
"1"
);
assert_eq!(
"%+.f".parse::<CFormatSpec>().unwrap().format_float(1.2345),
"+1"
);
assert_eq!(
"%+f".parse::<CFormatSpec>().unwrap().format_float(1.2345),
"+1.234500"
);
assert_eq!(
"% f".parse::<CFormatSpec>().unwrap().format_float(1.2345),
" 1.234500"
);
assert_eq!(
"%f".parse::<CFormatSpec>().unwrap().format_float(-1.2345),
"-1.234500"
);
assert_eq!(
"%f".parse::<CFormatSpec>()
.unwrap()
.format_float(1.234_567_890_1),
"1.234568"
);
}
#[test]