mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-17 01:51:39 +09:00
add endswith startswith
This commit is contained in:
committed by
jgirardet
parent
14658b6236
commit
8a7c46da7b
@@ -12,7 +12,8 @@ use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use super::objint;
|
||||
use super::objsequence::PySliceableSequence;
|
||||
use super::objtype;
|
||||
use super::objsequence::{PySliceableSequence, is_valid_slice_arg};
|
||||
use crate::obj::objint::PyInt;
|
||||
use num_integer::Integer;
|
||||
use num_traits::ToPrimitive;
|
||||
@@ -21,6 +22,7 @@ use super::objbytearray::{get_value as get_value_bytearray, PyByteArray};
|
||||
use super::objbytes::PyBytes;
|
||||
use super::objmemory::PyMemoryView;
|
||||
use super::objnone::PyNone;
|
||||
use super::objsequence;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct PyByteInner {
|
||||
@@ -495,6 +497,61 @@ impl PyByteInner {
|
||||
|
||||
Ok(vm.ctx.new_bytes(refs))
|
||||
}
|
||||
|
||||
pub fn startsendswith(
|
||||
&self,
|
||||
arg: PyObjectRef,
|
||||
start: OptionalArg<PyObjectRef>,
|
||||
end: OptionalArg<PyObjectRef>,
|
||||
endswith: bool, // true for endswith, false for startswith
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let suff = if objtype::isinstance(&arg, &vm.ctx.tuple_type()) {
|
||||
let mut flatten = vec![];
|
||||
for v in objsequence::get_elements(&arg).to_vec() {
|
||||
match try_as_bytes_like(&v) {
|
||||
None => {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"a bytes-like object is required, not {}",
|
||||
&v.class().name,
|
||||
)));
|
||||
}
|
||||
Some(value) => flatten.extend(value),
|
||||
}
|
||||
}
|
||||
flatten
|
||||
} else {
|
||||
match try_as_bytes_like(&arg) {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Err(vm.new_type_error(format!(
|
||||
"endswith first arg must be bytes or a tuple of bytes, not {}",
|
||||
arg
|
||||
)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if suff.is_empty() {
|
||||
return Ok(vm.new_bool(true));
|
||||
}
|
||||
let range = self.elements.get_slice_range(
|
||||
&is_valid_slice_arg(start, vm)?,
|
||||
&is_valid_slice_arg(end, vm)?,
|
||||
);
|
||||
|
||||
if range.end - range.start < suff.len() {
|
||||
return Ok(vm.new_bool(false));
|
||||
}
|
||||
|
||||
let offset = if endswith {
|
||||
(range.end - suff.len())..range.end
|
||||
} else {
|
||||
0..suff.len()
|
||||
};
|
||||
|
||||
Ok(vm.new_bool(suff.as_slice() == &self.elements.do_slice(range)[offset]))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_as_byte(obj: &PyObjectRef) -> Option<Vec<u8>> {
|
||||
|
||||
@@ -258,6 +258,28 @@ impl PyBytesRef {
|
||||
fn join(self, iter: PyIterable, vm: &VirtualMachine) -> PyResult {
|
||||
self.inner.join(iter, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "endswith")]
|
||||
fn endswith(
|
||||
self,
|
||||
suffix: PyObjectRef,
|
||||
start: OptionalArg<PyObjectRef>,
|
||||
end: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
self.inner.startsendswith(suffix, start, end, true, vm)
|
||||
}
|
||||
|
||||
#[pymethod(name = "startswith")]
|
||||
fn startswith(
|
||||
self,
|
||||
suffix: PyObjectRef,
|
||||
start: OptionalArg<PyObjectRef>,
|
||||
end: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
self.inner.startsendswith(suffix, start, end, false, vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::function::OptionalArg;
|
||||
use crate::obj::objnone::PyNone;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::Sized;
|
||||
use std::ops::{Deref, DerefMut, Range};
|
||||
@@ -371,3 +373,20 @@ pub fn get_mut_elements<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Vec<
|
||||
}
|
||||
panic!("Cannot extract elements from non-sequence");
|
||||
}
|
||||
|
||||
//Check if given arg could be used with PySciceableSequance.get_slice_range()
|
||||
pub fn is_valid_slice_arg(
|
||||
arg: OptionalArg<PyObjectRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> Result<Option<BigInt>, PyObjectRef> {
|
||||
if let OptionalArg::Present(value) = arg {
|
||||
match_class!(value,
|
||||
i @ PyInt => Ok(Some(i.as_bigint().clone())),
|
||||
_obj @ PyNone => Ok(None),
|
||||
_=> {return Err(vm.new_type_error("slice indices must be integers or None or have an __index__ method".to_string()));}
|
||||
// TODO: check for an __index__ method
|
||||
)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user