diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 4680c63bf9..2c6e0f84fa 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -156,8 +156,6 @@ def test_count(self): self.assertEqual(rem, 0, '%s != 0 for %s' % (rem, i)) self.assertEqual(r1, r2, '%s != %s for %s' % (r1, r2, i)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_find(self): self.checkequal(0, 'abcdefghiabc', 'find', 'abc') self.checkequal(9, 'abcdefghiabc', 'find', 'abc', 1) @@ -215,8 +213,6 @@ def test_find(self): if loc != -1: self.assertEqual(i[loc:loc+len(j)], j) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_rfind(self): self.checkequal(9, 'abcdefghiabc', 'rfind', 'abc') self.checkequal(12, 'abcdefghiabc', 'rfind', '') diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 60e8a3f1d1..a591593c0b 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -199,8 +199,7 @@ def test_count(self): self.checkequal(0, 'a' * 10, 'count', 'a\U00100304') self.checkequal(0, '\u0102' * 10, 'count', '\u0102\U00100304') - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.skip("TODO: RUSTPYTHON") def test_find(self): string_tests.CommonTest.test_find(self) # test implementation details of the memchr fast path @@ -232,8 +231,7 @@ def test_find(self): self.checkequal(-1, 'a' * 100, 'find', 'a\U00100304') self.checkequal(-1, '\u0102' * 100, 'find', '\u0102\U00100304') - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.skip("TODO: RUSTPYTHON") def test_rfind(self): string_tests.CommonTest.test_rfind(self) # test implementation details of the memrchr fast path diff --git a/vm/src/obj/objbyteinner.rs b/vm/src/obj/objbyteinner.rs index e684e0fdc9..38f6f0b718 100644 --- a/vm/src/obj/objbyteinner.rs +++ b/vm/src/obj/objbyteinner.rs @@ -154,10 +154,10 @@ impl ByteInnerNewOptions { pub struct ByteInnerFindOptions { #[pyarg(positional_only, optional = false)] sub: Either, - #[pyarg(positional_only, optional = true)] - start: OptionalArg>, - #[pyarg(positional_only, optional = true)] - end: OptionalArg>, + #[pyarg(positional_only, default = "None")] + start: Option, + #[pyarg(positional_only, default = "None")] + end: Option, } impl ByteInnerFindOptions { diff --git a/vm/src/obj/objstr.rs b/vm/src/obj/objstr.rs index 2fd535d591..35d75dba49 100644 --- a/vm/src/obj/objstr.rs +++ b/vm/src/obj/objstr.rs @@ -813,63 +813,35 @@ impl PyString { } #[inline] - fn _find( - &self, - sub: PyStringRef, - start: OptionalArg>, - end: OptionalArg>, - find: F, - ) -> Option + fn _find(&self, args: FindArgs, find: F) -> Option where F: Fn(&str, &str) -> Option, { - let range = adjust_indices(start, end, self.value.len()); + let (sub, range) = args.get_value(self.len()); self.value.py_find(&sub.value, range, find) } #[pymethod] - fn find( - &self, - sub: PyStringRef, - start: OptionalArg>, - end: OptionalArg>, - ) -> isize { - self._find(sub, start, end, |r, s| r.find(s)) + fn find(&self, args: FindArgs) -> isize { + self._find(args, |r, s| r.find(s)) .map_or(-1, |v| v as isize) } #[pymethod] - fn rfind( - &self, - sub: PyStringRef, - start: OptionalArg>, - end: OptionalArg>, - ) -> isize { - self._find(sub, start, end, |r, s| r.rfind(s)) + fn rfind(&self, args: FindArgs) -> isize { + self._find(args, |r, s| r.rfind(s)) .map_or(-1, |v| v as isize) } #[pymethod] - fn index( - &self, - sub: PyStringRef, - start: OptionalArg>, - end: OptionalArg>, - vm: &VirtualMachine, - ) -> PyResult { - self._find(sub, start, end, |r, s| r.find(s)) + fn index(&self, args: FindArgs, vm: &VirtualMachine) -> PyResult { + self._find(args, |r, s| r.find(s)) .ok_or_else(|| vm.new_value_error("substring not found".to_owned())) } #[pymethod] - fn rindex( - &self, - sub: PyStringRef, - start: OptionalArg>, - end: OptionalArg>, - vm: &VirtualMachine, - ) -> PyResult { - self._find(sub, start, end, |r, s| r.rfind(s)) + fn rindex(&self, args: FindArgs, vm: &VirtualMachine) -> PyResult { + self._find(args, |r, s| r.rfind(s)) .ok_or_else(|| vm.new_value_error("substring not found".to_owned())) } @@ -944,15 +916,10 @@ impl PyString { } #[pymethod] - fn count( - &self, - sub: PyStringRef, - start: OptionalArg>, - end: OptionalArg>, - ) -> usize { - let range = adjust_indices(start, end, self.value.len()); + fn count(&self, args: FindArgs) -> usize { + let (needle, range) = args.get_value(self.len()); self.value - .py_count(&sub.value, range, |h, n| h.matches(n).count()) + .py_count(&needle.value, range, |h, n| h.matches(n).count()) } #[pymethod] @@ -1250,6 +1217,23 @@ impl TryFromObject for std::ffi::CString { type SplitArgs = pystr::SplitArgs; +#[derive(FromArgs)] +pub struct FindArgs { + #[pyarg(positional_only, optional = false)] + sub: PyStringRef, + #[pyarg(positional_only, default = "None")] + start: Option, + #[pyarg(positional_only, default = "None")] + end: Option, +} + +impl FindArgs { + fn get_value(self, len: usize) -> (PyStringRef, std::ops::Range) { + let range = adjust_indices(self.start, self.end, len); + (self.sub, range) + } +} + pub fn init(ctx: &PyContext) { PyString::extend_class(ctx, &ctx.types.str_type); diff --git a/vm/src/obj/pystr.rs b/vm/src/obj/pystr.rs index fba47558ae..43a0260128 100644 --- a/vm/src/obj/pystr.rs +++ b/vm/src/obj/pystr.rs @@ -1,7 +1,8 @@ use crate::function::{single_or_tuple_any, OptionalOption}; +use crate::obj::objint::PyIntRef; use crate::pyobject::{PyObjectRef, PyResult, TryFromObject, TypeProtocol}; use crate::vm::VirtualMachine; -use num_traits::cast::ToPrimitive; +use num_traits::{cast::ToPrimitive, sign::Signed}; #[derive(FromArgs)] pub struct SplitArgs @@ -58,10 +59,10 @@ impl ExpandTabsArgs { pub struct StartsEndsWithArgs { #[pyarg(positional_only, optional = false)] affix: PyObjectRef, - #[pyarg(positional_only, optional = true)] - start: OptionalOption, - #[pyarg(positional_only, optional = true)] - end: OptionalOption, + #[pyarg(positional_only, default = "None")] + start: Option, + #[pyarg(positional_only, default = "None")] + end: Option, } impl StartsEndsWithArgs { @@ -71,14 +72,25 @@ impl StartsEndsWithArgs { } } +fn cap_to_isize(py_int: PyIntRef) -> isize { + let big = py_int.as_bigint(); + big.to_isize().unwrap_or_else(|| { + if big.is_negative() { + std::isize::MIN + } else { + std::isize::MAX + } + }) +} + // help get optional string indices pub fn adjust_indices( - start: OptionalOption, - end: OptionalOption, + start: Option, + end: Option, len: usize, ) -> std::ops::Range { - let mut start = start.flat_option().unwrap_or(0); - let mut end = end.flat_option().unwrap_or(len as isize); + let mut start = start.map_or(0, cap_to_isize); + let mut end = end.map_or(len as isize, cap_to_isize); if end > len as isize { end = len as isize; } else if end < 0 {