mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-29 03:04:38 +08:00
Fully integrate PyTupleTyped into PyTuple
This commit is contained in:
1 parent
14ce76e6c8
commit
6342ad4fa7
5 files changed
+92
-151
No files matched your search
@@ -2,8 +2,8 @@
|
||||
mod jit;
|
||||
|
||||
use super::{
|
||||
PyAsyncGen, PyCode, PyCoroutine, PyDictRef, PyGenerator, PyStr, PyStrRef, PyTupleRef, PyType,
|
||||
PyTypeRef, tuple::PyTupleTyped,
|
||||
PyAsyncGen, PyCode, PyCoroutine, PyDictRef, PyGenerator, PyStr, PyStrRef, PyTuple, PyTupleRef,
|
||||
PyType, PyTypeRef,
|
||||
};
|
||||
#[cfg(feature = "jit")]
|
||||
use crate::common::lock::OnceCell;
|
||||
@@ -31,7 +31,7 @@ pub struct PyFunction {
|
||||
code: PyRef<PyCode>,
|
||||
globals: PyDictRef,
|
||||
builtins: PyObjectRef,
|
||||
closure: Option<PyRef<PyTupleTyped<PyCellRef>>>,
|
||||
closure: Option<PyRef<PyTuple<PyCellRef>>>,
|
||||
defaults_and_kwdefaults: PyMutex<(Option<PyTupleRef>, Option<PyDictRef>)>,
|
||||
name: PyMutex<PyStrRef>,
|
||||
qualname: PyMutex<PyStrRef>,
|
||||
@@ -59,7 +59,7 @@ impl PyFunction {
|
||||
pub(crate) fn new(
|
||||
code: PyRef<PyCode>,
|
||||
globals: PyDictRef,
|
||||
closure: Option<PyRef<PyTupleTyped<PyCellRef>>>,
|
||||
closure: Option<PyRef<PyTuple<PyCellRef>>>,
|
||||
defaults: Option<PyTupleRef>,
|
||||
kw_only_defaults: Option<PyDictRef>,
|
||||
qualname: PyStrRef,
|
||||
|
||||
+79
-134
@@ -3,7 +3,6 @@ use crate::common::{
|
||||
hash::{PyHash, PyUHash},
|
||||
lock::PyMutex,
|
||||
};
|
||||
use crate::object::{MaybeTraverse, Traverse, TraverseFn};
|
||||
use crate::{
|
||||
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
atomic_func,
|
||||
@@ -22,14 +21,14 @@ use crate::{
|
||||
utils::collection_repr,
|
||||
vm::VirtualMachine,
|
||||
};
|
||||
use std::{fmt, marker::PhantomData, sync::LazyLock};
|
||||
use std::{fmt, sync::LazyLock};
|
||||
|
||||
#[pyclass(module = false, name = "tuple", traverse)]
|
||||
pub struct PyTuple {
|
||||
elements: Box<[PyObjectRef]>,
|
||||
pub struct PyTuple<R = PyObjectRef> {
|
||||
elements: Box<[R]>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for PyTuple {
|
||||
impl<R> fmt::Debug for PyTuple<R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// TODO: implement more informational, non-recursive Debug formatter
|
||||
f.write_str("tuple")
|
||||
@@ -140,39 +139,60 @@ impl Constructor for PyTuple {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[PyObjectRef]> for PyTuple {
|
||||
fn as_ref(&self) -> &[PyObjectRef] {
|
||||
self.as_slice()
|
||||
impl<R> AsRef<[R]> for PyTuple<R> {
|
||||
fn as_ref(&self) -> &[R] {
|
||||
&self.elements
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for PyTuple {
|
||||
type Target = [PyObjectRef];
|
||||
impl<R> std::ops::Deref for PyTuple<R> {
|
||||
type Target = [R];
|
||||
|
||||
fn deref(&self) -> &[PyObjectRef] {
|
||||
self.as_slice()
|
||||
fn deref(&self) -> &[R] {
|
||||
&self.elements
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::iter::IntoIterator for &'a PyTuple {
|
||||
type Item = &'a PyObjectRef;
|
||||
type IntoIter = std::slice::Iter<'a, PyObjectRef>;
|
||||
impl<'a, R> std::iter::IntoIterator for &'a PyTuple<R> {
|
||||
type Item = &'a R;
|
||||
type IntoIter = std::slice::Iter<'a, R>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::iter::IntoIterator for &'a Py<PyTuple> {
|
||||
type Item = &'a PyObjectRef;
|
||||
type IntoIter = std::slice::Iter<'a, PyObjectRef>;
|
||||
impl<'a, R> std::iter::IntoIterator for &'a Py<PyTuple<R>> {
|
||||
type Item = &'a R;
|
||||
type IntoIter = std::slice::Iter<'a, R>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl PyTuple {
|
||||
impl<R> PyTuple<R> {
|
||||
pub const fn as_slice(&self) -> &[R] {
|
||||
&self.elements
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.elements.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.elements.is_empty()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn iter(&self) -> std::slice::Iter<'_, R> {
|
||||
self.elements.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl PyTuple<PyObjectRef> {
|
||||
pub fn new_ref(elements: Vec<PyObjectRef>, ctx: &Context) -> PyRef<Self> {
|
||||
if elements.is_empty() {
|
||||
ctx.empty_tuple.clone()
|
||||
@@ -189,10 +209,6 @@ impl PyTuple {
|
||||
Self { elements }
|
||||
}
|
||||
|
||||
pub const fn as_slice(&self) -> &[PyObjectRef] {
|
||||
&self.elements
|
||||
}
|
||||
|
||||
fn repeat(zelf: PyRef<Self>, value: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
Ok(if zelf.elements.is_empty() || value == 0 {
|
||||
vm.ctx.empty_tuple.clone()
|
||||
@@ -214,6 +230,18 @@ impl PyTuple {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyTuple<PyRef<T>> {
|
||||
pub fn new_ref_typed(elements: Vec<PyRef<T>>, ctx: &Context) -> PyRef<PyTuple<PyRef<T>>> {
|
||||
// SAFETY: PyRef<T> has the same layout as PyObjectRef
|
||||
unsafe {
|
||||
let elements: Vec<PyObjectRef> =
|
||||
std::mem::transmute::<Vec<PyRef<T>>, Vec<PyObjectRef>>(elements);
|
||||
let tuple = PyTuple::<PyObjectRef>::new_ref(elements, ctx);
|
||||
std::mem::transmute::<PyRef<PyTuple>, PyRef<PyTuple<PyRef<T>>>>(tuple)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(
|
||||
flags(BASETYPE),
|
||||
with(
|
||||
@@ -272,11 +300,6 @@ impl PyTuple {
|
||||
self.elements.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.elements.is_empty()
|
||||
}
|
||||
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod]
|
||||
fn __mul__(zelf: PyRef<Self>, value: ArgSize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
@@ -449,21 +472,38 @@ impl Representable for PyTuple {
|
||||
}
|
||||
}
|
||||
|
||||
impl PyRef<PyTuple> {
|
||||
impl PyRef<PyTuple<PyObjectRef>> {
|
||||
pub fn try_into_typed<T: PyPayload>(
|
||||
self,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyRef<PyTupleTyped<PyRef<T>>>> {
|
||||
PyRef::<PyTupleTyped<PyRef<T>>>::try_from_untyped(self, vm)
|
||||
) -> PyResult<PyRef<PyTuple<PyRef<T>>>> {
|
||||
// Check that all elements are of the correct type
|
||||
for elem in self.as_slice() {
|
||||
<PyRef<T> as TransmuteFromObject>::check(vm, elem)?;
|
||||
}
|
||||
// SAFETY: We just verified all elements are of type T
|
||||
Ok(unsafe { std::mem::transmute::<PyRef<PyTuple>, PyRef<PyTuple<PyRef<T>>>>(self) })
|
||||
}
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that all elements in the tuple are valid instances
|
||||
/// of type `T` before calling this method. This is typically verified by
|
||||
/// calling `try_into_typed` first.
|
||||
unsafe fn into_typed_unchecked<T: PyPayload>(self) -> PyRef<PyTupleTyped<PyRef<T>>> {
|
||||
let obj: PyObjectRef = self.into();
|
||||
unsafe { obj.downcast_unchecked::<PyTupleTyped<PyRef<T>>>() }
|
||||
}
|
||||
|
||||
impl<T: PyPayload> PyRef<PyTuple<PyRef<T>>> {
|
||||
pub fn into_untyped(self) -> PyRef<PyTuple> {
|
||||
// SAFETY: PyTuple<PyRef<T>> has the same layout as PyTuple
|
||||
unsafe { std::mem::transmute::<PyRef<PyTuple<PyRef<T>>>, PyRef<PyTuple>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> Py<PyTuple<PyRef<T>>> {
|
||||
pub fn as_untyped(&self) -> &Py<PyTuple> {
|
||||
// SAFETY: PyTuple<PyRef<T>> has the same layout as PyTuple
|
||||
unsafe { std::mem::transmute::<&Py<PyTuple<PyRef<T>>>, &Py<PyTuple>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> From<PyRef<PyTuple<PyRef<T>>>> for PyTupleRef {
|
||||
#[inline]
|
||||
fn from(tup: PyRef<PyTuple<PyRef<T>>>) -> Self {
|
||||
tup.into_untyped()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,101 +558,6 @@ pub(crate) fn init(context: &Context) {
|
||||
PyTupleIterator::extend_class(context, context.types.tuple_iterator_type);
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct PyTupleTyped<R> {
|
||||
// SAFETY INVARIANT: T must be repr(transparent) over PyObjectRef, and the
|
||||
// elements must be logically valid when transmuted to T
|
||||
tuple: PyTuple,
|
||||
_marker: PhantomData<R>,
|
||||
}
|
||||
|
||||
unsafe impl<R> Traverse for PyTupleTyped<R>
|
||||
where
|
||||
R: TransmuteFromObject,
|
||||
{
|
||||
fn traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
|
||||
self.tuple.traverse(tracer_fn);
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: TransmuteFromObject + Traverse> MaybeTraverse for PyTupleTyped<R> {
|
||||
const IS_TRACE: bool = true;
|
||||
fn try_traverse(&self, tracer_fn: &mut TraverseFn<'_>) {
|
||||
self.traverse(tracer_fn);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> PyTupleTyped<PyRef<T>> {
|
||||
pub fn new_ref(elements: Vec<PyRef<T>>, ctx: &Context) -> PyRef<Self> {
|
||||
// SAFETY: PyRef<T> has the same layout as PyObjectRef
|
||||
unsafe {
|
||||
let elements: Vec<PyObjectRef> =
|
||||
std::mem::transmute::<Vec<PyRef<T>>, Vec<PyObjectRef>>(elements);
|
||||
let tuple = PyTuple::new_ref(elements, ctx);
|
||||
tuple.into_typed_unchecked::<T>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> PyRef<PyTupleTyped<PyRef<T>>> {
|
||||
pub fn into_untyped(self) -> PyRef<PyTuple> {
|
||||
// SAFETY: PyTupleTyped is transparent over PyTuple
|
||||
unsafe { std::mem::transmute::<PyRef<PyTupleTyped<PyRef<T>>>, PyRef<PyTuple>>(self) }
|
||||
}
|
||||
|
||||
pub fn try_from_untyped(tuple: PyTupleRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
// Check that all elements are of the correct type
|
||||
for elem in tuple.as_slice() {
|
||||
<PyRef<T> as TransmuteFromObject>::check(vm, elem)?;
|
||||
}
|
||||
// SAFETY: We just verified all elements are of type T, and PyTupleTyped has the same layout as PyTuple
|
||||
Ok(unsafe { std::mem::transmute::<PyRef<PyTuple>, PyRef<PyTupleTyped<PyRef<T>>>>(tuple) })
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> Py<PyTupleTyped<PyRef<T>>> {
|
||||
pub fn as_untyped(&self) -> &Py<PyTuple> {
|
||||
// SAFETY: PyTupleTyped is transparent over PyTuple
|
||||
unsafe { std::mem::transmute::<&Py<PyTupleTyped<PyRef<T>>>, &Py<PyTuple>>(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> AsRef<[PyRef<T>]> for PyTupleTyped<PyRef<T>> {
|
||||
fn as_ref(&self) -> &[PyRef<T>] {
|
||||
self.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> PyTupleTyped<PyRef<T>> {
|
||||
#[inline]
|
||||
pub fn as_slice(&self) -> &[PyRef<T>] {
|
||||
unsafe { &*(self.tuple.as_slice() as *const [PyObjectRef] as *const [PyRef<T>]) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.tuple.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.tuple.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: fmt::Debug> fmt::Debug for PyTupleTyped<R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.tuple.as_slice().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyPayload> From<PyRef<PyTupleTyped<PyRef<T>>>> for PyTupleRef {
|
||||
#[inline]
|
||||
fn from(tup: PyRef<PyTupleTyped<PyRef<T>>>) -> Self {
|
||||
tup.into_untyped()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn tuple_hash(elements: &[PyObjectRef], vm: &VirtualMachine) -> PyResult<PyHash> {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const PRIME1: PyUHash = 11400714785074694791;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::{
|
||||
PyClassMethod, PyDictRef, PyList, PyStr, PyStrInterned, PyStrRef, PyTuple, PyTupleRef, PyWeak,
|
||||
PyClassMethod, PyDictRef, PyList, PyStr, PyStrInterned, PyStrRef, PyTupleRef, PyWeak,
|
||||
mappingproxy::PyMappingProxy, object, union_,
|
||||
};
|
||||
use crate::{
|
||||
@@ -12,7 +12,7 @@ use crate::{
|
||||
PyMemberDescriptor,
|
||||
},
|
||||
function::PyCellRef,
|
||||
tuple::{IntoPyTuple, PyTupleTyped},
|
||||
tuple::{IntoPyTuple, PyTuple},
|
||||
},
|
||||
class::{PyClassImpl, StaticType},
|
||||
common::{
|
||||
@@ -62,7 +62,7 @@ unsafe impl crate::object::Traverse for PyType {
|
||||
pub struct HeapTypeExt {
|
||||
pub name: PyRwLock<PyStrRef>,
|
||||
pub qualname: PyRwLock<PyStrRef>,
|
||||
pub slots: Option<PyRef<PyTupleTyped<PyStrRef>>>,
|
||||
pub slots: Option<PyRef<PyTuple<PyStrRef>>>,
|
||||
pub sequence_methods: PySequenceMethods,
|
||||
pub mapping_methods: PyMappingMethods,
|
||||
}
|
||||
@@ -1041,11 +1041,11 @@ impl Constructor for PyType {
|
||||
// TODO: Flags is currently initialized with HAS_DICT. Should be
|
||||
// updated when __slots__ are supported (toggling the flag off if
|
||||
// a class has __slots__ defined).
|
||||
let heaptype_slots: Option<PyRef<PyTupleTyped<PyStrRef>>> =
|
||||
let heaptype_slots: Option<PyRef<PyTuple<PyStrRef>>> =
|
||||
if let Some(x) = attributes.get(identifier!(vm, __slots__)) {
|
||||
let slots = if x.class().is(vm.ctx.types.str_type) {
|
||||
let x = unsafe { x.downcast_unchecked_ref::<PyStr>() };
|
||||
PyTupleTyped::new_ref(vec![x.to_owned()], &vm.ctx)
|
||||
PyTuple::new_ref_typed(vec![x.to_owned()], &vm.ctx)
|
||||
} else {
|
||||
let iter = x.get_iter(vm)?;
|
||||
let elements = {
|
||||
|
||||
@@ -11,7 +11,6 @@ use crate::{
|
||||
},
|
||||
getset::PyGetSet,
|
||||
object, pystr,
|
||||
tuple::PyTupleTyped,
|
||||
type_::PyAttributes,
|
||||
},
|
||||
class::{PyClassImpl, StaticType},
|
||||
@@ -375,7 +374,7 @@ impl Context {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn empty_tuple_typed<T>(&self) -> &Py<PyTupleTyped<T>> {
|
||||
pub fn empty_tuple_typed<T>(&self) -> &Py<PyTuple<T>> {
|
||||
let py: &Py<PyTuple> = &self.empty_tuple;
|
||||
unsafe { std::mem::transmute(py) }
|
||||
}
|
||||
|
||||
+3
-6
@@ -20,10 +20,7 @@ use crate::{
|
||||
AsObject, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
|
||||
builtins::{
|
||||
PyBaseExceptionRef, PyDictRef, PyInt, PyList, PyModule, PyStr, PyStrInterned, PyStrRef,
|
||||
PyTypeRef,
|
||||
code::PyCode,
|
||||
pystr::AsPyStr,
|
||||
tuple::{PyTuple, PyTupleTyped},
|
||||
PyTypeRef, code::PyCode, pystr::AsPyStr, tuple::PyTuple,
|
||||
},
|
||||
codecs::CodecsRegistry,
|
||||
common::{hash::HashSecret, lock::PyMutex, rc::PyRc},
|
||||
@@ -609,7 +606,7 @@ impl VirtualMachine {
|
||||
pub fn import_from<'a>(
|
||||
&self,
|
||||
module_name: impl AsPyStr<'a>,
|
||||
from_list: &Py<PyTupleTyped<PyStrRef>>,
|
||||
from_list: &Py<PyTuple<PyStrRef>>,
|
||||
level: usize,
|
||||
) -> PyResult {
|
||||
let module_name = module_name.as_pystr(&self.ctx);
|
||||
@@ -619,7 +616,7 @@ impl VirtualMachine {
|
||||
fn import_inner(
|
||||
&self,
|
||||
module: &Py<PyStr>,
|
||||
from_list: &Py<PyTupleTyped<PyStrRef>>,
|
||||
from_list: &Py<PyTuple<PyStrRef>>,
|
||||
level: usize,
|
||||
) -> PyResult {
|
||||
// if the import inputs seem weird, e.g a package import or something, rather than just
|
||||
|
||||
Reference in new issue
Block a user