mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
trait SlotConstructor for tp_new blueprint
This commit is contained in:
@@ -485,7 +485,7 @@ where
|
||||
Self::#ident as _
|
||||
}
|
||||
};
|
||||
const NON_ATOMIC_SLOTS: &[&str] = &["new", "as_buffer"];
|
||||
const NON_ATOMIC_SLOTS: &[&str] = &["as_buffer"];
|
||||
if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) {
|
||||
quote! {
|
||||
slots.#slot_ident = Some(#into_func);
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::{float, IntoPyBool, PyByteArray, PyBytes, PyStr, PyStrRef, PyTypeRef}
|
||||
use crate::common::hash;
|
||||
use crate::format::FormatSpec;
|
||||
use crate::function::{OptionalArg, OptionalOption};
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp};
|
||||
use crate::slots::{Comparable, Hashable, PyComparisonOp, SlotConstructor};
|
||||
use crate::VirtualMachine;
|
||||
use crate::{bytesinner::PyBytesInner, byteslike::try_bytes_like};
|
||||
use crate::{
|
||||
@@ -235,7 +235,46 @@ fn inner_truediv(i1: &BigInt, i2: &BigInt, vm: &VirtualMachine) -> PyResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Comparable, Hashable))]
|
||||
impl SlotConstructor for PyInt {
|
||||
type Args = IntOptions;
|
||||
|
||||
fn py_new(cls: PyTypeRef, options: IntOptions, 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)?
|
||||
.as_bigint()
|
||||
.to_u32()
|
||||
.filter(|&v| v == 0 || (2..=36).contains(&v))
|
||||
.ok_or_else(|| {
|
||||
vm.new_value_error("int() base must be >= 2 and <= 36, or 0".to_owned())
|
||||
})?;
|
||||
try_int_radix(&val, base, vm)
|
||||
} else {
|
||||
let val = if cls.is(&vm.ctx.types.int_type) {
|
||||
match val.downcast_exact::<PyInt>(vm) {
|
||||
Ok(i) => {
|
||||
return Ok(i.into_pyobject(vm));
|
||||
}
|
||||
Err(val) => val,
|
||||
}
|
||||
} else {
|
||||
val
|
||||
};
|
||||
|
||||
try_int(&val, vm)
|
||||
}
|
||||
} else if let OptionalArg::Present(_) = options.base {
|
||||
Err(vm.new_type_error("int() missing string argument".to_owned()))
|
||||
} else {
|
||||
Ok(Zero::zero())
|
||||
}?;
|
||||
|
||||
Self::with_value(cls, value, vm).into_pyresult(vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl(flags(BASETYPE), with(Comparable, Hashable, SlotConstructor))]
|
||||
impl PyInt {
|
||||
fn with_value<T>(cls: PyTypeRef, value: T, vm: &VirtualMachine) -> PyResult<PyRef<Self>>
|
||||
where
|
||||
@@ -258,42 +297,6 @@ impl PyInt {
|
||||
&self.value
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyTypeRef, options: IntOptions, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
let value = if let OptionalArg::Present(val) = options.val_options {
|
||||
if let OptionalArg::Present(base) = options.base {
|
||||
let base = vm
|
||||
.to_index(&base)?
|
||||
.as_bigint()
|
||||
.to_u32()
|
||||
.filter(|&v| v == 0 || (2..=36).contains(&v))
|
||||
.ok_or_else(|| {
|
||||
vm.new_value_error("int() base must be >= 2 and <= 36, or 0".to_owned())
|
||||
})?;
|
||||
try_int_radix(&val, base, vm)
|
||||
} else {
|
||||
let val = if cls.is(&vm.ctx.types.int_type) {
|
||||
match val.downcast_exact::<PyInt>(vm) {
|
||||
Ok(i) => {
|
||||
return Ok(i);
|
||||
}
|
||||
Err(val) => val,
|
||||
}
|
||||
} else {
|
||||
val
|
||||
};
|
||||
|
||||
try_int(&val, vm)
|
||||
}
|
||||
} else if let OptionalArg::Present(_) = options.base {
|
||||
Err(vm.new_type_error("int() missing string argument".to_owned()))
|
||||
} else {
|
||||
Ok(Zero::zero())
|
||||
}?;
|
||||
|
||||
Self::with_value(cls, value, vm)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn int_op<F>(&self, other: PyObjectRef, op: F, vm: &VirtualMachine) -> PyArithmaticValue<BigInt>
|
||||
where
|
||||
@@ -735,7 +738,7 @@ impl Hashable for PyInt {
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct IntOptions {
|
||||
pub struct IntOptions {
|
||||
#[pyarg(positional, optional)]
|
||||
val_options: OptionalArg<PyObjectRef>,
|
||||
#[pyarg(any, optional)]
|
||||
|
||||
@@ -151,6 +151,17 @@ impl PyType {
|
||||
}};
|
||||
}
|
||||
match name {
|
||||
"__new__" => {
|
||||
let func: slots::NewFunc =
|
||||
|cls: PyTypeRef, mut args: FuncArgs, vm: &VirtualMachine| {
|
||||
let new = vm
|
||||
.get_attribute_opt(cls.as_object().clone(), "__new__")?
|
||||
.unwrap();
|
||||
args.prepend_arg(cls.into_object());
|
||||
vm.invoke(&new, args)
|
||||
};
|
||||
update_slot!(new, func);
|
||||
}
|
||||
"__call__" => {
|
||||
let func: slots::GenericMethod =
|
||||
|zelf, args, vm| vm.call_special_method(zelf.clone(), "__call__", args);
|
||||
@@ -442,10 +453,9 @@ impl PyType {
|
||||
let winner = calculate_meta_class(metatype.clone(), &bases, vm)?;
|
||||
let metatype = if !winner.is(&metatype) {
|
||||
#[allow(clippy::redundant_clone)] // false positive
|
||||
if let Some(ref tp_new) = winner.clone().slots.new {
|
||||
if let Some(ref tp_new) = winner.clone().slots.new.load() {
|
||||
// Pass it to the winner
|
||||
args.prepend_arg(winner.into_object());
|
||||
return tp_new(vm, args);
|
||||
return tp_new(winner, args, vm);
|
||||
}
|
||||
winner
|
||||
} else {
|
||||
@@ -787,9 +797,8 @@ fn call_tp_new(
|
||||
return vm.invoke(&new_meth, args);
|
||||
}
|
||||
}
|
||||
if let Some(tp_new) = cls.slots.new.as_ref() {
|
||||
args.prepend_arg(subtype.into_object());
|
||||
return tp_new(vm, args);
|
||||
if let Some(tp_new) = cls.slots.new.load() {
|
||||
return tp_new(subtype, args, vm);
|
||||
}
|
||||
}
|
||||
unreachable!("Should be able to find a new slot somewhere in the mro")
|
||||
|
||||
@@ -34,11 +34,6 @@ macro_rules! py_class {
|
||||
py_class
|
||||
}
|
||||
};
|
||||
(@extract_slots($ctx:expr, $slots:expr, (slot new), $value:expr)) => {
|
||||
$slots.new = Some(
|
||||
$crate::function::IntoPyNativeFunc::into_func($value)
|
||||
);
|
||||
};
|
||||
(@extract_slots($ctx:expr, $slots:expr, (slot $slot_name:ident), $value:expr)) => {
|
||||
$slots.$slot_name.store(Some($value));
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::buffer::PyBuffer;
|
||||
use crate::builtins::pystr::PyStrRef;
|
||||
use crate::builtins::{PyStrRef, PyTypeRef};
|
||||
use crate::common::hash::PyHash;
|
||||
use crate::common::lock::PyRwLock;
|
||||
use crate::function::{FuncArgs, OptionalArg, PyNativeFunc};
|
||||
use crate::function::{FromArgs, FuncArgs, OptionalArg};
|
||||
use crate::utils::Either;
|
||||
use crate::VirtualMachine;
|
||||
use crate::{
|
||||
@@ -45,6 +45,7 @@ impl Default for PyTpFlags {
|
||||
}
|
||||
|
||||
pub(crate) type GenericMethod = fn(&PyObjectRef, FuncArgs, &VirtualMachine) -> PyResult;
|
||||
pub(crate) type NewFunc = fn(PyTypeRef, FuncArgs, &VirtualMachine) -> PyResult;
|
||||
pub(crate) type DelFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult<()>;
|
||||
pub(crate) type DescrGetFunc =
|
||||
fn(PyObjectRef, Option<PyObjectRef>, Option<PyObjectRef>, &VirtualMachine) -> PyResult;
|
||||
@@ -108,7 +109,7 @@ pub struct PyTypeSlots {
|
||||
// tp_dictoffset
|
||||
// tp_init
|
||||
// tp_alloc
|
||||
pub new: Option<PyNativeFunc>,
|
||||
pub new: AtomicCell<Option<NewFunc>>,
|
||||
// tp_free
|
||||
// tp_is_gc
|
||||
// tp_bases
|
||||
@@ -134,6 +135,19 @@ impl std::fmt::Debug for PyTypeSlots {
|
||||
}
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait SlotConstructor: PyValue {
|
||||
type Args: FromArgs;
|
||||
|
||||
#[pyslot]
|
||||
fn tp_new(cls: PyTypeRef, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let args: Self::Args = args.bind(vm)?;
|
||||
Self::py_new(cls, args, vm)
|
||||
}
|
||||
|
||||
fn py_new(cls: PyTypeRef, args: Self::Args, vm: &VirtualMachine) -> PyResult;
|
||||
}
|
||||
|
||||
#[pyimpl]
|
||||
pub trait SlotDestructor: PyValue {
|
||||
#[pyslot]
|
||||
|
||||
Reference in New Issue
Block a user