mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
* PyBytes.title should be ASCII-only. * Use icu_casemap over unicode-casing for titles `icu_casemap` is consistently maintained, official, and tracks the latest Unicode versions. RustPython is also using other `icu4x` crates, so using `icu_casemap` is more consistent. As with islower and isupper, tracking the latest Unicode version is important because character definitions shift over time which causes discrepancies between RustPython and CPython. This commit fixes title(). * Use icu_casemap for capitalize() I dropped unicode-casing because it's cleaner to use icu4x for everything. `icu4x` will also stay up to date whereas unicode-casing will need to be periodically updated with new Unicode tables. Dropping unicode-casing also removes some binary bloat due to the tables. `capitalize()` mimics CPython behavior more closely now as well. Notably, I implemented CPython's sigma edge case handler. * Match CPython's title() exactly
90 lines
2.3 KiB
Rust
90 lines
2.3 KiB
Rust
use core::fmt;
|
|
|
|
use rustpython_common::wtf8::{Wtf8, Wtf8Buf};
|
|
|
|
use crate::{
|
|
PyObjectRef, PyResult, VirtualMachine,
|
|
builtins::{PyStr, PyUtf8Str},
|
|
convert::{ToPyException, ToPyObject},
|
|
exceptions::cstring_error,
|
|
};
|
|
|
|
pub fn hash_iter<'a, I: IntoIterator<Item = &'a PyObjectRef>>(
|
|
iter: I,
|
|
vm: &VirtualMachine,
|
|
) -> PyResult<rustpython_common::hash::PyHash> {
|
|
vm.state.hash_secret.hash_iter(iter, |obj| obj.hash(vm))
|
|
}
|
|
|
|
impl ToPyObject for core::convert::Infallible {
|
|
fn to_pyobject(self, _vm: &VirtualMachine) -> PyObjectRef {
|
|
match self {}
|
|
}
|
|
}
|
|
|
|
pub trait ToCString: AsRef<Wtf8> {
|
|
fn to_cstring(&self, vm: &VirtualMachine) -> PyResult<alloc::ffi::CString> {
|
|
alloc::ffi::CString::new(self.as_ref().as_bytes()).map_err(|err| err.to_pyexception(vm))
|
|
}
|
|
fn ensure_no_nul(&self, vm: &VirtualMachine) -> PyResult<()> {
|
|
if self.as_ref().as_bytes().contains(&b'\0') {
|
|
Err(cstring_error(vm))
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl ToCString for &str {}
|
|
impl ToCString for PyStr {}
|
|
impl ToCString for PyUtf8Str {}
|
|
|
|
pub(crate) fn collection_repr<'a, I>(
|
|
class_name: Option<&str>,
|
|
prefix: &str,
|
|
suffix: &str,
|
|
iter: I,
|
|
vm: &VirtualMachine,
|
|
) -> PyResult<Wtf8Buf>
|
|
where
|
|
I: core::iter::Iterator<Item = &'a PyObjectRef>,
|
|
{
|
|
let mut repr = Wtf8Buf::new();
|
|
if let Some(name) = class_name {
|
|
repr.push_str(name);
|
|
repr.push_char('(');
|
|
}
|
|
repr.push_str(prefix);
|
|
{
|
|
let mut parts_iter = iter.map(|o| o.repr(vm));
|
|
let first = parts_iter
|
|
.next()
|
|
.transpose()?
|
|
.expect("this is not called for empty collection");
|
|
repr.push_wtf8(first.as_wtf8());
|
|
for part in parts_iter {
|
|
repr.push_str(", ");
|
|
repr.push_wtf8(part?.as_wtf8());
|
|
}
|
|
}
|
|
repr.push_str(suffix);
|
|
if class_name.is_some() {
|
|
repr.push_char(')');
|
|
}
|
|
|
|
Ok(repr)
|
|
}
|
|
|
|
/// Wrapper around a bytes vector that implements [`fmt::Write`].
|
|
///
|
|
/// # Safety
|
|
/// Don't assume the contents of the internal vector are valid UTF-8/WTF-8.
|
|
pub(crate) struct VecFmtWriter(pub Vec<u8>);
|
|
|
|
impl fmt::Write for VecFmtWriter {
|
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
self.0.extend(s.bytes());
|
|
Ok(())
|
|
}
|
|
}
|