Skip to content

Commit 8b23271

Browse files
authored
Merge pull request RustPython#1852 from youknowone/bytes-strip
Fix {bytes|bytearray}.{|r|l}strip
2 parents 6e305c5 + 75ebaed commit 8b23271

File tree

6 files changed

+53
-72
lines changed

6 files changed

+53
-72
lines changed

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/string_tests.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,6 @@ def test_additional_rsplit(self):
777777
self.checkequal(['arf', 'barf'], b, 'rsplit', None)
778778
self.checkequal(['arf', 'barf'], b, 'rsplit', None, 2)
779779

780-
@unittest.skip("TODO: RUSTPYTHON test_bytes")
781780
def test_strip_whitespace(self):
782781
self.checkequal('hello', ' hello ', 'strip')
783782
self.checkequal('hello ', ' hello ', 'lstrip')
@@ -795,7 +794,6 @@ def test_strip_whitespace(self):
795794
self.checkequal(' hello', ' hello ', 'rstrip', None)
796795
self.checkequal('hello', 'hello', 'strip', None)
797796

798-
@unittest.skip("TODO: RUSTPYTHON test_bytes")
799797
def test_strip(self):
800798
# strip/lstrip/rstrip with str arg
801799
self.checkequal('hello', 'xyzzyhelloxyzzy', 'strip', 'xyz')

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ result-like = "^0.2.1"
7272
foreign-types = "0.3"
7373
num_enum = "0.4"
7474
smallbox = "0.8"
75+
bstr = "0.2.12"
7576

7677
flame = { version = "0.2", optional = true }
7778
flamer = { version = "0.3", optional = true }

vm/src/obj/objbytearray.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
55

