Skip to content

Commit 8ca22df

Browse files
authored
Merge pull request RustPython#1887 from youknowone/pystr-pad
Fix str.center & move pad methods into pystr
2 parents 832bff1 + a3eb9a3 commit 8ca22df

File tree

5 files changed

+162
-142
lines changed

5 files changed

+162
-142
lines changed

Lib/test/test_unicode.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -896,8 +896,6 @@ def test_swapcase(self):
896896
self.assertEqual('ß'.swapcase(), 'SS')
897897
self.assertEqual('\u1fd2'.swapcase(), '\u0399\u0308\u0300')
898898

899-
# TODO: RUSTPYTHON
900-
@unittest.expectedFailure
901899
def test_center(self):
902900
string_tests.CommonTest.test_center(self)
903901
self.assertEqual('x'.center(2, '\U0010FFFF'),
@@ -960,8 +958,6 @@ def test_contains(self):
960958
self.assertNotIn(delim * 2, fill)
961959
self.assertIn(delim * 2, fill + delim * 2)
962960

963-
# TODO: RUSTPYTHON
964-
@unittest.expectedFailure
965961
def test_issue18183(self):
966962
'\U00010000\U00100000'.lower()
967963
'\U00010000\U00100000'.casefold()

vm/src/obj/objbyteinner.rs

Lines changed: 56 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use bstr::ByteSlice;
22
use num_bigint::{BigInt, ToBigInt};
3-
use num_integer::Integer;
43
use num_traits::{One, Signed, ToPrimitive, Zero};
54
use std::convert::TryFrom;
65
use std::ops::Range;
@@ -179,25 +178,17 @@ impl ByteInnerFindOptions {
179178
#[derive(FromArgs)]
180179
pub struct ByteInnerPaddingOptions {
181180
#[pyarg(positional_only, optional = false)]
182-
width: PyIntRef,
181+
width: isize,
183182
#[pyarg(positional_only, optional = true)]
184-
fillbyte: OptionalArg<PyObjectRef>,
183+
fillchar: OptionalArg<PyObjectRef>,
185184
}
185+
186186
impl ByteInnerPaddingOptions {
187-
fn get_value(self, fn_name: &str, len: usize, vm: &VirtualMachine) -> PyResult<(u8, usize)> {
188-
let fillbyte = if let OptionalArg::Present(v) = &self.fillbyte {
189-
match try_as_byte(&v) {
190-
Some(x) => {
191-
if x.len() == 1 {
192-
x[0]
193-
} else {
194-
return Err(vm.new_type_error(format!(
195-
"{}() argument 2 must be a byte string of length 1, not {}",
196-
fn_name, &v
197-
)));
198-
}
199-
}
200-
None => {
187+
fn get_value(self, fn_name: &str, vm: &VirtualMachine) -> PyResult<(isize, u8)> {
188+
let fillchar = if let OptionalArg::Present(v) = self.fillchar {
189+
match try_as_byte(v.clone()) {
190+
Some(x) if x.len() == 1 => x[0],
191+
_ => {
201192
return Err(vm.new_type_error(format!(
202193
"{}() argument 2 must be a byte string of length 1, not {}",
203194
fn_name, &v
@@ -208,20 +199,7 @@ impl ByteInnerPaddingOptions {
208199
b' ' // default is space
209200
};
210201

211-
// <0 = no change
212-
let width = if let Some(x) = self.width.as_bigint().to_usize() {
213-
if x <= len {
214-
0
215-
} else {
216-
x
217-
}
218-
} else {
219-
0
220-
};
221-
222-
let diff: usize = if width != 0 { width - len } else { 0 };
223-
224-
Ok((fillbyte, diff))
202+
Ok((self.width, fillchar))
225203
}
226204
}
227205

@@ -724,59 +702,43 @@ impl PyByteInner {
724702
.collect::<Vec<u8>>())
725703
}
726704

727-
pub fn center(
705+
#[inline]
706+
fn pad(
728707
&self,
729708
options: ByteInnerPaddingOptions,
709+
pad: fn(&[u8], usize, u8) -> Vec<u8>,
730710
vm: &VirtualMachine,
731711
) -> PyResult<Vec<u8>> {
732-
let (fillbyte, diff) = options.get_value("center", self.len(), vm)?;
733-
734-
let mut ln: usize = diff / 2;
735-
let mut rn: usize = ln;
736-
737-
if diff.is_odd() && self.len() % 2 == 0 {
738-
ln += 1
739-
}
740-
741-
if diff.is_odd() && self.len() % 2 != 0 {
742-
rn += 1
743-
}
744-
745-
// merge all
746-
let mut res = vec![fillbyte; ln];
747-
res.extend_from_slice(&self.elements[..]);
748-
res.extend_from_slice(&vec![fillbyte; rn][..]);
712+
let (width, fillchar) = options.get_value("center", vm)?;
713+
Ok(if self.len() as isize >= width {
714+
Vec::from(&self.elements[..])
715+
} else {
716+
pad(&self.elements, width as usize, fillchar)
717+
})
718+
}
749719

750-
Ok(res)
720+
pub fn center(
721+
&self,
722+
options: ByteInnerPaddingOptions,
723+
vm: &VirtualMachine,
724+
) -> PyResult<Vec<u8>> {
725+
self.pad(options, PyCommonString::<u8>::py_center, vm)
751726
}
752727

753728
pub fn ljust(
754729
&self,
755730
options: ByteInnerPaddingOptions,
756731
vm: &VirtualMachine,
757732
) -> PyResult<Vec<u8>> {
758-
let (fillbyte, diff) = options.get_value("ljust", self.len(), vm)?;
759-
760-
// merge all
761-
let mut res = vec![];
762-
res.extend_from_slice(&self.elements[..]);
763-
res.extend_from_slice(&vec![fillbyte; diff][..]);
764-
765-
Ok(res)
733+
self.pad(options, PyCommonString::<u8>::py_ljust, vm)
766734
}
767735

768736
pub fn rjust(
769737
&self,
770738
options: ByteInnerPaddingOptions,
771739
vm: &VirtualMachine,
772740
) -> PyResult<Vec<u8>> {
773-
let (fillbyte, diff) = options.get_value("rjust", self.len(), vm)?;
774-
775-
// merge all
776-
let mut res = vec![fillbyte; diff];
777-
res.extend_from_slice(&self.elements[..]);
778-
779-
Ok(res)
741+
self.pad(options, PyCommonString::<u8>::py_rjust, vm)
780742
}
781743

782744
pub fn count(&self, options: ByteInnerFindOptions, vm: &VirtualMachine) -> PyResult<usize> {
@@ -1130,7 +1092,9 @@ impl PyByteInner {
11301092
{
11311093
return Err(vm.new_overflow_error("replace bytes is too long".to_owned()));
11321094
}
1133-
let result_len = self.elements.len() + count * (to.len() - from.len());
1095+
let result_len = (self.elements.len() as isize
1096+
+ count as isize * (to.len() as isize - from.len() as isize))
1097+
as usize;
11341098

11351099
let mut result = Vec::with_capacity(result_len);
11361100
let mut last_end = 0;
@@ -1259,8 +1223,8 @@ impl PyByteInner {
12591223
}
12601224
}
12611225

1262-
pub fn try_as_byte(obj: &PyObjectRef) -> Option<Vec<u8>> {
1263-
match_class!(match obj.clone() {
1226+
pub fn try_as_byte(obj: PyObjectRef) -> Option<Vec<u8>> {
1227+
match_class!(match obj {
12641228
i @ PyBytes => Some(i.get_value().to_vec()),
12651229
j @ PyByteArray => Some(j.borrow_value().elements.to_vec()),
12661230
_ => None,
@@ -1350,15 +1314,29 @@ impl PyCommonStringWrapper<[u8]> for PyByteInner {
13501314
const ASCII_WHITESPACES: [u8; 6] = [0x20, 0x09, 0x0a, 0x0c, 0x0d, 0x0b];
13511315

13521316
impl PyCommonString<u8> for [u8] {
1353-
fn get_slice(&self, range: std::ops::Range<usize>) -> &Self {
1317+
type Container = Vec<u8>;
1318+
1319+
fn with_capacity(capacity: usize) -> Self::Container {
1320+
Vec::with_capacity(capacity)
1321+
}
1322+
1323+
fn get_bytes<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self {
1324+
&self[range]
1325+
}
1326+
1327+
fn get_chars<'a>(&'a self, range: std::ops::Range<usize>) -> &'a Self {
13541328
&self[range]
13551329
}
13561330

13571331
fn is_empty(&self) -> bool {
13581332
Self::is_empty(self)
13591333
}
13601334

1361-
fn len(&self) -> usize {
1335+
fn bytes_len(&self) -> usize {
1336+
Self::len(self)
1337+
}
1338+
1339+
fn chars_len(&self) -> usize {
13621340
Self::len(self)
13631341
}
13641342

@@ -1407,4 +1385,12 @@ impl PyCommonString<u8> for [u8] {
14071385
}
14081386
splited
14091387
}
1388+
1389+
fn py_pad(&self, left: usize, right: usize, fill: u8) -> Self::Container {
1390+
let mut u = Vec::with_capacity(left + self.len() + right);
1391+
u.extend(std::iter::repeat(fill).take(left));
1392+
u.extend_from_slice(self);
1393+
u.extend(std::iter::repeat(fill).take(right));
1394+
u
1395+
}
14101396
}

vm/src/obj/objmemory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub type PyMemoryViewRef = PyRef<PyMemoryView>;
1818
#[pyimpl]
1919
impl PyMemoryView {
2020
pub fn try_value(&self) -> Option<Vec<u8>> {
21-
try_as_byte(&self.obj_ref)
21+
try_as_byte(self.obj_ref.clone())
2222
}
2323

2424
#[pyslot]

0 commit comments

Comments
 (0)