From 2d01cffbf95190ff84944f00742a03ec35d240fd Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 25 Jul 2020 04:35:42 +0900 Subject: [PATCH 01/12] common::str::get_chars with test --- common/src/lib.rs | 1 + common/src/str.rs | 30 ++++++++++++++++++++++++++++++ vm/src/obj/objstr.rs | 11 +---------- 3 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 common/src/str.rs 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..7dbc870a35 --- /dev/null +++ b/common/src/str.rs @@ -0,0 +1,30 @@ +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()] +} + +#[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/obj/objstr.rs b/vm/src/obj/objstr.rs index dd905416c6..357da1bf64 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -1406,16 +1406,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 { From 8ea113608b965e532db5436786d3a8d3d84fb27d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 07:32:48 +0900 Subject: [PATCH 02/12] zfill to common --- common/src/str.rs | 18 ++++++++++++++++++ vm/src/obj/pystr.rs | 17 +---------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/common/src/str.rs b/common/src/str.rs index 7dbc870a35..a89c25f49b 100644 --- a/common/src/str.rs +++ b/common/src/str.rs @@ -11,6 +11,24 @@ pub fn get_chars(s: &str, range: std::ops::Range) -> &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::*; diff --git a/vm/src/obj/pystr.rs b/vm/src/obj/pystr.rs index 3b37d4c9e6..93ecf4de66 100644 --- a/vm/src/obj/pystr.rs +++ b/vm/src/obj/pystr.rs @@ -393,23 +393,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 From e420db65fe73eeb12387de8ae45251ec2884f983 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 25 Jul 2020 04:42:36 +0900 Subject: [PATCH 03/12] PySliceableSequence for PyString reuse len cache --- vm/src/obj/objstr.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 357da1bf64..33a1f7f49b 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -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)) } } @@ -1206,20 +1206,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 +1228,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 +1237,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 +1248,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() } } From 6d26cfa20a379513279ef2c4eba498153ec5366f Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 25 Jul 2020 04:50:32 +0900 Subject: [PATCH 04/12] Clean up str/bytes pad to be prefixed with _ and embed get_fillchar --- vm/src/obj/objbyteinner.rs | 8 ++++---- vm/src/obj/objstr.rs | 28 ++++++++++++---------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/vm/src/obj/objbyteinner.rs b/vm/src/obj/objbyteinner.rs index 4e5428d291..aded4afefa 100644 --- a/vm/src/obj/objbyteinner.rs +++ b/vm/src/obj/objbyteinner.rs @@ -671,7 +671,7 @@ impl PyByteInner { } #[inline] - fn pad( + fn _pad( &self, options: ByteInnerPaddingOptions, pad: fn(&[u8], usize, u8, usize) -> Vec, @@ -690,7 +690,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 +698,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 +706,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 { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 33a1f7f49b..51ecd136d9 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -895,26 +895,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 +925,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 +935,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 +945,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] From 58bfd1d2216f6d3979454141497864268f8d1bcf Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 25 Jul 2020 05:58:32 +0900 Subject: [PATCH 05/12] {str,bytes}.partition into pystr --- vm/src/obj/objbytearray.rs | 2 +- vm/src/obj/objbyteinner.rs | 34 +++++++-------------- vm/src/obj/objbytes.rs | 2 +- vm/src/obj/objstr.rs | 60 +++++++++++++++++--------------------- vm/src/obj/pystr.rs | 24 +++++++++++++++ 5 files changed, 62 insertions(+), 60 deletions(-) diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 1be33d24f8..b6c176893f 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -432,7 +432,7 @@ impl PyByteArray { #[pymethod(name = "rpartition")] fn rpartition(&self, sep: PyByteInner, 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 diff --git a/vm/src/obj/objbyteinner.rs b/vm/src/obj/objbyteinner.rs index aded4afefa..8076801f2f 100644 --- a/vm/src/obj/objbyteinner.rs +++ b/vm/src/obj/objbyteinner.rs @@ -869,18 +869,11 @@ impl PyByteInner { sub: &PyByteInner, 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( @@ -888,18 +881,11 @@ impl PyByteInner { sub: &PyByteInner, 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 { diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 529ae1674c..0bdba5868b 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -396,7 +396,7 @@ 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 (back, has_mid, front) = self.inner.rpartition(&sub, vm)?; Ok(vm.ctx.new_tuple(vec![ vm.ctx.new_bytes(front), if has_mid { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 51ecd136d9..58d1bdb9c3 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -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 diff --git a/vm/src/obj/pystr.rs b/vm/src/obj/pystr.rs index 93ecf4de66..8749348886 100644 --- a/vm/src/obj/pystr.rs +++ b/vm/src/obj/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, From aaf95bb7fb22a299400d1971ef8d10d7ac9270a1 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 07:49:37 +0900 Subject: [PATCH 06/12] Remove unused ByteInnerSplitlinesOptions --- vm/src/obj/objbyteinner.rs | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/vm/src/obj/objbyteinner.rs b/vm/src/obj/objbyteinner.rs index 8076801f2f..10c13620e4 100644 --- a/vm/src/obj/objbyteinner.rs +++ b/vm/src/obj/objbyteinner.rs @@ -231,26 +231,6 @@ 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) - // } - } -} - #[allow(clippy::len_without_is_empty)] impl PyByteInner { pub fn repr(&self) -> String { From 50757499e552bb84dcca41537e4600a2452b9939 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 07:52:51 +0900 Subject: [PATCH 07/12] InnerDict -> DictInner for naming convention --- vm/src/dictdatatype.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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() } From 84b5475d4c2642882f1bd38d0acbaa6690ad5e7f Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 08:04:47 +0900 Subject: [PATCH 08/12] obj::objbyteinner::PyByteInner -> bytesinner::PyBytesInner --- vm/src/builtins.rs | 4 +- vm/src/{obj/objbyteinner.rs => bytesinner.rs} | 130 +++++++----------- vm/src/byteslike.rs | 40 ++++++ vm/src/lib.rs | 2 + vm/src/obj/mod.rs | 3 +- vm/src/obj/objbytearray.rs | 52 +++---- vm/src/obj/objbytes.rs | 44 +++--- vm/src/obj/objint.rs | 4 +- vm/src/obj/objlist.rs | 11 +- vm/src/obj/objmemory.rs | 2 +- vm/src/stdlib/binascii.rs | 2 +- vm/src/stdlib/io.rs | 2 +- vm/src/stdlib/multiprocessing.rs | 2 +- vm/src/stdlib/operator.rs | 2 +- vm/src/stdlib/os.rs | 2 +- vm/src/stdlib/socket.rs | 2 +- vm/src/stdlib/ssl.rs | 2 +- vm/src/stdlib/zlib.rs | 2 +- wasm/lib/src/convert.rs | 3 +- 19 files changed, 158 insertions(+), 153 deletions(-) rename vm/src/{obj/objbyteinner.rs => bytesinner.rs} (92%) create mode 100644 vm/src/byteslike.rs diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 896fa8b9d8..d27f39cb00 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::bytesinner::PyBytesInner; 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,7 +554,7 @@ 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(); diff --git a/vm/src/obj/objbyteinner.rs b/vm/src/bytesinner.rs similarity index 92% rename from vm/src/obj/objbyteinner.rs rename to vm/src/bytesinner.rs index 10c13620e4..4ac55adb1c 100644 --- a/vm/src/obj/objbyteinner.rs +++ b/vm/src/bytesinner.rs @@ -3,17 +3,18 @@ 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::obj::pystr::{self, PyCommonString, PyCommonStringContainer, PyCommonStringWrapper}; use crate::pyobject::{ Either, PyComparisonValue, PyIterable, PyObjectRef, PyResult, TryFromObject, TypeProtocol, }; @@ -21,26 +22,26 @@ use crate::vm::VirtualMachine; use rustpython_common::hash; #[derive(Debug, Default, Clone)] -pub struct PyByteInner { +pub struct PyBytesInner { pub 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 { + k @ PyMemoryView => Ok(PyBytesInner { elements: k.try_value().unwrap() }), l @ PyList => l.get_byte_inner(vm), @@ -49,7 +50,7 @@ impl TryFromObject for PyByteInner { 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")] @@ -202,9 +203,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,10 +230,10 @@ impl ByteInnerTranslateOptions { } } -pub type ByteInnerSplitOptions<'a> = pystr::SplitArgs<'a, PyByteInner, [u8], u8>; +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() { @@ -287,13 +288,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 { @@ -698,7 +699,7 @@ impl PyByteInner { pub fn join( &self, - iterable: PyIterable, + iterable: PyIterable, vm: &VirtualMachine, ) -> PyResult> { let iter = iterable.iter(vm)?; @@ -719,7 +720,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 { @@ -757,7 +758,7 @@ impl PyByteInner { Ok(res) } - pub fn strip(&self, chars: OptionalOption) -> Vec { + pub fn strip(&self, chars: OptionalOption) -> Vec { self.elements .py_strip( chars, @@ -767,7 +768,7 @@ impl PyByteInner { .to_vec() } - pub fn lstrip(&self, chars: OptionalOption) -> Vec { + pub fn lstrip(&self, chars: OptionalOption) -> Vec { self.elements .py_strip( chars, @@ -777,7 +778,7 @@ impl PyByteInner { .to_vec() } - pub fn rstrip(&self, chars: OptionalOption) -> Vec { + pub fn rstrip(&self, chars: OptionalOption) -> Vec { self.elements .py_strip( chars, @@ -788,7 +789,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) @@ -797,7 +798,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) @@ -846,7 +847,7 @@ impl PyByteInner { pub fn partition( &self, - sub: &PyByteInner, + sub: &PyBytesInner, vm: &VirtualMachine, ) -> PyResult<(Vec, bool, Vec)> { self.elements.py_partition( @@ -858,7 +859,7 @@ impl PyByteInner { pub fn rpartition( &self, - sub: &PyByteInner, + sub: &PyBytesInner, vm: &VirtualMachine, ) -> PyResult<(Vec, bool, Vec)> { self.elements.py_partition( @@ -912,7 +913,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(); @@ -927,7 +928,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 @@ -954,8 +955,8 @@ impl PyByteInner { pub fn replace_in_place( &self, - from: PyByteInner, - to: PyByteInner, + from: PyBytesInner, + to: PyBytesInner, maxcount: Option, ) -> Vec { let len = from.len(); @@ -986,8 +987,8 @@ impl PyByteInner { fn replace_general( &self, - from: PyByteInner, - to: PyByteInner, + from: PyBytesInner, + to: PyBytesInner, maxcount: Option, vm: &VirtualMachine, ) -> PyResult> { @@ -1027,8 +1028,8 @@ impl PyByteInner { pub fn replace( &self, - from: PyByteInner, - to: PyByteInner, + from: PyBytesInner, + to: PyBytesInner, maxcount: OptionalArg, vm: &VirtualMachine, ) -> PyResult> { @@ -1157,42 +1158,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/lib.rs b/vm/src/lib.rs index 014515018f..de79665f82 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")] diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index f11d0eccfe..e9d172325f 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,4 @@ pub mod objtype; pub mod objweakproxy; pub mod objweakref; pub mod objzip; -mod pystr; +pub(super) mod pystr; diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index b6c176893f..c74cff8c30 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -5,16 +5,16 @@ 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::function::{OptionalArg, OptionalOption}; use crate::pyobject::{ Either, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult, @@ -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,7 +430,7 @@ 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 (back, has_mid, front) = value.rpartition(&sep, vm)?; Ok(vm.ctx.new_tuple(vec![ @@ -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 0bdba5868b..9d013d6d9d 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -3,16 +3,16 @@ 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, @@ -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,7 +395,7 @@ impl PyBytes { #[pymethod(name = "rpartition")] fn rpartition(&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 (back, has_mid, front) = self.inner.rpartition(&sub, vm)?; Ok(vm.ctx.new_tuple(vec![ vm.ctx.new_bytes(front), @@ -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..a63c23f278 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)] diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 6c48f3b6cb..5ee728ed7b 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 get_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..4c1b9fdeab 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_byte; use crate::pyobject::{ ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; 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}; From c07d3f09cd06ec5e956f9d61e535ac30064ab794 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 08:16:03 +0900 Subject: [PATCH 09/12] obj::pystr -> pystr --- vm/src/bytesinner.rs | 4 ++-- vm/src/lib.rs | 1 + vm/src/obj/mod.rs | 1 - vm/src/obj/objbytearray.rs | 4 ++-- vm/src/obj/objbytes.rs | 2 +- vm/src/obj/objstr.rs | 6 +++--- vm/src/{obj => }/pystr.rs | 0 7 files changed, 9 insertions(+), 9 deletions(-) rename vm/src/{obj => }/pystr.rs (100%) diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index 4ac55adb1c..4d57c8423c 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -14,16 +14,16 @@ 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::obj::pystr::{self, PyCommonString, PyCommonStringContainer, PyCommonStringWrapper}; 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 PyBytesInner { - pub elements: Vec, + pub(crate) elements: Vec, } impl From> for PyBytesInner { diff --git a/vm/src/lib.rs b/vm/src/lib.rs index de79665f82..246e6f80e7 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -70,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 e9d172325f..b06f4d47f1 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -43,4 +43,3 @@ pub mod objtype; pub mod objweakproxy; pub mod objweakref; pub mod objzip; -pub(super) mod pystr; diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index c74cff8c30..49fad92239 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -1,5 +1,4 @@ //! 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; @@ -10,16 +9,17 @@ 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\ diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 9d013d6d9d..d1c0d87abd 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -8,7 +8,6 @@ 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, @@ -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; diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 58d1bdb9c3..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; diff --git a/vm/src/obj/pystr.rs b/vm/src/pystr.rs similarity index 100% rename from vm/src/obj/pystr.rs rename to vm/src/pystr.rs From 8e2a268c357779440e4d065e68d461bcef956df1 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 08:51:25 +0900 Subject: [PATCH 10/12] Use PyBytesLike rather than PyBytesInner --- vm/src/builtins.rs | 12 ++++++------ vm/src/bytesinner.rs | 2 +- vm/src/obj/objlist.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index d27f39cb00..95fb403b76 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -14,7 +14,7 @@ mod decl { use rustpython_parser::parser; use super::to_ascii; - use crate::bytesinner::PyBytesInner; + 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}; @@ -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/bytesinner.rs b/vm/src/bytesinner.rs index 4d57c8423c..e55d375878 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -44,7 +44,7 @@ impl TryFromObject for PyBytesInner { k @ PyMemoryView => Ok(PyBytesInner { elements: k.try_value().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()) diff --git a/vm/src/obj/objlist.rs b/vm/src/obj/objlist.rs index 5ee728ed7b..90e9629e6c 100644 --- a/vm/src/obj/objlist.rs +++ b/vm/src/obj/objlist.rs @@ -62,7 +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()) { From 28216a89355043d737737e3f5172e9083c278105 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 05:40:25 +0900 Subject: [PATCH 11/12] try_as_bytes take closure instead of returning vec --- vm/src/bytesinner.rs | 30 +++++++++++++++++++----------- vm/src/obj/objmemory.rs | 4 ++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index e55d375878..193585720b 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -183,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 }; @@ -1129,10 +1134,13 @@ impl PyBytesInner { } } -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, }) } diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs index 4c1b9fdeab..19986a6afe 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -1,5 +1,5 @@ use super::objtype::{issubclass, PyClassRef}; -use crate::bytesinner::try_as_byte; +use crate::bytesinner::try_as_bytes; use crate::pyobject::{ ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TypeProtocol, }; @@ -17,7 +17,7 @@ pub type PyMemoryViewRef = PyRef; #[pyimpl] impl PyMemoryView { pub fn try_value(&self) -> Option> { - try_as_byte(self.obj_ref.clone()) + try_as_bytes(self.obj_ref.clone(), |bytes| bytes.to_vec()) } #[pyslot] From 81d4bc7f9fbd345673363a5de9809b1130f5b89b Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Mon, 27 Jul 2020 05:45:34 +0900 Subject: [PATCH 12/12] PyMemoryView::try_bytes take closure instead of returning vec --- vm/src/bytesinner.rs | 4 ++-- vm/src/obj/objint.rs | 3 +-- vm/src/obj/objmemory.rs | 7 +++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/vm/src/bytesinner.rs b/vm/src/bytesinner.rs index 193585720b..c344ab9b6a 100644 --- a/vm/src/bytesinner.rs +++ b/vm/src/bytesinner.rs @@ -42,7 +42,7 @@ impl TryFromObject for PyBytesInner { elements: j.borrow_value().elements.to_vec() }), k @ PyMemoryView => Ok(PyBytesInner { - elements: k.try_value().unwrap() + elements: k.try_bytes(|v| v.to_vec()).unwrap() }), l @ PyList => l.to_byte_inner(vm), obj => { @@ -358,7 +358,7 @@ impl PyBytesInner { .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() diff --git a/vm/src/obj/objint.rs b/vm/src/obj/objint.rs index a63c23f278..f846c9f76a 100644 --- a/vm/src/obj/objint.rs +++ b/vm/src/obj/objint.rs @@ -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/objmemory.rs b/vm/src/obj/objmemory.rs index 19986a6afe..acdf09ad3f 100644 --- a/vm/src/obj/objmemory.rs +++ b/vm/src/obj/objmemory.rs @@ -16,8 +16,11 @@ pub type PyMemoryViewRef = PyRef; #[pyimpl] impl PyMemoryView { - pub fn try_value(&self) -> Option> { - try_as_bytes(self.obj_ref.clone(), |bytes| bytes.to_vec()) + pub fn try_bytes(&self, f: F) -> Option + where + F: Fn(&[u8]) -> R, + { + try_as_bytes(self.obj_ref.clone(), f) } #[pyslot]