66
use super::objbyteinner::{
77
ByteInnerExpandtabsOptions, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
8-
ByteInnerPosition, ByteInnerSplitOptions, ByteInnerSplitlinesOptions,
9-
ByteInnerTranslateOptions, ByteOr, PyByteInner,
8+
ByteInnerSplitOptions, ByteInnerSplitlinesOptions, ByteInnerTranslateOptions, ByteOr,
9+
PyByteInner,
1010
};
1111
use super::objint::PyIntRef;
1212
use super::objiter;
@@ -15,7 +15,7 @@ use super::objstr::{PyString, PyStringRef};
1515
use super::objtuple::PyTupleRef;
1616
use super::objtype::PyClassRef;
1717
use crate::cformat::CFormatString;
18-
use crate::function::OptionalArg;
18+
use crate::function::{OptionalArg, OptionalOption};
1919
use crate::obj::objstr::do_cformat_string;
2020
use crate::pyobject::{
2121
Either, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef, PyRef, PyResult,
@@ -373,27 +373,18 @@ impl PyByteArray {
373373
}
374374

375375
#[pymethod(name = "strip")]
376-
fn strip(&self, chars: OptionalArg<PyByteInner>) -> PyResult<PyByteArray> {
377-
Ok(self
378-
.borrow_value()
379-
.strip(chars, ByteInnerPosition::All)?
380-
.into())
376+
fn strip(&self, chars: OptionalOption<PyByteInner>) -> PyByteArray {
377+
self.borrow_value().strip(chars).into()
381378
}
382379

383380
#[pymethod(name = "lstrip")]
384-
fn lstrip(&self, chars: OptionalArg<PyByteInner>) -> PyResult<PyByteArray> {
385-
Ok(self
386-
.borrow_value()
387-
.strip(chars, ByteInnerPosition::Left)?
388-
.into())
381+
fn lstrip(&self, chars: OptionalOption<PyByteInner>) -> PyByteArray {
382+
self.borrow_value().lstrip(chars).into()
389383
}
390384

391385
#[pymethod(name = "rstrip")]
392-
fn rstrip(&self, chars: OptionalArg<PyByteInner>) -> PyResult<PyByteArray> {
393-
Ok(self
394-
.borrow_value()
395-
.strip(chars, ByteInnerPosition::Right)?
396-
.into())
386+
fn rstrip(&self, chars: OptionalOption<PyByteInner>) -> PyByteArray {
387+
self.borrow_value().rstrip(chars).into()
397388
}
398389

399390
#[pymethod(name = "split")]

vm/src/obj/objbyteinner.rs

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use std::convert::TryFrom;
2-
use std::ops::Range;
3-
1+
use bstr::ByteSlice;
42
use num_bigint::{BigInt, ToBigInt};
53
use num_integer::Integer;
64
use num_traits::{One, Signed, ToPrimitive, Zero};
5+
use std::convert::TryFrom;
6+
use std::ops::Range;
77

88
use super::objbytearray::{PyByteArray, PyByteArrayRef};
99
use super::objbytes::{PyBytes, PyBytesRef};
@@ -15,7 +15,7 @@ use super::objsequence::{is_valid_slice_arg, PySliceableSequence};
1515
use super::objslice::PySliceRef;
1616
use super::objstr::{self, adjust_indices, PyString, PyStringRef, StringRange};
1717
use super::objtuple::PyTupleRef;
18-
use crate::function::OptionalArg;
18+
use crate::function::{OptionalArg, OptionalOption};
1919
use crate::pyhash;
2020
use crate::pyobject::{
2121
Either, PyComparisonValue, PyIterable, PyObjectRef, PyResult, ThreadSafe, TryFromObject,
@@ -962,40 +962,37 @@ impl PyByteInner {
962962
Ok(res)
963963
}
964964

965-
pub fn strip(
966-
&self,
967-
chars: OptionalArg<PyByteInner>,
968-
position: ByteInnerPosition,
969-
) -> PyResult<Vec<u8>> {
970-
let is_valid_char = |c| {
971-
if let OptionalArg::Present(ref bytes) = chars {
972-
bytes.elements.contains(c)
973-
} else {
974-
c.is_ascii_whitespace()
975-
}
965+
pub fn strip(&self, chars: OptionalOption<PyByteInner>) -> Vec<u8> {
966+
let chars = chars.flat_option();
967+
let chars = match chars {
968+
Some(ref chars) => &chars.elements,
969+
None => return self.elements.trim().to_owned(),
976970
};
971+
self.elements
972+
.trim_with(|c| chars.contains(&(c as u8)))
973+
.to_owned()
974+
}
977975

978-
let mut start = 0;
979-
let mut end = self.len();
980-
981-
if let ByteInnerPosition::Left | ByteInnerPosition::All = position {
982-
for (i, c) in self.elements.iter().enumerate() {
983-
if !is_valid_char(c) {
984-
start = i;
985-
break;
986-
}
987-
}
988-
}
976+
pub fn lstrip(&self, chars: OptionalOption<PyByteInner>) -> Vec<u8> {
977+
let chars = chars.flat_option();
978+
let chars = match chars {
979+
Some(ref chars) => &chars.elements,
980+
None => return self.elements.trim_start().to_owned(),
981+
};
982+
self.elements
983+
.trim_start_with(|c| chars.contains(&(c as u8)))
984+
.to_owned()
985+
}
989986

990-
if let ByteInnerPosition::Right | ByteInnerPosition::All = position {
991-
for (i, c) in self.elements.iter().rev().enumerate() {
992-
if !is_valid_char(c) {
993-
end = self.len() - i;
994-
break;
995-
}
996-
}
997-
}
998-
Ok(self.elements[start..end].to_vec())
987+
pub fn rstrip(&self, chars: OptionalOption<PyByteInner>) -> Vec<u8> {
988+
let chars = chars.flat_option();
989+
let chars = match chars {
990+
Some(ref chars) => &chars.elements,
991+
None => return self.elements.trim_end().to_owned(),
992+
};
993+
self.elements
994+
.trim_end_with(|c| chars.contains(&(c as u8)))
995+
.to_owned()
999996
}
1000997

1001998
pub fn split(&self, options: ByteInnerSplitOptions, reverse: bool) -> PyResult<Vec<&[u8]>> {
@@ -1221,12 +1218,6 @@ pub trait ByteOr: ToPrimitive {
12211218

12221219
impl ByteOr for BigInt {}
12231220

1224-
pub enum ByteInnerPosition {
1225-
Left,
1226-
Right,
1227-
All,
1228-
}
1229-
12301221
fn split_slice<'a>(slice: &'a [u8], sep: &[u8], maxsplit: isize) -> Vec<&'a [u8]> {
12311222
let mut splitted: Vec<&[u8]> = vec![];
12321223
let mut prev_index = 0;

vm/src/obj/objbytes.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use std::ops::Deref;
44

55
use super::objbyteinner::{
66
ByteInnerExpandtabsOptions, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
7-
ByteInnerPosition, ByteInnerSplitOptions, ByteInnerSplitlinesOptions,
8-
ByteInnerTranslateOptions, PyByteInner,
7+
ByteInnerSplitOptions, ByteInnerSplitlinesOptions, ByteInnerTranslateOptions, PyByteInner,
98
};
109
use super::objint::PyIntRef;
1110
use super::objiter;
@@ -14,7 +13,7 @@ use super::objstr::{PyString, PyStringRef};
1413
use super::objtuple::PyTupleRef;
1514
use super::objtype::PyClassRef;
1615
use crate::cformat::CFormatString;
17-
use crate::function::OptionalArg;
16+
use crate::function::{OptionalArg, OptionalOption};
1817
use crate::obj::objstr::do_cformat_string;
1918
use crate::pyhash;
2019
use crate::pyobject::{
@@ -329,18 +328,18 @@ impl PyBytes {
329328
}
330329

331330
#[pymethod(name = "strip")]
332-
fn strip(&self, chars: OptionalArg<PyByteInner>) -> PyResult<PyBytes> {
333-
Ok(self.inner.strip(chars, ByteInnerPosition::All)?.into())
331+
fn strip(&self, chars: OptionalOption<PyByteInner>) -> PyBytes {
332+
self.inner.strip(chars).into()
334333
}
335334

336335
#[pymethod(name = "lstrip")]
337-
fn lstrip(&self, chars: OptionalArg<PyByteInner>) -> PyResult<PyBytes> {
338-
Ok(self.inner.strip(chars, ByteInnerPosition::Left)?.into())
336+
fn lstrip(&self, chars: OptionalOption<PyByteInner>) -> PyBytes {
337+
self.inner.lstrip(chars).into()
339338
}
340339

341340
#[pymethod(name = "rstrip")]
342-
fn rstrip(&self, chars: OptionalArg<PyByteInner>) -> PyResult<PyBytes> {
343-
Ok(self.inner.strip(chars, ByteInnerPosition::Right)?.into())
341+
fn rstrip(&self, chars: OptionalOption<PyByteInner>) -> PyBytes {
342+
self.inner.rstrip(chars).into()
344343
}
345344

346345
#[pymethod(name = "split")]

0 commit comments

Comments
 (0)