|
1 | 1 | use crate::{ |
2 | | - builtins::PyIntRef, |
| 2 | + builtins::{PyIntRef, PyTupleRef}, |
3 | 3 | cformat::CFormatString, |
4 | | - function::{single_or_tuple_any, OptionalOption}, |
| 4 | + function::OptionalOption, |
5 | 5 | protocol::PyIterIter, |
6 | | - AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, |
| 6 | + AsObject, PyObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine, |
7 | 7 | }; |
8 | 8 | use num_traits::{cast::ToPrimitive, sign::Signed}; |
9 | 9 | use std::str::FromStr; |
@@ -441,3 +441,33 @@ pub trait AnyStr<'s>: 's { |
441 | 441 | .format(vm, values) |
442 | 442 | } |
443 | 443 | } |
| 444 | + |
| 445 | +/// Tests that the predicate is True on a single value, or if the value is a tuple a tuple, then |
| 446 | +/// test that any of the values contained within the tuples satisfies the predicate. Type parameter |
| 447 | +/// T specifies the type that is expected, if the input value is not of that type or a tuple of |
| 448 | +/// values of that type, then a TypeError is raised. |
| 449 | +pub fn single_or_tuple_any<T, F, M>( |
| 450 | + obj: PyObjectRef, |
| 451 | + predicate: &F, |
| 452 | + message: &M, |
| 453 | + vm: &VirtualMachine, |
| 454 | +) -> PyResult<bool> |
| 455 | +where |
| 456 | + T: TryFromObject, |
| 457 | + F: Fn(&T) -> PyResult<bool>, |
| 458 | + M: Fn(&PyObject) -> String, |
| 459 | +{ |
| 460 | + match T::try_from_object(vm, obj.clone()) { |
| 461 | + Ok(single) => (predicate)(&single), |
| 462 | + Err(_) => { |
| 463 | + let tuple = PyTupleRef::try_from_object(vm, obj.clone()) |
| 464 | + .map_err(|_| vm.new_type_error((message)(&obj)))?; |
| 465 | + for obj in &tuple { |
| 466 | + if single_or_tuple_any(obj.clone(), predicate, message, vm)? { |
| 467 | + return Ok(true); |
| 468 | + } |
| 469 | + } |
| 470 | + Ok(false) |
| 471 | + } |
| 472 | + } |
| 473 | +} |
0 commit comments