pub(crate) use _string::make_module;
#[pymodule]
mod _string {
use crate::common::ascii;
use crate::{
builtins::{PyList, PyStrRef},
convert::ToPyException,
convert::ToPyObject,
PyObjectRef, PyResult, VirtualMachine,
};
use rustpython_format::{
FieldName, FieldNamePart, FieldType, FormatPart, FormatString, FromTemplate,
};
use std::mem;
fn create_format_part(
literal: String,
field_name: Option<String>,
format_spec: Option<String>,
conversion_spec: Option<char>,
vm: &VirtualMachine,
) -> PyObjectRef {
let tuple = (
literal,
field_name,
format_spec,
conversion_spec.map(|c| c.to_string()),
);
tuple.to_pyobject(vm)
}
#[pyfunction]
fn formatter_parser(text: PyStrRef, vm: &VirtualMachine) -> PyResult<PyList> {
let format_string =
FormatString::from_str(text.as_str()).map_err(|e| e.to_pyexception(vm))?;
let mut result = Vec::new();
let mut literal = String::new();
for part in format_string.format_parts {
match part {
FormatPart::Field {
field_name,
conversion_spec,
format_spec,
} => {
result.push(create_format_part(
mem::take(&mut literal),
Some(field_name),
Some(format_spec),
conversion_spec,
vm,
));
}
FormatPart::Literal(text) => literal.push_str(&text),
}
}
if !literal.is_empty() {
result.push(create_format_part(
mem::take(&mut literal),
None,
None,
None,
vm,
));
}
Ok(result.into())
}
#[pyfunction]
fn formatter_field_name_split(
text: PyStrRef,
vm: &VirtualMachine,
) -> PyResult<(PyObjectRef, PyList)> {
let field_name = FieldName::parse(text.as_str()).map_err(|e| e.to_pyexception(vm))?;
let first = match field_name.field_type {
FieldType::Auto => vm.ctx.new_str(ascii!("")).into(),
FieldType::Index(index) => index.to_pyobject(vm),
FieldType::Keyword(attribute) => attribute.to_pyobject(vm),
};
let rest = field_name
.parts
.iter()
.map(|p| match p {
FieldNamePart::Attribute(attribute) => (true, attribute).to_pyobject(vm),
FieldNamePart::StringIndex(index) => (false, index).to_pyobject(vm),
FieldNamePart::Index(index) => (false, *index).to_pyobject(vm),
})
.collect();
Ok((first, rest))
}
}