mirror of https://github.com/astral-sh/ruff
108 lines
3.2 KiB
Rust
108 lines
3.2 KiB
Rust
//! Implements helper functions for using vendored/cformat.rs
|
|
use std::convert::TryFrom;
|
|
use std::str::FromStr;
|
|
|
|
use rustc_hash::FxHashSet;
|
|
use rustpython_common::cformat::{
|
|
CFormatError, CFormatPart, CFormatPrecision, CFormatQuantity, CFormatSpec, CFormatString,
|
|
};
|
|
|
|
pub(crate) struct CFormatSummary {
|
|
pub starred: bool,
|
|
pub num_positional: usize,
|
|
pub keywords: FxHashSet<String>,
|
|
}
|
|
|
|
impl From<&CFormatString> for CFormatSummary {
|
|
fn from(format_string: &CFormatString) -> Self {
|
|
let mut starred = false;
|
|
let mut num_positional = 0;
|
|
let mut keywords = FxHashSet::default();
|
|
|
|
for format_part in format_string.iter() {
|
|
let CFormatPart::Spec(CFormatSpec {
|
|
ref mapping_key,
|
|
ref min_field_width,
|
|
ref precision,
|
|
..
|
|
}) = format_part.1 else
|
|
{
|
|
continue;
|
|
};
|
|
match mapping_key {
|
|
Some(k) => {
|
|
keywords.insert(k.clone());
|
|
}
|
|
None => {
|
|
num_positional += 1;
|
|
}
|
|
};
|
|
if min_field_width == &Some(CFormatQuantity::FromValuesTuple) {
|
|
num_positional += 1;
|
|
starred = true;
|
|
}
|
|
if precision == &Some(CFormatPrecision::Quantity(CFormatQuantity::FromValuesTuple)) {
|
|
num_positional += 1;
|
|
starred = true;
|
|
}
|
|
}
|
|
|
|
Self {
|
|
starred,
|
|
num_positional,
|
|
keywords,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<&str> for CFormatSummary {
|
|
type Error = CFormatError;
|
|
|
|
fn try_from(literal: &str) -> Result<Self, Self::Error> {
|
|
let format_string = CFormatString::from_str(literal)?;
|
|
Ok(Self::from(&format_string))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_cformat_summary() {
|
|
let literal = "%(foo)s %s %d %(bar)x";
|
|
|
|
let expected_positional = 2;
|
|
let expected_keywords = ["foo", "bar"].into_iter().map(String::from).collect();
|
|
|
|
let format_summary = CFormatSummary::try_from(literal).unwrap();
|
|
assert!(!format_summary.starred);
|
|
assert_eq!(format_summary.num_positional, expected_positional);
|
|
assert_eq!(format_summary.keywords, expected_keywords);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cformat_summary_starred() {
|
|
let format_summary1 = CFormatSummary::try_from("%*s %*d").unwrap();
|
|
assert!(format_summary1.starred);
|
|
assert_eq!(format_summary1.num_positional, 4);
|
|
|
|
let format_summary2 = CFormatSummary::try_from("%s %.*d").unwrap();
|
|
assert!(format_summary2.starred);
|
|
assert_eq!(format_summary2.num_positional, 3);
|
|
|
|
let format_summary3 = CFormatSummary::try_from("%s %*.*d").unwrap();
|
|
assert!(format_summary3.starred);
|
|
assert_eq!(format_summary3.num_positional, 4);
|
|
|
|
let format_summary4 = CFormatSummary::try_from("%s %1d").unwrap();
|
|
assert!(!format_summary4.starred);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cformat_summary_invalid() {
|
|
assert!(CFormatSummary::try_from("%").is_err());
|
|
assert!(CFormatSummary::try_from("%(foo).").is_err());
|
|
}
|
|
}
|