Downcastable (#5986)

* simplify int power

* downcastasble

* deprecate payload*
This commit is contained in:
Jeong, YunWon
2025-07-16 18:00:18 +09:00
committed by GitHub
parent 177bfb7077
commit 6a3dff63bb
49 changed files with 210 additions and 222 deletions

View File

@@ -60,6 +60,7 @@
"dedentations",
"dedents",
"deduped",
"downcastable",
"downcasted",
"dumpable",
"emscripten",

View File

@@ -667,7 +667,7 @@ mod array {
ArrayContentType::from_char(spec).map_err(|err| vm.new_value_error(err))?;
if let OptionalArg::Present(init) = init {
if let Some(init) = init.payload::<Self>() {
if let Some(init) = init.downcast_ref::<Self>() {
match (spec, init.read().typecode()) {
(spec, ch) if spec == ch => array.frombytes(&init.get_bytes()),
(spec, 'u') => {
@@ -681,7 +681,7 @@ mod array {
}
}
}
} else if let Some(wtf8) = init.payload::<PyStr>() {
} else if let Some(wtf8) = init.downcast_ref::<PyStr>() {
if spec == 'u' {
let bytes = Self::_unicode_to_wchar_bytes(wtf8.as_wtf8(), array.itemsize());
array.frombytes_move(bytes);
@@ -690,7 +690,7 @@ mod array {
"cannot use a str to initialize an array with typecode '{spec}'"
)));
}
} else if init.payload_is::<PyBytes>() || init.payload_is::<PyByteArray>() {
} else if init.downcastable::<PyBytes>() || init.downcastable::<PyByteArray>() {
init.try_bytes_like(vm, |x| array.frombytes(x))?;
} else if let Ok(iter) = ArgIterable::try_from_object(vm, init.clone()) {
for obj in iter.iter(vm)? {
@@ -765,7 +765,7 @@ mod array {
let mut w = zelf.try_resizable(vm)?;
if zelf.is(&obj) {
w.imul(2, vm)
} else if let Some(array) = obj.payload::<Self>() {
} else if let Some(array) = obj.downcast_ref::<Self>() {
w.iadd(&array.read(), vm)
} else {
let iter = ArgIterable::try_from_object(vm, obj)?;
@@ -1013,7 +1013,7 @@ mod array {
cloned = zelf.read().clone();
&cloned
} else {
match value.payload::<Self>() {
match value.downcast_ref::<Self>() {
Some(array) => {
guard = array.read();
&*guard
@@ -1059,7 +1059,7 @@ mod array {
#[pymethod]
fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
if let Some(other) = other.payload::<Self>() {
if let Some(other) = other.downcast_ref::<Self>() {
self.read()
.add(&other.read(), vm)
.map(|array| Self::from(array).into_ref(&vm.ctx))
@@ -1079,7 +1079,7 @@ mod array {
) -> PyResult<PyRef<Self>> {
if zelf.is(&other) {
zelf.try_resizable(vm)?.imul(2, vm)?;
} else if let Some(other) = other.payload::<Self>() {
} else if let Some(other) = other.downcast_ref::<Self>() {
zelf.try_resizable(vm)?.iadd(&other.read(), vm)?;
} else {
return Err(vm.new_type_error(format!(

View File

@@ -269,7 +269,7 @@ mod _csv {
mut _rest: FuncArgs,
vm: &VirtualMachine,
) -> PyResult<()> {
let Some(name) = name.payload_if_subclass::<PyStr>(vm) else {
let Some(name) = name.downcast_ref::<PyStr>() else {
return Err(vm.new_type_error("argument 0 must be a string"));
};
let dialect = match dialect {
@@ -290,7 +290,7 @@ mod _csv {
mut _rest: FuncArgs,
vm: &VirtualMachine,
) -> PyResult<PyDialect> {
let Some(name) = name.payload_if_subclass::<PyStr>(vm) else {
let Some(name) = name.downcast_ref::<PyStr>() else {
return Err(vm.new_exception_msg(
super::_csv::error(vm),
format!("argument 0 must be a string, not '{}'", name.class()),
@@ -309,7 +309,7 @@ mod _csv {
mut _rest: FuncArgs,
vm: &VirtualMachine,
) -> PyResult<()> {
let Some(name) = name.payload_if_subclass::<PyStr>(vm) else {
let Some(name) = name.downcast_ref::<PyStr>() else {
return Err(vm.new_exception_msg(
super::_csv::error(vm),
format!("argument 0 must be a string, not '{}'", name.class()),

View File

@@ -350,7 +350,7 @@ mod decl {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
let timeout = if vm.is_none(&obj) {
None
} else if let Some(float) = obj.payload::<PyFloat>() {
} else if let Some(float) = obj.downcast_ref::<PyFloat>() {
let float = float.to_f64();
if float.is_nan() {
return Err(vm.new_value_error("Invalid value NaN (not a number)"));

View File

@@ -535,7 +535,7 @@ mod _sqlite {
let access = ptr_to_str(access, vm)?;
let val = callable.call((action, arg1, arg2, db_name, access), vm)?;
let Some(val) = val.payload::<PyInt>() else {
let Some(val) = val.downcast_ref::<PyInt>() else {
return Ok(SQLITE_DENY);
};
val.try_to_primitive::<c_int>(vm)
@@ -1897,18 +1897,18 @@ mod _sqlite {
Ok(self
.description
.iter()
.map(|x| x.payload::<PyTuple>().unwrap().as_slice()[0].clone())
.map(|x| x.downcast_ref::<PyTuple>().unwrap().as_slice()[0].clone())
.collect())
}
fn subscript(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
if let Some(i) = needle.payload::<PyInt>() {
if let Some(i) = needle.downcast_ref::<PyInt>() {
let i = i.try_to_primitive::<isize>(vm)?;
self.data.getitem_by_index(vm, i)
} else if let Some(name) = needle.payload::<PyStr>() {
} else if let Some(name) = needle.downcast_ref::<PyStr>() {
for (obj, i) in self.description.iter().zip(0..) {
let obj = &obj.payload::<PyTuple>().unwrap().as_slice()[0];
let Some(obj) = obj.payload::<PyStr>() else {
let obj = &obj.downcast_ref::<PyTuple>().unwrap().as_slice()[0];
let Some(obj) = obj.downcast_ref::<PyStr>() else {
break;
};
let a_iter = name.as_str().chars().flat_map(|x| x.to_uppercase());
@@ -1919,7 +1919,7 @@ mod _sqlite {
}
}
Err(vm.new_index_error("No item with that key"))
} else if let Some(slice) = needle.payload::<PySlice>() {
} else if let Some(slice) = needle.downcast_ref::<PySlice>() {
let list = self.data.getitem_by_slice(vm, slice.to_saturated(vm)?)?;
Ok(vm.ctx.new_tuple(list).into())
} else {
@@ -1962,7 +1962,7 @@ mod _sqlite {
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
op.eq_only(|| {
if let Some(other) = other.payload::<Self>() {
if let Some(other) = other.downcast_ref::<Self>() {
let eq = vm
.bool_eq(zelf.description.as_object(), other.description.as_object())?
&& vm.bool_eq(zelf.data.as_object(), other.data.as_object())?;
@@ -2179,7 +2179,7 @@ mod _sqlite {
let mut byte: u8 = 0;
let ret = inner.blob.read_single(&mut byte, index);
self.check(ret, vm).map(|_| vm.ctx.new_int(byte).into())
} else if let Some(slice) = needle.payload::<PySlice>() {
} else if let Some(slice) = needle.downcast_ref::<PySlice>() {
let blob_len = inner.blob.bytes();
let slice = slice.to_saturated(vm)?;
let (range, step, length) = slice.adjust_indices(blob_len as usize);
@@ -2220,7 +2220,7 @@ mod _sqlite {
let inner = self.inner(vm)?;
if let Some(index) = needle.try_index_opt(vm) {
let Some(value) = value.payload::<PyInt>() else {
let Some(value) = value.downcast_ref::<PyInt>() else {
return Err(vm.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",
value.class()
@@ -2232,7 +2232,7 @@ mod _sqlite {
Self::expect_write(blob_len, 1, index, vm)?;
let ret = inner.blob.write_single(value, index);
self.check(ret, vm)
} else if let Some(_slice) = needle.payload::<PySlice>() {
} else if let Some(_slice) = needle.downcast_ref::<PySlice>() {
Err(vm.new_not_implemented_error("Blob slice assignment is not implemented"))
// let blob_len = inner.blob.bytes();
// let slice = slice.to_saturated(vm)?;
@@ -2645,15 +2645,15 @@ mod _sqlite {
let ret = if vm.is_none(obj) {
unsafe { sqlite3_bind_null(self.st, pos) }
} else if let Some(val) = obj.payload::<PyInt>() {
} else if let Some(val) = obj.downcast_ref::<PyInt>() {
let val = val.try_to_primitive::<i64>(vm).map_err(|_| {
vm.new_overflow_error("Python int too large to convert to SQLite INTEGER")
})?;
unsafe { sqlite3_bind_int64(self.st, pos, val) }
} else if let Some(val) = obj.payload::<PyFloat>() {
} else if let Some(val) = obj.downcast_ref::<PyFloat>() {
let val = val.to_f64();
unsafe { sqlite3_bind_double(self.st, pos, val) }
} else if let Some(val) = obj.payload::<PyStr>() {
} else if let Some(val) = obj.downcast_ref::<PyStr>() {
let (ptr, len) = str_to_ptr_len(val, vm)?;
unsafe { sqlite3_bind_text(self.st, pos, ptr, len, SQLITE_TRANSIENT()) }
} else if let Ok(buffer) = PyBuffer::try_from_borrowed_object(vm, obj) {
@@ -2900,11 +2900,11 @@ mod _sqlite {
unsafe {
if vm.is_none(val) {
sqlite3_result_null(self.ctx)
} else if let Some(val) = val.payload::<PyInt>() {
} else if let Some(val) = val.downcast_ref::<PyInt>() {
sqlite3_result_int64(self.ctx, val.try_to_primitive(vm)?)
} else if let Some(val) = val.payload::<PyFloat>() {
} else if let Some(val) = val.downcast_ref::<PyFloat>() {
sqlite3_result_double(self.ctx, val.to_f64())
} else if let Some(val) = val.payload::<PyStr>() {
} else if let Some(val) = val.downcast_ref::<PyStr>() {
let (ptr, len) = str_to_ptr_len(val, vm)?;
sqlite3_result_text(self.ctx, ptr, len, SQLITE_TRANSIENT())
} else if let Ok(buffer) = PyBuffer::try_from_borrowed_object(vm, val) {

View File

@@ -217,9 +217,12 @@ mod termios {
))
})?;
for (cc, x) in termios.c_cc.iter_mut().zip(cc.iter()) {
*cc = if let Some(c) = x.payload::<PyBytes>().filter(|b| b.as_bytes().len() == 1) {
*cc = if let Some(c) = x
.downcast_ref::<PyBytes>()
.filter(|b| b.as_bytes().len() == 1)
{
c.as_bytes()[0] as _
} else if let Some(i) = x.payload::<PyInt>() {
} else if let Some(i) = x.downcast_ref::<PyInt>() {
i.try_to_primitive(vm)?
} else {
return Err(vm.new_type_error(

View File

@@ -344,7 +344,9 @@ impl PyAsyncGenAThrow {
let ret = self.ag.inner.send(self.ag.as_object(), val, vm);
if self.aclose {
match ret {
Ok(PyIterReturn::Return(v)) if v.payload_is::<PyAsyncGenWrappedValue>() => {
Ok(PyIterReturn::Return(v))
if v.downcastable::<PyAsyncGenWrappedValue>() =>
{
Err(self.yield_close(vm))
}
other => other
@@ -392,7 +394,7 @@ impl PyAsyncGenAThrow {
fn ignored_close(&self, res: &PyResult<PyIterReturn>) -> bool {
res.as_ref().is_ok_and(|v| match v {
PyIterReturn::Return(obj) => obj.payload_is::<PyAsyncGenWrappedValue>(),
PyIterReturn::Return(obj) => obj.downcastable::<PyAsyncGenWrappedValue>(),
PyIterReturn::StopIteration(_) => false,
})
}

View File

@@ -57,7 +57,7 @@ impl PyObjectRef {
Some(method_or_err) => {
let method = method_or_err?;
let bool_obj = method.call((), vm)?;
let int_obj = bool_obj.payload::<PyInt>().ok_or_else(|| {
let int_obj = bool_obj.downcast_ref::<PyInt>().ok_or_else(|| {
vm.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",
bool_obj.class().name()
@@ -128,8 +128,8 @@ impl PyBool {
let lhs = get_value(&lhs);
let rhs = get_value(&rhs);
(lhs || rhs).to_pyobject(vm)
} else if let Some(lhs) = lhs.payload::<PyInt>() {
lhs.__or__(rhs, vm).to_pyobject(vm)
} else if let Some(lhs) = lhs.downcast_ref::<PyInt>() {
lhs.__or__(rhs).to_pyobject(vm)
} else {
vm.ctx.not_implemented()
}
@@ -144,8 +144,8 @@ impl PyBool {
let lhs = get_value(&lhs);
let rhs = get_value(&rhs);
(lhs && rhs).to_pyobject(vm)
} else if let Some(lhs) = lhs.payload::<PyInt>() {
lhs.__and__(rhs, vm).to_pyobject(vm)
} else if let Some(lhs) = lhs.downcast_ref::<PyInt>() {
lhs.__and__(rhs).to_pyobject(vm)
} else {
vm.ctx.not_implemented()
}
@@ -160,8 +160,8 @@ impl PyBool {
let lhs = get_value(&lhs);
let rhs = get_value(&rhs);
(lhs ^ rhs).to_pyobject(vm)
} else if let Some(lhs) = lhs.payload::<PyInt>() {
lhs.__xor__(rhs, vm).to_pyobject(vm)
} else if let Some(lhs) = lhs.downcast_ref::<PyInt>() {
lhs.__xor__(rhs).to_pyobject(vm)
} else {
vm.ctx.not_implemented()
}
@@ -212,5 +212,5 @@ pub(crate) fn init(context: &Context) {
// Retrieve inner int value:
pub(crate) fn get_value(obj: &PyObject) -> bool {
!obj.payload::<PyInt>().unwrap().as_bigint().is_zero()
!obj.downcast_ref::<PyInt>().unwrap().as_bigint().is_zero()
}

View File

@@ -213,7 +213,7 @@ impl Comparable for PyNativeMethod {
_vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
op.eq_only(|| {
if let Some(other) = other.payload::<Self>() {
if let Some(other) = other.downcast_ref::<Self>() {
let eq = match (zelf.func.zelf.as_ref(), other.func.zelf.as_ref()) {
(Some(z), Some(o)) => z.is(o),
(None, None) => true,

View File

@@ -58,7 +58,7 @@ impl PyObjectRef {
/// Tries converting a python object into a complex, returns an option of whether the complex
/// and whether the object was a complex originally or coerced into one
pub fn try_complex(&self, vm: &VirtualMachine) -> PyResult<Option<(Complex64, bool)>> {
if let Some(complex) = self.payload_if_exact::<PyComplex>(vm) {
if let Some(complex) = self.downcast_ref_if_exact::<PyComplex>(vm) {
return Ok(Some((complex.value, true)));
}
if let Some(method) = vm.get_method(self.clone(), identifier!(vm, __complex__)) {
@@ -79,7 +79,7 @@ impl PyObjectRef {
return Ok(Some((ret.value, true)));
} else {
return match result.payload::<PyComplex>() {
return match result.downcast_ref::<PyComplex>() {
Some(complex_obj) => Ok(Some((complex_obj.value, true))),
None => Err(vm.new_type_error(format!(
"__complex__ returned non-complex (type '{}')",
@@ -90,7 +90,7 @@ impl PyObjectRef {
}
// `complex` does not have a `__complex__` by default, so subclasses might not either,
// use the actual stored value in this case
if let Some(complex) = self.payload_if_subclass::<PyComplex>(vm) {
if let Some(complex) = self.downcast_ref::<PyComplex>() {
return Ok(Some((complex.value, true)));
}
if let Some(float) = self.try_float_opt(vm) {
@@ -105,7 +105,7 @@ pub fn init(context: &Context) {
}
fn to_op_complex(value: &PyObject, vm: &VirtualMachine) -> PyResult<Option<Complex64>> {
let r = if let Some(complex) = value.payload_if_subclass::<PyComplex>(vm) {
let r = if let Some(complex) = value.downcast_ref::<PyComplex>() {
Some(complex.value)
} else {
float::to_op_float(value, vm)?.map(|float| Complex64::new(float, 0.0))
@@ -175,7 +175,7 @@ impl Constructor for PyComplex {
if let Some(c) = val.try_complex(vm)? {
c
} else if let Some(s) = val.payload_if_subclass::<PyStr>(vm) {
} else if let Some(s) = val.downcast_ref::<PyStr>() {
if args.imag.is_present() {
return Err(vm.new_type_error(
"complex() can't take second arg if first is a string",
@@ -419,7 +419,7 @@ impl Comparable for PyComplex {
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
op.eq_only(|| {
let result = if let Some(other) = other.payload_if_subclass::<Self>(vm) {
let result = if let Some(other) = other.downcast_ref::<Self>() {
if zelf.value.re.is_nan()
&& zelf.value.im.is_nan()
&& other.value.re.is_nan()

View File

@@ -57,9 +57,9 @@ impl From<f64> for PyFloat {
}
pub(crate) fn to_op_float(obj: &PyObject, vm: &VirtualMachine) -> PyResult<Option<f64>> {
let v = if let Some(float) = obj.payload_if_subclass::<PyFloat>(vm) {
let v = if let Some(float) = obj.downcast_ref::<PyFloat>() {
Some(float.value)
} else if let Some(int) = obj.payload_if_subclass::<PyInt>(vm) {
} else if let Some(int) = obj.downcast_ref::<PyInt>() {
Some(try_bigint_to_f64(int.as_bigint(), vm)?)
} else {
None
@@ -154,7 +154,7 @@ impl Constructor for PyFloat {
fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
let (bytearray, buffer, buffer_lock, mapped_string);
let b = if let Some(s) = val.payload_if_subclass::<PyStr>(vm) {
let b = if let Some(s) = val.downcast_ref::<PyStr>() {
use crate::common::str::PyKindStr;
match s.as_str_kind() {
PyKindStr::Ascii(s) => s.trim().as_bytes(),
@@ -178,9 +178,9 @@ fn float_from_string(val: PyObjectRef, vm: &VirtualMachine) -> PyResult<f64> {
// so we can just choose a known bad value
PyKindStr::Wtf8(_) => b"",
}
} else if let Some(bytes) = val.payload_if_subclass::<PyBytes>(vm) {
} else if let Some(bytes) = val.downcast_ref::<PyBytes>() {
bytes.as_bytes()
} else if let Some(buf) = val.payload_if_subclass::<PyByteArray>(vm) {
} else if let Some(buf) = val.downcast_ref::<PyByteArray>() {
bytearray = buf.borrow_buf();
&*bytearray
} else if let Ok(b) = ArgBytesLike::try_from_borrowed_object(vm, &val) {
@@ -521,13 +521,13 @@ impl Comparable for PyFloat {
zelf: &Py<Self>,
other: &PyObject,
op: PyComparisonOp,
vm: &VirtualMachine,
_vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
let ret = if let Some(other) = other.payload_if_subclass::<Self>(vm) {
let ret = if let Some(other) = other.downcast_ref::<Self>() {
zelf.value
.partial_cmp(&other.value)
.map_or_else(|| op == PyComparisonOp::Ne, |ord| op.eval_ord(ord))
} else if let Some(other) = other.payload_if_subclass::<PyInt>(vm) {
} else if let Some(other) = other.downcast_ref::<PyInt>() {
let a = zelf.to_f64();
let b = other.as_bigint();
match op {
@@ -633,7 +633,7 @@ impl PyFloat {
// Retrieve inner float value:
#[cfg(feature = "serde")]
pub(crate) fn get_value(obj: &PyObject) -> f64 {
obj.payload::<PyFloat>().unwrap().value
obj.downcast_ref::<PyFloat>().unwrap().value
}
#[rustfmt::skip] // to avoid line splitting

View File

@@ -293,12 +293,12 @@ impl PyInt {
}
#[inline]
fn int_op<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyArithmeticValue<BigInt>
fn int_op<F>(&self, other: PyObjectRef, op: F) -> PyArithmeticValue<BigInt>
where
F: Fn(&BigInt, &BigInt) -> BigInt,
{
let r = other
.payload_if_subclass::<Self>(vm)
.downcast_ref::<Self>()
.map(|other| op(&self.value, &other.value));
PyArithmeticValue::from_option(r)
}
@@ -308,7 +308,7 @@ impl PyInt {
where
F: Fn(&BigInt, &BigInt) -> PyResult,
{
if let Some(other) = other.payload_if_subclass::<Self>(vm) {
if let Some(other) = other.downcast_ref::<Self>() {
op(&self.value, &other.value)
} else {
Ok(vm.ctx.not_implemented())
@@ -323,24 +323,24 @@ impl PyInt {
impl PyInt {
#[pymethod(name = "__radd__")]
#[pymethod]
fn __add__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a + b, vm)
fn __add__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a + b)
}
#[pymethod]
fn __sub__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a - b, vm)
fn __sub__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a - b)
}
#[pymethod]
fn __rsub__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| b - a, vm)
fn __rsub__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| b - a)
}
#[pymethod(name = "__rmul__")]
#[pymethod]
fn __mul__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a * b, vm)
fn __mul__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a * b)
}
#[pymethod]
@@ -385,24 +385,24 @@ impl PyInt {
#[pymethod(name = "__rxor__")]
#[pymethod]
pub fn __xor__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a ^ b, vm)
pub fn __xor__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a ^ b)
}
#[pymethod(name = "__ror__")]
#[pymethod]
pub fn __or__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a | b, vm)
pub fn __or__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a | b)
}
#[pymethod(name = "__rand__")]
#[pymethod]
pub fn __and__(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a & b, vm)
pub fn __and__(&self, other: PyObjectRef) -> PyArithmeticValue<BigInt> {
self.int_op(other, |a, b| a & b)
}
fn modpow(&self, other: PyObjectRef, modulus: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let modulus = match modulus.payload_if_subclass::<Self>(vm) {
let modulus = match modulus.downcast_ref::<Self>() {
Some(val) => val.as_bigint(),
None => return Ok(vm.ctx.not_implemented()),
};
@@ -714,10 +714,10 @@ impl Comparable for PyInt {
zelf: &Py<Self>,
other: &PyObject,
op: PyComparisonOp,
vm: &VirtualMachine,
_vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
let r = other
.payload_if_subclass::<Self>(vm)
.downcast_ref::<Self>()
.map(|other| op.eval_ord(zelf.value.cmp(&other.value)));
Ok(PyComparisonValue::from_option(r))
}
@@ -757,14 +757,7 @@ impl PyInt {
remainder: Some(|a, b, vm| Self::number_op(a, b, inner_mod, vm)),
divmod: Some(|a, b, vm| Self::number_op(a, b, inner_divmod, vm)),
power: Some(|a, b, c, vm| {
if let (Some(a), Some(b)) = (
a.payload::<Self>(),
if b.payload_is::<Self>() {
Some(b)
} else {
None
},
) {
if let Some(a) = a.downcast_ref::<Self>() {
if vm.is_none(c) {
a.general_op(b.to_owned(), |a, b| inner_pow(a, b, vm), vm)
} else {
@@ -800,7 +793,7 @@ impl PyInt {
F: FnOnce(&BigInt, &BigInt, &VirtualMachine) -> R,
R: ToPyResult,
{
if let (Some(a), Some(b)) = (a.payload::<Self>(), b.payload::<Self>()) {
if let (Some(a), Some(b)) = (a.downcast_ref::<Self>(), b.downcast_ref::<Self>()) {
op(&a.value, &b.value, vm).to_pyresult(vm)
} else {
Ok(vm.ctx.not_implemented())
@@ -867,7 +860,7 @@ fn try_int_radix(obj: &PyObject, base: u32, vm: &VirtualMachine) -> PyResult<Big
// Retrieve inner int value:
pub(crate) fn get_value(obj: &PyObject) -> &BigInt {
&obj.payload::<PyInt>().unwrap().value
&obj.downcast_ref::<PyInt>().unwrap().value
}
pub fn try_to_float(int: &BigInt, vm: &VirtualMachine) -> PyResult<f64> {

View File

@@ -59,7 +59,7 @@ impl<T> PositionIterInternal<T> {
F: FnOnce(&T, usize) -> usize,
{
if let IterStatus::Active(obj) = &self.status {
if let Some(i) = state.payload::<PyInt>() {
if let Some(i) = state.downcast_ref::<PyInt>() {
let i = i.try_to_primitive(vm).unwrap_or(0);
self.position = f(obj, i);
Ok(())

View File

@@ -131,7 +131,7 @@ impl PyList {
}
fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
let other = other.payload_if_subclass::<Self>(vm).ok_or_else(|| {
let other = other.downcast_ref::<Self>().ok_or_else(|| {
vm.new_type_error(format!(
"Cannot add {} and {}",
Self::class(&vm.ctx).name(),
@@ -346,9 +346,9 @@ where
F: FnMut(PyObjectRef) -> PyResult<R>,
{
use crate::builtins::PyTuple;
if let Some(tuple) = obj.payload_if_exact::<PyTuple>(vm) {
if let Some(tuple) = obj.downcast_ref_if_exact::<PyTuple>(vm) {
tuple.iter().map(|x| f(x.clone())).collect()
} else if let Some(list) = obj.payload_if_exact::<PyList>(vm) {
} else if let Some(list) = obj.downcast_ref_if_exact::<PyList>(vm) {
list.borrow_vec().iter().map(|x| f(x.clone())).collect()
} else {
let iter = obj.to_owned().get_iter(vm)?;

View File

@@ -63,9 +63,7 @@ impl Constructor for PyMappingProxy {
fn py_new(cls: PyTypeRef, mapping: Self::Args, vm: &VirtualMachine) -> PyResult {
if let Some(methods) = PyMapping::find_methods(&mapping) {
if mapping.payload_if_subclass::<PyList>(vm).is_none()
&& mapping.payload_if_subclass::<PyTuple>(vm).is_none()
{
if !mapping.downcastable::<PyList>() && !mapping.downcastable::<PyTuple>() {
return Self {
mapping: MappingProxyInner::Mapping(ArgMapping::with_methods(
mapping,

View File

@@ -75,7 +75,7 @@ impl PyMemoryView {
/// this should be the main entrance to create the memoryview
/// to avoid the chained memoryview
pub fn from_object(obj: &PyObject, vm: &VirtualMachine) -> PyResult<Self> {
if let Some(other) = obj.payload::<Self>() {
if let Some(other) = obj.downcast_ref::<Self>() {
Ok(other.new_view())
} else {
let buffer = PyBuffer::try_from_borrowed_object(vm, obj)?;
@@ -330,7 +330,7 @@ impl PyMemoryView {
return Ok(false);
}
if let Some(other) = other.payload::<Self>() {
if let Some(other) = other.downcast_ref::<Self>() {
if other.released.load() {
return Ok(false);
}
@@ -665,7 +665,7 @@ impl PyMemoryView {
if needle.is(&vm.ctx.ellipsis) {
return Ok(zelf.into());
}
if let Some(tuple) = needle.payload::<PyTuple>() {
if let Some(tuple) = needle.downcast_ref::<PyTuple>() {
if tuple.is_empty() {
return zelf.unpack_single(0, vm);
}
@@ -864,7 +864,7 @@ impl Py<PyMemoryView> {
// TODO: merge branches when we got conditional if let
if needle.is(&vm.ctx.ellipsis) {
return self.pack_single(0, value, vm);
} else if let Some(tuple) = needle.payload::<PyTuple>() {
} else if let Some(tuple) = needle.downcast_ref::<PyTuple>() {
if tuple.is_empty() {
return self.pack_single(0, value, vm);
}
@@ -907,15 +907,15 @@ enum SubscriptNeedle {
impl TryFromObject for SubscriptNeedle {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
// TODO: number protocol
if let Some(i) = obj.payload::<PyInt>() {
if let Some(i) = obj.downcast_ref::<PyInt>() {
Ok(Self::Index(i.try_to_primitive(vm)?))
} else if obj.payload_is::<PySlice>() {
} else if obj.downcastable::<PySlice>() {
Ok(Self::Slice(unsafe { obj.downcast_unchecked::<PySlice>() }))
} else if let Ok(i) = obj.try_index(vm) {
Ok(Self::Index(i.try_to_primitive(vm)?))
} else {
if let Some(tuple) = obj.payload::<PyTuple>() {
if tuple.iter().all(|x| x.payload_is::<PyInt>()) {
if let Some(tuple) = obj.downcast_ref::<PyTuple>() {
if tuple.iter().all(|x| x.downcastable::<PyInt>()) {
let v = tuple
.iter()
.map(|x| {
@@ -924,7 +924,7 @@ impl TryFromObject for SubscriptNeedle {
})
.try_collect()?;
return Ok(Self::MultiIndex(v));
} else if tuple.iter().all(|x| x.payload_is::<PySlice>()) {
} else if tuple.iter().all(|x| x.downcastable::<PySlice>()) {
return Err(vm.new_not_implemented_error(
"multi-dimensional slicing is not implemented",
));

View File

@@ -165,7 +165,7 @@ impl PyRange {
}
// pub fn get_value(obj: &PyObject) -> PyRange {
// obj.payload::<PyRange>().unwrap().clone()
// obj.downcast_ref::<PyRange>().unwrap().clone()
// }
pub fn init(context: &Context) {
@@ -677,7 +677,7 @@ fn range_iter_reduce(
// Silently clips state (i.e index) in range [0, usize::MAX].
fn range_state(length: &BigInt, state: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
if let Some(i) = state.payload::<PyInt>() {
if let Some(i) = state.downcast_ref::<PyInt>() {
let mut index = i.as_bigint();
let max_usize = BigInt::from(usize::MAX);
if index > length {

View File

@@ -474,7 +474,7 @@ impl PySetInner {
F: Fn(&PyObject, &VirtualMachine) -> PyResult<T>,
{
op(item, vm).or_else(|original_err| {
item.payload_if_subclass::<PySet>(vm)
item.downcast_ref::<PySet>()
// Keep original error around.
.ok_or(original_err)
.and_then(|set| {

View File

@@ -549,7 +549,7 @@ impl PyStr {
impl PyStr {
#[pymethod]
fn __add__(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
if let Some(other) = other.payload::<Self>() {
if let Some(other) = other.downcast_ref::<Self>() {
let bytes = zelf.as_wtf8().py_add(other.as_wtf8());
Ok(unsafe {
// SAFETY: `kind` is safely decided
@@ -569,7 +569,7 @@ impl PyStr {
}
fn _contains(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
if let Some(needle) = needle.payload::<Self>() {
if let Some(needle) = needle.downcast_ref::<Self>() {
Ok(memchr::memmem::find(self.as_bytes(), needle.as_bytes()).is_some())
} else {
Err(vm.new_type_error(format!(
@@ -1374,9 +1374,9 @@ impl PyStr {
for c in self.as_str().chars() {
match table.get_item(&*(c as u32).to_pyobject(vm), vm) {
Ok(value) => {
if let Some(text) = value.payload::<Self>() {
if let Some(text) = value.downcast_ref::<Self>() {
translated.push_str(text.as_str());
} else if let Some(bigint) = value.payload::<PyInt>() {
} else if let Some(bigint) = value.downcast_ref::<PyInt>() {
let ch = bigint
.as_bigint()
.to_u32()
@@ -1438,13 +1438,13 @@ impl PyStr {
Ok(dict) => {
for (key, val) in dict {
// FIXME: ints are key-compatible
if let Some(num) = key.payload::<PyInt>() {
if let Some(num) = key.downcast_ref::<PyInt>() {
new_dict.set_item(
&*num.as_bigint().to_i32().to_pyobject(vm),
val,
vm,
)?;
} else if let Some(string) = key.payload::<Self>() {
} else if let Some(string) = key.downcast_ref::<Self>() {
if string.len() == 1 {
let num_value = string.as_str().chars().next().unwrap() as u32;
new_dict.set_item(&*num_value.to_pyobject(vm), val, vm)?;

View File

@@ -592,7 +592,7 @@ impl PyType {
PyType::resolve_mro(&cls.bases.read()).map_err(|msg| vm.new_type_error(msg))?;
for subclass in cls.subclasses.write().iter() {
let subclass = subclass.upgrade().unwrap();
let subclass: &PyType = subclass.payload().unwrap();
let subclass: &Py<PyType> = subclass.downcast_ref().unwrap();
update_mro_recursively(subclass, vm)?;
}
Ok(())

View File

@@ -153,7 +153,7 @@ impl PyUnion {
pub fn is_unionable(obj: PyObjectRef, vm: &VirtualMachine) -> bool {
obj.class().is(vm.ctx.types.none_type)
|| obj.payload_if_subclass::<PyType>(vm).is_some()
|| obj.downcastable::<PyType>()
|| obj.class().is(vm.ctx.types.generic_alias_type)
|| obj.class().is(vm.ctx.types.union_type)
}

View File

@@ -63,7 +63,7 @@ fn spec_format_bytes(
obj => {
if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) {
let result = method?.call((), vm)?;
if let Some(i) = result.payload::<PyInt>() {
if let Some(i) = result.downcast_ref::<PyInt>() {
return Ok(spec.format_number(i.as_bigint()).into_bytes());
}
}
@@ -76,7 +76,7 @@ fn spec_format_bytes(
})
}
_ => {
if let Some(i) = obj.payload::<PyInt>() {
if let Some(i) = obj.downcast_ref::<PyInt>() {
Ok(spec.format_number(i.as_bigint()).into_bytes())
} else {
Err(vm.new_type_error(format!(
@@ -101,17 +101,17 @@ fn spec_format_bytes(
Ok(spec.format_float(value.into()).into_bytes())
}
CFormatType::Character(CCharacterType::Character) => {
if let Some(i) = obj.payload::<PyInt>() {
if let Some(i) = obj.downcast_ref::<PyInt>() {
let ch = i
.try_to_primitive::<u8>(vm)
.map_err(|_| vm.new_overflow_error("%c arg not in range(256)"))?;
return Ok(spec.format_char(ch));
}
if let Some(b) = obj.payload::<PyBytes>() {
if let Some(b) = obj.downcast_ref::<PyBytes>() {
if b.len() == 1 {
return Ok(spec.format_char(b.as_bytes()[0]));
}
} else if let Some(ba) = obj.payload::<PyByteArray>() {
} else if let Some(ba) = obj.downcast_ref::<PyByteArray>() {
let buf = ba.borrow_buf();
if buf.len() == 1 {
return Ok(spec.format_char(buf[0]));
@@ -158,7 +158,7 @@ fn spec_format_string(
obj => {
if let Some(method) = vm.get_method(obj.clone(), identifier!(vm, __int__)) {
let result = method?.call((), vm)?;
if let Some(i) = result.payload::<PyInt>() {
if let Some(i) = result.downcast_ref::<PyInt>() {
return Ok(spec.format_number(i.as_bigint()).into());
}
}
@@ -171,7 +171,7 @@ fn spec_format_string(
})
}
_ => {
if let Some(i) = obj.payload::<PyInt>() {
if let Some(i) = obj.downcast_ref::<PyInt>() {
Ok(spec.format_number(i.as_bigint()).into())
} else {
Err(vm.new_type_error(format!(
@@ -187,7 +187,7 @@ fn spec_format_string(
Ok(spec.format_float(value.into()).into())
}
CFormatType::Character(CCharacterType::Character) => {
if let Some(i) = obj.payload::<PyInt>() {
if let Some(i) = obj.downcast_ref::<PyInt>() {
let ch = i
.as_bigint()
.to_u32()
@@ -195,7 +195,7 @@ fn spec_format_string(
.ok_or_else(|| vm.new_overflow_error("%c arg not in range(0x110000)"))?;
return Ok(spec.format_char(ch));
}
if let Some(s) = obj.payload::<PyStr>() {
if let Some(s) = obj.downcast_ref::<PyStr>() {
if let Ok(ch) = s.as_wtf8().code_points().exactly_one() {
return Ok(spec.format_char(ch));
}
@@ -211,7 +211,7 @@ fn try_update_quantity_from_element(
) -> PyResult<CFormatQuantity> {
match element {
Some(width_obj) => {
if let Some(i) = width_obj.payload::<PyInt>() {
if let Some(i) = width_obj.downcast_ref::<PyInt>() {
let i = i.try_to_primitive::<i32>(vm)?.unsigned_abs();
Ok(CFormatQuantity::Amount(i as usize))
} else {
@@ -228,7 +228,7 @@ fn try_conversion_flag_from_tuple(
) -> PyResult<CConversionFlags> {
match element {
Some(width_obj) => {
if let Some(i) = width_obj.payload::<PyInt>() {
if let Some(i) = width_obj.downcast_ref::<PyInt>() {
let i = i.try_to_primitive::<i32>(vm)?;
let flags = if i < 0 {
CConversionFlags::LEFT_ADJUST
@@ -299,7 +299,7 @@ pub(crate) fn cformat_bytes(
// literal only
return if is_mapping
|| values_obj
.payload::<tuple::PyTuple>()
.downcast_ref::<tuple::PyTuple>()
.is_some_and(|e| e.is_empty())
{
for (_, part) in format.iter_mut() {
@@ -335,7 +335,7 @@ pub(crate) fn cformat_bytes(
}
// tuple
let values = if let Some(tup) = values_obj.payload_if_subclass::<tuple::PyTuple>(vm) {
let values = if let Some(tup) = values_obj.downcast_ref::<tuple::PyTuple>() {
tup.as_slice()
} else {
std::slice::from_ref(&values_obj)
@@ -393,7 +393,7 @@ pub(crate) fn cformat_string(
// literal only
return if is_mapping
|| values_obj
.payload::<tuple::PyTuple>()
.downcast_ref::<tuple::PyTuple>()
.is_some_and(|e| e.is_empty())
{
for (_, part) in format.iter() {
@@ -428,7 +428,7 @@ pub(crate) fn cformat_string(
}
// tuple
let values = if let Some(tup) = values_obj.payload_if_subclass::<tuple::PyTuple>(vm) {
let values = if let Some(tup) = values_obj.downcast_ref::<tuple::PyTuple>() {
tup.as_slice()
} else {
std::slice::from_ref(&values_obj)

View File

@@ -852,7 +852,7 @@ impl<'a> EncodeErrorHandler<PyEncodeContext<'a>> for ErrorsHandler<'_> {
let res = handler.call((encode_exc.clone(),), vm)?;
let tuple_err =
|| vm.new_type_error("encoding error handler must return (str/bytes, int) tuple");
let (replace, restart) = match res.payload::<PyTuple>().map(|tup| tup.as_slice()) {
let (replace, restart) = match res.downcast_ref::<PyTuple>().map(|tup| tup.as_slice()) {
Some([replace, restart]) => (replace.clone(), restart),
_ => return Err(tuple_err()),
};
@@ -910,7 +910,7 @@ impl<'a> DecodeErrorHandler<PyDecodeContext<'a>> for ErrorsHandler<'_> {
}
let data = &*ctx.data;
let tuple_err = || vm.new_type_error("decoding error handler must return (str, int) tuple");
match res.payload::<PyTuple>().map(|tup| tup.as_slice()) {
match res.downcast_ref::<PyTuple>().map(|tup| tup.as_slice()) {
Some([replace, restart]) => {
let replace = replace
.downcast_ref::<PyStr>()

View File

@@ -17,7 +17,7 @@ unsafe impl<T: PyPayload> TransmuteFromObject for PyRef<T> {
fn check(vm: &VirtualMachine, obj: &PyObject) -> PyResult<()> {
let class = T::class(&vm.ctx);
if obj.fast_isinstance(class) {
if obj.payload_is::<T>() {
if obj.downcastable::<T>() {
Ok(())
} else {
Err(vm.new_downcast_runtime_error(class, obj))

View File

@@ -124,7 +124,7 @@ impl<'a, T: PyPayload> TryFromBorrowedObject<'a> for &'a Py<T> {
impl TryFromObject for std::time::Duration {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
if let Some(float) = obj.payload::<PyFloat>() {
if let Some(float) = obj.downcast_ref::<PyFloat>() {
let f = float.to_f64();
if f < 0.0 {
return Err(vm.new_value_error("negative duration"));

View File

@@ -777,7 +777,7 @@ impl DictKey for Py<PyStr> {
fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult<bool> {
if self.is(other_key) {
Ok(true)
} else if let Some(pystr) = other_key.payload_if_exact::<PyStr>(vm) {
} else if let Some(pystr) = other_key.downcast_ref_if_exact::<PyStr>(vm) {
Ok(self.as_wtf8() == pystr.as_wtf8())
} else {
vm.bool_eq(self.as_object(), other_key)
@@ -875,7 +875,7 @@ impl DictKey for str {
}
fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult<bool> {
if let Some(pystr) = other_key.payload_if_exact::<PyStr>(vm) {
if let Some(pystr) = other_key.downcast_ref_if_exact::<PyStr>(vm) {
Ok(pystr.as_wtf8() == self)
} else {
// Fall back to PyObjectRef implementation.
@@ -936,7 +936,7 @@ impl DictKey for Wtf8 {
}
fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult<bool> {
if let Some(pystr) = other_key.payload_if_exact::<PyStr>(vm) {
if let Some(pystr) = other_key.downcast_ref_if_exact::<PyStr>(vm) {
Ok(pystr.as_wtf8() == self)
} else {
// Fall back to PyObjectRef implementation.
@@ -997,7 +997,7 @@ impl DictKey for [u8] {
}
fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult<bool> {
if let Some(pystr) = other_key.payload_if_exact::<PyBytes>(vm) {
if let Some(pystr) = other_key.downcast_ref_if_exact::<PyBytes>(vm) {
Ok(pystr.as_bytes() == self)
} else {
// Fall back to PyObjectRef implementation.
@@ -1053,7 +1053,7 @@ impl DictKey for usize {
}
fn key_eq(&self, vm: &VirtualMachine, other_key: &PyObject) -> PyResult<bool> {
if let Some(int) = other_key.payload_if_exact::<PyInt>(vm) {
if let Some(int) = other_key.downcast_ref_if_exact::<PyInt>(vm) {
if let Some(i) = int.as_bigint().to_usize() {
Ok(i == *self)
} else {

View File

@@ -1445,7 +1445,7 @@ pub(super) mod types {
if (2..=5).contains(&len) {
let errno = &args[0];
errno
.payload_if_subclass::<PyInt>(vm)
.downcast_ref::<PyInt>()
.and_then(|errno| errno.try_to_primitive::<i32>(vm).ok())
.and_then(|errno| super::errno_to_exc_type(errno, vm))
.and_then(|typ| vm.invoke_exception(typ.to_owned(), args.to_vec()).ok())

View File

@@ -733,7 +733,7 @@ impl ExecutingFrame<'_> {
.pop_multiple(size.get(arg) as usize)
.as_slice()
.iter()
.map(|pyobj| pyobj.payload::<PyStr>().unwrap())
.map(|pyobj| pyobj.downcast_ref::<PyStr>().unwrap())
.collect::<Wtf8Buf>();
let str_obj = vm.ctx.new_str(s);
self.push_value(str_obj.into());
@@ -1077,7 +1077,7 @@ impl ExecutingFrame<'_> {
}
bytecode::Instruction::GetAwaitable => {
let awaited_obj = self.pop_value();
let awaitable = if awaited_obj.payload_is::<PyCoroutine>() {
let awaitable = if awaited_obj.downcastable::<PyCoroutine>() {
awaited_obj
} else {
let await_method = vm.get_method_or_type_error(
@@ -1595,7 +1595,7 @@ impl ExecutingFrame<'_> {
let kwarg_names = kwarg_names
.as_slice()
.iter()
.map(|pyobj| pyobj.payload::<PyStr>().unwrap().as_str().to_owned());
.map(|pyobj| pyobj.downcast_ref::<PyStr>().unwrap().as_str().to_owned());
FuncArgs::with_kwargs_names(args, kwarg_names)
}
@@ -1607,7 +1607,7 @@ impl ExecutingFrame<'_> {
// Use keys() method for all mapping objects to preserve order
Self::iterate_mapping_keys(vm, &kw_obj, "argument after **", |key| {
let key_str = key
.payload_if_subclass::<PyStr>(vm)
.downcast_ref::<PyStr>()
.ok_or_else(|| vm.new_type_error("keywords must be strings"))?;
let value = kw_obj.get_item(&*key, vm)?;
kwargs.insert(key_str.as_str().to_owned(), value);
@@ -2337,7 +2337,7 @@ impl fmt::Debug for Frame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let state = self.state.lock();
let stack_str = state.stack.iter().fold(String::new(), |mut s, elem| {
if elem.payload_is::<Self>() {
if elem.downcastable::<Self>() {
s.push_str("\n > {frame}");
} else {
std::fmt::write(&mut s, format_args!("\n > {elem:?}")).unwrap();

View File

@@ -145,7 +145,7 @@ macro_rules! match_class {
}
};
(match ($obj:expr) { ref $binding:ident @ $class:ty => $expr:expr, $($rest:tt)* }) => {
match $obj.payload::<$class>() {
match $obj.downcast_ref::<$class>() {
::std::option::Option::Some($binding) => $expr,
::std::option::Option::None => $crate::match_class!(match ($obj) { $($rest)* }),
}
@@ -160,7 +160,7 @@ macro_rules! match_class {
// An arm taken when the object is an instance of the specified built-in
// class.
(match ($obj:expr) { $class:ty => $expr:expr, $($rest:tt)* }) => {
if $obj.payload_is::<$class>() {
if $obj.downcastable::<$class>() {
$expr
} else {
$crate::match_class!(match ($obj) { $($rest)* })

View File

@@ -534,24 +534,13 @@ impl PyObjectRef {
/// another downcast can be attempted without unnecessary cloning.
#[inline(always)]
pub fn downcast<T: PyObjectPayload>(self) -> Result<PyRef<T>, Self> {
if self.payload_is::<T>() {
if self.downcastable::<T>() {
Ok(unsafe { self.downcast_unchecked() })
} else {
Err(self)
}
}
#[inline(always)]
pub fn downcast_ref<T: PyObjectPayload>(&self) -> Option<&Py<T>> {
if self.payload_is::<T>() {
// SAFETY: just checked that the payload is T, and PyRef is repr(transparent) over
// PyObjectRef
Some(unsafe { &*(self as *const Self as *const PyRef<T>) })
} else {
None
}
}
/// Force to downcast this reference to a subclass.
///
/// # Safety
@@ -566,15 +555,6 @@ impl PyObjectRef {
}
}
/// # Safety
/// T must be the exact payload type
#[inline(always)]
pub unsafe fn downcast_unchecked_ref<T: PyObjectPayload>(&self) -> &Py<T> {
debug_assert!(self.payload_is::<T>());
// SAFETY: requirements forwarded from caller
unsafe { &*(self as *const Self as *const PyRef<T>) }
}
// ideally we'd be able to define these in pyobject.rs, but method visibility rules are weird
/// Attempt to downcast this reference to the specific class that is associated `T`.
@@ -589,10 +569,10 @@ impl PyObjectRef {
if self.class().is(T::class(&vm.ctx)) {
// TODO: is this always true?
assert!(
self.payload_is::<T>(),
self.downcastable::<T>(),
"obj.__class__ is T::class() but payload is not T"
);
// SAFETY: just asserted that payload_is::<T>()
// SAFETY: just asserted that downcastable::<T>()
Ok(unsafe { PyRefExact::new_unchecked(PyRef::from_obj_unchecked(self)) })
} else {
Err(self)
@@ -670,6 +650,7 @@ impl PyObject {
&inner.payload
}
#[deprecated(note = "use downcast_ref instead")]
#[inline(always)]
pub fn payload<T: PyObjectPayload>(&self) -> Option<&T> {
if self.payload_is::<T>() {
@@ -688,12 +669,14 @@ impl PyObject {
self.0.typ.swap_to_temporary_refs(typ, vm);
}
#[deprecated(note = "use downcast_ref_if_exact instead")]
#[inline(always)]
pub fn payload_if_exact<T: PyObjectPayload + crate::PyPayload>(
&self,
vm: &VirtualMachine,
) -> Option<&T> {
if self.class().is(T::class(&vm.ctx)) {
#[allow(deprecated)]
self.payload()
} else {
None
@@ -722,18 +705,27 @@ impl PyObject {
}
}
#[deprecated(note = "use downcast_ref instead")]
#[inline(always)]
pub fn payload_if_subclass<T: crate::PyPayload>(&self, vm: &VirtualMachine) -> Option<&T> {
if self.class().fast_issubclass(T::class(&vm.ctx)) {
#[allow(deprecated)]
self.payload()
} else {
None
}
}
/// Check if this object can be downcast to T.
#[inline(always)]
pub fn downcastable<T: PyObjectPayload>(&self) -> bool {
self.payload_is::<T>()
}
/// Attempt to downcast this reference to a subclass.
#[inline(always)]
pub fn downcast_ref<T: PyObjectPayload>(&self) -> Option<&Py<T>> {
if self.payload_is::<T>() {
if self.downcastable::<T>() {
// SAFETY: just checked that the payload is T, and PyRef is repr(transparent) over
// PyObjectRef
Some(unsafe { self.downcast_unchecked_ref::<T>() })
@@ -756,7 +748,7 @@ impl PyObject {
/// T must be the exact payload type
#[inline(always)]
pub unsafe fn downcast_unchecked_ref<T: PyObjectPayload>(&self) -> &Py<T> {
debug_assert!(self.payload_is::<T>());
debug_assert!(self.downcastable::<T>());
// SAFETY: requirements forwarded from caller
unsafe { &*(self as *const Self as *const Py<T>) }
}
@@ -1045,7 +1037,7 @@ impl<T: PyObjectPayload> PyRef<T> {
/// Safety: payload type of `obj` must be `T`
#[inline(always)]
unsafe fn from_obj_unchecked(obj: PyObjectRef) -> Self {
debug_assert!(obj.payload_is::<T>());
debug_assert!(obj.downcast_ref::<T>().is_some());
let obj = ManuallyDrop::new(obj);
Self {
ptr: obj.ptr.cast(),

View File

@@ -25,7 +25,7 @@ impl PyObject {
pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
if let Some(i) = self.downcast_ref_if_exact::<PyInt>(vm) {
Some(Ok(i.to_owned()))
} else if let Some(i) = self.payload::<PyInt>() {
} else if let Some(i) = self.downcast_ref::<PyInt>() {
Some(Ok(vm.ctx.new_bigint(i.as_bigint())))
} else {
self.to_number().index(vm)
@@ -75,11 +75,11 @@ impl PyObject {
ret.class()
))
})
} else if let Some(s) = self.payload::<PyStr>() {
} else if let Some(s) = self.downcast_ref::<PyStr>() {
try_convert(self, s.as_wtf8().trim().as_bytes(), vm)
} else if let Some(bytes) = self.payload::<PyBytes>() {
} else if let Some(bytes) = self.downcast_ref::<PyBytes>() {
try_convert(self, bytes, vm)
} else if let Some(bytearray) = self.payload::<PyByteArray>() {
} else if let Some(bytearray) = self.downcast_ref::<PyByteArray>() {
try_convert(self, &bytearray.borrow_buf(), vm)
} else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self) {
// TODO: replace to PyBuffer
@@ -450,7 +450,7 @@ impl<'a> PyNumber<'a> {
methods.int.load().is_some()
|| methods.index.load().is_some()
|| methods.float.load().is_some()
|| obj.payload_is::<PyComplex>()
|| obj.downcastable::<PyComplex>()
}
}

View File

@@ -93,7 +93,7 @@ impl PyObject {
// PyObject *PyObject_GetAIter(PyObject *o)
pub fn get_aiter(&self, vm: &VirtualMachine) -> PyResult {
if self.payload_is::<PyAsyncGen>() {
if self.downcastable::<PyAsyncGen>() {
vm.call_special_method(self, identifier!(vm, __aiter__), ())
} else {
Err(vm.new_type_error("wrong argument type"))

View File

@@ -337,9 +337,9 @@ impl PySequence<'_> {
where
F: FnMut(&PyObject) -> PyResult<R>,
{
if let Some(tuple) = self.obj.payload_if_exact::<PyTuple>(vm) {
if let Some(tuple) = self.obj.downcast_ref_if_exact::<PyTuple>(vm) {
tuple.iter().map(|x| f(x.as_ref())).collect()
} else if let Some(list) = self.obj.payload_if_exact::<PyList>(vm) {
} else if let Some(list) = self.obj.downcast_ref_if_exact::<PyList>(vm) {
list.borrow_vec().iter().map(|x| f(x.as_ref())).collect()
} else {
let iter = self.obj.to_owned().get_iter(vm)?;

View File

@@ -62,7 +62,7 @@ impl serde::Serialize for PyObjectSerializer<'_> {
}
seq.end()
};
if let Some(s) = self.pyobject.payload::<PyStr>() {
if let Some(s) = self.pyobject.downcast_ref::<PyStr>() {
serializer.serialize_str(s.as_ref())
} else if self.pyobject.fast_isinstance(self.vm.ctx.types.float_type) {
serializer.serialize_f64(float::get_value(self.pyobject))
@@ -80,9 +80,9 @@ impl serde::Serialize for PyObjectSerializer<'_> {
} else {
serializer.serialize_i64(v.to_i64().ok_or_else(int_too_large)?)
}
} else if let Some(list) = self.pyobject.payload_if_subclass::<PyList>(self.vm) {
} else if let Some(list) = self.pyobject.downcast_ref::<PyList>() {
serialize_seq_elements(serializer, &list.borrow_vec())
} else if let Some(tuple) = self.pyobject.payload_if_subclass::<PyTuple>(self.vm) {
} else if let Some(tuple) = self.pyobject.downcast_ref::<PyTuple>() {
serialize_seq_elements(serializer, tuple)
} else if self.pyobject.fast_isinstance(self.vm.ctx.types.dict_type) {
let dict: PyDictRef = self.pyobject.to_owned().downcast().unwrap();

View File

@@ -263,12 +263,12 @@ impl SequenceIndex {
obj: &PyObject,
type_name: &str,
) -> PyResult<Self> {
if let Some(i) = obj.payload::<PyInt>() {
if let Some(i) = obj.downcast_ref::<PyInt>() {
// TODO: number protocol
i.try_to_primitive(vm)
.map_err(|_| vm.new_index_error("cannot fit 'int' into an index-sized integer"))
.map(Self::Int)
} else if let Some(slice) = obj.payload::<PySlice>() {
} else if let Some(slice) = obj.downcast_ref::<PySlice>() {
slice.to_saturated(vm).map(Self::Slice)
} else if let Some(i) = obj.try_index_opt(vm) {
// TODO: __index__ for indices is no more supported?

View File

@@ -365,7 +365,7 @@ mod _collections {
}
fn concat(&self, other: &PyObject, vm: &VirtualMachine) -> PyResult<Self> {
if let Some(o) = other.payload_if_subclass::<Self>(vm) {
if let Some(o) = other.downcast_ref::<Self>() {
let mut deque = self.borrow_deque().clone();
let elements = o.borrow_deque().clone();
deque.extend(elements);
@@ -446,7 +446,7 @@ mod _collections {
let maxlen = if let Some(obj) = maxlen.into_option() {
if !vm.is_none(&obj) {
let maxlen: isize = obj
.payload::<PyInt>()
.downcast_ref::<PyInt>()
.ok_or_else(|| vm.new_type_error("an integer is required."))?
.try_to_primitive(vm)?;

View File

@@ -108,8 +108,8 @@ impl PyCArray {
impl PyCArray {
pub fn to_arg(&self, _vm: &VirtualMachine) -> PyResult<libffi::middle::Arg> {
let value = self.value.read();
let py_bytes = value.payload::<PyBytes>().unwrap();
let bytes = py_bytes.as_ref().to_vec();
let py_bytes = value.downcast_ref::<PyBytes>().unwrap();
let bytes = py_bytes.payload().to_vec();
Ok(libffi::middle::Arg::new(&bytes))
}
}

View File

@@ -43,14 +43,14 @@ impl Function {
let args = args
.iter()
.map(|arg| {
if let Some(arg) = arg.payload_if_subclass::<PyCSimple>(vm) {
if let Some(arg) = arg.downcast_ref::<PyCSimple>() {
let converted = ffi_type_from_str(&arg._type_);
return match converted {
Some(t) => Ok(t),
None => Err(vm.new_type_error("Invalid type")), // TODO: add type name
};
}
if let Some(arg) = arg.payload_if_subclass::<PyCArray>(vm) {
if let Some(arg) = arg.downcast_ref::<PyCArray>() {
let t = arg.typ.read();
let ty_attributes = t.attributes.read();
let ty_pystr = ty_attributes
@@ -107,10 +107,10 @@ impl Function {
.enumerate()
.map(|(count, arg)| {
// none type check
if let Some(d) = arg.payload_if_subclass::<PyCSimple>(vm) {
if let Some(d) = arg.downcast_ref::<PyCSimple>() {
return Ok(d.to_arg(self.args[count].clone(), vm).unwrap());
}
if let Some(d) = arg.payload_if_subclass::<PyCArray>(vm) {
if let Some(d) = arg.downcast_ref::<PyCArray>() {
return Ok(d.to_arg(vm).unwrap());
}
Err(vm.new_type_error("Expected a ctypes simple type"))

View File

@@ -2370,7 +2370,7 @@ mod _io {
codec.get_incremental_encoder(Some(errors.to_owned()), vm)?;
let encoding_name = vm.get_attribute_opt(incremental_encoder.clone(), "name")?;
let encode_func = encoding_name.and_then(|name| {
let name = name.payload::<PyStr>()?;
let name = name.downcast_ref::<PyStr>()?;
match name.as_str() {
"utf-8" => Some(textio_encode_utf8 as EncodeFunc),
_ => None,
@@ -3090,7 +3090,7 @@ mod _io {
obj.class().name()
))
})?;
let flags = flags.payload::<int::PyInt>().ok_or_else(state_err)?;
let flags = flags.downcast_ref::<int::PyInt>().ok_or_else(state_err)?;
let flags = flags.try_to_primitive(vm)?;
Ok((buf, flags))
}
@@ -4273,7 +4273,7 @@ mod fileio {
fn init(zelf: PyRef<Self>, args: Self::Args, vm: &VirtualMachine) -> PyResult<()> {
// TODO: let atomic_flag_works
let name = args.name;
let arg_fd = if let Some(i) = name.payload::<crate::builtins::PyInt>() {
let arg_fd = if let Some(i) = name.downcast_ref::<crate::builtins::PyInt>() {
let fd = i.try_to_primitive(vm)?;
if fd < 0 {
return Err(vm.new_value_error("negative file descriptor"));

View File

@@ -1699,7 +1699,7 @@ mod decl {
let r = match r.flatten() {
Some(r) => {
let val = r
.payload::<PyInt>()
.downcast_ref::<PyInt>()
.ok_or_else(|| vm.new_type_error("Expected int as r"))?
.as_bigint();

View File

@@ -229,7 +229,7 @@ mod _operator {
v.class().name()
)));
}
v.payload::<PyInt>().unwrap().try_to_primitive(vm)
v.downcast_ref::<PyInt>().unwrap().try_to_primitive(vm)
})
.unwrap_or(Ok(0))?;
obj.length_hint(default, vm)

View File

@@ -801,7 +801,7 @@ pub(super) mod _os {
let mut vec_args = Vec::from(r);
loop {
if let Ok(obj) = vec_args.iter().exactly_one() {
match obj.payload::<PyTuple>() {
match obj.downcast_ref::<PyTuple>() {
Some(t) => {
vec_args = Vec::from(t.as_slice());
}
@@ -1045,7 +1045,7 @@ pub(super) mod _os {
#[pyfunction]
fn utime(args: UtimeArgs, vm: &VirtualMachine) -> PyResult<()> {
let parse_tup = |tup: &PyTuple| -> Option<(PyObjectRef, PyObjectRef)> {
let parse_tup = |tup: &Py<PyTuple>| -> Option<(PyObjectRef, PyObjectRef)> {
if tup.len() != 2 {
None
} else {
@@ -1065,17 +1065,16 @@ pub(super) mod _os {
let ns_in_sec: PyObjectRef = vm.ctx.new_int(1_000_000_000).into();
let ns_to_dur = |obj: PyObjectRef| {
let divmod = vm._divmod(&obj, &ns_in_sec)?;
let (div, rem) =
divmod
.payload::<PyTuple>()
.and_then(parse_tup)
.ok_or_else(|| {
vm.new_type_error(format!(
"{}.__divmod__() must return a 2-tuple, not {}",
obj.class().name(),
divmod.class().name()
))
})?;
let (div, rem) = divmod
.downcast_ref::<PyTuple>()
.and_then(parse_tup)
.ok_or_else(|| {
vm.new_type_error(format!(
"{}.__divmod__() must return a 2-tuple, not {}",
obj.class().name(),
divmod.class().name()
))
})?;
let secs = div.try_index(vm)?.try_to_primitive(vm)?;
let ns = rem.try_index(vm)?.try_to_primitive(vm)?;
Ok(Duration::new(secs, ns))

View File

@@ -99,7 +99,7 @@ mod _sre {
// re.Scanner has no official API and in CPython's implement
// isbytes will be hanging (-1)
// here is just a hack to let re.Scanner works only with str not bytes
let isbytes = !vm.is_none(&pattern) && !pattern.payload_is::<PyStr>();
let isbytes = !vm.is_none(&pattern) && !pattern.downcastable::<PyStr>();
let code = code.try_to_value(vm)?;
Ok(Pattern {
pattern,
@@ -155,7 +155,7 @@ mod _sre {
for trunk in trunks {
let index: usize = trunk[0]
.payload::<PyInt>()
.downcast_ref::<PyInt>()
.ok_or_else(|| vm.new_type_error("expected usize"))?
.try_to_primitive(vm)?;
items.push((index, trunk[1].clone()));
@@ -218,7 +218,7 @@ mod _sre {
where
F: FnOnce(&Wtf8) -> PyResult<R>,
{
let string = string.payload::<PyStr>().ok_or_else(|| {
let string = string.downcast_ref::<PyStr>().ok_or_else(|| {
vm.new_type_error(format!("expected string got '{}'", string.class()))
})?;
f(string.as_wtf8())

View File

@@ -56,7 +56,7 @@ mod _weakref {
dict._as_dict_inner()
.delete_if(vm, &*key, |wr| {
let wr = wr
.payload::<PyWeak>()
.downcast_ref::<PyWeak>()
.ok_or_else(|| vm.new_type_error("not a weakref"))?;
Ok(wr.is_dead())
})

View File

@@ -192,7 +192,7 @@ pub(crate) type DelFunc = fn(&PyObject, &VirtualMachine) -> PyResult<()>;
// slot_sq_length
pub(crate) fn len_wrapper(obj: &PyObject, vm: &VirtualMachine) -> PyResult<usize> {
let ret = vm.call_special_method(obj, identifier!(vm, __len__), ())?;
let len = ret.payload::<PyInt>().ok_or_else(|| {
let len = ret.downcast_ref::<PyInt>().ok_or_else(|| {
vm.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",
ret.class()
@@ -262,7 +262,7 @@ fn repr_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyStrRef> {
fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
let hash_obj = vm.call_special_method(zelf, identifier!(vm, __hash__), ())?;
let py_int = hash_obj
.payload_if_subclass::<PyInt>(vm)
.downcast_ref::<PyInt>()
.ok_or_else(|| vm.new_type_error("__hash__ method should return an integer"))?;
let big_int = py_int.as_bigint();
let hash: PyHash = big_int

View File

@@ -161,7 +161,7 @@ mod tests {
let a = vm.new_pyobj(crate::common::ascii!("Hello "));
let b = vm.new_pyobj(4_i32);
let res = vm._mul(&a, &b).unwrap();
let value = res.payload::<PyStr>().unwrap();
let value = res.downcast_ref::<PyStr>().unwrap();
assert_eq!(value.as_str(), "Hello Hello Hello Hello ")
})
}

View File

@@ -657,9 +657,9 @@ impl VirtualMachine {
let cls = value.class();
let list_borrow;
let slice = if cls.is(self.ctx.types.tuple_type) {
value.payload::<PyTuple>().unwrap().as_slice()
value.downcast_ref::<PyTuple>().unwrap().as_slice()
} else if cls.is(self.ctx.types.list_type) {
list_borrow = value.payload::<PyList>().unwrap().borrow_vec();
list_borrow = value.downcast_ref::<PyList>().unwrap().borrow_vec();
&list_borrow
} else {
return self.map_py_iter(value, func);

View File

@@ -119,7 +119,7 @@ impl VirtualMachine {
}
};
let hint = result
.payload_if_subclass::<PyInt>(self)
.downcast_ref::<PyInt>()
.ok_or_else(|| {
self.new_type_error(format!(
"'{}' object cannot be interpreted as an integer",

View File

@@ -41,7 +41,7 @@ pub fn py_err_to_js_err(vm: &VirtualMachine, py_err: &PyBaseExceptionRef) -> JsV
};
let js_arg = js_arg
.as_ref()
.and_then(|x| x.payload::<js_module::PyJsValue>());
.and_then(|x| x.downcast_ref::<js_module::PyJsValue>());
match js_arg {
Some(val) => val.value.clone(),
None => {
@@ -134,7 +134,7 @@ pub fn py_to_js(vm: &VirtualMachine, py_obj: PyObjectRef) -> JsValue {
}
// the browser module might not be injected
if vm.try_class("_js", "Promise").is_ok() {
if let Some(py_prom) = py_obj.payload::<js_module::PyPromise>() {
if let Some(py_prom) = py_obj.downcast_ref::<js_module::PyPromise>() {
return py_prom.as_js(vm).into();
}
}