Skip to content

Commit 592fa0f

Browse files
committed
unified implementation of removeprefix and removesuffix, added pydocs
1 parent 06437e2 commit 592fa0f

File tree

5 files changed

+114
-30
lines changed

5 files changed

+114
-30
lines changed

vm/src/obj/objbytearray.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -389,24 +389,38 @@ impl PyByteArray {
389389
self.borrow_value().rstrip(chars).into()
390390
}
391391

392+
/// removeprefix($self, prefix, /)
393+
///
394+
///
395+
/// Return a bytearray object with the given prefix string removed if present.
396+
///
397+
/// If the bytearray starts with the prefix string, return string[len(prefix):]
398+
/// Otherwise, return a copy of the original bytearray.
392399
#[pymethod(name = "removeprefix")]
393400
fn removeprefix(&self, prefix: PyByteInner) -> PyByteArray {
394-
let value = self.borrow_value();
395-
if value.elements.starts_with(&prefix.elements) {
396-
return value.elements[prefix.elements.len()..].to_vec().into();
397-
}
398-
value.elements.to_vec().into()
401+
self.borrow_value().elements[..]
402+
.py_removeprefix(&prefix.elements, prefix.elements.len(), |s, p| {
403+
s.starts_with(p)
404+
})
405+
.to_vec()
406+
.into()
399407
}
400408

409+
/// removesuffix(self, prefix, /)
410+
///
411+
///
412+
/// Return a bytearray object with the given suffix string removed if present.
413+
///
414+
/// If the bytearray ends with the suffix string, return string[:len(suffix)]
415+
/// Otherwise, return a copy of the original bytearray.
401416
#[pymethod(name = "removesuffix")]
402417
fn removesuffix(&self, suffix: PyByteInner) -> PyByteArray {
403-
let value = self.borrow_value();
404-
if value.elements.ends_with(&suffix.elements) {
405-
return value.elements[..value.elements.len() - suffix.elements.len()]
406-
.to_vec()
407-
.into();
408-
}
409-
value.elements.to_vec().into()
418+
self.borrow_value().elements[..]
419+
.py_removesuffix(&suffix.elements, suffix.elements.len(), |s, p| {
420+
s.ends_with(p)
421+
})
422+
.to_vec()
423+
.into()
410424
}
411425

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

