mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Merge pull request #3819 from qingshi163/heaptypeext
HeapTypeExt and Protocol Methods Pointer
This commit is contained in:
@@ -564,10 +564,15 @@ where
|
||||
let slot_name = slot_ident.to_string();
|
||||
let tokens = {
|
||||
const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"];
|
||||
const POINTER_SLOTS: &[&str] = &["as_number"];
|
||||
if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) {
|
||||
quote_spanned! { span =>
|
||||
slots.#slot_ident = Some(Self::#ident as _);
|
||||
}
|
||||
} else if POINTER_SLOTS.contains(&slot_name.as_str()) {
|
||||
quote_spanned! { span =>
|
||||
slots.#slot_ident.store(Some(PointerSlot::from(Self::#ident())));
|
||||
}
|
||||
} else {
|
||||
quote_spanned! { span =>
|
||||
slots.#slot_ident.store(Some(Self::#ident as _));
|
||||
|
||||
@@ -25,7 +25,7 @@ mod _bisect {
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<isize>> {
|
||||
arg.into_option()
|
||||
.map(|v| vm.to_index(&v)?.try_to_primitive(vm))
|
||||
.map(|v| v.try_index(vm)?.try_to_primitive(vm))
|
||||
.transpose()
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ mod math {
|
||||
|
||||
#[pyfunction]
|
||||
fn isqrt(x: PyObjectRef, vm: &VirtualMachine) -> PyResult<BigInt> {
|
||||
let index = vm.to_index(&x)?;
|
||||
let index = x.try_index(vm)?;
|
||||
let value = index.as_bigint();
|
||||
|
||||
if value.is_negative() {
|
||||
|
||||
@@ -347,7 +347,7 @@ mod decl {
|
||||
Some(ms) => {
|
||||
let ms = if let Some(float) = ms.payload::<PyFloat>() {
|
||||
float.to_f64().to_i32()
|
||||
} else if let Some(int) = vm.to_index_opt(ms.clone()) {
|
||||
} else if let Some(int) = ms.try_index_opt(vm) {
|
||||
int?.as_bigint().to_i32()
|
||||
} else {
|
||||
return Err(vm.new_type_error(format!(
|
||||
|
||||
@@ -734,8 +734,8 @@ mod _socket {
|
||||
if obj.fast_isinstance(vm.ctx.types.float_type) {
|
||||
return Err(vm.new_type_error("integer argument expected, got float".to_owned()));
|
||||
}
|
||||
let int = vm
|
||||
.to_index_opt(obj)
|
||||
let int = obj
|
||||
.try_index_opt(vm)
|
||||
.unwrap_or_else(|| Err(vm.new_type_error("an integer is required".to_owned())))?;
|
||||
int.try_to_primitive::<CastFrom>(vm)
|
||||
.map(|sock| sock as RawSocket)
|
||||
@@ -1382,7 +1382,7 @@ mod _socket {
|
||||
let (flags, address) = match arg3 {
|
||||
OptionalArg::Present(arg3) => {
|
||||
// should just be i32::try_from_obj but tests check for error message
|
||||
let int = vm.to_index_opt(arg2).unwrap_or_else(|| {
|
||||
let int = arg2.try_index_opt(vm).unwrap_or_else(|| {
|
||||
Err(vm.new_type_error("an integer is required".to_owned()))
|
||||
})?;
|
||||
let flags = int.try_to_primitive::<i32>(vm)?;
|
||||
|
||||
@@ -491,15 +491,15 @@ fn get_int_or_index<T>(vm: &VirtualMachine, arg: PyObjectRef) -> PyResult<T>
|
||||
where
|
||||
T: PrimInt + for<'a> TryFrom<&'a BigInt>,
|
||||
{
|
||||
match vm.to_index_opt(arg) {
|
||||
Some(index) => index?
|
||||
.try_to_primitive(vm)
|
||||
.map_err(|_| new_struct_error(vm, "argument out of range".to_owned())),
|
||||
None => Err(new_struct_error(
|
||||
let index = arg.try_index_opt(vm).unwrap_or_else(|| {
|
||||
Err(new_struct_error(
|
||||
vm,
|
||||
"required argument is not an integer".to_owned(),
|
||||
)),
|
||||
}
|
||||
))
|
||||
})?;
|
||||
index
|
||||
.try_to_primitive(vm)
|
||||
.map_err(|_| new_struct_error(vm, "argument out of range".to_owned()))
|
||||
}
|
||||
|
||||
make_pack_primint!(i8);
|
||||
|
||||
@@ -3,6 +3,7 @@ use super::{
|
||||
};
|
||||
use crate::{
|
||||
anystr::{self, AnyStr},
|
||||
atomic_func,
|
||||
bytesinner::{
|
||||
bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
|
||||
ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner,
|
||||
@@ -608,14 +609,17 @@ impl AsSequence for PyBytes {
|
||||
}
|
||||
|
||||
impl AsNumber for PyBytes {
|
||||
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
remainder: Some(|number, other, vm| {
|
||||
Self::number_downcast(number)
|
||||
.mod_(other.to_owned(), vm)
|
||||
.to_pyresult(vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
remainder: atomic_func!(|number, other, vm| {
|
||||
PyBytes::number_downcast(number)
|
||||
.mod_(other.to_owned(), vm)
|
||||
.to_pyresult(vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
&AS_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
impl Hashable for PyBytes {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::{float, PyStr, PyType, PyTypeRef};
|
||||
use crate::{
|
||||
atomic_func,
|
||||
class::PyClassImpl,
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
function::{
|
||||
@@ -421,30 +422,44 @@ impl Hashable for PyComplex {
|
||||
}
|
||||
|
||||
impl AsNumber for PyComplex {
|
||||
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
add: Some(|number, other, vm| Self::number_complex_op(number, other, |a, b| a + b, vm)),
|
||||
subtract: Some(|number, other, vm| {
|
||||
Self::number_complex_op(number, other, |a, b| a - b, vm)
|
||||
}),
|
||||
multiply: Some(|number, other, vm| {
|
||||
Self::number_complex_op(number, other, |a, b| a * b, vm)
|
||||
}),
|
||||
power: Some(|number, other, vm| Self::number_general_op(number, other, inner_pow, vm)),
|
||||
negative: Some(|number, vm| {
|
||||
let value = Self::number_downcast(number).value;
|
||||
(-value).to_pyresult(vm)
|
||||
}),
|
||||
positive: Some(|number, vm| Self::number_complex(number, vm).to_pyresult(vm)),
|
||||
absolute: Some(|number, vm| {
|
||||
let value = Self::number_downcast(number).value;
|
||||
value.norm().to_pyresult(vm)
|
||||
}),
|
||||
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
|
||||
true_divide: Some(|number, other, vm| {
|
||||
Self::number_general_op(number, other, inner_div, vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
add: atomic_func!(|number, other, vm| PyComplex::number_complex_op(
|
||||
number,
|
||||
other,
|
||||
|a, b| a + b,
|
||||
vm
|
||||
)),
|
||||
subtract: atomic_func!(|number, other, vm| {
|
||||
PyComplex::number_complex_op(number, other, |a, b| a - b, vm)
|
||||
}),
|
||||
multiply: atomic_func!(|number, other, vm| {
|
||||
PyComplex::number_complex_op(number, other, |a, b| a * b, vm)
|
||||
}),
|
||||
power: atomic_func!(|number, other, vm| PyComplex::number_general_op(
|
||||
number, other, inner_pow, vm
|
||||
)),
|
||||
negative: atomic_func!(|number, vm| {
|
||||
let value = PyComplex::number_downcast(number).value;
|
||||
(-value).to_pyresult(vm)
|
||||
}),
|
||||
positive: atomic_func!(
|
||||
|number, vm| PyComplex::number_complex(number, vm).to_pyresult(vm)
|
||||
),
|
||||
absolute: atomic_func!(|number, vm| {
|
||||
let value = PyComplex::number_downcast(number).value;
|
||||
value.norm().to_pyresult(vm)
|
||||
}),
|
||||
boolean: atomic_func!(|number, _vm| Ok(PyComplex::number_downcast(number)
|
||||
.value
|
||||
.is_zero())),
|
||||
true_divide: atomic_func!(|number, other, vm| {
|
||||
PyComplex::number_general_op(number, other, inner_div, vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
&AS_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
impl PyComplex {
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::{
|
||||
try_bigint_to_f64, PyByteArray, PyBytes, PyInt, PyIntRef, PyStr, PyStrRef, PyType, PyTypeRef,
|
||||
};
|
||||
use crate::{
|
||||
atomic_func,
|
||||
class::PyClassImpl,
|
||||
common::{float_ops, hash},
|
||||
convert::{ToPyObject, ToPyResult},
|
||||
@@ -57,16 +58,6 @@ impl From<f64> for PyFloat {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyObject {
|
||||
pub fn try_float_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
|
||||
PyNumber::new(self, vm).float_opt(vm)
|
||||
}
|
||||
|
||||
pub fn try_float(&self, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
|
||||
PyNumber::new(self, vm).float(vm)
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
Some(float.value)
|
||||
@@ -553,36 +544,63 @@ impl Hashable for PyFloat {
|
||||
}
|
||||
|
||||
impl AsNumber for PyFloat {
|
||||
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
add: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a + b, vm)),
|
||||
subtract: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a - b, vm)),
|
||||
multiply: Some(|number, other, vm| Self::number_float_op(number, other, |a, b| a * b, vm)),
|
||||
remainder: Some(|number, other, vm| Self::number_general_op(number, other, inner_mod, vm)),
|
||||
divmod: Some(|number, other, vm| Self::number_general_op(number, other, inner_divmod, vm)),
|
||||
power: Some(|number, other, vm| Self::number_general_op(number, other, float_pow, vm)),
|
||||
negative: Some(|number, vm| {
|
||||
let value = Self::number_downcast(number).value;
|
||||
(-value).to_pyresult(vm)
|
||||
}),
|
||||
positive: Some(|number, vm| Self::number_float(number, vm).to_pyresult(vm)),
|
||||
absolute: Some(|number, vm| {
|
||||
let value = Self::number_downcast(number).value;
|
||||
value.abs().to_pyresult(vm)
|
||||
}),
|
||||
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
|
||||
int: Some(|number, vm| {
|
||||
let value = Self::number_downcast(number).value;
|
||||
try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x))
|
||||
}),
|
||||
float: Some(|number, vm| Ok(Self::number_float(number, vm))),
|
||||
floor_divide: Some(|number, other, vm| {
|
||||
Self::number_general_op(number, other, inner_floordiv, vm)
|
||||
}),
|
||||
true_divide: Some(|number, other, vm| {
|
||||
Self::number_general_op(number, other, inner_div, vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
add: atomic_func!(|num, other, vm| PyFloat::number_float_op(
|
||||
num,
|
||||
other,
|
||||
|a, b| a + b,
|
||||
vm
|
||||
)),
|
||||
subtract: atomic_func!(|num, other, vm| PyFloat::number_float_op(
|
||||
num,
|
||||
other,
|
||||
|a, b| a - b,
|
||||
vm
|
||||
)),
|
||||
multiply: atomic_func!(|num, other, vm| PyFloat::number_float_op(
|
||||
num,
|
||||
other,
|
||||
|a, b| a * b,
|
||||
vm
|
||||
)),
|
||||
remainder: atomic_func!(|num, other, vm| PyFloat::number_general_op(
|
||||
num, other, inner_mod, vm
|
||||
)),
|
||||
divmod: atomic_func!(|num, other, vm| PyFloat::number_general_op(
|
||||
num,
|
||||
other,
|
||||
inner_divmod,
|
||||
vm
|
||||
)),
|
||||
power: atomic_func!(|num, other, vm| PyFloat::number_general_op(
|
||||
num, other, float_pow, vm
|
||||
)),
|
||||
negative: atomic_func!(|num, vm| {
|
||||
let value = PyFloat::number_downcast(num).value;
|
||||
(-value).to_pyresult(vm)
|
||||
}),
|
||||
positive: atomic_func!(|num, vm| PyFloat::number_float(num, vm).to_pyresult(vm)),
|
||||
absolute: atomic_func!(|num, vm| {
|
||||
let value = PyFloat::number_downcast(num).value;
|
||||
value.abs().to_pyresult(vm)
|
||||
}),
|
||||
boolean: atomic_func!(|num, _vm| Ok(PyFloat::number_downcast(num).value.is_zero())),
|
||||
int: atomic_func!(|num, vm| {
|
||||
let value = PyFloat::number_downcast(num).value;
|
||||
try_to_bigint(value, vm).map(|x| vm.ctx.new_int(x))
|
||||
}),
|
||||
float: atomic_func!(|num, vm| Ok(PyFloat::number_float(num, vm))),
|
||||
floor_divide: atomic_func!(|num, other, vm| {
|
||||
PyFloat::number_general_op(num, other, inner_floordiv, vm)
|
||||
}),
|
||||
true_divide: atomic_func!(|num, other, vm| {
|
||||
PyFloat::number_general_op(num, other, inner_div, vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
&AS_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
impl PyFloat {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::{float, PyByteArray, PyBytes, PyStr, PyStrRef, PyType, PyTypeRef};
|
||||
use crate::{
|
||||
atomic_func,
|
||||
bytesinner::PyBytesInner,
|
||||
class::PyClassImpl,
|
||||
common::hash,
|
||||
@@ -68,7 +69,7 @@ impl PyPayload for PyInt {
|
||||
}
|
||||
|
||||
fn special_retrieve(vm: &VirtualMachine, obj: &PyObject) -> Option<PyResult<PyRef<Self>>> {
|
||||
Some(vm.to_index(obj))
|
||||
Some(obj.try_index(vm))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,8 +245,8 @@ impl Constructor for PyInt {
|
||||
fn py_new(cls: PyTypeRef, options: Self::Args, vm: &VirtualMachine) -> PyResult {
|
||||
let value = if let OptionalArg::Present(val) = options.val_options {
|
||||
if let OptionalArg::Present(base) = options.base {
|
||||
let base = vm
|
||||
.to_index(&base)?
|
||||
let base = base
|
||||
.try_index(vm)?
|
||||
.as_bigint()
|
||||
.to_u32()
|
||||
.filter(|&v| v == 0 || (2..=36).contains(&v))
|
||||
@@ -265,9 +266,7 @@ impl Constructor for PyInt {
|
||||
val
|
||||
};
|
||||
|
||||
PyNumber::new(val.as_ref(), vm)
|
||||
.int(vm)
|
||||
.map(|x| x.as_bigint().clone())
|
||||
val.try_int(vm).map(|x| x.as_bigint().clone())
|
||||
}
|
||||
} else if let OptionalArg::Present(_) = options.base {
|
||||
Err(vm.new_type_error("int() missing string argument".to_owned()))
|
||||
@@ -756,37 +755,76 @@ impl Hashable for PyInt {
|
||||
}
|
||||
|
||||
impl AsNumber for PyInt {
|
||||
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
add: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a + b, vm)),
|
||||
subtract: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a - b, vm)),
|
||||
multiply: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a * b, vm)),
|
||||
remainder: Some(|number, other, vm| Self::number_general_op(number, other, inner_mod, vm)),
|
||||
divmod: Some(|number, other, vm| Self::number_general_op(number, other, inner_divmod, vm)),
|
||||
power: Some(|number, other, vm| Self::number_general_op(number, other, inner_pow, vm)),
|
||||
negative: Some(|number, vm| (&Self::number_downcast(number).value).neg().to_pyresult(vm)),
|
||||
positive: Some(|number, vm| Ok(Self::number_int(number, vm).into())),
|
||||
absolute: Some(|number, vm| Self::number_downcast(number).value.abs().to_pyresult(vm)),
|
||||
boolean: Some(|number, _vm| Ok(Self::number_downcast(number).value.is_zero())),
|
||||
invert: Some(|number, vm| (&Self::number_downcast(number).value).not().to_pyresult(vm)),
|
||||
lshift: Some(|number, other, vm| Self::number_general_op(number, other, inner_lshift, vm)),
|
||||
rshift: Some(|number, other, vm| Self::number_general_op(number, other, inner_rshift, vm)),
|
||||
and: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a & b, vm)),
|
||||
xor: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a ^ b, vm)),
|
||||
or: Some(|number, other, vm| Self::number_int_op(number, other, |a, b| a | b, vm)),
|
||||
int: Some(|number, other| Ok(Self::number_int(number, other))),
|
||||
float: Some(|number, vm| {
|
||||
let zelf = Self::number_downcast(number);
|
||||
try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x))
|
||||
}),
|
||||
floor_divide: Some(|number, other, vm| {
|
||||
Self::number_general_op(number, other, inner_floordiv, vm)
|
||||
}),
|
||||
true_divide: Some(|number, other, vm| {
|
||||
Self::number_general_op(number, other, inner_truediv, vm)
|
||||
}),
|
||||
index: Some(|number, vm| Ok(Self::number_int(number, vm))),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
add: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a + b, vm)),
|
||||
subtract: atomic_func!(|num, other, vm| PyInt::number_int_op(
|
||||
num,
|
||||
other,
|
||||
|a, b| a - b,
|
||||
vm
|
||||
)),
|
||||
multiply: atomic_func!(|num, other, vm| PyInt::number_int_op(
|
||||
num,
|
||||
other,
|
||||
|a, b| a * b,
|
||||
vm
|
||||
)),
|
||||
remainder: atomic_func!(|num, other, vm| PyInt::number_general_op(
|
||||
num, other, inner_mod, vm
|
||||
)),
|
||||
divmod: atomic_func!(|num, other, vm| PyInt::number_general_op(
|
||||
num,
|
||||
other,
|
||||
inner_divmod,
|
||||
vm
|
||||
)),
|
||||
power: atomic_func!(|num, other, vm| PyInt::number_general_op(
|
||||
num, other, inner_pow, vm
|
||||
)),
|
||||
negative: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value)
|
||||
.neg()
|
||||
.to_pyresult(vm)),
|
||||
positive: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm).into())),
|
||||
absolute: atomic_func!(|num, vm| PyInt::number_downcast(num)
|
||||
.value
|
||||
.abs()
|
||||
.to_pyresult(vm)),
|
||||
boolean: atomic_func!(|num, _vm| Ok(PyInt::number_downcast(num).value.is_zero())),
|
||||
invert: atomic_func!(|num, vm| (&PyInt::number_downcast(num).value)
|
||||
.not()
|
||||
.to_pyresult(vm)),
|
||||
lshift: atomic_func!(|num, other, vm| PyInt::number_general_op(
|
||||
num,
|
||||
other,
|
||||
inner_lshift,
|
||||
vm
|
||||
)),
|
||||
rshift: atomic_func!(|num, other, vm| PyInt::number_general_op(
|
||||
num,
|
||||
other,
|
||||
inner_rshift,
|
||||
vm
|
||||
)),
|
||||
and: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a & b, vm)),
|
||||
xor: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a ^ b, vm)),
|
||||
or: atomic_func!(|num, other, vm| PyInt::number_int_op(num, other, |a, b| a | b, vm)),
|
||||
int: atomic_func!(|num, other| Ok(PyInt::number_int(num, other))),
|
||||
float: atomic_func!(|num, vm| {
|
||||
let zelf = PyInt::number_downcast(num);
|
||||
try_to_float(&zelf.value, vm).map(|x| vm.ctx.new_float(x))
|
||||
}),
|
||||
floor_divide: atomic_func!(|num, other, vm| {
|
||||
PyInt::number_general_op(num, other, inner_floordiv, vm)
|
||||
}),
|
||||
true_divide: atomic_func!(|num, other, vm| {
|
||||
PyInt::number_general_op(num, other, inner_truediv, vm)
|
||||
}),
|
||||
index: atomic_func!(|num, vm| Ok(PyInt::number_int(num, vm))),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
&AS_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
impl PyInt {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::{PyDict, PyDictRef, PyGenericAlias, PyList, PyTuple, PyType, PyTypeRef};
|
||||
use crate::{
|
||||
atomic_func,
|
||||
class::PyClassImpl,
|
||||
convert::ToPyObject,
|
||||
function::{ArgMapping, OptionalArg, PyComparisonValue},
|
||||
@@ -217,11 +218,18 @@ impl AsSequence for PyMappingProxy {
|
||||
}
|
||||
|
||||
impl AsNumber for PyMappingProxy {
|
||||
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
or: Some(|num, args, vm| Self::number_downcast(num).or(args.to_pyobject(vm), vm)),
|
||||
inplace_or: Some(|num, args, vm| Self::number_downcast(num).ior(args.to_pyobject(vm), vm)),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
or: atomic_func!(|num, args, vm| {
|
||||
PyMappingProxy::number_downcast(num).or(args.to_pyobject(vm), vm)
|
||||
}),
|
||||
inplace_or: atomic_func!(|num, args, vm| {
|
||||
PyMappingProxy::number_downcast(num).ior(args.to_pyobject(vm), vm)
|
||||
}),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
&AS_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterable for PyMappingProxy {
|
||||
|
||||
@@ -904,7 +904,7 @@ impl TryFromObject for SubscriptNeedle {
|
||||
Ok(Self::Index(i.try_to_primitive(vm)?))
|
||||
} else if obj.payload_is::<PySlice>() {
|
||||
Ok(Self::Slice(unsafe { obj.downcast_unchecked::<PySlice>() }))
|
||||
} else if let Ok(i) = vm.to_index(&obj) {
|
||||
} 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>() {
|
||||
|
||||
@@ -682,7 +682,7 @@ impl TryFromObject for RangeIndex {
|
||||
i @ PyInt => Ok(RangeIndex::Int(i)),
|
||||
s @ PySlice => Ok(RangeIndex::Slice(s)),
|
||||
obj => {
|
||||
let val = vm.to_index(&obj).map_err(|_| vm.new_type_error(format!(
|
||||
let val = obj.try_index(vm).map_err(|_| vm.new_type_error(format!(
|
||||
"sequence indices be integers or slices or classes that override __index__ operator, not '{}'",
|
||||
obj.class().name()
|
||||
)))?;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::{PyType, PyTypeRef};
|
||||
use crate::{
|
||||
atomic_func,
|
||||
class::PyClassImpl,
|
||||
convert::ToPyObject,
|
||||
protocol::PyNumberMethods,
|
||||
@@ -56,10 +57,13 @@ impl PyNone {
|
||||
}
|
||||
|
||||
impl AsNumber for PyNone {
|
||||
const AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
boolean: Some(|_number, _vm| Ok(false)),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
fn as_number() -> &'static PyNumberMethods {
|
||||
static AS_NUMBER: PyNumberMethods = PyNumberMethods {
|
||||
boolean: atomic_func!(|_number, _vm| Ok(false)),
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
};
|
||||
&AS_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(module = false, name = "NotImplementedType")]
|
||||
|
||||
@@ -12,12 +12,13 @@ use crate::{
|
||||
class::{PyClassImpl, StaticType},
|
||||
function::{FuncArgs, KwArgs, OptionalArg},
|
||||
identifier,
|
||||
protocol::PyNumberMethods,
|
||||
types::{Callable, GetAttr, PyTypeFlags, PyTypeSlots, SetAttr},
|
||||
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
use indexmap::{map::Entry, IndexMap};
|
||||
use itertools::Itertools;
|
||||
use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref};
|
||||
use std::{borrow::Borrow, collections::HashSet, fmt, ops::Deref, pin::Pin, ptr::NonNull};
|
||||
|
||||
/// type(object_or_name, bases, dict)
|
||||
/// type(object) -> the object's type
|
||||
@@ -30,10 +31,62 @@ pub struct PyType {
|
||||
pub subclasses: PyRwLock<Vec<PyRef<PyWeak>>>,
|
||||
pub attributes: PyRwLock<PyAttributes>,
|
||||
pub slots: PyTypeSlots,
|
||||
pub heaptype_ext: Option<Pin<Box<HeapTypeExt>>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct HeapTypeExt {
|
||||
pub number_methods: PyNumberMethods,
|
||||
}
|
||||
|
||||
pub struct PointerSlot<T>(NonNull<T>);
|
||||
|
||||
impl<T> PointerSlot<T> {
|
||||
pub unsafe fn borrow_static(&self) -> &'static T {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for PointerSlot<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for PointerSlot<T> {}
|
||||
|
||||
impl<T> From<&'static T> for PointerSlot<T> {
|
||||
fn from(x: &'static T) -> Self {
|
||||
Self(NonNull::from(x))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for PointerSlot<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PointerSlot<T> {
|
||||
pub unsafe fn from_heaptype<F>(typ: &PyType, f: F) -> Option<Self>
|
||||
where
|
||||
F: FnOnce(&HeapTypeExt) -> &T,
|
||||
{
|
||||
typ.heaptype_ext
|
||||
.as_ref()
|
||||
.map(|ext| Self(NonNull::from(f(ext))))
|
||||
}
|
||||
}
|
||||
|
||||
pub type PyTypeRef = PyRef<PyType>;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "threading")] {
|
||||
unsafe impl Send for PyType {}
|
||||
unsafe impl Sync for PyType {}
|
||||
}
|
||||
}
|
||||
|
||||
/// For attributes we do not use a dict, but an IndexMap, which is an Hash Table
|
||||
/// that maintains order and is compatible with the standard HashMap This is probably
|
||||
/// faster and only supports strings as keys.
|
||||
@@ -112,6 +165,7 @@ impl PyType {
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(attrs),
|
||||
slots,
|
||||
heaptype_ext: Some(Pin::new(Box::new(HeapTypeExt::default()))),
|
||||
},
|
||||
metaclass,
|
||||
None,
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn bytes_from_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Vec<u8
|
||||
}
|
||||
|
||||
pub fn value_from_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<u8> {
|
||||
vm.to_index(obj)?
|
||||
obj.try_index(vm)?
|
||||
.as_bigint()
|
||||
.to_u8()
|
||||
.ok_or_else(|| vm.new_value_error("byte must be in range(0, 256)".to_owned()))
|
||||
|
||||
@@ -108,7 +108,7 @@ impl TryFromObject for std::time::Duration {
|
||||
use std::time::Duration;
|
||||
if let Some(float) = obj.payload::<PyFloat>() {
|
||||
Ok(Duration::from_secs_f64(float.to_f64()))
|
||||
} else if let Some(int) = vm.to_index_opt(obj.clone()) {
|
||||
} else if let Some(int) = obj.try_index_opt(vm) {
|
||||
let sec = int?
|
||||
.as_bigint()
|
||||
.to_u64()
|
||||
|
||||
@@ -717,7 +717,7 @@ impl DictKey for PyObject {
|
||||
}
|
||||
#[inline]
|
||||
fn key_as_isize(&self, vm: &VirtualMachine) -> PyResult<isize> {
|
||||
vm.to_index(self)?.try_to_primitive(vm)
|
||||
self.try_index(vm)?.try_to_primitive(vm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{protocol::PyNumber, AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
|
||||
use crate::{AsObject, PyObjectRef, PyResult, TryFromObject, VirtualMachine};
|
||||
use num_complex::Complex64;
|
||||
use std::ops::Deref;
|
||||
|
||||
@@ -82,7 +82,7 @@ impl Deref for ArgIntoFloat {
|
||||
impl TryFromObject for ArgIntoFloat {
|
||||
// Equivalent to PyFloat_AsDouble.
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let value = PyNumber::new(obj.as_ref(), vm).float(vm)?.to_f64();
|
||||
let value = obj.try_float(vm)?.to_f64();
|
||||
Ok(ArgIntoFloat { value })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,6 +1105,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(Default::default()),
|
||||
slots: PyType::make_slots(),
|
||||
heaptype_ext: None,
|
||||
};
|
||||
let object_payload = PyType {
|
||||
base: None,
|
||||
@@ -1113,6 +1114,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::new(Default::default()),
|
||||
slots: object::PyBaseObject::make_slots(),
|
||||
heaptype_ext: None,
|
||||
};
|
||||
let type_type_ptr = Box::into_raw(Box::new(partially_init!(
|
||||
PyInner::<PyType> {
|
||||
@@ -1173,6 +1175,7 @@ pub(crate) fn init_type_hierarchy() -> (PyTypeRef, PyTypeRef, PyTypeRef) {
|
||||
subclasses: PyRwLock::default(),
|
||||
attributes: PyRwLock::default(),
|
||||
slots: PyWeak::make_slots(),
|
||||
heaptype_ext: None,
|
||||
};
|
||||
let weakref_type = PyRef::new_ref(weakref_type, type_type.clone(), None);
|
||||
|
||||
|
||||
@@ -1,192 +1,48 @@
|
||||
use crate::{
|
||||
builtins::{int, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr},
|
||||
builtins::{
|
||||
int, type_::PointerSlot, PyByteArray, PyBytes, PyComplex, PyFloat, PyInt, PyIntRef, PyStr,
|
||||
},
|
||||
function::ArgBytesLike,
|
||||
stdlib::warnings,
|
||||
AsObject, PyObject, PyPayload, PyRef, PyResult, TryFromBorrowedObject, VirtualMachine,
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromBorrowedObject,
|
||||
VirtualMachine,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[derive(Clone)]
|
||||
pub struct PyNumberMethods {
|
||||
/* Number implementations must check *both*
|
||||
arguments for proper type and implement the necessary conversions
|
||||
in the slot functions themselves. */
|
||||
pub add: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub subtract: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub multiply: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub remainder: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub divmod: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub power: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub negative: Option<fn(&PyNumber, &VirtualMachine) -> PyResult>,
|
||||
pub positive: Option<fn(&PyNumber, &VirtualMachine) -> PyResult>,
|
||||
pub absolute: Option<fn(&PyNumber, &VirtualMachine) -> PyResult>,
|
||||
pub boolean: Option<fn(&PyNumber, &VirtualMachine) -> PyResult<bool>>,
|
||||
pub invert: Option<fn(&PyNumber, &VirtualMachine) -> PyResult>,
|
||||
pub lshift: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub rshift: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub and: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub xor: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub or: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub int: Option<fn(&PyNumber, &VirtualMachine) -> PyResult<PyIntRef>>,
|
||||
pub float: Option<fn(&PyNumber, &VirtualMachine) -> PyResult<PyRef<PyFloat>>>,
|
||||
type UnaryFunc<R = PyObjectRef> = AtomicCell<Option<fn(&PyNumber, &VirtualMachine) -> PyResult<R>>>;
|
||||
type BinaryFunc<R = PyObjectRef> =
|
||||
AtomicCell<Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult<R>>>;
|
||||
|
||||
pub inplace_add: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_subtract: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_multiply: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_remainder: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_divmod: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_power: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_lshift: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_rshift: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_and: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_xor: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_or: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
|
||||
pub floor_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub true_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_floor_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_true_divide: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
|
||||
pub index: Option<fn(&PyNumber, &VirtualMachine) -> PyResult<PyIntRef>>,
|
||||
|
||||
pub matrix_multiply: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
pub inplace_matrix_multiply: Option<fn(&PyNumber, &PyObject, &VirtualMachine) -> PyResult>,
|
||||
}
|
||||
|
||||
impl PyNumberMethods {
|
||||
pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods {
|
||||
add: None,
|
||||
subtract: None,
|
||||
multiply: None,
|
||||
remainder: None,
|
||||
divmod: None,
|
||||
power: None,
|
||||
negative: None,
|
||||
positive: None,
|
||||
absolute: None,
|
||||
boolean: None,
|
||||
invert: None,
|
||||
lshift: None,
|
||||
rshift: None,
|
||||
and: None,
|
||||
xor: None,
|
||||
or: None,
|
||||
int: None,
|
||||
float: None,
|
||||
inplace_add: None,
|
||||
inplace_subtract: None,
|
||||
inplace_multiply: None,
|
||||
inplace_remainder: None,
|
||||
inplace_divmod: None,
|
||||
inplace_power: None,
|
||||
inplace_lshift: None,
|
||||
inplace_rshift: None,
|
||||
inplace_and: None,
|
||||
inplace_xor: None,
|
||||
inplace_or: None,
|
||||
floor_divide: None,
|
||||
true_divide: None,
|
||||
inplace_floor_divide: None,
|
||||
inplace_true_divide: None,
|
||||
index: None,
|
||||
matrix_multiply: None,
|
||||
inplace_matrix_multiply: None,
|
||||
};
|
||||
|
||||
pub(crate) fn generic(
|
||||
has_int: bool,
|
||||
has_float: bool,
|
||||
has_index: bool,
|
||||
) -> &'static PyNumberMethods {
|
||||
static METHODS: &[PyNumberMethods] = &[
|
||||
new_generic(false, false, false),
|
||||
new_generic(true, false, false),
|
||||
new_generic(false, true, false),
|
||||
new_generic(true, true, false),
|
||||
new_generic(false, false, true),
|
||||
new_generic(true, false, true),
|
||||
new_generic(false, true, true),
|
||||
new_generic(true, true, true),
|
||||
];
|
||||
|
||||
fn int(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyInt>> {
|
||||
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?;
|
||||
ret.downcast::<PyInt>().map_err(|obj| {
|
||||
vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class()))
|
||||
})
|
||||
}
|
||||
fn float(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
|
||||
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?;
|
||||
ret.downcast::<PyFloat>().map_err(|obj| {
|
||||
vm.new_type_error(format!(
|
||||
"__float__ returned non-float (type {})",
|
||||
obj.class()
|
||||
))
|
||||
})
|
||||
}
|
||||
fn index(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyInt>> {
|
||||
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?;
|
||||
ret.downcast::<PyInt>().map_err(|obj| {
|
||||
vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class()))
|
||||
})
|
||||
}
|
||||
|
||||
const fn new_generic(has_int: bool, has_float: bool, has_index: bool) -> PyNumberMethods {
|
||||
PyNumberMethods {
|
||||
int: if has_int { Some(int) } else { None },
|
||||
float: if has_float { Some(float) } else { None },
|
||||
index: if has_index { Some(index) } else { None },
|
||||
..PyNumberMethods::NOT_IMPLEMENTED
|
||||
}
|
||||
}
|
||||
|
||||
let key = (has_int as usize) | ((has_float as usize) << 1) | ((has_index as usize) << 2);
|
||||
|
||||
&METHODS[key]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PyNumber<'a> {
|
||||
pub obj: &'a PyObject,
|
||||
// some fast path do not need methods, so we do lazy initialize
|
||||
pub methods: Option<&'static PyNumberMethods>,
|
||||
}
|
||||
|
||||
impl<'a> PyNumber<'a> {
|
||||
pub fn new(obj: &'a PyObject, vm: &VirtualMachine) -> Self {
|
||||
Self {
|
||||
obj,
|
||||
methods: Self::find_methods(obj, vm),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyNumber<'_> {
|
||||
pub fn find_methods(obj: &PyObject, vm: &VirtualMachine) -> Option<&'static PyNumberMethods> {
|
||||
let as_number = obj.class().mro_find_map(|x| x.slots.as_number.load());
|
||||
as_number.map(|f| f(obj, vm))
|
||||
impl PyObject {
|
||||
#[inline]
|
||||
pub fn to_number(&self) -> PyNumber<'_> {
|
||||
PyNumber::from(self)
|
||||
}
|
||||
|
||||
pub fn methods(&self) -> &'static PyNumberMethods {
|
||||
self.methods.unwrap_or(&PyNumberMethods::NOT_IMPLEMENTED)
|
||||
}
|
||||
|
||||
// PyNumber_Check
|
||||
pub fn check(obj: &PyObject, vm: &VirtualMachine) -> bool {
|
||||
Self::find_methods(obj, vm).map_or(false, |methods| {
|
||||
methods.int.is_some()
|
||||
|| methods.index.is_some()
|
||||
|| methods.float.is_some()
|
||||
|| obj.payload_is::<PyComplex>()
|
||||
pub fn try_index_opt(&self, vm: &VirtualMachine) -> Option<PyResult<PyIntRef>> {
|
||||
#[allow(clippy::question_mark)]
|
||||
Some(if let Some(i) = self.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
Ok(i.to_owned())
|
||||
} else if let Some(i) = self.payload::<PyInt>() {
|
||||
Ok(vm.ctx.new_bigint(i.as_bigint()))
|
||||
} else if let Some(i) = self.to_number().index(vm).transpose() {
|
||||
i
|
||||
} else {
|
||||
return None;
|
||||
})
|
||||
}
|
||||
|
||||
// PyIndex_Check
|
||||
pub fn is_index(&self) -> bool {
|
||||
self.methods().index.is_some()
|
||||
#[inline]
|
||||
pub fn try_index(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
|
||||
self.try_index_opt(vm).transpose()?.ok_or_else(|| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
self.class()
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn int(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
|
||||
pub fn try_int(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
|
||||
fn try_convert(obj: &PyObject, lit: &[u8], vm: &VirtualMachine) -> PyResult<PyIntRef> {
|
||||
let base = 10;
|
||||
match int::bytes_to_int(lit, base) {
|
||||
@@ -199,11 +55,216 @@ impl PyNumber<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(i) = self.obj.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
if let Some(i) = self.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
Ok(i.to_owned())
|
||||
} else if let Some(f) = self.methods().int {
|
||||
} else {
|
||||
let number = self.to_number();
|
||||
if let Some(i) = number.int(vm)? {
|
||||
Ok(i)
|
||||
} else if let Some(i) = self.try_index_opt(vm) {
|
||||
i
|
||||
} else if let Ok(Ok(f)) =
|
||||
vm.get_special_method(self.to_owned(), identifier!(vm, __trunc__))
|
||||
{
|
||||
// TODO: Deprecate in 3.11
|
||||
// warnings::warn(
|
||||
// vm.ctx.exceptions.deprecation_warning.clone(),
|
||||
// "The delegation of int() to __trunc__ is deprecated.".to_owned(),
|
||||
// 1,
|
||||
// vm,
|
||||
// )?;
|
||||
let ret = f.invoke((), vm)?;
|
||||
ret.try_index(vm).map_err(|_| {
|
||||
vm.new_type_error(format!(
|
||||
"__trunc__ returned non-Integral (type {})",
|
||||
ret.class()
|
||||
))
|
||||
})
|
||||
} else if let Some(s) = self.payload::<PyStr>() {
|
||||
try_convert(self, s.as_str().as_bytes(), vm)
|
||||
} else if let Some(bytes) = self.payload::<PyBytes>() {
|
||||
try_convert(self, bytes, vm)
|
||||
} else if let Some(bytearray) = self.payload::<PyByteArray>() {
|
||||
try_convert(self, &bytearray.borrow_buf(), vm)
|
||||
} else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self) {
|
||||
// TODO: replace to PyBuffer
|
||||
try_convert(self, &buffer.borrow_buf(), vm)
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"int() argument must be a string, a bytes-like object or a real number, not '{}'",
|
||||
self.class()
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_float_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
|
||||
let value = if let Some(float) = self.downcast_ref_if_exact::<PyFloat>(vm) {
|
||||
Some(float.to_owned())
|
||||
} else {
|
||||
let number = self.to_number();
|
||||
#[allow(clippy::manual_map)]
|
||||
if let Some(f) = number.float(vm)? {
|
||||
Some(f)
|
||||
} else if let Some(i) = self.try_index_opt(vm) {
|
||||
let value = int::try_to_float(i?.as_bigint(), vm)?;
|
||||
Some(vm.ctx.new_float(value))
|
||||
} else if let Some(value) = self.downcast_ref::<PyFloat>() {
|
||||
Some(vm.ctx.new_float(value.to_f64()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_float(&self, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
|
||||
self.try_float_opt(vm)?
|
||||
.ok_or_else(|| vm.new_type_error(format!("must be real number, not {}", self.class())))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PyNumberMethods {
|
||||
/* Number implementations must check *both*
|
||||
arguments for proper type and implement the necessary conversions
|
||||
in the slot functions themselves. */
|
||||
pub add: BinaryFunc,
|
||||
pub subtract: BinaryFunc,
|
||||
pub multiply: BinaryFunc,
|
||||
pub remainder: BinaryFunc,
|
||||
pub divmod: BinaryFunc,
|
||||
pub power: BinaryFunc,
|
||||
pub negative: UnaryFunc,
|
||||
pub positive: UnaryFunc,
|
||||
pub absolute: UnaryFunc,
|
||||
pub boolean: UnaryFunc<bool>,
|
||||
pub invert: UnaryFunc,
|
||||
pub lshift: BinaryFunc,
|
||||
pub rshift: BinaryFunc,
|
||||
pub and: BinaryFunc,
|
||||
pub xor: BinaryFunc,
|
||||
pub or: BinaryFunc,
|
||||
pub int: UnaryFunc<PyRef<PyInt>>,
|
||||
pub float: UnaryFunc<PyRef<PyFloat>>,
|
||||
|
||||
pub inplace_add: BinaryFunc,
|
||||
pub inplace_subtract: BinaryFunc,
|
||||
pub inplace_multiply: BinaryFunc,
|
||||
pub inplace_remainder: BinaryFunc,
|
||||
pub inplace_divmod: BinaryFunc,
|
||||
pub inplace_power: BinaryFunc,
|
||||
pub inplace_lshift: BinaryFunc,
|
||||
pub inplace_rshift: BinaryFunc,
|
||||
pub inplace_and: BinaryFunc,
|
||||
pub inplace_xor: BinaryFunc,
|
||||
pub inplace_or: BinaryFunc,
|
||||
|
||||
pub floor_divide: BinaryFunc,
|
||||
pub true_divide: BinaryFunc,
|
||||
pub inplace_floor_divide: BinaryFunc,
|
||||
pub inplace_true_divide: BinaryFunc,
|
||||
|
||||
pub index: UnaryFunc<PyRef<PyInt>>,
|
||||
|
||||
pub matrix_multiply: BinaryFunc,
|
||||
pub inplace_matrix_multiply: BinaryFunc,
|
||||
}
|
||||
|
||||
impl PyNumberMethods {
|
||||
/// this is NOT a global variable
|
||||
// TODO: weak order read for performance
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
pub const NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods {
|
||||
add: AtomicCell::new(None),
|
||||
subtract: AtomicCell::new(None),
|
||||
multiply: AtomicCell::new(None),
|
||||
remainder: AtomicCell::new(None),
|
||||
divmod: AtomicCell::new(None),
|
||||
power: AtomicCell::new(None),
|
||||
negative: AtomicCell::new(None),
|
||||
positive: AtomicCell::new(None),
|
||||
absolute: AtomicCell::new(None),
|
||||
boolean: AtomicCell::new(None),
|
||||
invert: AtomicCell::new(None),
|
||||
lshift: AtomicCell::new(None),
|
||||
rshift: AtomicCell::new(None),
|
||||
and: AtomicCell::new(None),
|
||||
xor: AtomicCell::new(None),
|
||||
or: AtomicCell::new(None),
|
||||
int: AtomicCell::new(None),
|
||||
float: AtomicCell::new(None),
|
||||
inplace_add: AtomicCell::new(None),
|
||||
inplace_subtract: AtomicCell::new(None),
|
||||
inplace_multiply: AtomicCell::new(None),
|
||||
inplace_remainder: AtomicCell::new(None),
|
||||
inplace_divmod: AtomicCell::new(None),
|
||||
inplace_power: AtomicCell::new(None),
|
||||
inplace_lshift: AtomicCell::new(None),
|
||||
inplace_rshift: AtomicCell::new(None),
|
||||
inplace_and: AtomicCell::new(None),
|
||||
inplace_xor: AtomicCell::new(None),
|
||||
inplace_or: AtomicCell::new(None),
|
||||
floor_divide: AtomicCell::new(None),
|
||||
true_divide: AtomicCell::new(None),
|
||||
inplace_floor_divide: AtomicCell::new(None),
|
||||
inplace_true_divide: AtomicCell::new(None),
|
||||
index: AtomicCell::new(None),
|
||||
matrix_multiply: AtomicCell::new(None),
|
||||
inplace_matrix_multiply: AtomicCell::new(None),
|
||||
};
|
||||
}
|
||||
|
||||
pub struct PyNumber<'a> {
|
||||
pub obj: &'a PyObject,
|
||||
methods: &'a PyNumberMethods,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PyObject> for PyNumber<'a> {
|
||||
fn from(obj: &'a PyObject) -> Self {
|
||||
static GLOBAL_NOT_IMPLEMENTED: PyNumberMethods = PyNumberMethods::NOT_IMPLEMENTED;
|
||||
Self {
|
||||
obj,
|
||||
methods: Self::find_methods(obj)
|
||||
.map_or(&GLOBAL_NOT_IMPLEMENTED, |m| unsafe { m.borrow_static() }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PyNumber<'_> {
|
||||
fn find_methods(obj: &PyObject) -> Option<PointerSlot<PyNumberMethods>> {
|
||||
obj.class().mro_find_map(|x| x.slots.as_number.load())
|
||||
}
|
||||
|
||||
pub fn methods(&self) -> &PyNumberMethods {
|
||||
self.methods
|
||||
}
|
||||
|
||||
// PyNumber_Check
|
||||
pub fn check(obj: &PyObject) -> bool {
|
||||
let methods = if let Some(m) = Self::find_methods(obj) {
|
||||
m
|
||||
} else {
|
||||
return false;
|
||||
};
|
||||
let methods = methods.as_ref();
|
||||
methods.int.load().is_some()
|
||||
|| methods.index.load().is_some()
|
||||
|| methods.float.load().is_some()
|
||||
|| obj.payload_is::<PyComplex>()
|
||||
}
|
||||
|
||||
// PyIndex_Check
|
||||
pub fn is_index(&self) -> bool {
|
||||
self.methods().index.load().is_some()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn int(&self, vm: &VirtualMachine) -> PyResult<Option<PyIntRef>> {
|
||||
Ok(if let Some(f) = self.methods().int.load() {
|
||||
let ret = f(self, vm)?;
|
||||
if !ret.class().is(PyInt::class(vm)) {
|
||||
Some(if !ret.class().is(PyInt::class(vm)) {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
@@ -215,52 +276,18 @@ impl PyNumber<'_> {
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
Ok(vm.ctx.new_bigint(ret.as_bigint()))
|
||||
vm.ctx.new_bigint(ret.as_bigint())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
} else if self.methods().index.is_some() {
|
||||
self.index(vm)
|
||||
} else if let Ok(Ok(f)) =
|
||||
vm.get_special_method(self.obj.to_owned(), identifier!(vm, __trunc__))
|
||||
{
|
||||
// TODO: Deprecate in 3.11
|
||||
// warnings::warn(
|
||||
// vm.ctx.exceptions.deprecation_warning.clone(),
|
||||
// "The delegation of int() to __trunc__ is deprecated.".to_owned(),
|
||||
// 1,
|
||||
// vm,
|
||||
// )?;
|
||||
let ret = f.invoke((), vm)?;
|
||||
PyNumber::new(ret.as_ref(), vm).index(vm).map_err(|_| {
|
||||
vm.new_type_error(format!(
|
||||
"__trunc__ returned non-Integral (type {})",
|
||||
ret.class()
|
||||
))
|
||||
ret
|
||||
})
|
||||
} else if let Some(s) = self.obj.payload::<PyStr>() {
|
||||
try_convert(self.obj, s.as_str().as_bytes(), vm)
|
||||
} else if let Some(bytes) = self.obj.payload::<PyBytes>() {
|
||||
try_convert(self.obj, bytes, vm)
|
||||
} else if let Some(bytearray) = self.obj.payload::<PyByteArray>() {
|
||||
try_convert(self.obj, &bytearray.borrow_buf(), vm)
|
||||
} else if let Ok(buffer) = ArgBytesLike::try_from_borrowed_object(vm, self.obj) {
|
||||
// TODO: replace to PyBuffer
|
||||
try_convert(self.obj, &buffer.borrow_buf(), vm)
|
||||
} else {
|
||||
Err(vm.new_type_error(format!(
|
||||
"int() argument must be a string, a bytes-like object or a real number, not '{}'",
|
||||
self.obj.class()
|
||||
)))
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn index_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyIntRef>> {
|
||||
if let Some(i) = self.obj.downcast_ref_if_exact::<PyInt>(vm) {
|
||||
Ok(Some(i.to_owned()))
|
||||
} else if let Some(i) = self.obj.payload::<PyInt>() {
|
||||
Ok(Some(vm.ctx.new_bigint(i.as_bigint())))
|
||||
} else if let Some(f) = self.methods().index {
|
||||
#[inline]
|
||||
pub fn index(&self, vm: &VirtualMachine) -> PyResult<Option<PyIntRef>> {
|
||||
if let Some(f) = self.methods().index.load() {
|
||||
let ret = f(self, vm)?;
|
||||
if !ret.class().is(PyInt::class(vm)) {
|
||||
warnings::warn(
|
||||
@@ -283,21 +310,11 @@ impl PyNumber<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index(&self, vm: &VirtualMachine) -> PyResult<PyIntRef> {
|
||||
self.index_opt(vm)?.ok_or_else(|| {
|
||||
vm.new_type_error(format!(
|
||||
"'{}' object cannot be interpreted as an integer",
|
||||
self.obj.class()
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn float_opt(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
|
||||
if let Some(float) = self.obj.downcast_ref_if_exact::<PyFloat>(vm) {
|
||||
Ok(Some(float.to_owned()))
|
||||
} else if let Some(f) = self.methods().float {
|
||||
#[inline]
|
||||
pub fn float(&self, vm: &VirtualMachine) -> PyResult<Option<PyRef<PyFloat>>> {
|
||||
Ok(if let Some(f) = self.methods().float.load() {
|
||||
let ret = f(self, vm)?;
|
||||
if !ret.class().is(PyFloat::class(vm)) {
|
||||
Some(if !ret.class().is(PyFloat::class(vm)) {
|
||||
warnings::warn(
|
||||
vm.ctx.exceptions.deprecation_warning,
|
||||
format!(
|
||||
@@ -309,24 +326,12 @@ impl PyNumber<'_> {
|
||||
1,
|
||||
vm,
|
||||
)?;
|
||||
Ok(Some(vm.ctx.new_float(ret.to_f64())))
|
||||
vm.ctx.new_float(ret.to_f64())
|
||||
} else {
|
||||
Ok(Some(ret))
|
||||
}
|
||||
} else if self.methods().index.is_some() {
|
||||
let i = self.index(vm)?;
|
||||
let value = int::try_to_float(i.as_bigint(), vm)?;
|
||||
Ok(Some(vm.ctx.new_float(value)))
|
||||
} else if let Some(value) = self.obj.downcast_ref::<PyFloat>() {
|
||||
Ok(Some(vm.ctx.new_float(value.to_f64())))
|
||||
ret
|
||||
})
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float(&self, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
|
||||
self.float_opt(vm)?.ok_or_else(|| {
|
||||
vm.new_type_error(format!("must be real number, not {}", self.obj.class()))
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ impl SequenceIndex {
|
||||
.map(Self::Int)
|
||||
} else if let Some(slice) = obj.payload::<PySlice>() {
|
||||
slice.to_saturated(vm).map(Self::Slice)
|
||||
} else if let Some(i) = vm.to_index_opt(obj.to_owned()) {
|
||||
} else if let Some(i) = obj.try_index_opt(vm) {
|
||||
// TODO: __index__ for indices is no more supported?
|
||||
i?.try_to_primitive(vm)
|
||||
.map_err(|_| {
|
||||
@@ -465,7 +465,7 @@ fn to_isize_index(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Option<isize>
|
||||
if vm.is_none(obj) {
|
||||
return Ok(None);
|
||||
}
|
||||
let result = vm.to_index_opt(obj.to_owned()).unwrap_or_else(|| {
|
||||
let result = obj.try_index_opt(vm).unwrap_or_else(|| {
|
||||
Err(vm.new_type_error(
|
||||
"slice indices must be integers or None or have an __index__ method".to_owned(),
|
||||
))
|
||||
|
||||
@@ -719,7 +719,7 @@ mod builtins {
|
||||
})?;
|
||||
match ndigits.flatten() {
|
||||
Some(obj) => {
|
||||
let ndigits = vm.to_index(&obj)?;
|
||||
let ndigits = obj.try_index(vm)?;
|
||||
meth.invoke((ndigits,), vm)
|
||||
}
|
||||
None => {
|
||||
|
||||
@@ -1336,7 +1336,7 @@ mod _io {
|
||||
}
|
||||
|
||||
pub fn get_offset(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<Offset> {
|
||||
let int = vm.to_index(&obj)?;
|
||||
let int = obj.try_index(vm)?;
|
||||
int.as_bigint().try_into().map_err(|_| {
|
||||
vm.new_value_error(format!(
|
||||
"cannot fit '{}' into an offset-sized integer",
|
||||
|
||||
@@ -196,7 +196,7 @@ mod decl {
|
||||
) -> PyResult {
|
||||
let start = start.into_option().unwrap_or_else(|| vm.new_pyobj(0));
|
||||
let step = step.into_option().unwrap_or_else(|| vm.new_pyobj(1));
|
||||
if !PyNumber::check(&start, vm) || !PyNumber::check(&step, vm) {
|
||||
if !PyNumber::check(&start) || !PyNumber::check(&step) {
|
||||
return Err(vm.new_type_error("a number is required".to_owned()));
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ mod _operator {
|
||||
/// Return a converted to an integer. Equivalent to a.__index__().
|
||||
#[pyfunction]
|
||||
fn index(a: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIntRef> {
|
||||
vm.to_index(&a)
|
||||
a.try_index(vm)
|
||||
}
|
||||
|
||||
/// Return the bitwise inverse of the number obj. This is equivalent to ~obj.
|
||||
|
||||
@@ -349,7 +349,7 @@ impl<const AVAILABLE: usize> FromArgs for DirFd<AVAILABLE> {
|
||||
Some(o) if vm.is_none(&o) => DEFAULT_DIR_FD,
|
||||
None => DEFAULT_DIR_FD,
|
||||
Some(o) => {
|
||||
let fd = vm.to_index_opt(o.clone()).unwrap_or_else(|| {
|
||||
let fd = o.try_index_opt(vm).unwrap_or_else(|| {
|
||||
Err(vm.new_type_error(format!(
|
||||
"argument should be integer or None, not {}",
|
||||
o.class().name()
|
||||
@@ -1364,8 +1364,8 @@ pub(super) mod _os {
|
||||
divmod.class().name()
|
||||
))
|
||||
})?;
|
||||
let secs = vm.to_index(&div)?.try_to_primitive(vm)?;
|
||||
let ns = vm.to_index(&rem)?.try_to_primitive(vm)?;
|
||||
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))
|
||||
};
|
||||
// TODO: do validation to make sure this doesn't.. underflow?
|
||||
|
||||
@@ -745,7 +745,7 @@ mod _sre {
|
||||
}
|
||||
|
||||
fn get_index(&self, group: PyObjectRef, vm: &VirtualMachine) -> Option<usize> {
|
||||
let i = if let Ok(i) = vm.to_index(&group) {
|
||||
let i = if let Ok(i) = group.try_index(vm) {
|
||||
i
|
||||
} else {
|
||||
self.pattern
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::common::{hash::PyHash, lock::PyRwLock};
|
||||
use crate::{
|
||||
builtins::{PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef},
|
||||
builtins::{type_::PointerSlot, PyFloat, PyInt, PyStrInterned, PyStrRef, PyType, PyTypeRef},
|
||||
bytecode::ComparisonOperator,
|
||||
convert::ToPyResult,
|
||||
function::Either,
|
||||
@@ -17,6 +17,13 @@ use crossbeam_utils::atomic::AtomicCell;
|
||||
use num_traits::{Signed, ToPrimitive};
|
||||
use std::{borrow::Borrow, cmp::Ordering};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! atomic_func {
|
||||
($x:expr) => {
|
||||
crossbeam_utils::atomic::AtomicCell::new(Some($x))
|
||||
};
|
||||
}
|
||||
|
||||
// The corresponding field in CPython is `tp_` prefixed.
|
||||
// e.g. name -> tp_name
|
||||
#[derive(Default)]
|
||||
@@ -30,7 +37,7 @@ pub struct PyTypeSlots {
|
||||
// Methods to implement standard operations
|
||||
|
||||
// Method suites for standard classes
|
||||
pub as_number: AtomicCell<Option<AsNumberFunc>>,
|
||||
pub as_number: AtomicCell<Option<PointerSlot<PyNumberMethods>>>,
|
||||
pub as_sequence: AtomicCell<Option<AsSequenceFunc>>,
|
||||
pub as_mapping: AtomicCell<Option<AsMappingFunc>>,
|
||||
|
||||
@@ -139,7 +146,6 @@ impl Default for PyTypeFlags {
|
||||
|
||||
pub(crate) type GenericMethod = fn(&PyObject, FuncArgs, &VirtualMachine) -> PyResult;
|
||||
pub(crate) type AsMappingFunc = fn(&PyObject, &VirtualMachine) -> &'static PyMappingMethods;
|
||||
pub(crate) type AsNumberFunc = fn(&PyObject, &VirtualMachine) -> &'static PyNumberMethods;
|
||||
pub(crate) type HashFunc = fn(&PyObject, &VirtualMachine) -> PyResult<PyHash>;
|
||||
// CallFunc = GenericMethod
|
||||
pub(crate) type GetattroFunc = fn(&PyObject, PyStrRef, &VirtualMachine) -> PyResult;
|
||||
@@ -205,13 +211,28 @@ fn slot_as_sequence(zelf: &PyObject, vm: &VirtualMachine) -> &'static PySequence
|
||||
PySequenceMethods::generic(has_length, has_ass_item)
|
||||
}
|
||||
|
||||
fn slot_as_number(zelf: &PyObject, vm: &VirtualMachine) -> &'static PyNumberMethods {
|
||||
let (has_int, has_float, has_index) = (
|
||||
zelf.class().has_attr(identifier!(vm, __int__)),
|
||||
zelf.class().has_attr(identifier!(vm, __float__)),
|
||||
zelf.class().has_attr(identifier!(vm, __index__)),
|
||||
);
|
||||
PyNumberMethods::generic(has_int, has_float, has_index)
|
||||
fn int_wrapper(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyInt>> {
|
||||
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __int__), ())?;
|
||||
ret.downcast::<PyInt>().map_err(|obj| {
|
||||
vm.new_type_error(format!("__int__ returned non-int (type {})", obj.class()))
|
||||
})
|
||||
}
|
||||
|
||||
fn index_wrapper(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyInt>> {
|
||||
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __index__), ())?;
|
||||
ret.downcast::<PyInt>().map_err(|obj| {
|
||||
vm.new_type_error(format!("__index__ returned non-int (type {})", obj.class()))
|
||||
})
|
||||
}
|
||||
|
||||
fn float_wrapper(num: &PyNumber, vm: &VirtualMachine) -> PyResult<PyRef<PyFloat>> {
|
||||
let ret = vm.call_special_method(num.obj.to_owned(), identifier!(vm, __float__), ())?;
|
||||
ret.downcast::<PyFloat>().map_err(|obj| {
|
||||
vm.new_type_error(format!(
|
||||
"__float__ returned non-float (type {})",
|
||||
obj.class()
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn hash_wrapper(zelf: &PyObject, vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
@@ -327,21 +348,35 @@ impl PyType {
|
||||
debug_assert!(name.as_str().starts_with("__"));
|
||||
debug_assert!(name.as_str().ends_with("__"));
|
||||
|
||||
macro_rules! update_slot {
|
||||
macro_rules! toggle_slot {
|
||||
($name:ident, $func:expr) => {{
|
||||
self.slots.$name.store(if add { Some($func) } else { None });
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! update_slot {
|
||||
($name:ident, $func:expr) => {{
|
||||
self.slots.$name.store(Some($func));
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! update_pointer_slot {
|
||||
($name:ident, $pointed:ident) => {{
|
||||
self.slots
|
||||
.$name
|
||||
.store(unsafe { PointerSlot::from_heaptype(self, |ext| &ext.$pointed) });
|
||||
}};
|
||||
}
|
||||
match name.as_str() {
|
||||
"__len__" | "__getitem__" | "__setitem__" | "__delitem__" => {
|
||||
update_slot!(as_mapping, slot_as_mapping);
|
||||
update_slot!(as_sequence, slot_as_sequence);
|
||||
}
|
||||
"__hash__" => {
|
||||
update_slot!(hash, hash_wrapper);
|
||||
toggle_slot!(hash, hash_wrapper);
|
||||
}
|
||||
"__call__" => {
|
||||
update_slot!(call, call_wrapper);
|
||||
toggle_slot!(call, call_wrapper);
|
||||
}
|
||||
"__getattr__" | "__getattribute__" => {
|
||||
update_slot!(getattro, getattro_wrapper);
|
||||
@@ -353,28 +388,52 @@ impl PyType {
|
||||
update_slot!(richcompare, richcompare_wrapper);
|
||||
}
|
||||
"__iter__" => {
|
||||
update_slot!(iter, iter_wrapper);
|
||||
toggle_slot!(iter, iter_wrapper);
|
||||
}
|
||||
"__next__" => {
|
||||
update_slot!(iternext, iternext_wrapper);
|
||||
toggle_slot!(iternext, iternext_wrapper);
|
||||
}
|
||||
"__get__" => {
|
||||
update_slot!(descr_get, descr_get_wrapper);
|
||||
toggle_slot!(descr_get, descr_get_wrapper);
|
||||
}
|
||||
"__set__" | "__delete__" => {
|
||||
update_slot!(descr_set, descr_set_wrapper);
|
||||
}
|
||||
"__init__" => {
|
||||
update_slot!(init, init_wrapper);
|
||||
toggle_slot!(init, init_wrapper);
|
||||
}
|
||||
"__new__" => {
|
||||
update_slot!(new, new_wrapper);
|
||||
toggle_slot!(new, new_wrapper);
|
||||
}
|
||||
"__del__" => {
|
||||
update_slot!(del, del_wrapper);
|
||||
toggle_slot!(del, del_wrapper);
|
||||
}
|
||||
"__int__" | "__index__" | "__float__" => {
|
||||
update_slot!(as_number, slot_as_number);
|
||||
"__int__" => {
|
||||
self.heaptype_ext
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.number_methods
|
||||
.int
|
||||
.store(Some(int_wrapper));
|
||||
update_pointer_slot!(as_number, number_methods);
|
||||
}
|
||||
"__index__" => {
|
||||
self.heaptype_ext
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.number_methods
|
||||
.index
|
||||
.store(Some(index_wrapper));
|
||||
update_pointer_slot!(as_number, number_methods);
|
||||
}
|
||||
"__float__" => {
|
||||
self.heaptype_ext
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.number_methods
|
||||
.float
|
||||
.store(Some(float_wrapper));
|
||||
update_pointer_slot!(as_number, number_methods);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -880,13 +939,8 @@ pub trait AsSequence: PyPayload {
|
||||
|
||||
#[pyimpl]
|
||||
pub trait AsNumber: PyPayload {
|
||||
const AS_NUMBER: PyNumberMethods;
|
||||
|
||||
#[inline]
|
||||
#[pyslot]
|
||||
fn as_number(_zelf: &PyObject, _vm: &VirtualMachine) -> &'static PyNumberMethods {
|
||||
&Self::AS_NUMBER
|
||||
}
|
||||
fn as_number() -> &'static PyNumberMethods;
|
||||
|
||||
fn number_downcast<'a>(number: &'a PyNumber) -> &'a Py<Self> {
|
||||
unsafe { number.obj.downcast_unchecked_ref() }
|
||||
|
||||
@@ -3,22 +3,12 @@ use crate::{
|
||||
builtins::{PyInt, PyIntRef, PyStrInterned},
|
||||
function::PyArithmeticValue,
|
||||
object::{AsObject, PyObject, PyObjectRef, PyResult},
|
||||
protocol::{PyIterReturn, PyNumber},
|
||||
protocol::PyIterReturn,
|
||||
types::PyComparisonOp,
|
||||
};
|
||||
|
||||
/// Collection of operators
|
||||
impl VirtualMachine {
|
||||
pub fn to_index_opt(&self, obj: PyObjectRef) -> Option<PyResult<PyIntRef>> {
|
||||
PyNumber::new(obj.as_ref(), self)
|
||||
.index_opt(self)
|
||||
.transpose()
|
||||
}
|
||||
|
||||
pub fn to_index(&self, obj: &PyObject) -> PyResult<PyIntRef> {
|
||||
PyNumber::new(obj, self).index(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bool_eq(&self, a: &PyObject, b: &PyObject) -> PyResult<bool> {
|
||||
a.rich_compare_bool(b, PyComparisonOp::Eq, self)
|
||||
|
||||
Reference in New Issue
Block a user