diff --git a/Cargo.lock b/Cargo.lock index d67bbb849a..ba657ddbe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,6 +537,17 @@ dependencies = [ "syn", ] +[[package]] +name = "derive_more" +version = "0.99.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dcfabdab475c16a93d669dddfc393027803e347d09663f524447f642fbb84ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "diff" version = "0.1.12" @@ -1621,6 +1632,7 @@ name = "rustpython-common" version = "0.0.0" dependencies = [ "cfg-if", + "derive_more", "hexf-parse", "lexical-core", "num-bigint", diff --git a/common/Cargo.toml b/common/Cargo.toml index e0573e365b..54d47cf6b5 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -18,3 +18,4 @@ cfg-if = "0.1" once_cell = "1.4.1" siphasher = "0.3" rand = "0.7.3" +derive_more = "0.99.9" diff --git a/common/src/borrow.rs b/common/src/borrow.rs new file mode 100644 index 0000000000..07bff49a98 --- /dev/null +++ b/common/src/borrow.rs @@ -0,0 +1,66 @@ +use crate::cell::{ + PyMappedMutexGuard, PyMappedRwLockReadGuard, PyMappedRwLockWriteGuard, PyMutexGuard, + PyRwLockReadGuard, PyRwLockWriteGuard, +}; +use std::ops::{Deref, DerefMut}; + +pub trait BorrowValue<'a> { + type Borrowed: 'a + Deref; + fn borrow_value(&'a self) -> Self::Borrowed; +} + +#[derive(Debug, derive_more::From)] +pub enum BorrowedValue<'a, T: ?Sized> { + Ref(&'a T), + MuLock(PyMutexGuard<'a, T>), + MappedMuLock(PyMappedMutexGuard<'a, T>), + ReadLock(PyRwLockReadGuard<'a, T>), + MappedReadLock(PyMappedRwLockReadGuard<'a, T>), +} + +impl Deref for BorrowedValue<'_, T> { + type Target = T; + fn deref(&self) -> &T { + match self { + Self::Ref(r) => r, + Self::MuLock(m) => &m, + Self::MappedMuLock(m) => &m, + Self::ReadLock(r) => &r, + Self::MappedReadLock(m) => &m, + } + } +} + +#[derive(Debug, derive_more::From)] +pub enum BorrowedValueMut<'a, T: ?Sized> { + RefMut(&'a mut T), + MuLock(PyMutexGuard<'a, T>), + MappedMuLock(PyMappedMutexGuard<'a, T>), + WriteLock(PyRwLockWriteGuard<'a, T>), + MappedWriteLock(PyMappedRwLockWriteGuard<'a, T>), +} + +impl Deref for BorrowedValueMut<'_, T> { + type Target = T; + fn deref(&self) -> &T { + match self { + Self::RefMut(r) => r, + Self::MuLock(m) => &m, + Self::MappedMuLock(m) => &m, + Self::WriteLock(w) => &w, + Self::MappedWriteLock(w) => &w, + } + } +} + +impl DerefMut for BorrowedValueMut<'_, T> { + fn deref_mut(&mut self) -> &mut T { + match self { + Self::RefMut(r) => r, + Self::MuLock(m) => &mut *m, + Self::MappedMuLock(m) => &mut *m, + Self::WriteLock(w) => &mut *w, + Self::MappedWriteLock(w) => &mut *w, + } + } +} diff --git a/common/src/cell.rs b/common/src/cell.rs index d8c0339ee5..5277cf8a05 100644 --- a/common/src/cell.rs +++ b/common/src/cell.rs @@ -4,8 +4,8 @@ pub use once_cell::sync::{Lazy, OnceCell}; pub use once_cell::unsync::{Lazy, OnceCell}; #[cfg(feature = "threading")] use parking_lot::{ - MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, MutexGuard, RwLock, RwLockReadGuard, - RwLockWriteGuard, + MappedMutexGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard, Mutex, MutexGuard, RwLock, + RwLockReadGuard, RwLockWriteGuard, }; #[cfg(not(feature = "threading"))] use std::cell::{Ref, RefCell, RefMut}; @@ -15,6 +15,7 @@ cfg_if::cfg_if! { if #[cfg(feature = "threading")] { type MutexInner = Mutex; type MutexGuardInner<'a, T> = MutexGuard<'a, T>; + type MappedMutexGuardInner<'a, T> = MappedMutexGuard<'a, T>; const fn new_mutex(value: T) -> MutexInner { parking_lot::const_mutex(value) } @@ -24,6 +25,7 @@ cfg_if::cfg_if! { } else { type MutexInner = RefCell; type MutexGuardInner<'a, T> = RefMut<'a, T>; + type MappedMutexGuardInner<'a, T> = RefMut<'a, T>; const fn new_mutex(value: T) -> MutexInner { RefCell::new(value) } @@ -63,6 +65,39 @@ impl DerefMut for PyMutexGuard<'_, T> { self.0.deref_mut() } } +impl<'a, T: ?Sized> PyMutexGuard<'a, T> { + #[inline] + pub fn map(s: Self, f: F) -> PyMappedMutexGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + { + PyMappedMutexGuard(MutexGuardInner::map(s.0, f)) + } +} + +#[derive(Debug)] +#[repr(transparent)] +pub struct PyMappedMutexGuard<'a, T: ?Sized>(MappedMutexGuardInner<'a, T>); +impl Deref for PyMappedMutexGuard<'_, T> { + type Target = T; + fn deref(&self) -> &T { + self.0.deref() + } +} +impl DerefMut for PyMappedMutexGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + self.0.deref_mut() + } +} +impl<'a, T: ?Sized> PyMappedMutexGuard<'a, T> { + #[inline] + pub fn map(s: Self, f: F) -> PyMappedMutexGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + { + PyMappedMutexGuard(MappedMutexGuardInner::map(s.0, f)) + } +} cfg_if::cfg_if! { if #[cfg(feature = "threading")] { @@ -127,6 +162,7 @@ impl Deref for PyRwLockReadGuard<'_, T> { } } +#[derive(Debug)] #[repr(transparent)] pub struct PyMappedRwLockReadGuard<'a, T: ?Sized>(MappedRwLockReadInner<'a, T>); impl Deref for PyMappedRwLockReadGuard<'_, T> { @@ -145,6 +181,15 @@ impl<'a, T: ?Sized> PyRwLockReadGuard<'a, T> { PyMappedRwLockReadGuard(RwLockReadInner::map(s.0, f)) } } +impl<'a, T: ?Sized> PyMappedRwLockReadGuard<'a, T> { + #[inline] + pub fn map(s: Self, f: F) -> PyMappedRwLockReadGuard<'a, U> + where + F: FnOnce(&T) -> &U, + { + PyMappedRwLockReadGuard(MappedRwLockReadInner::map(s.0, f)) + } +} #[derive(Debug)] #[repr(transparent)] @@ -161,6 +206,7 @@ impl DerefMut for PyRwLockWriteGuard<'_, T> { } } +#[derive(Debug)] #[repr(transparent)] pub struct PyMappedRwLockWriteGuard<'a, T: ?Sized>(MappedRwLockWriteInner<'a, T>); impl Deref for PyMappedRwLockWriteGuard<'_, T> { @@ -184,3 +230,12 @@ impl<'a, T: ?Sized> PyRwLockWriteGuard<'a, T> { PyMappedRwLockWriteGuard(RwLockWriteInner::map(s.0, f)) } } +impl<'a, T: ?Sized> PyMappedRwLockWriteGuard<'a, T> { + #[inline] + pub fn map(s: Self, f: F) -> PyMappedRwLockWriteGuard<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + { + PyMappedRwLockWriteGuard(MappedRwLockWriteInner::map(s.0, f)) + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 7519f9d94a..f13b39371d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,5 +1,6 @@ //! A crate to hold types and functions common to all rustpython components. +pub mod borrow; pub mod cell; pub mod float_ops; pub mod hash; diff --git a/vm/src/byteslike.rs b/vm/src/byteslike.rs index 764a1c8501..ed887b04bd 100644 --- a/vm/src/byteslike.rs +++ b/vm/src/byteslike.rs @@ -1,3 +1,5 @@ +use crate::common::borrow::{BorrowedValue, BorrowedValueMut}; +use crate::common::cell::{PyRwLockReadGuard, PyRwLockWriteGuard}; use crate::obj::objbytearray::{PyByteArray, PyByteArrayRef}; use crate::obj::objbytes::{PyBytes, PyBytesRef}; use crate::pyobject::PyObjectRef; @@ -26,6 +28,19 @@ impl TryFromObject for PyBytesLike { } } +impl<'a> BorrowValue<'a> for PyBytesLike { + type Borrowed = BorrowedValue<'a, [u8]>; + fn borrow_value(&'a self) -> Self::Borrowed { + match self { + Self::Bytes(b) => b.borrow_value().into(), + Self::Bytearray(b) => { + PyRwLockReadGuard::map(b.borrow_value(), |b| b.elements.as_slice()).into() + } + Self::Array(a) => a.get_bytes().into(), + } + } +} + impl PyBytesLike { pub fn len(&self) -> usize { match self { @@ -73,6 +88,18 @@ impl TryFromObject for PyRwBytesLike { } } +impl<'a> BorrowValue<'a> for PyRwBytesLike { + type Borrowed = BorrowedValueMut<'a, [u8]>; + fn borrow_value(&'a self) -> Self::Borrowed { + match self { + Self::Bytearray(b) => { + PyRwLockWriteGuard::map(b.borrow_value_mut(), |b| b.elements.as_mut_slice()).into() + } + Self::Array(a) => a.get_bytes_mut().into(), + } + } +} + impl PyRwBytesLike { pub fn len(&self) -> usize { match self { diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index a304f0627e..36242242d6 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -43,6 +43,8 @@ use crate::vm::VirtualMachine; use rustpython_common::cell::{PyRwLock, PyRwLockReadGuard}; use rustpython_common::rc::PyRc; +pub use crate::common::borrow::BorrowValue; + /* Python objects and references. Okay, so each python object itself is an class itself (PyObject). Each @@ -1175,11 +1177,6 @@ pub trait PyValue: fmt::Debug + PyThreadingConstraint + Sized + 'static { } } -pub trait BorrowValue<'a>: PyValue { - type Borrowed: 'a + Deref; - fn borrow_value(&'a self) -> Self::Borrowed; -} - pub trait PyObjectPayload: Any + fmt::Debug + PyThreadingConstraint + 'static { fn as_any(&self) -> &dyn Any; }