mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
ReprGuard to recursion
This commit is contained in:
1 parent
f959ab9159
commit
0294473704
13 files changed
+64
-55
No files matched your search
@@ -16,11 +16,12 @@ use crate::{
|
||||
},
|
||||
protocol::{PyIterIter, PyIterReturn, PyMappingMethods, PySequenceMethods},
|
||||
pyclass::{PyClassDef, PyClassImpl},
|
||||
recursion::ReprGuard,
|
||||
types::{
|
||||
AsMapping, AsSequence, Callable, Comparable, Constructor, Hashable, IterNext,
|
||||
IterNextIterable, Iterable, PyComparisonOp, Unconstructible, Unhashable,
|
||||
},
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
vm::VirtualMachine,
|
||||
AsObject, Py, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
};
|
||||
use rustpython_common::lock::PyMutex;
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::{
|
||||
function::{FuncArgs, OptionalArg, PyComparisonValue},
|
||||
protocol::{PyIterReturn, PyMappingMethods, PySequence, PySequenceMethods},
|
||||
pyclass::PyClassImpl,
|
||||
recursion::ReprGuard,
|
||||
sequence::{MutObjectSequenceOp, ObjectSequenceOp, SequenceMutOp, SequenceOp},
|
||||
sliceable::{saturate_index, SequenceIndex, SliceableSequenceMutOp, SliceableSequenceOp},
|
||||
types::{
|
||||
@@ -15,7 +16,7 @@ use crate::{
|
||||
Iterable, PyComparisonOp, Unconstructible, Unhashable,
|
||||
},
|
||||
utils::collection_repr,
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
vm::VirtualMachine,
|
||||
AsObject, Py, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
|
||||
};
|
||||
use std::{borrow::Cow, fmt, ops::DerefMut};
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::{
|
||||
builtins::PyDict,
|
||||
function::{FuncArgs, PyComparisonValue},
|
||||
pyclass::PyClassImpl,
|
||||
recursion::ReprGuard,
|
||||
types::{Comparable, Constructor, PyComparisonOp},
|
||||
vm::ReprGuard,
|
||||
AsObject, PyContext, PyObject, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
|
||||
|
||||
@@ -11,12 +11,13 @@ use crate::{
|
||||
function::{ArgIterable, FuncArgs, OptionalArg, PosArgs, PyArithmeticValue, PyComparisonValue},
|
||||
protocol::{PyIterReturn, PySequenceMethods},
|
||||
pyclass::PyClassImpl,
|
||||
recursion::ReprGuard,
|
||||
types::{
|
||||
AsSequence, Comparable, Constructor, Hashable, IterNext, IterNextIterable, Iterable,
|
||||
PyComparisonOp, Unconstructible, Unhashable,
|
||||
},
|
||||
utils::collection_repr,
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
vm::VirtualMachine,
|
||||
AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::{
|
||||
function::{OptionalArg, PyArithmeticValue, PyComparisonValue},
|
||||
protocol::{PyIterReturn, PyMappingMethods, PySequenceMethods},
|
||||
pyclass::PyClassImpl,
|
||||
recursion::ReprGuard,
|
||||
sequence::{ObjectSequenceOp, SequenceOp},
|
||||
sliceable::{SequenceIndex, SliceableSequenceOp},
|
||||
stdlib::sys,
|
||||
@@ -13,7 +14,7 @@ use crate::{
|
||||
Iterable, PyComparisonOp, Unconstructible,
|
||||
},
|
||||
utils::collection_repr,
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
vm::VirtualMachine,
|
||||
AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
};
|
||||
use std::{borrow::Cow, fmt, marker::PhantomData};
|
||||
|
||||
@@ -67,6 +67,7 @@ pub mod py_io;
|
||||
pub mod py_serde;
|
||||
pub mod pyclass;
|
||||
pub mod readline;
|
||||
pub mod recursion;
|
||||
pub mod scope;
|
||||
pub mod sequence;
|
||||
pub mod signal;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
use crate::{AsObject, PyObject, VirtualMachine};
|
||||
|
||||
pub struct ReprGuard<'vm> {
|
||||
vm: &'vm VirtualMachine,
|
||||
id: usize,
|
||||
}
|
||||
|
||||
/// A guard to protect repr methods from recursion into itself,
|
||||
impl<'vm> ReprGuard<'vm> {
|
||||
/// Returns None if the guard against 'obj' is still held otherwise returns the guard. The guard
|
||||
/// which is released if dropped.
|
||||
pub fn enter(vm: &'vm VirtualMachine, obj: &PyObject) -> Option<Self> {
|
||||
let mut guards = vm.repr_guards.borrow_mut();
|
||||
|
||||
// Should this be a flag on the obj itself? putting it in a global variable for now until it
|
||||
// decided the form of PyObject. https://github.com/RustPython/RustPython/issues/371
|
||||
let id = obj.get_id();
|
||||
if guards.contains(&id) {
|
||||
return None;
|
||||
}
|
||||
guards.insert(id);
|
||||
Some(ReprGuard { vm, id })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'vm> Drop for ReprGuard<'vm> {
|
||||
fn drop(&mut self) {
|
||||
self.vm.repr_guards.borrow_mut().remove(&self.id);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ mod _collections {
|
||||
common::lock::{PyMutex, PyRwLock, PyRwLockReadGuard, PyRwLockWriteGuard},
|
||||
function::{FuncArgs, KwArgs, OptionalArg, PyComparisonValue},
|
||||
protocol::{PyIterReturn, PySequenceMethods},
|
||||
recursion::ReprGuard,
|
||||
sequence::{MutObjectSequenceOp, ObjectSequenceOp},
|
||||
sliceable,
|
||||
sliceable::saturate_index,
|
||||
@@ -18,7 +19,6 @@ mod _collections {
|
||||
PyComparisonOp, Unhashable,
|
||||
},
|
||||
utils::collection_repr,
|
||||
vm::ReprGuard,
|
||||
AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
+2
-1
@@ -111,9 +111,10 @@ mod _io {
|
||||
BufferDescriptor, BufferMethods, BufferResizeGuard, PyBuffer, PyIterReturn, VecBuffer,
|
||||
},
|
||||
pyclass::StaticType,
|
||||
recursion::ReprGuard,
|
||||
types::{Constructor, Destructor, IterNext, Iterable},
|
||||
utils::Either,
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
vm::VirtualMachine,
|
||||
AsObject, PyContext, PyObject, PyObjectRef, PyPayload, PyRef, PyResult,
|
||||
TryFromBorrowedObject, TryFromObject,
|
||||
};
|
||||
|
||||
@@ -14,12 +14,12 @@ mod _operator {
|
||||
builtins::{PyInt, PyIntRef, PyStrRef, PyTupleRef, PyTypeRef},
|
||||
function::{ArgBytesLike, FuncArgs, KwArgs, OptionalArg},
|
||||
protocol::PyIter,
|
||||
recursion::ReprGuard,
|
||||
types::{
|
||||
Callable, Constructor,
|
||||
PyComparisonOp::{Eq, Ge, Gt, Le, Lt, Ne},
|
||||
},
|
||||
utils::Either,
|
||||
vm::ReprGuard,
|
||||
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
};
|
||||
|
||||
|
||||
+2
-1
@@ -412,10 +412,11 @@ pub(super) mod _os {
|
||||
crt_fd::{Fd, Offset},
|
||||
function::{ArgBytesLike, FuncArgs, OptionalArg},
|
||||
protocol::PyIterReturn,
|
||||
recursion::ReprGuard,
|
||||
suppress_iph,
|
||||
types::{IterNext, IterNextIterable, PyStructSequence},
|
||||
utils::Either,
|
||||
vm::{ReprGuard, VirtualMachine},
|
||||
vm::VirtualMachine,
|
||||
AsObject, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject,
|
||||
};
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
|
||||
+18
-17
@@ -46,24 +46,25 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
|
||||
let s = value.repr(vm)?;
|
||||
Ok(format!("{}={}", name, s))
|
||||
};
|
||||
let (body, suffix) =
|
||||
if let Some(_guard) = rustpython_vm::vm::ReprGuard::enter(vm, zelf.as_object()) {
|
||||
if Self::FIELD_NAMES.len() == 1 {
|
||||
let value = zelf.as_slice().first().unwrap();
|
||||
let formatted = format_field((value, Self::FIELD_NAMES[0]))?;
|
||||
(formatted, ",")
|
||||
} else {
|
||||
let fields: PyResult<Vec<_>> = zelf
|
||||
.as_slice()
|
||||
.iter()
|
||||
.zip(Self::FIELD_NAMES.iter().copied())
|
||||
.map(format_field)
|
||||
.collect();
|
||||
(fields?.join(", "), "")
|
||||
}
|
||||
let (body, suffix) = if let Some(_guard) =
|
||||
rustpython_vm::recursion::ReprGuard::enter(vm, zelf.as_object())
|
||||
{
|
||||
if Self::FIELD_NAMES.len() == 1 {
|
||||
let value = zelf.as_slice().first().unwrap();
|
||||
let formatted = format_field((value, Self::FIELD_NAMES[0]))?;
|
||||
(formatted, ",")
|
||||
} else {
|
||||
(String::new(), "...")
|
||||
};
|
||||
let fields: PyResult<Vec<_>> = zelf
|
||||
.as_slice()
|
||||
.iter()
|
||||
.zip(Self::FIELD_NAMES.iter().copied())
|
||||
.map(format_field)
|
||||
.collect();
|
||||
(fields?.join(", "), "")
|
||||
}
|
||||
} else {
|
||||
(String::new(), "...")
|
||||
};
|
||||
Ok(format!("{}({}{})", Self::TP_NAME, body, suffix))
|
||||
}
|
||||
|
||||
|
||||
@@ -750,32 +750,3 @@ impl VirtualMachine {
|
||||
.map(|code| PyCode::new(self.map_codeobj(code)).into_ref(self))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReprGuard<'vm> {
|
||||
vm: &'vm VirtualMachine,
|
||||
id: usize,
|
||||
}
|
||||
|
||||
/// A guard to protect repr methods from recursion into itself,
|
||||
impl<'vm> ReprGuard<'vm> {
|
||||
/// Returns None if the guard against 'obj' is still held otherwise returns the guard. The guard
|
||||
/// which is released if dropped.
|
||||
pub fn enter(vm: &'vm VirtualMachine, obj: &PyObject) -> Option<Self> {
|
||||
let mut guards = vm.repr_guards.borrow_mut();
|
||||
|
||||
// Should this be a flag on the obj itself? putting it in a global variable for now until it
|
||||
// decided the form of PyObject. https://github.com/RustPython/RustPython/issues/371
|
||||
let id = obj.get_id();
|
||||
if guards.contains(&id) {
|
||||
return None;
|
||||
}
|
||||
guards.insert(id);
|
||||
Some(ReprGuard { vm, id })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'vm> Drop for ReprGuard<'vm> {
|
||||
fn drop(&mut self) {
|
||||
self.vm.repr_guards.borrow_mut().remove(&self.id);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user