vm/src/obj/objbyteinner.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -845,18 +845,22 @@ impl PyByteInner {
845845

846846
// new in Python 3.9
847847
pub fn removeprefix(&self, prefix: PyByteInner) -> Vec<u8> {
848-
if self.elements.starts_with(&prefix.elements) {
849-
return self.elements[prefix.elements.len()..].to_vec();
850-
}
851-
self.elements.to_vec()
848+
// self.elements.py_removeprefix(&prefix.elements, prefix.elements.len(), |s:&Self, p:&Vec<u8>| s.elements.starts_with(&p)).to_vec()
849+
850+
self.elements
851+
.py_removeprefix(&prefix.elements, prefix.elements.len(), |s, p| {
852+
s.starts_with(p)
853+
})
854+
.to_vec()
852855
}
853856

854857
// new in Python 3.9
855858
pub fn removesuffix(&self, suffix: PyByteInner) -> Vec<u8> {
856-
if self.elements.ends_with(&suffix.elements) {
857-
return self.elements[..self.elements.len() - suffix.elements.len()].to_vec();
858-
}
859-
self.elements.to_vec()
859+
self.elements
860+
.py_removesuffix(&suffix.elements, suffix.elements.len(), |s, p| {
861+
s.ends_with(p)
862+
})
863+
.to_vec()
860864
}
861865

862866
pub fn split<F>(

vm/src/obj/objbytes.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,25 @@ impl PyBytes {
347347
self.inner.rstrip(chars).into()
348348
}
349349

350+
/// removeprefix($self, prefix, /)
351+
///
352+
///
353+
/// Return a bytes object with the given prefix string removed if present.
354+
///
355+
/// If the bytes starts with the prefix string, return string[len(prefix):]
356+
/// Otherwise, return a copy of the original bytes.
350357
#[pymethod(name = "removeprefix")]
351358
fn removeprefix(&self, prefix: PyByteInner) -> PyBytes {
352359
self.inner.removeprefix(prefix).into()
353360
}
354361

362+
/// removesuffix(self, prefix, /)
363+
///
364+
///
365+
/// Return a bytes object with the given suffix string removed if present.
366+
///
367+
/// If the bytes ends with the suffix string, return string[:len(suffix)]
368+
/// Otherwise, return a copy of the original bytes.
355369
#[pymethod(name = "removesuffix")]
356370
fn removesuffix(&self, suffix: PyByteInner) -> PyBytes {
357371
self.inner.removesuffix(suffix).into()

vm/src/obj/objstr.rs

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -532,20 +532,34 @@ impl PyString {
532532
)
533533
}
534534

535+
/// removeprefix($self, prefix, /)
536+
///
537+
///
538+
/// Return a str with the given prefix string removed if present.
539+
///
540+
/// If the string starts with the prefix string, return string[len(prefix):]
541+
/// Otherwise, return a copy of the original string.
535542
#[pymethod]
536-
fn removeprefix(&self, pref: PyStringRef) -> PyResult<String> {
537-
if self.value.as_str().starts_with(&pref.value) {
538-
return Ok(self.value[pref.value.len()..].to_string());
539-
}
540-
Ok(self.value.to_string())
543+
fn removeprefix(&self, pref: PyStringRef) -> String {
544+
self.value
545+
.as_str()
546+
.py_removeprefix(&pref.value, pref.value.len(), |s, p| s.starts_with(p))
547+
.to_string()
541548
}
542549

550+
/// removesuffix(self, prefix, /)
551+
///
552+
///
553+
/// Return a str with the given suffix string removed if present.
554+
///
555+
/// If the string ends with the suffix string, return string[:len(suffix)]
556+
/// Otherwise, return a copy of the original string.
543557
#[pymethod]
544-
fn removesuffix(&self, suff: PyStringRef) -> PyResult<String> {
545-
if self.value.as_str().ends_with(&suff.value) {
546-
return Ok(self.value[..self.value.len() - suff.value.len()].to_string());
547-
}
548-
Ok(self.value.to_string())
558+
fn removesuffix(&self, suff: PyStringRef) -> String {
559+
self.value
560+
.as_str()
561+
.py_removesuffix(&suff.value, suff.value.len(), |s, p| s.ends_with(p))
562+
.to_string()
549563
}
550564

551565
#[pymethod]

vm/src/obj/pystr.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::obj::objint::PyIntRef;
33
use crate::pyobject::{PyObjectRef, PyResult, TryFromObject, TypeProtocol};
44
use crate::vm::VirtualMachine;
55
use num_traits::{cast::ToPrimitive, sign::Signed};
6+
use std::ops::Range;
67

78
#[derive(FromArgs)]
89
pub struct SplitArgs<T, S, E>
@@ -264,4 +265,41 @@ pub trait PyCommonString<E> {
264265
fn py_rjust(&self, width: usize, fillchar: E) -> Self::Container {
265266
self.py_pad(width - self.chars_len(), 0, fillchar)
266267
}
268+
269+
fn py_removeprefix<FC>(
270+
&self,
271+
prefix: &Self::Container,
272+
prefix_len: usize,
273+
is_prefix: FC,
274+
) -> &Self
275+
where
276+
FC: Fn(&Self, &Self::Container) -> bool,
277+
{
278+
//if self.py_starts_with(prefix) {
279+
if is_prefix(&self, &prefix) {
280+
return self.get_bytes(Range {
281+
start: prefix_len,
282+
end: self.bytes_len(),
283+
});
284+
}
285+
&self
286+
}
287+
288+
fn py_removesuffix<FC>(
289+
&self,
290+
suffix: &Self::Container,
291+
suffix_len: usize,
292+
is_suffix: FC,
293+
) -> &Self
294+
where
295+
FC: Fn(&Self, &Self::Container) -> bool,
296+
{
297+
if is_suffix(&self, &suffix) {
298+
return self.get_bytes(Range {
299+
start: 0,
300+
end: self.bytes_len() - suffix_len,
301+
});
302+
}
303+
&self
304+
}
267305
}

0 commit comments

Comments
 (0)