diff --git a/common/src/lib.rs b/common/src/lib.rs index f6d7047442..7519f9d94a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,3 +4,4 @@ pub mod cell; pub mod float_ops; pub mod hash; pub mod rc; +pub mod str; diff --git a/common/src/str.rs b/common/src/str.rs new file mode 100644 index 0000000000..a89c25f49b --- /dev/null +++ b/common/src/str.rs @@ -0,0 +1,48 @@ +pub fn get_chars(s: &str, range: std::ops::Range) -> &str { + let mut chars = s.chars(); + for _ in 0..range.start { + let _ = chars.next(); + } + let start = chars.as_str(); + for _ in range { + let _ = chars.next(); + } + let end = chars.as_str(); + &start[..start.len() - end.len()] +} + +pub fn zfill(bytes: &[u8], width: usize) -> Vec { + if width <= bytes.len() { + bytes.to_vec() + } else { + let (sign, s) = match bytes.first() { + Some(_sign @ b'+') | Some(_sign @ b'-') => { + (unsafe { bytes.get_unchecked(..1) }, &bytes[1..]) + } + _ => (&b""[..], bytes), + }; + let mut filled = Vec::new(); + filled.extend_from_slice(sign); + filled.extend(std::iter::repeat(b'0').take(width - bytes.len())); + filled.extend_from_slice(s); + filled + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_chars() { + let s = "0123456789"; + assert_eq!(get_chars(s, 3..7), "3456"); + assert_eq!(get_chars(s, 3..7), &s[3..7]); + + let s = "0유니코드 문자열9"; + assert_eq!(get_chars(s, 3..7), "코드 문"); + + let s = "0😀😃😄😁😆😅😂🤣9"; + assert_eq!(get_chars(s, 3..7), "😄😁😆😅"); + } +} diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 896fa8b9d8..95fb403b76 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -14,10 +14,10 @@ mod decl { use rustpython_parser::parser; use super::to_ascii; + use crate::byteslike::PyBytesLike; use crate::exceptions::PyBaseExceptionRef; use crate::function::{single_or_tuple_any, Args, KwArgs, OptionalArg, PyFuncArgs}; use crate::obj::objbool::{self, IntoPyBool}; - use crate::obj::objbyteinner::PyByteInner; use crate::obj::objbytes::PyBytesRef; use crate::obj::objcode::PyCodeRef; use crate::obj::objdict::PyDictRef; @@ -554,18 +554,18 @@ mod decl { } #[pyfunction] - fn ord(string: Either, vm: &VirtualMachine) -> PyResult { + fn ord(string: Either, vm: &VirtualMachine) -> PyResult { match string { - Either::A(bytes) => { - let bytes_len = bytes.elements.len(); + Either::A(bytes) => bytes.with_ref(|bytes| { + let bytes_len = bytes.len(); if bytes_len != 1 { return Err(vm.new_type_error(format!( "ord() expected a character, but string of length {} found", bytes_len ))); } - Ok(u32::from(bytes.elements[0])) - } + Ok(u32::from(bytes[0])) + }), Either::B(string) => { let string = string.as_str(); let string_len = string.chars().count(); diff --git a/vm/src/obj/objbyteinner.rs b/vm/src/bytesinner.rs similarity index 87% rename from vm/src/obj/objbyteinner.rs rename to vm/src/bytesinner.rs index 4e5428d291..c344ab9b6a 100644 --- a/vm/src/obj/objbyteinner.rs +++ b/vm/src/bytesinner.rs @@ -3,53 +3,54 @@ use num_bigint::{BigInt, ToBigInt}; use num_traits::{One, Signed, ToPrimitive, Zero}; use std::ops::Range; -use super::objbytearray::{PyByteArray, PyByteArrayRef}; -use super::objbytes::{PyBytes, PyBytesRef}; -use super::objint::{self, PyInt, PyIntRef}; -use super::objlist::PyList; -use super::objmemory::PyMemoryView; -use super::objnone::PyNoneRef; -use super::objsequence::{PySliceableSequence, SequenceIndex}; -use super::objslice::PySliceRef; -use super::objstr::{self, PyString, PyStringRef}; -use super::pystr::{self, PyCommonString, PyCommonStringContainer, PyCommonStringWrapper}; +use crate::byteslike::PyBytesLike; use crate::function::{OptionalArg, OptionalOption}; +use crate::obj::objbytearray::PyByteArray; +use crate::obj::objbytes::PyBytes; +use crate::obj::objint::{self, PyInt, PyIntRef}; +use crate::obj::objlist::PyList; +use crate::obj::objmemory::PyMemoryView; +use crate::obj::objnone::PyNoneRef; +use crate::obj::objsequence::{PySliceableSequence, SequenceIndex}; +use crate::obj::objslice::PySliceRef; +use crate::obj::objstr::{self, PyString, PyStringRef}; use crate::pyobject::{ Either, PyComparisonValue, PyIterable, PyObjectRef, PyResult, TryFromObject, TypeProtocol, }; +use crate::pystr::{self, PyCommonString, PyCommonStringContainer, PyCommonStringWrapper}; use crate::vm::VirtualMachine; use rustpython_common::hash; #[derive(Debug, Default, Clone)] -pub struct PyByteInner { - pub elements: Vec, +pub struct PyBytesInner { + pub(crate) elements: Vec, } -impl From> for PyByteInner { - fn from(elements: Vec) -> PyByteInner { +impl From> for PyBytesInner { + fn from(elements: Vec) -> PyBytesInner { Self { elements } } } -impl TryFromObject for PyByteInner { +impl TryFromObject for PyBytesInner { fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { match_class!(match obj { - i @ PyBytes => Ok(PyByteInner { + i @ PyBytes => Ok(PyBytesInner { elements: i.get_value().to_vec() }), - j @ PyByteArray => Ok(PyByteInner { + j @ PyByteArray => Ok(PyBytesInner { elements: j.borrow_value().elements.to_vec() }), - k @ PyMemoryView => Ok(PyByteInner { - elements: k.try_value().unwrap() + k @ PyMemoryView => Ok(PyBytesInner { + elements: k.try_bytes(|v| v.to_vec()).unwrap() }), - l @ PyList => l.get_byte_inner(vm), + l @ PyList => l.to_byte_inner(vm), obj => { let iter = vm.get_method_or_type_error(obj.clone(), "__iter__", || { format!("a bytes-like object is required, not {}", obj.class()) })?; let iter = PyIterable::from_method(iter); - Ok(PyByteInner { + Ok(PyBytesInner { elements: iter.iter(vm)?.collect::>()?, }) } @@ -66,13 +67,13 @@ pub struct ByteInnerNewOptions { } impl ByteInnerNewOptions { - pub fn get_value(self, vm: &VirtualMachine) -> PyResult { + pub fn get_value(self, vm: &VirtualMachine) -> PyResult { // First handle bytes(string, encoding[, errors]) if let OptionalArg::Present(enc) = self.encoding { if let OptionalArg::Present(eval) = self.val_option { if let Ok(input) = eval.downcast::() { let bytes = objstr::encode_string(input, Some(enc), None, vm)?; - Ok(PyByteInner { + Ok(PyBytesInner { elements: bytes.get_value().to_vec(), }) } else { @@ -112,7 +113,7 @@ impl ByteInnerNewOptions { // TODO: only support this method in the bytes() constructor if let Some(bytes_method) = vm.get_method(obj.clone(), "__bytes__") { let bytes = vm.invoke(&bytes_method?, vec![])?; - return PyByteInner::try_from_object(vm, bytes); + return PyBytesInner::try_from_object(vm, bytes); } let elements = vm.extract_elements(&obj).map_err(|_| { vm.new_type_error(format!( @@ -139,7 +140,7 @@ impl ByteInnerNewOptions { Ok(vec![]) }; match value { - Ok(val) => Ok(PyByteInner { elements: val }), + Ok(val) => Ok(PyBytesInner { elements: val }), Err(err) => Err(err), } } @@ -149,7 +150,7 @@ impl ByteInnerNewOptions { #[derive(FromArgs)] pub struct ByteInnerFindOptions { #[pyarg(positional_only, optional = false)] - sub: Either, + sub: Either, #[pyarg(positional_only, default = "None")] start: Option, #[pyarg(positional_only, default = "None")] @@ -182,15 +183,20 @@ pub struct ByteInnerPaddingOptions { impl ByteInnerPaddingOptions { fn get_value(self, fn_name: &str, vm: &VirtualMachine) -> PyResult<(isize, u8)> { let fillchar = if let OptionalArg::Present(v) = self.fillchar { - match try_as_byte(v.clone()) { - Some(x) if x.len() == 1 => x[0], - _ => { - return Err(vm.new_type_error(format!( - "{}() argument 2 must be a byte string of length 1, not {}", - fn_name, &v - ))); + try_as_bytes(v.clone(), |bytes| { + if bytes.len() == 1 { + Some(bytes[0]) + } else { + None } - } + }) + .flatten() + .ok_or_else(|| { + vm.new_type_error(format!( + "{}() argument 2 must be a byte string of length 1, not {}", + fn_name, &v + )) + })? } else { b' ' // default is space }; @@ -202,9 +208,9 @@ impl ByteInnerPaddingOptions { #[derive(FromArgs)] pub struct ByteInnerTranslateOptions { #[pyarg(positional_only, optional = false)] - table: Either, + table: Either, #[pyarg(positional_or_keyword, optional = true)] - delete: OptionalArg, + delete: OptionalArg, } impl ByteInnerTranslateOptions { @@ -229,30 +235,10 @@ impl ByteInnerTranslateOptions { } } -pub type ByteInnerSplitOptions<'a> = pystr::SplitArgs<'a, PyByteInner, [u8], u8>; - -#[derive(FromArgs)] -pub struct ByteInnerSplitlinesOptions { - #[pyarg(positional_or_keyword, optional = true)] - keepends: OptionalArg, -} - -impl ByteInnerSplitlinesOptions { - pub fn get_value(self) -> bool { - match self.keepends.into_option() { - Some(x) => x, - None => false, - } - // if let OptionalArg::Present(value) = self.keepends { - // Ok(bool::try_from_object(vm, value)?) - // } else { - // Ok(false) - // } - } -} +pub type ByteInnerSplitOptions<'a> = pystr::SplitArgs<'a, PyBytesInner, [u8], u8>; #[allow(clippy::len_without_is_empty)] -impl PyByteInner { +impl PyBytesInner { pub fn repr(&self) -> String { let mut res = String::with_capacity(self.elements.len()); for i in self.elements.iter() { @@ -307,13 +293,13 @@ impl PyByteInner { hash::hash_value(&self.elements) } - pub fn add(&self, other: PyByteInner) -> Vec { + pub fn add(&self, other: PyBytesInner) -> Vec { self.elements.py_add(&other.elements) } pub fn contains( &self, - needle: Either, + needle: Either, vm: &VirtualMachine, ) -> PyResult { Ok(match needle { @@ -372,7 +358,7 @@ impl PyByteInner { .collect::>>()?) } _ => match_class!(match object { - i @ PyMemoryView => Ok(i.try_value().unwrap()), + i @ PyMemoryView => Ok(i.try_bytes(|v| v.to_vec()).unwrap()), _ => Err(vm.new_index_error( "can assign only bytes, buffers, or iterables of ints in range(0, 256)" .to_owned() @@ -671,7 +657,7 @@ impl PyByteInner { } #[inline] - fn pad( + fn _pad( &self, options: ByteInnerPaddingOptions, pad: fn(&[u8], usize, u8, usize) -> Vec, @@ -690,7 +676,7 @@ impl PyByteInner { options: ByteInnerPaddingOptions, vm: &VirtualMachine, ) -> PyResult> { - self.pad(options, PyCommonString::::py_center, vm) + self._pad(options, PyCommonString::::py_center, vm) } pub fn ljust( @@ -698,7 +684,7 @@ impl PyByteInner { options: ByteInnerPaddingOptions, vm: &VirtualMachine, ) -> PyResult> { - self.pad(options, PyCommonString::::py_ljust, vm) + self._pad(options, PyCommonString::::py_ljust, vm) } pub fn rjust( @@ -706,7 +692,7 @@ impl PyByteInner { options: ByteInnerPaddingOptions, vm: &VirtualMachine, ) -> PyResult> { - self.pad(options, PyCommonString::::py_rjust, vm) + self._pad(options, PyCommonString::::py_rjust, vm) } pub fn count(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult { @@ -718,7 +704,7 @@ impl PyByteInner { pub fn join( &self, - iterable: PyIterable, + iterable: PyIterable, vm: &VirtualMachine, ) -> PyResult> { let iter = iterable.iter(vm)?; @@ -739,7 +725,7 @@ impl PyByteInner { Ok(self.elements.py_find(&needle, range, find)) } - pub fn maketrans(from: PyByteInner, to: PyByteInner, vm: &VirtualMachine) -> PyResult { + pub fn maketrans(from: PyBytesInner, to: PyBytesInner, vm: &VirtualMachine) -> PyResult { let mut res = vec![]; for i in 0..=255 { @@ -777,7 +763,7 @@ impl PyByteInner { Ok(res) } - pub fn strip(&self, chars: OptionalOption) -> Vec { + pub fn strip(&self, chars: OptionalOption) -> Vec { self.elements .py_strip( chars, @@ -787,7 +773,7 @@ impl PyByteInner { .to_vec() } - pub fn lstrip(&self, chars: OptionalOption) -> Vec { + pub fn lstrip(&self, chars: OptionalOption) -> Vec { self.elements .py_strip( chars, @@ -797,7 +783,7 @@ impl PyByteInner { .to_vec() } - pub fn rstrip(&self, chars: OptionalOption) -> Vec { + pub fn rstrip(&self, chars: OptionalOption) -> Vec { self.elements .py_strip( chars, @@ -808,7 +794,7 @@ impl PyByteInner { } // new in Python 3.9 - pub fn removeprefix(&self, prefix: PyByteInner) -> Vec { + pub fn removeprefix(&self, prefix: PyBytesInner) -> Vec { self.elements .py_removeprefix(&prefix.elements, prefix.elements.len(), |s, p| { s.starts_with(p) @@ -817,7 +803,7 @@ impl PyByteInner { } // new in Python 3.9 - pub fn removesuffix(&self, suffix: PyByteInner) -> Vec { + pub fn removesuffix(&self, suffix: PyBytesInner) -> Vec { self.elements .py_removesuffix(&suffix.elements, suffix.elements.len(), |s, p| { s.ends_with(p) @@ -866,40 +852,26 @@ impl PyByteInner { pub fn partition( &self, - sub: &PyByteInner, + sub: &PyBytesInner, vm: &VirtualMachine, ) -> PyResult<(Vec, bool, Vec)> { - if sub.elements.is_empty() { - return Err(vm.new_value_error("empty separator".to_owned())); - } - - let mut sp = self.elements.splitn_str(2, &sub.elements); - let front = sp.next().unwrap().to_vec(); - let (has_mid, back) = if let Some(back) = sp.next() { - (true, back.to_vec()) - } else { - (false, Vec::new()) - }; - Ok((front, has_mid, back)) + self.elements.py_partition( + &sub.elements, + || self.elements.splitn_str(2, &sub.elements), + vm, + ) } pub fn rpartition( &self, - sub: &PyByteInner, + sub: &PyBytesInner, vm: &VirtualMachine, ) -> PyResult<(Vec, bool, Vec)> { - if sub.elements.is_empty() { - return Err(vm.new_value_error("empty separator".to_owned())); - } - - let mut sp = self.elements.rsplitn_str(2, &sub.elements); - let back = sp.next().unwrap().to_vec(); - let (has_mid, front) = if let Some(front) = sp.next() { - (true, front.to_vec()) - } else { - (false, Vec::new()) - }; - Ok((front, has_mid, back)) + self.elements.py_partition( + &sub.elements, + || self.elements.rsplitn_str(2, &sub.elements), + vm, + ) } pub fn expandtabs(&self, options: pystr::ExpandTabsArgs) -> Vec { @@ -946,7 +918,7 @@ impl PyByteInner { } // len(self)>=1, from="", len(to)>=1, maxcount>=1 - fn replace_interleave(&self, to: PyByteInner, maxcount: Option) -> Vec { + fn replace_interleave(&self, to: PyBytesInner, maxcount: Option) -> Vec { let place_count = self.elements.len() + 1; let count = maxcount.map_or(place_count, |v| std::cmp::min(v, place_count)) - 1; let capacity = self.elements.len() + count * to.len(); @@ -961,7 +933,7 @@ impl PyByteInner { result } - fn replace_delete(&self, from: PyByteInner, maxcount: Option) -> Vec { + fn replace_delete(&self, from: PyBytesInner, maxcount: Option) -> Vec { let count = count_substring(self.elements.as_slice(), from.elements.as_slice(), maxcount); if count == 0 { // no matches @@ -988,8 +960,8 @@ impl PyByteInner { pub fn replace_in_place( &self, - from: PyByteInner, - to: PyByteInner, + from: PyBytesInner, + to: PyBytesInner, maxcount: Option, ) -> Vec { let len = from.len(); @@ -1020,8 +992,8 @@ impl PyByteInner { fn replace_general( &self, - from: PyByteInner, - to: PyByteInner, + from: PyBytesInner, + to: PyBytesInner, maxcount: Option, vm: &VirtualMachine, ) -> PyResult> { @@ -1061,8 +1033,8 @@ impl PyByteInner { pub fn replace( &self, - from: PyByteInner, - to: PyByteInner, + from: PyBytesInner, + to: PyBytesInner, maxcount: OptionalArg, vm: &VirtualMachine, ) -> PyResult> { @@ -1162,10 +1134,13 @@ impl PyByteInner { } } -pub fn try_as_byte(obj: PyObjectRef) -> Option> { +pub fn try_as_bytes(obj: PyObjectRef, f: F) -> Option +where + F: Fn(&[u8]) -> R, +{ match_class!(match obj { - i @ PyBytes => Some(i.get_value().to_vec()), - j @ PyByteArray => Some(j.borrow_value().elements.to_vec()), + i @ PyBytes => Some(f(i.get_value())), + j @ PyByteArray => Some(f(&j.borrow_value().elements)), _ => None, }) } @@ -1191,42 +1166,7 @@ pub trait ByteOr: ToPrimitive { impl ByteOr for BigInt {} -pub enum PyBytesLike { - Bytes(PyBytesRef), - Bytearray(PyByteArrayRef), -} - -impl TryFromObject for PyBytesLike { - fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { - match_class!(match obj { - b @ PyBytes => Ok(PyBytesLike::Bytes(b)), - b @ PyByteArray => Ok(PyBytesLike::Bytearray(b)), - obj => Err(vm.new_type_error(format!( - "a bytes-like object is required, not {}", - obj.class() - ))), - }) - } -} - -impl PyBytesLike { - pub fn to_cow(&self) -> std::borrow::Cow<[u8]> { - match self { - PyBytesLike::Bytes(b) => b.get_value().into(), - PyBytesLike::Bytearray(b) => b.borrow_value().elements.clone().into(), - } - } - - #[inline] - pub fn with_ref(&self, f: impl FnOnce(&[u8]) -> R) -> R { - match self { - PyBytesLike::Bytes(b) => f(b.get_value()), - PyBytesLike::Bytearray(b) => f(&b.borrow_value().elements), - } - } -} - -impl PyCommonStringWrapper<[u8]> for PyByteInner { +impl PyCommonStringWrapper<[u8]> for PyBytesInner { fn as_ref(&self) -> &[u8] { &self.elements } diff --git a/vm/src/byteslike.rs b/vm/src/byteslike.rs new file mode 100644 index 0000000000..1c1a7c252e --- /dev/null +++ b/vm/src/byteslike.rs @@ -0,0 +1,40 @@ +use crate::obj::objbytearray::{PyByteArray, PyByteArrayRef}; +use crate::obj::objbytes::{PyBytes, PyBytesRef}; +use crate::pyobject::PyObjectRef; +use crate::pyobject::{PyResult, TryFromObject, TypeProtocol}; +use crate::vm::VirtualMachine; + +pub enum PyBytesLike { + Bytes(PyBytesRef), + Bytearray(PyByteArrayRef), +} + +impl TryFromObject for PyBytesLike { + fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { + match_class!(match obj { + b @ PyBytes => Ok(PyBytesLike::Bytes(b)), + b @ PyByteArray => Ok(PyBytesLike::Bytearray(b)), + obj => Err(vm.new_type_error(format!( + "a bytes-like object is required, not {}", + obj.class() + ))), + }) + } +} + +impl PyBytesLike { + pub fn to_cow(&self) -> std::borrow::Cow<[u8]> { + match self { + PyBytesLike::Bytes(b) => b.get_value().into(), + PyBytesLike::Bytearray(b) => b.borrow_value().elements.clone().into(), + } + } + + #[inline] + pub fn with_ref(&self, f: impl FnOnce(&[u8]) -> R) -> R { + match self { + PyBytesLike::Bytes(b) => f(b.get_value()), + PyBytesLike::Bytearray(b) => f(&b.borrow_value().elements), + } + } +} diff --git a/vm/src/dictdatatype.rs b/vm/src/dictdatatype.rs index 6116af321a..d18863884e 100644 --- a/vm/src/dictdatatype.rs +++ b/vm/src/dictdatatype.rs @@ -20,18 +20,18 @@ type HashIndex = hash::PyHash; type EntryIndex = usize; pub struct Dict { - inner: PyRwLock>, + inner: PyRwLock>, } -struct InnerDict { +struct DictInner { size: usize, indices: HashMap, entries: Vec>>, } -impl Clone for InnerDict { +impl Clone for DictInner { fn clone(&self) -> Self { - InnerDict { + DictInner { size: self.size, indices: self.indices.clone(), entries: self.entries.clone(), @@ -50,7 +50,7 @@ impl Clone for Dict { impl Default for Dict { fn default() -> Self { Dict { - inner: PyRwLock::new(InnerDict { + inner: PyRwLock::new(DictInner { size: 0, indices: HashMap::new(), entries: Vec::new(), @@ -82,11 +82,11 @@ pub struct DictSize { } impl Dict { - fn borrow_value(&self) -> PyRwLockReadGuard<'_, InnerDict> { + fn borrow_value(&self) -> PyRwLockReadGuard<'_, DictInner> { self.inner.read() } - fn borrow_value_mut(&self) -> PyRwLockWriteGuard<'_, InnerDict> { + fn borrow_value_mut(&self) -> PyRwLockWriteGuard<'_, DictInner> { self.inner.write() } diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 014515018f..246e6f80e7 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -55,6 +55,8 @@ macro_rules! py_compile_bytecode { pub mod macros; mod builtins; +mod bytesinner; +pub mod byteslike; pub mod cformat; mod dictdatatype; #[cfg(feature = "rustpython-compiler")] @@ -68,6 +70,7 @@ pub mod import; pub mod obj; pub mod py_serde; pub mod pyobject; +mod pystr; pub mod readline; pub mod scope; mod sequence; diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index f11d0eccfe..b06f4d47f1 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -4,7 +4,6 @@ pub mod objasyncgenerator; pub mod objbool; pub mod objbuiltinfunc; pub mod objbytearray; -pub mod objbyteinner; pub mod objbytes; pub mod objclassmethod; pub mod objcode; @@ -44,4 +43,3 @@ pub mod objtype; pub mod objweakproxy; pub mod objweakref; pub mod objzip; -mod pystr; diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 1be33d24f8..49fad92239 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -1,25 +1,25 @@ //! Implementation of the python bytearray object. -use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; use bstr::ByteSlice; use crossbeam_utils::atomic::AtomicCell; use num_traits::cast::ToPrimitive; use std::mem::size_of; -use super::objbyteinner::{ - ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, - ByteInnerTranslateOptions, ByteOr, PyByteInner, -}; use super::objint::PyIntRef; use super::objiter; use super::objsequence::SequenceIndex; use super::objstr::{PyString, PyStringRef}; use super::objtype::PyClassRef; -use super::pystr::{self, PyCommonString}; +use crate::bytesinner::{ + ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, + ByteInnerTranslateOptions, ByteOr, PyBytesInner, +}; +use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; use crate::function::{OptionalArg, OptionalOption}; use crate::pyobject::{ Either, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, }; +use crate::pystr::{self, PyCommonString}; use crate::vm::VirtualMachine; /// "bytearray(iterable_of_ints) -> bytearray\n\ @@ -36,7 +36,7 @@ use crate::vm::VirtualMachine; #[pyclass(name = "bytearray")] #[derive(Debug)] pub struct PyByteArray { - inner: PyRwLock, + inner: PyRwLock, } pub type PyByteArrayRef = PyRef; @@ -44,21 +44,21 @@ pub type PyByteArrayRef = PyRef; impl PyByteArray { pub fn new(data: Vec) -> Self { PyByteArray { - inner: PyRwLock::new(PyByteInner { elements: data }), + inner: PyRwLock::new(PyBytesInner { elements: data }), } } - fn from_inner(inner: PyByteInner) -> Self { + fn from_inner(inner: PyBytesInner) -> Self { PyByteArray { inner: PyRwLock::new(inner), } } - pub fn borrow_value(&self) -> PyRwLockReadGuard<'_, PyByteInner> { + pub fn borrow_value(&self) -> PyRwLockReadGuard<'_, PyBytesInner> { self.inner.read() } - pub fn borrow_value_mut(&self) -> PyRwLockWriteGuard<'_, PyByteInner> { + pub fn borrow_value_mut(&self) -> PyRwLockWriteGuard<'_, PyBytesInner> { self.inner.write() } } @@ -80,7 +80,7 @@ pub(crate) fn init(context: &PyContext) { PyByteArray::extend_class(context, &context.types.bytearray_type); let bytearray_type = &context.types.bytearray_type; extend_class!(context, bytearray_type, { - "maketrans" => context.new_method(PyByteInner::maketrans), + "maketrans" => context.new_method(PyBytesInner::maketrans), }); PyByteArrayIterator::extend_class(context, &context.types.bytearrayiterator_type); @@ -152,7 +152,7 @@ impl PyByteArray { #[pymethod(name = "__add__")] fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult { - if let Ok(other) = PyByteInner::try_from_object(vm, other) { + if let Ok(other) = PyBytesInner::try_from_object(vm, other) { Ok(vm.ctx.new_bytearray(self.borrow_value().add(other))) } else { Ok(vm.ctx.not_implemented()) @@ -162,7 +162,7 @@ impl PyByteArray { #[pymethod(name = "__contains__")] fn contains( &self, - needle: Either, + needle: Either, vm: &VirtualMachine, ) -> PyResult { self.borrow_value().contains(needle, vm) @@ -250,7 +250,7 @@ impl PyByteArray { #[pymethod] fn fromhex(string: PyStringRef, vm: &VirtualMachine) -> PyResult { - Ok(PyByteInner::fromhex(string.as_str(), vm)?.into()) + Ok(PyBytesInner::fromhex(string.as_str(), vm)?.into()) } #[pymethod(name = "center")] @@ -286,7 +286,7 @@ impl PyByteArray { } #[pymethod(name = "join")] - fn join(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult { + fn join(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult { Ok(self.borrow_value().join(iter, vm)?.into()) } @@ -296,7 +296,7 @@ impl PyByteArray { options, "endswith", "bytes", - |s, x: &PyByteInner| s.ends_with(&x.elements[..]), + |s, x: &PyBytesInner| s.ends_with(&x.elements[..]), vm, ) } @@ -311,7 +311,7 @@ impl PyByteArray { options, "startswith", "bytes", - |s, x: &PyByteInner| s.starts_with(&x.elements[..]), + |s, x: &PyBytesInner| s.starts_with(&x.elements[..]), vm, ) } @@ -365,17 +365,17 @@ impl PyByteArray { } #[pymethod(name = "strip")] - fn strip(&self, chars: OptionalOption) -> PyByteArray { + fn strip(&self, chars: OptionalOption) -> PyByteArray { self.borrow_value().strip(chars).into() } #[pymethod(name = "lstrip")] - fn lstrip(&self, chars: OptionalOption) -> PyByteArray { + fn lstrip(&self, chars: OptionalOption) -> PyByteArray { self.borrow_value().lstrip(chars).into() } #[pymethod(name = "rstrip")] - fn rstrip(&self, chars: OptionalOption) -> PyByteArray { + fn rstrip(&self, chars: OptionalOption) -> PyByteArray { self.borrow_value().rstrip(chars).into() } @@ -387,7 +387,7 @@ impl PyByteArray { /// If the bytearray starts with the prefix string, return string[len(prefix):] /// Otherwise, return a copy of the original bytearray. #[pymethod(name = "removeprefix")] - fn removeprefix(&self, prefix: PyByteInner) -> PyByteArray { + fn removeprefix(&self, prefix: PyBytesInner) -> PyByteArray { self.borrow_value().removeprefix(prefix).into() } @@ -399,7 +399,7 @@ impl PyByteArray { /// If the bytearray ends with the suffix string, return string[:len(suffix)] /// Otherwise, return a copy of the original bytearray. #[pymethod(name = "removesuffix")] - fn removesuffix(&self, suffix: PyByteInner) -> PyByteArray { + fn removesuffix(&self, suffix: PyBytesInner) -> PyByteArray { self.borrow_value().removesuffix(suffix).to_vec().into() } @@ -416,9 +416,9 @@ impl PyByteArray { } #[pymethod(name = "partition")] - fn partition(&self, sep: PyByteInner, vm: &VirtualMachine) -> PyResult { + fn partition(&self, sep: PyBytesInner, vm: &VirtualMachine) -> PyResult { // sep ALWAYS converted to bytearray even it's bytes or memoryview - // so its ok to accept PyByteInner + // so its ok to accept PyBytesInner let value = self.borrow_value(); let (front, has_mid, back) = value.partition(&sep, vm)?; Ok(vm.ctx.new_tuple(vec![ @@ -430,9 +430,9 @@ impl PyByteArray { } #[pymethod(name = "rpartition")] - fn rpartition(&self, sep: PyByteInner, vm: &VirtualMachine) -> PyResult { + fn rpartition(&self, sep: PyBytesInner, vm: &VirtualMachine) -> PyResult { let value = self.borrow_value(); - let (front, has_mid, back) = value.rpartition(&sep, vm)?; + let (back, has_mid, front) = value.rpartition(&sep, vm)?; Ok(vm.ctx.new_tuple(vec![ vm.ctx.new_bytearray(front.to_vec()), vm.ctx @@ -462,8 +462,8 @@ impl PyByteArray { #[pymethod(name = "replace")] fn replace( &self, - old: PyByteInner, - new: PyByteInner, + old: PyBytesInner, + new: PyBytesInner, count: OptionalArg, vm: &VirtualMachine, ) -> PyResult { diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 529ae1674c..d1c0d87abd 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -3,16 +3,15 @@ use crossbeam_utils::atomic::AtomicCell; use std::mem::size_of; use std::ops::Deref; -use super::objbyteinner::{ - ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, - ByteInnerTranslateOptions, PyByteInner, -}; use super::objint::PyIntRef; use super::objiter; use super::objsequence::SequenceIndex; use super::objstr::{PyString, PyStringRef}; use super::objtype::PyClassRef; -use super::pystr::{self, PyCommonString}; +use crate::bytesinner::{ + ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions, ByteInnerSplitOptions, + ByteInnerTranslateOptions, PyBytesInner, +}; use crate::function::{OptionalArg, OptionalOption}; use crate::pyobject::{ Either, IntoPyObject, @@ -20,6 +19,7 @@ use crate::pyobject::{ PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol, }; +use crate::pystr::{self, PyCommonString}; use crate::vm::VirtualMachine; use rustpython_common::hash::PyHash; @@ -35,7 +35,7 @@ use rustpython_common::hash::PyHash; #[pyclass(name = "bytes")] #[derive(Clone, Debug)] pub struct PyBytes { - inner: PyByteInner, + inner: PyBytesInner, } pub type PyBytesRef = PyRef; @@ -43,7 +43,7 @@ pub type PyBytesRef = PyRef; impl PyBytes { pub fn new(elements: Vec) -> Self { PyBytes { - inner: PyByteInner { elements }, + inner: PyBytesInner { elements }, } } @@ -82,7 +82,7 @@ pub(crate) fn init(context: &PyContext) { PyBytes::extend_class(context, &context.types.bytes_type); let bytes_type = &context.types.bytes_type; extend_class!(context, bytes_type, { - "maketrans" => context.new_method(PyByteInner::maketrans), + "maketrans" => context.new_method(PyBytesInner::maketrans), }); PyBytesIterator::extend_class(context, &context.types.bytesiterator_type); } @@ -152,7 +152,7 @@ impl PyBytes { #[pymethod(name = "__add__")] fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmaticValue { - if let Ok(other) = PyByteInner::try_from_object(vm, other) { + if let Ok(other) = PyBytesInner::try_from_object(vm, other) { Implemented(self.inner.add(other).into()) } else { NotImplemented @@ -162,7 +162,7 @@ impl PyBytes { #[pymethod(name = "__contains__")] fn contains( &self, - needle: Either, + needle: Either, vm: &VirtualMachine, ) -> PyResult { self.inner.contains(needle, vm) @@ -240,7 +240,7 @@ impl PyBytes { #[pymethod] fn fromhex(string: PyStringRef, vm: &VirtualMachine) -> PyResult { - Ok(PyByteInner::fromhex(string.as_str(), vm)?.into()) + Ok(PyBytesInner::fromhex(string.as_str(), vm)?.into()) } #[pymethod(name = "center")] @@ -264,7 +264,7 @@ impl PyBytes { } #[pymethod(name = "join")] - fn join(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult { + fn join(&self, iter: PyIterable, vm: &VirtualMachine) -> PyResult { Ok(self.inner.join(iter, vm)?.into()) } @@ -274,7 +274,7 @@ impl PyBytes { options, "endswith", "bytes", - |s, x: &PyByteInner| s.ends_with(&x.elements[..]), + |s, x: &PyBytesInner| s.ends_with(&x.elements[..]), vm, ) } @@ -289,7 +289,7 @@ impl PyBytes { options, "startswith", "bytes", - |s, x: &PyByteInner| s.starts_with(&x.elements[..]), + |s, x: &PyBytesInner| s.starts_with(&x.elements[..]), vm, ) } @@ -328,17 +328,17 @@ impl PyBytes { } #[pymethod(name = "strip")] - fn strip(&self, chars: OptionalOption) -> PyBytes { + fn strip(&self, chars: OptionalOption) -> PyBytes { self.inner.strip(chars).into() } #[pymethod(name = "lstrip")] - fn lstrip(&self, chars: OptionalOption) -> PyBytes { + fn lstrip(&self, chars: OptionalOption) -> PyBytes { self.inner.lstrip(chars).into() } #[pymethod(name = "rstrip")] - fn rstrip(&self, chars: OptionalOption) -> PyBytes { + fn rstrip(&self, chars: OptionalOption) -> PyBytes { self.inner.rstrip(chars).into() } @@ -350,7 +350,7 @@ impl PyBytes { /// If the bytes starts with the prefix string, return string[len(prefix):] /// Otherwise, return a copy of the original bytes. #[pymethod(name = "removeprefix")] - fn removeprefix(&self, prefix: PyByteInner) -> PyBytes { + fn removeprefix(&self, prefix: PyBytesInner) -> PyBytes { self.inner.removeprefix(prefix).into() } @@ -362,7 +362,7 @@ impl PyBytes { /// If the bytes ends with the suffix string, return string[:len(suffix)] /// Otherwise, return a copy of the original bytes. #[pymethod(name = "removesuffix")] - fn removesuffix(&self, suffix: PyByteInner) -> PyBytes { + fn removesuffix(&self, suffix: PyBytesInner) -> PyBytes { self.inner.removesuffix(suffix).into() } @@ -380,7 +380,7 @@ impl PyBytes { #[pymethod(name = "partition")] fn partition(&self, sep: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let sub = PyByteInner::try_from_object(vm, sep.clone())?; + let sub = PyBytesInner::try_from_object(vm, sep.clone())?; let (front, has_mid, back) = self.inner.partition(&sub, vm)?; Ok(vm.ctx.new_tuple(vec![ vm.ctx.new_bytes(front), @@ -395,8 +395,8 @@ impl PyBytes { #[pymethod(name = "rpartition")] fn rpartition(&self, sep: PyObjectRef, vm: &VirtualMachine) -> PyResult { - let sub = PyByteInner::try_from_object(vm, sep.clone())?; - let (front, has_mid, back) = self.inner.rpartition(&sub, vm)?; + let sub = PyBytesInner::try_from_object(vm, sep.clone())?; + let (back, has_mid, front) = self.inner.rpartition(&sub, vm)?; Ok(vm.ctx.new_tuple(vec![ vm.ctx.new_bytes(front), if has_mid { @@ -429,8 +429,8 @@ impl PyBytes { #[pymethod(name = "replace")] fn replace( &self, - old: PyByteInner, - new: PyByteInner, + old: PyBytesInner, + new: PyBytesInner, count: OptionalArg, vm: &VirtualMachine, ) -> PyResult { diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index e011f23c0b..f846c9f76a 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -7,12 +7,12 @@ use num_traits::{Num, One, Pow, Signed, ToPrimitive, Zero}; use super::objbool::IntoPyBool; use super::objbytearray::PyByteArray; -use super::objbyteinner::PyByteInner; use super::objbytes::PyBytes; use super::objfloat; use super::objmemory::PyMemoryView; use super::objstr::{PyString, PyStringRef}; use super::objtype::{self, PyClassRef}; +use crate::bytesinner::PyBytesInner; use crate::format::FormatSpec; use crate::function::{OptionalArg, PyFuncArgs}; use crate::pyobject::{ @@ -714,7 +714,7 @@ impl IntOptions { #[derive(FromArgs)] struct IntFromByteArgs { #[pyarg(positional_or_keyword)] - bytes: PyByteInner, + bytes: PyBytesInner, #[pyarg(positional_or_keyword)] byteorder: PyStringRef, #[pyarg(keyword_only, optional = true)] @@ -759,8 +759,7 @@ pub fn to_int(vm: &VirtualMachine, obj: &PyObjectRef, base: &BigInt) -> PyResult } memoryview @ PyMemoryView => { // TODO: proper error handling instead of `unwrap()` - let bytes = memoryview.try_value().unwrap(); - bytes_to_int(&bytes) + memoryview.try_bytes(|bytes| bytes_to_int(&bytes)).unwrap() } array @ PyArray => { let bytes = array.tobytes(); diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 6c48f3b6cb..90e9629e6c 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -2,18 +2,18 @@ use std::fmt; use std::mem::size_of; use std::ops::{DerefMut, Range}; -use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; use crossbeam_utils::atomic::AtomicCell; use num_bigint::{BigInt, ToBigInt}; use num_traits::{One, Signed, ToPrimitive, Zero}; use super::objbool; -use super::objbyteinner; use super::objint::PyIntRef; use super::objiter; use super::objsequence::{get_item, get_pos, get_slice_range, SequenceIndex}; use super::objslice::PySliceRef; use super::objtype::PyClassRef; +use crate::bytesinner; +use crate::common::cell::{PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard}; use crate::function::OptionalArg; use crate::pyobject::{ IdProtocol, PyArithmaticValue::*, PyClassImpl, PyComparisonValue, PyContext, PyIterable, @@ -62,10 +62,7 @@ impl PyList { self.elements.write() } - pub(crate) fn get_byte_inner( - &self, - vm: &VirtualMachine, - ) -> PyResult { + pub(crate) fn to_byte_inner(&self, vm: &VirtualMachine) -> PyResult { let mut elements = Vec::::with_capacity(self.borrow_elements().len()); for elem in self.borrow_elements().iter() { match PyIntRef::try_from_object(vm, elem.clone()) { @@ -83,7 +80,7 @@ impl PyList { } } } - Ok(objbyteinner::PyByteInner { elements }) + Ok(bytesinner::PyBytesInner { elements }) } } diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index afdfbb1319..acdf09ad3f 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -1,5 +1,5 @@ -use super::objbyteinner::try_as_byte; use super::objtype::{issubclass, PyClassRef}; +use crate::bytesinner::try_as_bytes; use crate::pyobject::{ ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; @@ -16,8 +16,11 @@ pub type PyMemoryViewRef = PyRef; #[pyimpl] impl PyMemoryView { - pub fn try_value(&self) -> Option> { - try_as_byte(self.obj_ref.clone()) + pub fn try_bytes(&self, f: F) -> Option + where + F: Fn(&[u8]) -> R, + { + try_as_bytes(self.obj_ref.clone(), f) } #[pyslot] diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index dd905416c6..21b57976eb 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -19,15 +19,15 @@ use super::objiter; use super::objnone::PyNone; use super::objsequence::{PySliceableSequence, SequenceIndex}; use super::objtype::{self, PyClassRef}; -use super::pystr::{ - self, adjust_indices, PyCommonString, PyCommonStringContainer, PyCommonStringWrapper, -}; use crate::format::{FormatParseError, FormatSpec, FormatString, FromTemplate}; use crate::function::{OptionalArg, OptionalOption, PyFuncArgs}; use crate::pyobject::{ IdProtocol, IntoPyObject, ItemProtocol, PyClassImpl, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TryIntoRef, TypeProtocol, }; +use crate::pystr::{ + self, adjust_indices, PyCommonString, PyCommonStringContainer, PyCommonStringWrapper, +}; use crate::vm::VirtualMachine; use rustpython_common::hash; @@ -253,7 +253,7 @@ impl PyString { } } SequenceIndex::Slice(slice) => { - let string = self.value.get_slice_items(vm, &slice)?; + let string = self.get_slice_items(vm, &slice)?; Ok(vm.new_str(string)) } } @@ -813,43 +813,35 @@ impl PyString { } #[pymethod] - fn partition(&self, sub: PyStringRef, vm: &VirtualMachine) -> PyResult { - if sub.value.is_empty() { - return Err(vm.new_value_error("empty separator".to_owned())); - } - let mut sp = self.value.splitn(2, &sub.value); - let front = sp.next().unwrap(); - let elems = if let Some(back) = sp.next() { - [front, &sub.value, back] - } else { - [front, "", ""] - }; - Ok(vm.ctx.new_tuple( - elems - .iter() - .map(|&s| vm.ctx.new_str(s.to_owned())) - .collect(), - )) + fn partition(&self, sep: PyStringRef, vm: &VirtualMachine) -> PyResult { + let (front, has_mid, back) = + self.value + .py_partition(&sep.value, || self.value.splitn(2, &sep.value), vm)?; + Ok(vm.ctx.new_tuple(vec![ + vm.ctx.new_str(front), + if has_mid { + sep.into_object() + } else { + vm.ctx.new_str("") + }, + vm.ctx.new_str(back), + ])) } #[pymethod] - fn rpartition(&self, sub: PyStringRef, vm: &VirtualMachine) -> PyResult { - if sub.value.is_empty() { - return Err(vm.new_value_error("empty separator".to_owned())); - } - let mut sp = self.value.rsplitn(2, &sub.value); - let back = sp.next().unwrap(); - let elems = if let Some(front) = sp.next() { - [front, &sub.value, back] - } else { - ["", "", back] - }; - Ok(vm.ctx.new_tuple( - elems - .iter() - .map(|&s| vm.ctx.new_str(s.to_owned())) - .collect(), - )) + fn rpartition(&self, sep: PyStringRef, vm: &VirtualMachine) -> PyResult { + let (back, has_mid, front) = + self.value + .py_partition(&sep.value, || self.value.rsplitn(2, &sep.value), vm)?; + Ok(vm.ctx.new_tuple(vec![ + vm.ctx.new_str(front), + if has_mid { + sep.into_object() + } else { + vm.ctx.new_str("") + }, + vm.ctx.new_str(back), + ])) } /// Return `true` if the sequence is ASCII titlecase and the sequence is not @@ -895,26 +887,22 @@ impl PyString { unsafe { String::from_utf8_unchecked(self.value.py_zfill(width)) } } - fn get_fill_char(fillchar: OptionalArg, vm: &VirtualMachine) -> PyResult { - match fillchar { - OptionalArg::Present(ref s) => s.value.chars().exactly_one().map_err(|_| { - vm.new_type_error( - "The fill character must be exactly one character long".to_owned(), - ) - }), - OptionalArg::Missing => Ok(' '), - } - } - #[inline] - fn pad( + fn _pad( &self, width: isize, fillchar: OptionalArg, pad: fn(&str, usize, char, usize) -> String, vm: &VirtualMachine, ) -> PyResult { - let fillchar = Self::get_fill_char(fillchar, vm)?; + let fillchar = match fillchar { + OptionalArg::Present(ref s) => s.value.chars().exactly_one().map_err(|_| { + vm.new_type_error( + "The fill character must be exactly one character long".to_owned(), + ) + }), + OptionalArg::Missing => Ok(' '), + }?; Ok(if self.len() as isize >= width { String::from(&self.value) } else { @@ -929,7 +917,7 @@ impl PyString { fillchar: OptionalArg, vm: &VirtualMachine, ) -> PyResult { - self.pad(width, fillchar, PyCommonString::::py_center, vm) + self._pad(width, fillchar, PyCommonString::::py_center, vm) } #[pymethod] @@ -939,7 +927,7 @@ impl PyString { fillchar: OptionalArg, vm: &VirtualMachine, ) -> PyResult { - self.pad(width, fillchar, PyCommonString::::py_ljust, vm) + self._pad(width, fillchar, PyCommonString::::py_ljust, vm) } #[pymethod] @@ -949,7 +937,7 @@ impl PyString { fillchar: OptionalArg, vm: &VirtualMachine, ) -> PyResult { - self.pad(width, fillchar, PyCommonString::::py_rjust, vm) + self._pad(width, fillchar, PyCommonString::::py_rjust, vm) } #[pymethod] @@ -1206,20 +1194,21 @@ pub fn borrow_value(obj: &PyObjectRef) -> &str { &obj.payload::().unwrap().value } -impl PySliceableSequence for str { +impl PySliceableSequence for PyString { type Sliced = String; fn do_slice(&self, range: Range) -> Self::Sliced { - self.chars() + self.value + .chars() .skip(range.start) .take(range.end - range.start) .collect() } fn do_slice_reverse(&self, range: Range) -> Self::Sliced { - let count = self.chars().count(); - - self.chars() + let count = self.len(); + self.value + .chars() .rev() .skip(count - range.end) .take(range.end - range.start) @@ -1227,7 +1216,8 @@ impl PySliceableSequence for str { } fn do_stepped_slice(&self, range: Range, step: usize) -> Self::Sliced { - self.chars() + self.value + .chars() .skip(range.start) .take(range.end - range.start) .step_by(step) @@ -1235,9 +1225,9 @@ impl PySliceableSequence for str { } fn do_stepped_slice_reverse(&self, range: Range, step: usize) -> Self::Sliced { - let count = self.chars().count(); - - self.chars() + let count = self.len(); + self.value + .chars() .rev() .skip(count - range.end) .take(range.end - range.start) @@ -1246,15 +1236,15 @@ impl PySliceableSequence for str { } fn empty() -> Self::Sliced { - String::default() + String::new() } fn len(&self) -> usize { - self.chars().count() + self.len() } fn is_empty(&self) -> bool { - self.is_empty() + self.value.is_empty() } } @@ -1406,16 +1396,7 @@ impl<'s> PyCommonString<'s, char> for str { } fn get_chars<'a>(&'a self, range: std::ops::Range) -> &'a Self { - let mut chars = self.chars(); - for _ in 0..range.start { - let _ = chars.next(); - } - let start = chars.as_str(); - for _ in range { - let _ = chars.next(); - } - let end = chars.as_str(); - &start[..start.len() - end.len()] + rustpython_common::str::get_chars(self, range) } fn is_empty(&self) -> bool { diff --git a/vm/src/obj/pystr.rs b/vm/src/pystr.rs similarity index 94% rename from vm/src/obj/pystr.rs rename to vm/src/pystr.rs index 3b37d4c9e6..8749348886 100644 --- a/vm/src/obj/pystr.rs +++ b/vm/src/pystr.rs @@ -325,6 +325,30 @@ where Ok(joined) } + fn py_partition<'a, F, S>( + &'a self, + sub: &Self, + split: F, + vm: &VirtualMachine, + ) -> PyResult<(Self::Container, bool, Self::Container)> + where + F: Fn() -> S, + S: std::iter::Iterator, + { + if sub.is_empty() { + return Err(vm.new_value_error("empty separator".to_owned())); + } + + let mut sp = split(); + let front = sp.next().unwrap().to_container(); + let (has_mid, back) = if let Some(back) = sp.next() { + (true, back.to_container()) + } else { + (false, Self::Container::new()) + }; + Ok((front, has_mid, back)) + } + fn py_removeprefix( &self, prefix: &Self::Container, @@ -393,23 +417,8 @@ where } fn py_zfill(&self, width: isize) -> Vec { - let bytes = self.as_bytes(); let width = width.to_usize().unwrap_or(0); - if width <= bytes.len() { - bytes.to_vec() - } else { - let (sign, s) = match bytes.first() { - Some(_sign @ b'+') | Some(_sign @ b'-') => { - (unsafe { bytes.get_unchecked(..1) }, &bytes[1..]) - } - _ => (&b""[..], bytes), - }; - let mut filled = Vec::new(); - filled.extend_from_slice(sign); - filled.extend(std::iter::repeat(b'0').take(width - bytes.len())); - filled.extend_from_slice(s); - filled - } + rustpython_common::str::zfill(self.as_bytes(), width) } fn py_iscase(&'s self, is_case: F, is_opposite: G) -> bool diff --git a/vm/src/stdlib/binascii.rs b/vm/src/stdlib/binascii.rs index 9803463e83..c8b1733219 100644 --- a/vm/src/stdlib/binascii.rs +++ b/vm/src/stdlib/binascii.rs @@ -2,9 +2,9 @@ pub(crate) use decl::make_module; #[pymodule(name = "binascii")] mod decl { + use crate::byteslike::PyBytesLike; use crate::function::OptionalArg; use crate::obj::objbytearray::{PyByteArray, PyByteArrayRef}; - use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objbytes::{PyBytes, PyBytesRef}; use crate::obj::objstr::{PyString, PyStringRef}; use crate::pyobject::{PyObjectRef, PyResult, TryFromObject, TypeProtocol}; diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 743e9955f0..226011e324 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -7,12 +7,12 @@ use std::io::{self, prelude::*, Cursor, SeekFrom}; use crossbeam_utils::atomic::AtomicCell; use num_traits::ToPrimitive; +use crate::byteslike::PyBytesLike; use crate::common::cell::{PyRwLock, PyRwLockWriteGuard}; use crate::exceptions::PyBaseExceptionRef; use crate::function::{Args, KwArgs, OptionalArg, OptionalOption, PyFuncArgs}; use crate::obj::objbool; use crate::obj::objbytearray::PyByteArray; -use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objbytes::PyBytesRef; use crate::obj::objint; use crate::obj::objiter; diff --git a/vm/src/stdlib/multiprocessing.rs b/vm/src/stdlib/multiprocessing.rs index 64580dc312..f948030f0f 100644 --- a/vm/src/stdlib/multiprocessing.rs +++ b/vm/src/stdlib/multiprocessing.rs @@ -1,5 +1,5 @@ #[allow(unused_imports)] -use crate::obj::objbyteinner::PyBytesLike; +use crate::byteslike::PyBytesLike; #[allow(unused_imports)] use crate::pyobject::{PyObjectRef, PyResult}; use crate::VirtualMachine; diff --git a/vm/src/stdlib/operator.rs b/vm/src/stdlib/operator.rs index 11606cfe87..b386892bf3 100644 --- a/vm/src/stdlib/operator.rs +++ b/vm/src/stdlib/operator.rs @@ -1,5 +1,5 @@ +use crate::byteslike::PyBytesLike; use crate::function::OptionalArg; -use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objstr::PyStringRef; use crate::obj::{objiter, objtype}; use crate::pyobject::{Either, PyObjectRef, PyResult, TypeProtocol}; diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 746e98d48b..81af1ae606 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -25,10 +25,10 @@ use std::os::unix::io::RawFd; use std::os::windows::io::RawHandle; use super::errno::errors; +use crate::byteslike::PyBytesLike; use crate::common::cell::PyRwLock; use crate::exceptions::PyBaseExceptionRef; use crate::function::{IntoPyNativeFunc, OptionalArg, PyFuncArgs}; -use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objbytes::{PyBytes, PyBytesRef}; use crate::obj::objdict::PyDictRef; use crate::obj::objint::{PyInt, PyIntRef}; diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs index ad423d083e..8238c4d641 100644 --- a/vm/src/stdlib/socket.rs +++ b/vm/src/stdlib/socket.rs @@ -13,10 +13,10 @@ use socket2::{Domain, Protocol, Socket, Type as SocketType}; use super::os::convert_io_error; #[cfg(unix)] use super::os::convert_nix_error; +use crate::byteslike::PyBytesLike; use crate::exceptions::PyBaseExceptionRef; use crate::function::{OptionalArg, PyFuncArgs}; use crate::obj::objbytearray::PyByteArrayRef; -use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objbytes::PyBytesRef; use crate::obj::objstr::{PyString, PyStringRef}; use crate::obj::objtuple::PyTupleRef; diff --git a/vm/src/stdlib/ssl.rs b/vm/src/stdlib/ssl.rs index 3386df8cef..0263f748c4 100644 --- a/vm/src/stdlib/ssl.rs +++ b/vm/src/stdlib/ssl.rs @@ -1,8 +1,8 @@ use super::socket::PySocketRef; +use crate::byteslike::PyBytesLike; use crate::exceptions::PyBaseExceptionRef; use crate::function::OptionalArg; use crate::obj::objbytearray::PyByteArrayRef; -use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objstr::PyStringRef; use crate::obj::{objtype::PyClassRef, objweakref::PyWeak}; use crate::pyobject::{ diff --git a/vm/src/stdlib/zlib.rs b/vm/src/stdlib/zlib.rs index 43feb1cc56..a95cc81b47 100644 --- a/vm/src/stdlib/zlib.rs +++ b/vm/src/stdlib/zlib.rs @@ -1,7 +1,7 @@ +use crate::byteslike::PyBytesLike; use crate::common::cell::PyMutex; use crate::exceptions::PyBaseExceptionRef; use crate::function::OptionalArg; -use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objbytes::{PyBytes, PyBytesRef}; use crate::obj::objtype::PyClassRef; use crate::pyobject::{PyClassImpl, PyObjectRef, PyResult, PyValue}; diff --git a/wasm/lib/src/convert.rs b/wasm/lib/src/convert.rs index d48aab27cb..8d114b9ac4 100644 --- a/wasm/lib/src/convert.rs +++ b/wasm/lib/src/convert.rs @@ -6,9 +6,10 @@ use wasm_bindgen::{closure::Closure, prelude::*, JsCast}; use rustpython_compiler::error::{CompileError, CompileErrorType}; use rustpython_parser::error::ParseErrorType; +use rustpython_vm::byteslike::PyBytesLike; use rustpython_vm::exceptions::PyBaseExceptionRef; use rustpython_vm::function::PyFuncArgs; -use rustpython_vm::obj::{objbyteinner::PyBytesLike, objtype}; +use rustpython_vm::obj::objtype; use rustpython_vm::pyobject::{ItemProtocol, PyObjectRef, PyResult, PyValue, TryFromObject}; use rustpython_vm::VirtualMachine; use rustpython_vm::{exceptions, py_serde};