trait SlotConstructor for tp_new blueprint

This commit is contained in:
Jeong YunWon
2021-08-28 17:43:59 +09:00
parent 7dc55d5663
commit 407cc7aae2
5 changed files with 75 additions and 54 deletions

View File

@@ -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);

View File

@@ -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)]

View File

@@ -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")

View File

@@ -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));
};

View File

@@ -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]