Merge pull request #4706 from youknowone/py-type

#[pyclass] impl Py<PyType>
This commit is contained in:
Jeong YunWon authored and GitHub committed 2023-03-19 07:49:50 +09:00
commit 4fba939726
38 files changed
+1374 -1206

No files matched your search

+1
View File
@@ -61,6 +61,7 @@
"rsplitn",
"rustc",
"rustfmt",
"seekfrom",
"splitn",
"subsec",
"timsort",
+114 -24
View File
@@ -105,39 +105,114 @@ pub(crate) fn impl_pyimpl(attr: AttributeArgs, item: Item) -> Result<TokenStream
Item::Impl(mut imp) => {
extract_items_into_context(&mut context, imp.items.iter_mut());
let ty = &imp.self_ty;
let (impl_ty, payload_guess) = match imp.self_ty.as_ref() {
syn::Type::Path(syn::TypePath {
path: syn::Path { segments, .. },
..
}) if segments.len() == 1 => {
let segment = &segments[0];
let payload_ty = if segment.ident == "Py" || segment.ident == "PyRef" {
match &segment.arguments {
syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments { args, .. },
) if args.len() == 1 => {
let arg = &args[0];
match arg {
syn::GenericArgument::Type(syn::Type::Path(
syn::TypePath {
path: syn::Path { segments, .. },
..
},
)) if segments.len() == 1 => segments[0].ident.clone(),
_ => {
return Err(syn::Error::new_spanned(
segment,
"Py{Ref}<T> is expected but Py{Ref}<?> is found",
))
}
}
}
_ => {
return Err(syn::Error::new_spanned(
segment,
"Py{Ref}<T> is expected but Py{Ref}? is found",
))
}
}
} else {
if !matches!(segment.arguments, syn::PathArguments::None) {
return Err(syn::Error::new_spanned(
segment,
"PyImpl can only be implemented for Py{Ref}<T> or T",
));
}
segment.ident.clone()
};
(segment.ident.clone(), payload_ty)
}
_ => {
return Err(syn::Error::new_spanned(
imp.self_ty,
"PyImpl can only be implemented for Py{Ref}<T> or T",
))
}
};
let ExtractedImplAttrs {
payload: attr_payload,
with_impl,
flags,
with_slots,
} = extract_impl_attrs(attr, &Ident::new(&quote!(ty).to_string(), ty.span()))?;
} = extract_impl_attrs(attr, &impl_ty)?;
let payload_ty = attr_payload.unwrap_or(payload_guess);
let getset_impl = &context.getset_items;
let member_impl = &context.member_items;
let extend_impl = context.impl_extend_items.validate()?;
let slots_impl = context.extend_slots_items.validate()?;
let class_extensions = &context.class_extensions;
quote! {
#imp
impl ::rustpython_vm::class::PyClassImpl for #ty {
const TP_FLAGS: ::rustpython_vm::types::PyTypeFlags = #flags;
fn impl_extend_class(
let extra_methods = iter_chain![
parse_quote! {
fn __extend_py_class(
ctx: &::rustpython_vm::Context,
class: &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType>,
) {
#getset_impl
#member_impl
#extend_impl
#with_impl
#(#class_extensions)*
}
fn extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
#with_slots
},
parse_quote! {
fn __extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
#slots_impl
}
},
];
imp.items.extend(extra_methods);
let is_main_impl = impl_ty == payload_ty;
if is_main_impl {
quote! {
#imp
impl ::rustpython_vm::class::PyClassImpl for #payload_ty {
const TP_FLAGS: ::rustpython_vm::types::PyTypeFlags = #flags;
fn impl_extend_class(
ctx: &::rustpython_vm::Context,
class: &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType>,
) {
#impl_ty::__extend_py_class(ctx, class);
#with_impl
}
fn extend_slots(slots: &mut ::rustpython_vm::types::PyTypeSlots) {
#impl_ty::__extend_slots(slots);
#with_slots
}
}
}
} else {
imp.into_token_stream()
}
}
Item::Trait(mut trai) => {
@@ -1163,6 +1238,7 @@ impl MemberItemMeta {
}
struct ExtractedImplAttrs {
payload: Option<Ident>,
with_impl: TokenStream,
with_slots: TokenStream,
flags: TokenStream,
@@ -1182,6 +1258,7 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
}
}
}];
let mut payload = None;
for attr in attr {
match attr {
@@ -1191,18 +1268,19 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
let NestedMeta::Meta(Meta::Path(path)) = meta else {
bail_span!(meta, "#[pyclass(with(...))] arguments should be paths")
};
let (extend_class, extend_slots) = if path.is_ident("PyRef") {
// special handling for PyRef
(
quote!(PyRef::<Self>::impl_extend_class),
quote!(PyRef::<Self>::extend_slots),
)
} else {
(
quote!(<Self as #path>::__extend_py_class),
quote!(<Self as #path>::__extend_slots),
)
};
let (extend_class, extend_slots) =
if path.is_ident("PyRef") || path.is_ident("Py") {
// special handling for PyRef
(
quote!(#path::<Self>::__extend_py_class),
quote!(#path::<Self>::__extend_slots),
)
} else {
(
quote!(<Self as #path>::__extend_py_class),
quote!(<Self as #path>::__extend_slots),
)
};
let item_span = item.span().resolved_at(Span::call_site());
withs.push(quote_spanned! { path.span() =>
#extend_class(ctx, class);
@@ -1227,11 +1305,23 @@ fn extract_impl_attrs(attr: AttributeArgs, item: &Ident) -> Result<ExtractedImpl
bail_span!(path, "Unknown pyimpl attribute")
}
}
NestedMeta::Meta(Meta::NameValue(syn::MetaNameValue { path, lit, .. })) => {
if path.is_ident("payload") {
if let syn::Lit::Str(lit) = lit {
payload = Some(Ident::new(&lit.value(), lit.span()));
} else {
bail_span!(lit, "payload must be a string literal")
}
} else {
bail_span!(path, "Unknown pyimpl attribute")
}
}
attr => bail_span!(attr, "Unknown pyimpl attribute"),
}
}
Ok(ExtractedImplAttrs {
payload,
with_impl: quote! {
#(#withs)*
},
+2 -2
View File
@@ -86,8 +86,8 @@ python_person.name: {}",
name: String,
}
impl TryFromBorrowedObject for PythonPerson {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for PythonPerson {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let name = obj.get_attr("name", vm)?.try_into_value::<String>(vm)?;
Ok(PythonPerson { name })
}
+13 -18
View File
@@ -746,7 +746,7 @@ mod array {
}
#[pymethod]
fn append(zelf: PyRef<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn append(zelf: &Py<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
zelf.try_resizable(vm)?.push(x, vm)
}
@@ -762,12 +762,12 @@ mod array {
}
#[pymethod]
fn remove(zelf: PyRef<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn remove(zelf: &Py<Self>, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
zelf.try_resizable(vm)?.remove(x, vm)
}
#[pymethod]
fn extend(zelf: PyRef<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn extend(zelf: &Py<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let mut w = zelf.try_resizable(vm)?;
if zelf.is(&obj) {
w.imul(2, vm)
@@ -828,7 +828,7 @@ mod array {
}
#[pymethod]
fn fromunicode(zelf: PyRef<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
fn fromunicode(zelf: &Py<Self>, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let utf8 = PyStrRef::try_from_object(vm, obj.clone()).map_err(|_| {
vm.new_type_error(format!(
"fromunicode() argument must be str, not {}",
@@ -922,18 +922,13 @@ mod array {
}
#[pymethod]
fn insert(
zelf: PyRef<Self>,
i: isize,
x: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
fn insert(zelf: &Py<Self>, i: isize, x: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let mut w = zelf.try_resizable(vm)?;
w.insert(i, x, vm)
}
#[pymethod]
fn pop(zelf: PyRef<Self>, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
fn pop(zelf: &Py<Self>, i: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult {
let mut w = zelf.try_resizable(vm)?;
if w.len() == 0 {
Err(vm.new_index_error("pop from empty array".to_owned()))
@@ -982,7 +977,7 @@ mod array {
}
#[pymethod]
fn fromlist(zelf: PyRef<Self>, list: PyListRef, vm: &VirtualMachine) -> PyResult<()> {
fn fromlist(zelf: &Py<Self>, list: PyListRef, vm: &VirtualMachine) -> PyResult<()> {
zelf.try_resizable(vm)?.fromlist(&list, vm)
}
@@ -1014,7 +1009,7 @@ mod array {
}
fn _setitem(
zelf: PyRef<Self>,
zelf: &Py<Self>,
needle: &PyObject,
value: PyObjectRef,
vm: &VirtualMachine,
@@ -1052,7 +1047,7 @@ mod array {
#[pymethod(magic)]
fn setitem(
zelf: PyRef<Self>,
zelf: &Py<Self>,
needle: PyObjectRef,
value: PyObjectRef,
vm: &VirtualMachine,
@@ -1120,7 +1115,7 @@ mod array {
}
#[pymethod(magic)]
fn repr(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<String> {
fn repr(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
let class = zelf.class();
let class_name = class.name();
if zelf.read().typecode() == 'u' {
@@ -1167,7 +1162,7 @@ mod array {
#[pymethod(magic)]
fn reduce_ex(
zelf: PyRef<Self>,
zelf: &Py<Self>,
proto: usize,
vm: &VirtualMachine,
) -> PyResult<(PyObjectRef, PyTupleRef, Option<PyDictRef>)> {
@@ -1191,7 +1186,7 @@ mod array {
#[pymethod(magic)]
fn reduce(
zelf: PyRef<Self>,
zelf: &Py<Self>,
vm: &VirtualMachine,
) -> PyResult<(PyObjectRef, PyTupleRef, Option<PyDictRef>)> {
let array = zelf.read();
@@ -1325,7 +1320,7 @@ mod array {
ass_subscript: atomic_func!(|mapping, needle, value, vm| {
let zelf = PyArray::mapping_downcast(mapping);
if let Some(value) = value {
PyArray::_setitem(zelf.to_owned(), needle, value, vm)
PyArray::_setitem(zelf, needle, value, vm)
} else {
zelf._delitem(needle, vm)
}
+2 -4
View File
@@ -2,11 +2,9 @@ pub(crate) use decl::make_module;
#[pymodule(name = "faulthandler")]
mod decl {
use crate::vm::{
frame::FrameRef, function::OptionalArg, stdlib::sys::PyStderr, VirtualMachine,
};
use crate::vm::{frame::Frame, function::OptionalArg, stdlib::sys::PyStderr, VirtualMachine};
fn dump_frame(frame: &FrameRef, vm: &VirtualMachine) {
fn dump_frame(frame: &Frame, vm: &VirtualMachine) {
let stderr = PyStderr(vm);
writeln!(
stderr,
+2 -2
View File
@@ -72,8 +72,8 @@ mod mmap {
Copy = 3,
}
impl TryFromBorrowedObject for AccessMode {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for AccessMode {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let i = u32::try_from_borrowed_object(vm, obj)?;
Ok(match i {
0 => Self::Default,
+2 -2
View File
@@ -129,8 +129,8 @@ mod resource {
}
struct Limits(libc::rlimit);
impl TryFromBorrowedObject for Limits {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for Limits {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let seq: Vec<libc::rlim_t> = obj.try_to_value(vm)?;
match *seq {
[cur, max] => Ok(Self(libc::rlimit {
+15 -15
View File
@@ -883,7 +883,8 @@ mod _sqlite {
unsafe { cursor.row_factory.swap(zelf.row_factory.to_owned()) };
cursor
} else {
Cursor::new(zelf.clone(), zelf.row_factory.to_owned(), vm).into_ref(vm)
let row_factory = zelf.row_factory.to_owned();
Cursor::new(zelf, row_factory, vm).into_ref(vm)
};
Ok(cursor)
}
@@ -952,7 +953,8 @@ mod _sqlite {
parameters: OptionalArg<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<PyRef<Cursor>> {
let cursor = Cursor::new(zelf.clone(), zelf.row_factory.to_owned(), vm).into_ref(vm);
let row_factory = zelf.row_factory.to_owned();
let cursor = Cursor::new(zelf, row_factory, vm).into_ref(vm);
Cursor::execute(cursor, sql, parameters, vm)
}
@@ -963,7 +965,8 @@ mod _sqlite {
seq_of_params: ArgIterable,
vm: &VirtualMachine,
) -> PyResult<PyRef<Cursor>> {
let cursor = Cursor::new(zelf.clone(), zelf.row_factory.to_owned(), vm).into_ref(vm);
let row_factory = zelf.row_factory.to_owned();
let cursor = Cursor::new(zelf, row_factory, vm).into_ref(vm);
Cursor::executemany(cursor, sql, seq_of_params, vm)
}
@@ -973,15 +976,12 @@ mod _sqlite {
script: PyStrRef,
vm: &VirtualMachine,
) -> PyResult<PyRef<Cursor>> {
Cursor::executescript(
Cursor::new(zelf.clone(), zelf.row_factory.to_owned(), vm).into_ref(vm),
script,
vm,
)
let row_factory = zelf.row_factory.to_owned();
Cursor::executescript(Cursor::new(zelf, row_factory, vm).into_ref(vm), script, vm)
}
#[pymethod]
fn backup(zelf: PyRef<Self>, args: BackupArgs, vm: &VirtualMachine) -> PyResult<()> {
fn backup(zelf: &Py<Self>, args: BackupArgs, vm: &VirtualMachine) -> PyResult<()> {
let BackupArgs {
target,
pages,
@@ -1550,8 +1550,8 @@ mod _sqlite {
}
#[pymethod]
fn fetchone(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
Self::next(&zelf, vm).map(|x| match x {
fn fetchone(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult {
Self::next(zelf, vm).map(|x| match x {
PyIterReturn::Return(row) => row,
PyIterReturn::StopIteration(_) => vm.ctx.none(),
})
@@ -1559,13 +1559,13 @@ mod _sqlite {
#[pymethod]
fn fetchmany(
zelf: PyRef<Self>,
zelf: &Py<Self>,
max_rows: OptionalArg<c_int>,
vm: &VirtualMachine,
) -> PyResult<Vec<PyObjectRef>> {
let max_rows = max_rows.unwrap_or_else(|| zelf.arraysize.load(Ordering::Relaxed));
let mut list = vec![];
while let PyIterReturn::Return(row) = Self::next(&zelf, vm)? {
while let PyIterReturn::Return(row) = Self::next(zelf, vm)? {
list.push(row);
if list.len() as c_int >= max_rows {
break;
@@ -1575,9 +1575,9 @@ mod _sqlite {
}
#[pymethod]
fn fetchall(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
fn fetchall(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
let mut list = vec![];
while let PyIterReturn::Return(row) = Self::next(&zelf, vm)? {
while let PyIterReturn::Return(row) = Self::next(zelf, vm)? {
list.push(row);
}
Ok(list)
+2 -2
View File
@@ -41,8 +41,8 @@ enum NormalizeForm {
Nfkd,
}
impl TryFromBorrowedObject for NormalizeForm {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for NormalizeForm {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
obj.try_value_with(
|form: &PyStr| {
Ok(match form.as_str() {
+2 -2
View File
@@ -581,8 +581,8 @@ mod zlib {
}
}
impl TryFromBorrowedObject for Level {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for Level {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let int: i32 = obj.try_index(vm)?.try_to_primitive(vm)?;
Ok(Self::new(int))
}
+57 -54
View File
@@ -26,7 +26,7 @@ impl PyPayload for PyAsyncGen {
}
}
#[pyclass(with(Constructor, Representable))]
#[pyclass(with(PyRef, Constructor, Representable))]
impl PyAsyncGen {
pub fn as_coro(&self) -> &Coro {
&self.inner
@@ -49,59 +49,6 @@ impl PyAsyncGen {
self.inner.set_name(name)
}
#[pymethod(magic)]
fn aiter(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyRef<Self> {
zelf
}
#[pymethod(magic)]
fn anext(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyAsyncGenASend {
Self::asend(zelf, vm.ctx.none(), vm)
}
#[pymethod]
fn asend(zelf: PyRef<Self>, value: PyObjectRef, _vm: &VirtualMachine) -> PyAsyncGenASend {
PyAsyncGenASend {
ag: zelf,
state: AtomicCell::new(AwaitableState::Init),
value,
}
}
#[pymethod]
fn athrow(
zelf: PyRef<Self>,
exc_type: PyObjectRef,
exc_val: OptionalArg,
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyAsyncGenAThrow {
PyAsyncGenAThrow {
ag: zelf,
aclose: false,
state: AtomicCell::new(AwaitableState::Init),
value: (
exc_type,
exc_val.unwrap_or_none(vm),
exc_tb.unwrap_or_none(vm),
),
}
}
#[pymethod]
fn aclose(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyAsyncGenAThrow {
PyAsyncGenAThrow {
ag: zelf,
aclose: true,
state: AtomicCell::new(AwaitableState::Init),
value: (
vm.ctx.exceptions.generator_exit.to_owned().into(),
vm.ctx.none(),
vm.ctx.none(),
),
}
}
#[pygetset]
fn ag_await(&self, _vm: &VirtualMachine) -> Option<PyObjectRef> {
self.inner.frame().yield_from_target()
@@ -125,6 +72,62 @@ impl PyAsyncGen {
}
}
#[pyclass]
impl PyRef<PyAsyncGen> {
#[pymethod(magic)]
fn aiter(self, _vm: &VirtualMachine) -> PyRef<PyAsyncGen> {
self
}
#[pymethod(magic)]
fn anext(self, vm: &VirtualMachine) -> PyAsyncGenASend {
Self::asend(self, vm.ctx.none(), vm)
}
#[pymethod]
fn asend(self, value: PyObjectRef, _vm: &VirtualMachine) -> PyAsyncGenASend {
PyAsyncGenASend {
ag: self,
state: AtomicCell::new(AwaitableState::Init),
value,
}
}
#[pymethod]
fn athrow(
self,
exc_type: PyObjectRef,
exc_val: OptionalArg,
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyAsyncGenAThrow {
PyAsyncGenAThrow {
ag: self,
aclose: false,
state: AtomicCell::new(AwaitableState::Init),
value: (
exc_type,
exc_val.unwrap_or_none(vm),
exc_tb.unwrap_or_none(vm),
),
}
}
#[pymethod]
fn aclose(self, vm: &VirtualMachine) -> PyAsyncGenAThrow {
PyAsyncGenAThrow {
ag: self,
aclose: true,
state: AtomicCell::new(AwaitableState::Init),
value: (
vm.ctx.exceptions.generator_exit.to_owned().into(),
vm.ctx.none(),
vm.ctx.none(),
),
}
}
}
impl Representable for PyAsyncGen {
#[inline]
fn repr_str(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<String> {
+2 -2
View File
@@ -19,8 +19,8 @@ impl ToPyObject for bool {
}
}
impl TryFromBorrowedObject for bool {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<bool> {
impl<'a> TryFromBorrowedObject<'a> for bool {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<bool> {
if obj.fast_isinstance(vm.ctx.types.int_type) {
Ok(get_value(obj))
} else {
+210 -225
View File
@@ -48,31 +48,6 @@ pub struct PyByteArray {
pub type PyByteArrayRef = PyRef<PyByteArray>;
impl PyByteArray {
pub fn new_ref(data: Vec<u8>, ctx: &Context) -> PyRef<Self> {
PyRef::new_ref(Self::from(data), ctx.types.bytearray_type.to_owned(), None)
}
fn from_inner(inner: PyBytesInner) -> Self {
PyByteArray {
inner: PyRwLock::new(inner),
exports: AtomicUsize::new(0),
}
}
pub fn borrow_buf(&self) -> PyMappedRwLockReadGuard<'_, [u8]> {
PyRwLockReadGuard::map(self.inner.read(), |inner| &*inner.elements)
}
pub fn borrow_buf_mut(&self) -> PyMappedRwLockWriteGuard<'_, Vec<u8>> {
PyRwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.elements)
}
fn repeat(&self, value: isize, vm: &VirtualMachine) -> PyResult<Self> {
self.inner().mul(value, vm).map(|x| x.into())
}
}
impl From<PyBytesInner> for PyByteArray {
fn from(inner: PyBytesInner) -> Self {
Self::from_inner(inner)
@@ -97,9 +72,107 @@ pub(crate) fn init(context: &Context) {
PyByteArrayIterator::extend_class(context, context.types.bytearray_iterator_type);
}
impl PyByteArray {
pub fn new_ref(data: Vec<u8>, ctx: &Context) -> PyRef<Self> {
PyRef::new_ref(Self::from(data), ctx.types.bytearray_type.to_owned(), None)
}
fn from_inner(inner: PyBytesInner) -> Self {
PyByteArray {
inner: PyRwLock::new(inner),
exports: AtomicUsize::new(0),
}
}
pub fn borrow_buf(&self) -> PyMappedRwLockReadGuard<'_, [u8]> {
PyRwLockReadGuard::map(self.inner.read(), |inner| &*inner.elements)
}
pub fn borrow_buf_mut(&self) -> PyMappedRwLockWriteGuard<'_, Vec<u8>> {
PyRwLockWriteGuard::map(self.inner.write(), |inner| &mut inner.elements)
}
fn repeat(&self, value: isize, vm: &VirtualMachine) -> PyResult<Self> {
self.inner().mul(value, vm).map(|x| x.into())
}
fn _setitem_by_index(&self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &value)?;
self.borrow_buf_mut().setitem_by_index(vm, i, value)
}
fn _setitem(
zelf: &Py<Self>,
needle: &PyObject,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? {
SequenceIndex::Int(i) => zelf._setitem_by_index(i, value, vm),
SequenceIndex::Slice(slice) => {
let items = if zelf.is(&value) {
zelf.borrow_buf().to_vec()
} else {
bytes_from_object(vm, &value)?
};
if let Some(mut w) = zelf.try_resizable_opt() {
w.elements.setitem_by_slice(vm, slice, &items)
} else {
zelf.borrow_buf_mut()
.setitem_by_slice_no_resize(vm, slice, &items)
}
}
}
}
fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? {
SequenceIndex::Int(i) => self
.borrow_buf()
.getitem_by_index(vm, i)
.map(|x| vm.ctx.new_int(x).into()),
SequenceIndex::Slice(slice) => self
.borrow_buf()
.getitem_by_slice(vm, slice)
.map(|x| Self::new_ref(x, &vm.ctx).into()),
}
}
pub fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? {
SequenceIndex::Int(i) => self.try_resizable(vm)?.elements.delitem_by_index(vm, i),
SequenceIndex::Slice(slice) => {
// TODO: delete 0 elements don't need resizable
self.try_resizable(vm)?.elements.delitem_by_slice(vm, slice)
}
}
}
fn irepeat(zelf: &Py<Self>, n: isize, vm: &VirtualMachine) -> PyResult<()> {
if n == 1 {
return Ok(());
}
let mut w = match zelf.try_resizable(vm) {
Ok(w) => w,
Err(err) => {
return if zelf.borrow_buf().is_empty() {
// We can multiple an empty vector by any integer
Ok(())
} else {
Err(err)
};
}
};
w.imul(n, vm)
}
}
#[pyclass(
flags(BASETYPE),
with(
Py,
PyRef,
Constructor,
Initializer,
Comparable,
@@ -156,45 +229,6 @@ impl PyByteArray {
self.inner().contains(needle, vm)
}
fn _setitem_by_index(&self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &value)?;
self.borrow_buf_mut().setitem_by_index(vm, i, value)
}
fn _setitem(
zelf: PyRef<Self>,
needle: &PyObject,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? {
SequenceIndex::Int(i) => zelf._setitem_by_index(i, value, vm),
SequenceIndex::Slice(slice) => {
let items = if zelf.is(&value) {
zelf.borrow_buf().to_vec()
} else {
bytes_from_object(vm, &value)?
};
if let Some(mut w) = zelf.try_resizable_opt() {
w.elements.setitem_by_slice(vm, slice, &items)
} else {
zelf.borrow_buf_mut()
.setitem_by_slice_no_resize(vm, slice, &items)
}
}
}
}
#[pymethod(magic)]
fn setitem(
zelf: PyRef<Self>,
needle: PyObjectRef,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
Self::_setitem(zelf, &needle, value, vm)
}
#[pymethod(magic)]
fn iadd(zelf: PyRef<Self>, other: ArgBytesLike, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
zelf.try_resizable(vm)?
@@ -203,34 +237,11 @@ impl PyByteArray {
Ok(zelf)
}
fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? {
SequenceIndex::Int(i) => self
.borrow_buf()
.getitem_by_index(vm, i)
.map(|x| vm.ctx.new_int(x).into()),
SequenceIndex::Slice(slice) => self
.borrow_buf()
.getitem_by_slice(vm, slice)
.map(|x| Self::new_ref(x, &vm.ctx).into()),
}
}
#[pymethod(magic)]
fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self._getitem(&needle, vm)
}
pub fn _delitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult<()> {
match SequenceIndex::try_from_borrowed_object(vm, needle, "bytearray")? {
SequenceIndex::Int(i) => self.try_resizable(vm)?.elements.delitem_by_index(vm, i),
SequenceIndex::Slice(slice) => {
// TODO: delete 0 elements don't need resizable
self.try_resizable(vm)?.elements.delitem_by_slice(vm, slice)
}
}
}
#[pymethod(magic)]
pub fn delitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
self._delitem(&needle, vm)
@@ -241,78 +252,6 @@ impl PyByteArray {
PyBytesInner::maketrans(from, to, vm)
}
#[pymethod]
fn pop(zelf: PyRef<Self>, index: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult<u8> {
let elements = &mut zelf.try_resizable(vm)?.elements;
let index = elements
.wrap_index(index.unwrap_or(-1))
.ok_or_else(|| vm.new_index_error("index out of range".to_owned()))?;
Ok(elements.remove(index))
}
#[pymethod]
fn insert(
zelf: PyRef<Self>,
index: isize,
object: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
let value = value_from_object(vm, &object)?;
let elements = &mut zelf.try_resizable(vm)?.elements;
let index = elements.saturate_index(index);
elements.insert(index, value);
Ok(())
}
#[pymethod]
fn append(zelf: PyRef<Self>, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &object)?;
zelf.try_resizable(vm)?.elements.push(value);
Ok(())
}
#[pymethod]
fn remove(zelf: PyRef<Self>, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &object)?;
let elements = &mut zelf.try_resizable(vm)?.elements;
if let Some(index) = elements.find_byte(value) {
elements.remove(index);
Ok(())
} else {
Err(vm.new_value_error("value not found in bytearray".to_owned()))
}
}
#[pymethod]
fn extend(zelf: PyRef<Self>, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if zelf.is(&object) {
Self::irepeat(&zelf, 2, vm)
} else {
let items = bytes_from_object(vm, &object)?;
zelf.try_resizable(vm)?.elements.extend(items);
Ok(())
}
}
fn irepeat(zelf: &Py<Self>, n: isize, vm: &VirtualMachine) -> PyResult<()> {
if n == 1 {
return Ok(());
}
let mut w = match zelf.try_resizable(vm) {
Ok(w) => w,
Err(err) => {
return if zelf.borrow_buf().is_empty() {
// We can multiple an empty vector by any integer
Ok(())
} else {
Err(err)
};
}
};
w.imul(n, vm)
}
#[pymethod]
fn isalnum(&self) -> bool {
self.inner().isalnum()
@@ -503,59 +442,11 @@ impl PyByteArray {
self.inner().strip(chars).into()
}
#[pymethod]
fn lstrip(
zelf: PyRef<Self>,
chars: OptionalOption<PyBytesInner>,
vm: &VirtualMachine,
) -> PyRef<Self> {
let inner = zelf.inner();
let stripped = inner.lstrip(chars);
let elements = &inner.elements;
if stripped == elements {
drop(inner);
zelf
} else {
vm.new_pyref(PyByteArray::from(stripped.to_vec()))
}
}
#[pymethod]
fn rstrip(
zelf: PyRef<Self>,
chars: OptionalOption<PyBytesInner>,
vm: &VirtualMachine,
) -> PyRef<Self> {
let inner = zelf.inner();
let stripped = inner.rstrip(chars);
let elements = &inner.elements;
if stripped == elements {
drop(inner);
zelf
} else {
vm.new_pyref(PyByteArray::from(stripped.to_vec()))
}
}
/// removeprefix($self, prefix, /)
///
///
/// Return a bytearray object with the given prefix string removed if present.
///
/// If the bytearray starts with the prefix string, return string[len(prefix):]
/// Otherwise, return a copy of the original bytearray.
#[pymethod]
fn removeprefix(&self, prefix: PyBytesInner) -> Self {
self.inner().removeprefix(prefix).into()
}
/// removesuffix(self, prefix, /)
///
///
/// Return a bytearray object with the given suffix string removed if present.
///
/// If the bytearray ends with the suffix string, return string[:len(suffix)]
/// Otherwise, return a copy of the original bytearray.
#[pymethod]
fn removesuffix(&self, suffix: PyBytesInner) -> Self {
self.inner().removesuffix(suffix).to_vec().into()
@@ -638,12 +529,6 @@ impl PyByteArray {
Ok(self.inner().replace(old, new, count, vm)?.into())
}
#[pymethod]
fn clear(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<()> {
zelf.try_resizable(vm)?.elements.clear();
Ok(())
}
#[pymethod]
fn copy(&self) -> Self {
self.borrow_buf().to_vec().into()
@@ -681,35 +566,135 @@ impl PyByteArray {
fn reverse(&self) {
self.borrow_buf_mut().reverse();
}
}
#[pyclass]
impl Py<PyByteArray> {
#[pymethod(magic)]
fn setitem(
&self,
needle: PyObjectRef,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
PyByteArray::_setitem(self, &needle, value, vm)
}
#[pymethod]
fn decode(zelf: PyRef<Self>, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStrRef> {
bytes_decode(zelf.into(), args, vm)
fn pop(&self, index: OptionalArg<isize>, vm: &VirtualMachine) -> PyResult<u8> {
let elements = &mut self.try_resizable(vm)?.elements;
let index = elements
.wrap_index(index.unwrap_or(-1))
.ok_or_else(|| vm.new_index_error("index out of range".to_owned()))?;
Ok(elements.remove(index))
}
#[pymethod]
fn insert(&self, index: isize, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &object)?;
let elements = &mut self.try_resizable(vm)?.elements;
let index = elements.saturate_index(index);
elements.insert(index, value);
Ok(())
}
#[pymethod]
fn append(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &object)?;
self.try_resizable(vm)?.elements.push(value);
Ok(())
}
#[pymethod]
fn remove(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let value = value_from_object(vm, &object)?;
let elements = &mut self.try_resizable(vm)?.elements;
let index = elements
.find_byte(value)
.ok_or_else(|| vm.new_value_error("value not found in bytearray".to_owned()))?;
elements.remove(index);
Ok(())
}
#[pymethod]
fn extend(&self, object: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if self.is(&object) {
PyByteArray::irepeat(self, 2, vm)
} else {
let items = bytes_from_object(vm, &object)?;
self.try_resizable(vm)?.elements.extend(items);
Ok(())
}
}
#[pymethod]
fn clear(&self, vm: &VirtualMachine) -> PyResult<()> {
self.try_resizable(vm)?.elements.clear();
Ok(())
}
#[pymethod(magic)]
fn reduce_ex(
zelf: PyRef<Self>,
&self,
_proto: usize,
vm: &VirtualMachine,
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
Self::reduce(zelf, vm)
Self::reduce(self, vm)
}
#[pymethod(magic)]
fn reduce(
zelf: PyRef<Self>,
vm: &VirtualMachine,
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
let bytes = PyBytes::from(zelf.borrow_buf().to_vec()).to_pyobject(vm);
fn reduce(&self, vm: &VirtualMachine) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
let bytes = PyBytes::from(self.borrow_buf().to_vec()).to_pyobject(vm);
(
zelf.class().to_owned(),
self.class().to_owned(),
PyTuple::new_ref(vec![bytes], &vm.ctx),
zelf.as_object().dict(),
self.as_object().dict(),
)
}
}
#[pyclass]
impl PyRef<PyByteArray> {
#[pymethod]
fn lstrip(
self,
chars: OptionalOption<PyBytesInner>,
vm: &VirtualMachine,
) -> PyRef<PyByteArray> {
let inner = self.inner();
let stripped = inner.lstrip(chars);
let elements = &inner.elements;
if stripped == elements {
drop(inner);
self
} else {
vm.new_pyref(PyByteArray::from(stripped.to_vec()))
}
}
#[pymethod]
fn rstrip(
self,
chars: OptionalOption<PyBytesInner>,
vm: &VirtualMachine,
) -> PyRef<PyByteArray> {
let inner = self.inner();
let stripped = inner.rstrip(chars);
let elements = &inner.elements;
if stripped == elements {
drop(inner);
self
} else {
vm.new_pyref(PyByteArray::from(stripped.to_vec()))
}
}
#[pymethod]
fn decode(self, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStrRef> {
bytes_decode(self.into(), args, vm)
}
}
impl Constructor for PyByteArray {
type Args = FuncArgs;
@@ -796,7 +781,7 @@ impl AsMapping for PyByteArray {
ass_subscript: atomic_func!(|mapping, needle, value, vm| {
let zelf = PyByteArray::mapping_downcast(mapping);
if let Some(value) = value {
PyByteArray::setitem(zelf.to_owned(), needle.to_owned(), value, vm)
Py::setitem(zelf, needle.to_owned(), value, vm)
} else {
zelf.delitem(needle.to_owned(), vm)
}
+89 -105
View File
@@ -101,23 +101,38 @@ impl PyBytes {
PyRef::new_ref(Self::from(data), ctx.types.bytes_type.to_owned(), None)
}
fn repeat(zelf: PyRef<Self>, count: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
if count == 1 && zelf.class().is(vm.ctx.types.bytes_type) {
fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
match SequenceIndex::try_from_borrowed_object(vm, needle, "byte")? {
SequenceIndex::Int(i) => self
.getitem_by_index(vm, i)
.map(|x| vm.ctx.new_int(x).into()),
SequenceIndex::Slice(slice) => self
.getitem_by_slice(vm, slice)
.map(|x| vm.ctx.new_bytes(x).into()),
}
}
}
impl PyRef<PyBytes> {
fn repeat(self, count: isize, vm: &VirtualMachine) -> PyResult<PyRef<PyBytes>> {
if count == 1 && self.class().is(vm.ctx.types.bytes_type) {
// Special case: when some `bytes` is multiplied by `1`,
// nothing really happens, we need to return an object itself
// with the same `id()` to be compatible with CPython.
// This only works for `bytes` itself, not its subclasses.
return Ok(zelf);
return Ok(self);
}
zelf.inner
self.inner
.mul(count, vm)
.map(|x| Self::from(x).into_ref(vm))
.map(|x| PyBytes::from(x).into_ref(vm))
}
}
#[pyclass(
flags(BASETYPE),
with(
Py,
PyRef,
AsMapping,
AsSequence,
Hashable,
@@ -146,15 +161,6 @@ impl PyBytes {
self.inner.as_bytes()
}
#[pymethod(magic)]
fn bytes(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyRef<Self> {
if zelf.is(vm.ctx.types.bytes_type) {
zelf
} else {
PyBytes::from(zelf.inner.clone()).into_ref(vm)
}
}
#[pymethod(magic)]
fn sizeof(&self) -> usize {
size_of::<Self>() + self.len() * size_of::<u8>()
@@ -179,17 +185,6 @@ impl PyBytes {
PyBytesInner::maketrans(from, to, vm)
}
fn _getitem(&self, needle: &PyObject, vm: &VirtualMachine) -> PyResult {
match SequenceIndex::try_from_borrowed_object(vm, needle, "byte")? {
SequenceIndex::Int(i) => self
.getitem_by_index(vm, i)
.map(|x| vm.ctx.new_int(x).into()),
SequenceIndex::Slice(slice) => self
.getitem_by_slice(vm, slice)
.map(|x| vm.ctx.new_bytes(x).into()),
}
}
#[pymethod(magic)]
fn getitem(&self, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self._getitem(&needle, vm)
@@ -371,53 +366,11 @@ impl PyBytes {
self.inner.strip(chars).into()
}
#[pymethod]
fn lstrip(
zelf: PyRef<Self>,
chars: OptionalOption<PyBytesInner>,
vm: &VirtualMachine,
) -> PyRef<Self> {
let stripped = zelf.inner.lstrip(chars);
if stripped == zelf.as_bytes() {
zelf
} else {
vm.ctx.new_bytes(stripped.to_vec())
}
}
#[pymethod]
fn rstrip(
zelf: PyRef<Self>,
chars: OptionalOption<PyBytesInner>,
vm: &VirtualMachine,
) -> PyRef<Self> {
let stripped = zelf.inner.rstrip(chars);
if stripped == zelf.as_bytes() {
zelf
} else {
vm.ctx.new_bytes(stripped.to_vec())
}
}
/// removeprefix($self, prefix, /)
///
///
/// Return a bytes object with the given prefix string removed if present.
///
/// If the bytes starts with the prefix string, return string[len(prefix):]
/// Otherwise, return a copy of the original bytes.
#[pymethod]
fn removeprefix(&self, prefix: PyBytesInner) -> Self {
self.inner.removeprefix(prefix).into()
}
/// removesuffix(self, prefix, /)
///
///
/// Return a bytes object with the given suffix string removed if present.
///
/// If the bytes ends with the suffix string, return string[:len(suffix)]
/// Otherwise, return a copy of the original bytes.
#[pymethod]
fn removesuffix(&self, suffix: PyBytesInner) -> Self {
self.inner.removesuffix(suffix).into()
@@ -508,7 +461,7 @@ impl PyBytes {
#[pymethod(name = "__rmul__")]
#[pymethod(magic)]
fn mul(zelf: PyRef<Self>, value: ArgIndex, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
Self::repeat(zelf, value.try_to_primitive(vm)?, vm)
zelf.repeat(value.try_to_primitive(vm)?, vm)
}
#[pymethod(name = "__mod__")]
@@ -522,6 +475,66 @@ impl PyBytes {
vm.ctx.not_implemented()
}
#[pymethod(magic)]
fn getnewargs(&self, vm: &VirtualMachine) -> PyTupleRef {
let param: Vec<PyObjectRef> = self.elements().map(|x| x.to_pyobject(vm)).collect();
PyTuple::new_ref(param, &vm.ctx)
}
}
#[pyclass]
impl Py<PyBytes> {
#[pymethod(magic)]
fn reduce_ex(
&self,
_proto: usize,
vm: &VirtualMachine,
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
Self::reduce(self, vm)
}
#[pymethod(magic)]
fn reduce(&self, vm: &VirtualMachine) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
let bytes = PyBytes::from(self.to_vec()).to_pyobject(vm);
(
self.class().to_owned(),
PyTuple::new_ref(vec![bytes], &vm.ctx),
self.as_object().dict(),
)
}
}
#[pyclass]
impl PyRef<PyBytes> {
#[pymethod(magic)]
fn bytes(self, vm: &VirtualMachine) -> PyRef<PyBytes> {
if self.is(vm.ctx.types.bytes_type) {
self
} else {
PyBytes::from(self.inner.clone()).into_ref(vm)
}
}
#[pymethod]
fn lstrip(self, chars: OptionalOption<PyBytesInner>, vm: &VirtualMachine) -> PyRef<PyBytes> {
let stripped = self.inner.lstrip(chars);
if stripped == self.as_bytes() {
self
} else {
vm.ctx.new_bytes(stripped.to_vec())
}
}
#[pymethod]
fn rstrip(self, chars: OptionalOption<PyBytesInner>, vm: &VirtualMachine) -> PyRef<PyBytes> {
let stripped = self.inner.rstrip(chars);
if stripped == self.as_bytes() {
self
} else {
vm.ctx.new_bytes(stripped.to_vec())
}
}
/// Return a string decoded from the given bytes.
/// Default encoding is 'utf-8'.
/// Default errors is 'strict', meaning that encoding errors raise a UnicodeError.
@@ -530,36 +543,8 @@ impl PyBytes {
/// see https://docs.python.org/3/library/codecs.html#standard-encodings
/// currently, only 'utf-8' and 'ascii' emplemented
#[pymethod]
fn decode(zelf: PyRef<Self>, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStrRef> {
bytes_decode(zelf.into(), args, vm)
}
#[pymethod(magic)]
fn getnewargs(&self, vm: &VirtualMachine) -> PyTupleRef {
let param: Vec<PyObjectRef> = self.elements().map(|x| x.to_pyobject(vm)).collect();
PyTuple::new_ref(param, &vm.ctx)
}
#[pymethod(magic)]
fn reduce_ex(
zelf: PyRef<Self>,
_proto: usize,
vm: &VirtualMachine,
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
Self::reduce(zelf, vm)
}
#[pymethod(magic)]
fn reduce(
zelf: PyRef<Self>,
vm: &VirtualMachine,
) -> (PyTypeRef, PyTupleRef, Option<PyDictRef>) {
let bytes = PyBytes::from(zelf.to_vec()).to_pyobject(vm);
(
zelf.class().to_owned(),
PyTuple::new_ref(vec![bytes], &vm.ctx),
zelf.as_object().dict(),
)
fn decode(self, args: DecodeArgs, vm: &VirtualMachine) -> PyResult<PyStrRef> {
bytes_decode(self.into(), args, vm)
}
}
@@ -605,11 +590,10 @@ impl AsSequence for PyBytes {
.map(|x| vm.ctx.new_bytes(x).into())
}),
repeat: atomic_func!(|seq, n, vm| {
if let Ok(zelf) = seq.obj.to_owned().downcast::<PyBytes>() {
PyBytes::repeat(zelf, n, vm).to_pyresult(vm)
} else {
Err(vm.new_type_error("bad argument type for built-in operation".to_owned()))
}
let zelf = seq.obj.to_owned().downcast::<PyBytes>().map_err(|_| {
vm.new_type_error("bad argument type for built-in operation".to_owned())
})?;
zelf.repeat(n, vm).to_pyresult(vm)
}),
item: atomic_func!(|seq, i, vm| {
PyBytes::sequence_downcast(seq)
@@ -742,8 +726,8 @@ impl IterNext for PyBytesIterator {
}
}
impl TryFromBorrowedObject for PyBytes {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for PyBytes {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
PyBytesInner::try_from_borrowed_object(vm, obj).map(|x| x.into())
}
}
+34 -22
View File
@@ -10,7 +10,7 @@ use crate::{
convert::ToPyObject,
function::{FuncArgs, OptionalArg},
types::Representable,
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
AsObject, Context, Py, PyObject, PyObjectRef, PyPayload, PyResult, VirtualMachine,
};
use num_traits::Zero;
use std::{borrow::Borrow, fmt, ops::Deref};
@@ -216,9 +216,6 @@ impl PyPayload for PyCode {
}
}
#[pyclass(with(PyRef, Representable))]
impl PyCode {}
impl Representable for PyCode {
#[inline]
fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
@@ -233,35 +230,35 @@ impl Representable for PyCode {
}
}
#[pyclass]
impl PyRef<PyCode> {
#[pyclass(with(Py))]
impl PyCode {
#[pyslot]
fn slot_new(_cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult {
Err(vm.new_type_error("Cannot directly create code object".to_owned()))
}
#[pygetset]
fn co_posonlyargcount(self) -> usize {
fn co_posonlyargcount(&self) -> usize {
self.code.posonlyarg_count as usize
}
#[pygetset]
fn co_argcount(self) -> usize {
fn co_argcount(&self) -> usize {
self.code.arg_count as usize
}
#[pygetset]
fn co_stacksize(self) -> u32 {
fn co_stacksize(&self) -> u32 {
self.code.max_stackdepth
}
#[pygetset]
pub fn co_filename(self) -> PyStrRef {
pub fn co_filename(&self) -> PyStrRef {
self.code.source_path.to_owned()
}
#[pygetset]
pub fn co_cellvars(self, vm: &VirtualMachine) -> PyTupleRef {
pub fn co_cellvars(&self, vm: &VirtualMachine) -> PyTupleRef {
let cellvars = self
.code
.cellvars
@@ -273,33 +270,33 @@ impl PyRef<PyCode> {
}
#[pygetset]
fn co_nlocals(self) -> usize {
fn co_nlocals(&self) -> usize {
self.varnames.len()
}
#[pygetset]
fn co_firstlineno(self) -> usize {
fn co_firstlineno(&self) -> usize {
self.code.first_line_number as usize
}
#[pygetset]
fn co_kwonlyargcount(self) -> usize {
fn co_kwonlyargcount(&self) -> usize {
self.code.kwonlyarg_count as usize
}
#[pygetset]
fn co_consts(self, vm: &VirtualMachine) -> PyTupleRef {
fn co_consts(&self, vm: &VirtualMachine) -> PyTupleRef {
let consts = self.code.constants.iter().map(|x| x.0.clone()).collect();
vm.ctx.new_tuple(consts)
}
#[pygetset]
fn co_name(self) -> PyStrRef {
fn co_name(&self) -> PyStrRef {
self.code.obj_name.to_owned()
}
#[pygetset]
fn co_names(self, vm: &VirtualMachine) -> PyTupleRef {
fn co_names(&self, vm: &VirtualMachine) -> PyTupleRef {
let names = self
.code
.names
@@ -311,18 +308,18 @@ impl PyRef<PyCode> {
}
#[pygetset]
fn co_flags(self) -> u16 {
fn co_flags(&self) -> u16 {
self.code.flags.bits()
}
#[pygetset]
pub fn co_varnames(self, vm: &VirtualMachine) -> PyTupleRef {
pub fn co_varnames(&self, vm: &VirtualMachine) -> PyTupleRef {
let varnames = self.code.varnames.iter().map(|s| s.to_object()).collect();
vm.ctx.new_tuple(varnames)
}
#[pygetset]
pub fn co_freevars(self, vm: &VirtualMachine) -> PyTupleRef {
pub fn co_freevars(&self, vm: &VirtualMachine) -> PyTupleRef {
let names = self
.code
.freevars
@@ -334,7 +331,7 @@ impl PyRef<PyCode> {
}
#[pymethod]
pub fn replace(self, args: ReplaceArgs, vm: &VirtualMachine) -> PyResult<PyCode> {
pub fn replace(&self, args: ReplaceArgs, vm: &VirtualMachine) -> PyResult<PyCode> {
let posonlyarg_count = match args.co_posonlyargcount {
OptionalArg::Present(posonlyarg_count) => posonlyarg_count,
OptionalArg::Missing => self.code.posonlyarg_count,
@@ -421,6 +418,21 @@ impl PyRef<PyCode> {
}
}
#[pyclass]
impl Py<PyCode> {
#[pymethod(magic)]
fn repr(&self) -> String {
let code = &self.code;
format!(
"<code object {} at {:#x} file {:?}, line {}>",
code.obj_name,
self.get_id(),
code.source_path.as_str(),
code.first_line_number
)
}
}
impl fmt::Display for PyCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
@@ -440,5 +452,5 @@ impl ToPyObject for bytecode::CodeObject {
}
pub fn init(ctx: &Context) {
PyRef::<PyCode>::extend_class(ctx, ctx.types.code_type);
PyCode::extend_class(ctx, ctx.types.code_type);
}
+8 -8
View File
@@ -45,13 +45,13 @@ impl PyCoroutine {
}
#[pymethod]
fn send(zelf: PyRef<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
fn send(zelf: &Py<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
zelf.inner.send(zelf.as_object(), value, vm)
}
#[pymethod]
fn throw(
zelf: PyRef<Self>,
zelf: &Py<Self>,
exc_type: PyObjectRef,
exc_val: OptionalArg,
exc_tb: OptionalArg,
@@ -67,7 +67,7 @@ impl PyCoroutine {
}
#[pymethod]
fn close(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<()> {
fn close(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<()> {
zelf.inner.close(zelf.as_object(), vm)
}
@@ -111,7 +111,7 @@ impl Representable for PyCoroutine {
impl IterNextIterable for PyCoroutine {}
impl IterNext for PyCoroutine {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
Self::send(zelf.to_owned(), vm.ctx.none(), vm)
Self::send(zelf, vm.ctx.none(), vm)
}
}
@@ -131,8 +131,8 @@ impl PyPayload for PyCoroutineWrapper {
#[pyclass(with(IterNext))]
impl PyCoroutineWrapper {
#[pymethod]
fn send(zelf: PyRef<Self>, val: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
PyCoroutine::send(zelf.coro.clone(), val, vm)
fn send(&self, val: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
PyCoroutine::send(&self.coro, val, vm)
}
#[pymethod]
@@ -143,14 +143,14 @@ impl PyCoroutineWrapper {
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyResult<PyIterReturn> {
PyCoroutine::throw(self.coro.clone(), exc_type, exc_val, exc_tb, vm)
PyCoroutine::throw(&self.coro, exc_type, exc_val, exc_tb, vm)
}
}
impl IterNextIterable for PyCoroutineWrapper {}
impl IterNext for PyCoroutineWrapper {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
Self::send(zelf.to_owned(), vm.ctx.none(), vm)
Self::send(zelf, vm.ctx.none(), vm)
}
}
+3 -3
View File
@@ -3,7 +3,7 @@ use crate::{
class::PyClassImpl,
function::PySetterValue,
types::{Constructor, GetDescriptor, Representable, Unconstructible},
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
AsObject, Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
};
use rustpython_common::lock::PyRwLock;
@@ -103,8 +103,8 @@ fn calculate_qualname(descr: &DescrObject, vm: &VirtualMachine) -> PyResult<Opti
#[pyclass(with(GetDescriptor, Constructor, Representable), flags(BASETYPE))]
impl MemberDescrObject {
#[pygetset(magic)]
fn doc(zelf: PyRef<Self>) -> Option<String> {
zelf.member.doc.to_owned()
fn doc(&self) -> Option<String> {
self.member.doc.to_owned()
}
#[pygetset(magic)]
+39 -31
View File
@@ -203,6 +203,8 @@ impl PyDict {
#[allow(clippy::len_without_is_empty)]
#[pyclass(
with(
Py,
PyRef,
Constructor,
Initializer,
AsMapping,
@@ -270,32 +272,11 @@ impl PyDict {
self.entries.clear()
}
#[pymethod]
fn keys(zelf: PyRef<Self>) -> PyDictKeys {
PyDictKeys::new(zelf)
}
#[pymethod]
fn values(zelf: PyRef<Self>) -> PyDictValues {
PyDictValues::new(zelf)
}
#[pymethod]
fn items(zelf: PyRef<Self>) -> PyDictItems {
PyDictItems::new(zelf)
}
#[pymethod(magic)]
fn setitem(&self, key: PyObjectRef, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
self.inner_setitem(&*key, value, vm)
}
#[pymethod(magic)]
#[cfg_attr(feature = "flame-it", flame("PyDictRef"))]
fn getitem(zelf: PyRef<Self>, key: PyObjectRef, vm: &VirtualMachine) -> PyResult {
zelf.inner_getitem(&*key, vm)
}
#[pymethod]
fn get(
&self,
@@ -396,17 +377,44 @@ impl PyDict {
Ok((key, value))
}
#[pymethod(magic)]
fn reversed(zelf: PyRef<Self>) -> PyDictReverseKeyIterator {
PyDictReverseKeyIterator::new(zelf)
}
#[pyclassmethod(magic)]
fn class_getitem(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
PyGenericAlias::new(cls, args, vm)
}
}
#[pyclass]
impl Py<PyDict> {
#[pymethod(magic)]
#[cfg_attr(feature = "flame-it", flame("PyDictRef"))]
fn getitem(&self, key: PyObjectRef, vm: &VirtualMachine) -> PyResult {
self.inner_getitem(&*key, vm)
}
}
#[pyclass]
impl PyRef<PyDict> {
#[pymethod]
fn keys(self) -> PyDictKeys {
PyDictKeys::new(self)
}
#[pymethod]
fn values(self) -> PyDictValues {
PyDictValues::new(self)
}
#[pymethod]
fn items(self) -> PyDictItems {
PyDictItems::new(self)
}
#[pymethod(magic)]
fn reversed(self) -> PyDictReverseKeyIterator {
PyDictReverseKeyIterator::new(self)
}
}
impl Constructor for PyDict {
type Args = FuncArgs;
@@ -847,9 +855,9 @@ macro_rules! dict_view {
#[allow(clippy::redundant_closure_call)]
#[pymethod(magic)]
fn reduce(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyTupleRef {
fn reduce(&self, vm: &VirtualMachine) -> PyTupleRef {
let iter = builtins_iter(vm).to_owned();
let internal = zelf.internal.lock();
let internal = self.internal.lock();
let entries = match &internal.status {
IterStatus::Active(dict) => dict
.into_iter()
@@ -917,9 +925,9 @@ macro_rules! dict_view {
#[allow(clippy::redundant_closure_call)]
#[pymethod(magic)]
fn reduce(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyTupleRef {
fn reduce(&self, vm: &VirtualMachine) -> PyTupleRef {
let iter = builtins_reversed(vm).to_owned();
let internal = zelf.internal.lock();
let internal = self.internal.lock();
// TODO: entries must be reversed too
let entries = match &internal.status {
IterStatus::Active(dict) => dict
@@ -1240,7 +1248,7 @@ impl PyDictItems {
return Ok(false);
}
let value = needle.fast_getitem(1);
let found = PyDict::getitem(zelf.dict().clone(), key, vm)?;
let found = zelf.dict().getitem(key, vm)?;
vm.identical_or_equal(&found, &value)
}
#[pygetset]
+9 -5
View File
@@ -8,7 +8,7 @@ use crate::{
function::OptionalArg,
protocol::{PyIter, PyIterReturn},
types::{Constructor, IterNext, IterNextIterable},
AsObject, Context, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine,
AsObject, Context, Py, PyObjectRef, PyPayload, PyResult, VirtualMachine,
};
use num_bigint::BigInt;
use num_traits::Zero;
@@ -51,17 +51,21 @@ impl Constructor for PyEnumerate {
}
}
#[pyclass(with(IterNext, Constructor), flags(BASETYPE))]
#[pyclass(with(Py, IterNext, Constructor), flags(BASETYPE))]
impl PyEnumerate {
#[pyclassmethod(magic)]
fn class_getitem(cls: PyTypeRef, args: PyObjectRef, vm: &VirtualMachine) -> PyGenericAlias {
PyGenericAlias::new(cls, args, vm)
}
}
#[pyclass]
impl Py<PyEnumerate> {
#[pymethod(magic)]
fn reduce(zelf: PyRef<Self>) -> (PyTypeRef, (PyIter, BigInt)) {
fn reduce(&self) -> (PyTypeRef, (PyIter, BigInt)) {
(
zelf.class().to_owned(),
(zelf.iterator.clone(), zelf.counter.read().clone()),
self.class().to_owned(),
(self.iterator.clone(), self.counter.read().clone()),
)
}
}
+29 -29
View File
@@ -13,12 +13,9 @@ use crate::{
use num_traits::Zero;
pub fn init(context: &Context) {
FrameRef::extend_class(context, context.types.frame_type);
Frame::extend_class(context, context.types.frame_type);
}
#[pyclass(with(Constructor, PyRef, Representable))]
impl Frame {}
impl Unconstructible for Frame {}
impl Representable for Frame {
@@ -34,61 +31,46 @@ impl Representable for Frame {
}
}
#[pyclass]
impl FrameRef {
#[pyclass(with(Constructor, Py))]
impl Frame {
#[pymethod]
fn clear(self) {
fn clear(&self) {
// TODO
}
#[pygetset]
fn f_globals(self) -> PyDictRef {
fn f_globals(&self) -> PyDictRef {
self.globals.clone()
}
#[pygetset]
fn f_locals(self, vm: &VirtualMachine) -> PyResult {
fn f_locals(&self, vm: &VirtualMachine) -> PyResult {
self.locals(vm).map(Into::into)
}
#[pygetset]
pub fn f_code(self) -> PyRef<PyCode> {
pub fn f_code(&self) -> PyRef<PyCode> {
self.code.clone()
}
#[pygetset]
pub fn f_back(self, vm: &VirtualMachine) -> Option<Self> {
// TODO: actually store f_back inside Frame struct
// get the frame in the frame stack that appears before this one.
// won't work if this frame isn't in the frame stack, hence the todo above
vm.frames
.borrow()
.iter()
.rev()
.skip_while(|p| !p.is(&self))
.nth(1)
.cloned()
}
#[pygetset]
fn f_lasti(self) -> u32 {
fn f_lasti(&self) -> u32 {
self.lasti()
}
#[pygetset]
pub fn f_lineno(self) -> usize {
pub fn f_lineno(&self) -> usize {
self.current_location().row()
}
#[pygetset]
fn f_trace(self) -> PyObjectRef {
fn f_trace(&self) -> PyObjectRef {
let boxed = self.trace.lock();
boxed.clone()
}
#[pygetset(setter)]
fn set_f_trace(self, value: PySetterValue, vm: &VirtualMachine) {
fn set_f_trace(&self, value: PySetterValue, vm: &VirtualMachine) {
let mut storage = self.trace.lock();
*storage = value.unwrap_or_none(vm);
}
@@ -126,3 +108,21 @@ impl FrameRef {
}
}
}
#[pyclass]
impl Py<Frame> {
#[pygetset]
pub fn f_back(&self, vm: &VirtualMachine) -> Option<PyRef<Frame>> {
// TODO: actually store f_back inside Frame struct
// get the frame in the frame stack that appears before this one.
// won't work if this frame isn't in the frame stack, hence the todo above
vm.frames
.borrow()
.iter()
.rev()
.skip_while(|p| !p.is(self.as_object()))
.nth(1)
.cloned()
}
}
+32 -29
View File
@@ -25,7 +25,7 @@ impl PyPayload for PyGenerator {
}
}
#[pyclass(with(Constructor, IterNext))]
#[pyclass(with(Py, Constructor, IterNext))]
impl PyGenerator {
pub fn as_coro(&self) -> &Coro {
&self.inner
@@ -47,33 +47,6 @@ impl PyGenerator {
self.inner.set_name(name)
}
#[pymethod]
fn send(zelf: PyRef<Self>, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
zelf.inner.send(zelf.as_object(), value, vm)
}
#[pymethod]
fn throw(
zelf: PyRef<Self>,
exc_type: PyObjectRef,
exc_val: OptionalArg,
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyResult<PyIterReturn> {
zelf.inner.throw(
zelf.as_object(),
exc_type,
exc_val.unwrap_or_none(vm),
exc_tb.unwrap_or_none(vm),
vm,
)
}
#[pymethod]
fn close(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<()> {
zelf.inner.close(zelf.as_object(), vm)
}
#[pygetset]
fn gi_frame(&self, _vm: &VirtualMachine) -> FrameRef {
self.inner.frame()
@@ -92,6 +65,36 @@ impl PyGenerator {
}
}
#[pyclass]
impl Py<PyGenerator> {
#[pymethod]
fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
self.inner.send(self.as_object(), value, vm)
}
#[pymethod]
fn throw(
&self,
exc_type: PyObjectRef,
exc_val: OptionalArg,
exc_tb: OptionalArg,
vm: &VirtualMachine,
) -> PyResult<PyIterReturn> {
self.inner.throw(
self.as_object(),
exc_type,
exc_val.unwrap_or_none(vm),
exc_tb.unwrap_or_none(vm),
vm,
)
}
#[pymethod]
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
self.inner.close(self.as_object(), vm)
}
}
impl Unconstructible for PyGenerator {}
impl Representable for PyGenerator {
@@ -104,7 +107,7 @@ impl Representable for PyGenerator {
impl IterNextIterable for PyGenerator {}
impl IterNext for PyGenerator {
fn next(zelf: &Py<Self>, vm: &VirtualMachine) -> PyResult<PyIterReturn> {
Self::send(zelf.to_owned(), vm.ctx.none(), vm)
zelf.send(vm.ctx.none(), vm)
}
}
+1 -1
View File
@@ -179,7 +179,7 @@ impl PyGenericAlias {
}
#[pymethod(magic)]
fn reduce(zelf: PyRef<Self>, vm: &VirtualMachine) -> (PyTypeRef, (PyTypeRef, PyTupleRef)) {
fn reduce(zelf: &Py<Self>, vm: &VirtualMachine) -> (PyTypeRef, (PyTypeRef, PyTupleRef)) {
(
vm.ctx.types.generic_alias_type.to_owned(),
(zelf.origin.clone(), zelf.args.clone()),
+2 -2
View File
@@ -72,8 +72,8 @@ impl_into_pyobject_int!(isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 BigI
macro_rules! impl_try_from_object_int {
($(($t:ty, $to_prim:ident),)*) => {$(
impl TryFromBorrowedObject for $t {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for $t {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
obj.try_value_with(|int: &PyInt| {
int.try_to_primitive(vm)
}, vm)
+419 -412
View File
@@ -68,16 +68,6 @@ impl Constructor for PyMemoryView {
}
}
#[pyclass(with(
Hashable,
Comparable,
AsBuffer,
AsMapping,
AsSequence,
Constructor,
Iterable,
Representable
))]
impl PyMemoryView {
fn parse_format(format: &str, vm: &VirtualMachine) -> PyResult<FormatSpec> {
FormatSpec::parse(format.as_bytes(), vm)
@@ -143,13 +133,6 @@ impl PyMemoryView {
zelf
}
#[pymethod]
pub fn release(&self) {
if self.released.compare_exchange(false, true).is_ok() {
self.buffer.release();
}
}
fn try_not_released(&self, vm: &VirtualMachine) -> PyResult<()> {
if self.released.load() {
Err(vm.new_value_error("operation forbidden on released memoryview object".to_owned()))
@@ -158,100 +141,6 @@ impl PyMemoryView {
}
}
#[pygetset]
fn obj(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
self.try_not_released(vm).map(|_| self.buffer.obj.clone())
}
#[pygetset]
fn nbytes(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm).map(|_| self.desc.len)
}
#[pygetset]
fn readonly(&self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_not_released(vm).map(|_| self.desc.readonly)
}
#[pygetset]
fn itemsize(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm).map(|_| self.desc.itemsize)
}
#[pygetset]
fn ndim(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm).map(|_| self.desc.ndim())
}
#[pygetset]
fn shape(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
self.try_not_released(vm)?;
Ok(vm.ctx.new_tuple(
self.desc
.dim_desc
.iter()
.map(|(shape, _, _)| shape.to_pyobject(vm))
.collect(),
))
}
#[pygetset]
fn strides(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
self.try_not_released(vm)?;
Ok(vm.ctx.new_tuple(
self.desc
.dim_desc
.iter()
.map(|(_, stride, _)| stride.to_pyobject(vm))
.collect(),
))
}
#[pygetset]
fn suboffsets(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
self.try_not_released(vm)?;
Ok(vm.ctx.new_tuple(
self.desc
.dim_desc
.iter()
.map(|(_, _, suboffset)| suboffset.to_pyobject(vm))
.collect(),
))
}
#[pygetset]
fn format(&self, vm: &VirtualMachine) -> PyResult<PyStr> {
self.try_not_released(vm)
.map(|_| PyStr::from(self.desc.format.clone()))
}
#[pygetset]
fn contiguous(&self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_not_released(vm).map(|_| self.desc.is_contiguous())
}
#[pygetset]
fn c_contiguous(&self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_not_released(vm).map(|_| self.desc.is_contiguous())
}
#[pygetset]
fn f_contiguous(&self, vm: &VirtualMachine) -> PyResult<bool> {
// TODO: fortain order
self.try_not_released(vm)
.map(|_| self.desc.ndim() <= 1 && self.desc.is_contiguous())
}
#[pymethod(magic)]
fn enter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
zelf.try_not_released(vm).map(|_| zelf)
}
#[pymethod(magic)]
fn exit(&self, _args: FuncArgs) {
self.release();
}
fn getitem_by_idx(&self, i: isize, vm: &VirtualMachine) -> PyResult {
if self.desc.ndim() != 1 {
return Err(vm.new_not_implemented_error(
@@ -281,29 +170,6 @@ impl PyMemoryView {
format_unpack(&self.format_spec, &bytes[pos..pos + self.desc.itemsize], vm)
}
#[pymethod(magic)]
fn getitem(zelf: PyRef<Self>, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
zelf.try_not_released(vm)?;
if zelf.desc.ndim() == 0 {
// 0-d memoryview can be referenced using mv[...] or mv[()] only
if needle.is(&vm.ctx.ellipsis) {
return Ok(zelf.into());
}
if let Some(tuple) = needle.payload::<PyTuple>() {
if tuple.is_empty() {
return zelf.unpack_single(0, vm);
}
}
return Err(vm.new_type_error("invalid indexing of 0-dim memory".to_owned()));
}
match SubscriptNeedle::try_from_object(vm, needle)? {
SubscriptNeedle::Index(i) => zelf.getitem_by_idx(i, vm),
SubscriptNeedle::Slice(slice) => zelf.getitem_by_slice(&slice, vm),
SubscriptNeedle::MultiIndex(indices) => zelf.getitem_by_multi_idx(&indices, vm),
}
}
fn setitem_by_idx(&self, i: isize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if self.desc.ndim() != 1 {
return Err(vm.new_not_implemented_error("sub-views are not implemented".to_owned()));
@@ -317,60 +183,6 @@ impl PyMemoryView {
self.pack_single(pos, value, vm)
}
fn setitem_by_slice(
zelf: PyRef<Self>,
slice: &PySlice,
src: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
if zelf.desc.ndim() != 1 {
return Err(vm.new_not_implemented_error("sub-view are not implemented".to_owned()));
}
let mut dest = zelf.new_view();
dest.init_slice(slice, 0, vm)?;
dest.init_len();
if zelf.is(&src) {
return if !is_equiv_structure(&zelf.desc, &dest.desc) {
Err(vm.new_value_error(
"memoryview assignment: lvalue and rvalue have different structures".to_owned(),
))
} else {
// assign self[:] to self
Ok(())
};
};
let src = if let Some(src) = src.downcast_ref::<PyMemoryView>() {
if zelf.buffer.obj.is(&src.buffer.obj) {
src.to_contiguous(vm)
} else {
AsBuffer::as_buffer(src, vm)?
}
} else {
PyBuffer::try_from_object(vm, src)?
};
if !is_equiv_structure(&src.desc, &dest.desc) {
return Err(vm.new_value_error(
"memoryview assignment: lvalue and rvalue have different structures".to_owned(),
));
}
let mut bytes_mut = dest.buffer.obj_bytes_mut();
let src_bytes = src.obj_bytes();
dest.desc.zip_eq(&src.desc, true, |a_range, b_range| {
let a_range = (a_range.start + dest.start as isize) as usize
..(a_range.end + dest.start as isize) as usize;
let b_range = b_range.start as usize..b_range.end as usize;
bytes_mut[a_range].copy_from_slice(&src_bytes[b_range]);
false
});
Ok(())
}
fn setitem_by_multi_idx(
&self,
indexes: &[isize],
@@ -381,47 +193,6 @@ impl PyMemoryView {
self.pack_single(pos, value, vm)
}
#[pymethod(magic)]
fn delitem(&self, _needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if self.desc.readonly {
return Err(vm.new_type_error("cannot modify read-only memory".to_owned()));
}
Err(vm.new_type_error("cannot delete memory".to_owned()))
}
#[pymethod(magic)]
fn setitem(
zelf: PyRef<Self>,
needle: PyObjectRef,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
zelf.try_not_released(vm)?;
if zelf.desc.readonly {
return Err(vm.new_type_error("cannot modify read-only memory".to_owned()));
}
if value.is(&vm.ctx.none) {
return Err(vm.new_type_error("cannot delete memory".to_owned()));
}
if zelf.desc.ndim() == 0 {
// TODO: merge branches when we got conditional if let
if needle.is(&vm.ctx.ellipsis) {
return zelf.pack_single(0, value, vm);
} else if let Some(tuple) = needle.payload::<PyTuple>() {
if tuple.is_empty() {
return zelf.pack_single(0, value, vm);
}
}
return Err(vm.new_type_error("invalid indexing of 0-dim memory".to_owned()));
}
match SubscriptNeedle::try_from_object(vm, needle)? {
SubscriptNeedle::Index(i) => zelf.setitem_by_idx(i, value, vm),
SubscriptNeedle::Slice(slice) => Self::setitem_by_slice(zelf, &slice, value, vm),
SubscriptNeedle::MultiIndex(indices) => zelf.setitem_by_multi_idx(&indices, value, vm),
}
}
fn pack_single(&self, pos: usize, value: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
let mut bytes = self.buffer.obj_bytes_mut();
// TODO: Optimize
@@ -522,26 +293,6 @@ impl PyMemoryView {
Ok(())
}
/// return the length of the first dimension
#[pymethod(magic)]
fn len(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm)?;
Ok(if self.desc.ndim() == 0 {
1
} else {
// shape for dim[0]
self.desc.dim_desc[0].0
})
}
#[pymethod]
fn tobytes(&self, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
self.try_not_released(vm)?;
let mut v = vec![];
self.append_to(&mut v);
Ok(PyBytes::from(v).into_ref(vm))
}
fn _to_list(
&self,
bytes: &[u8],
@@ -572,6 +323,389 @@ impl PyMemoryView {
Ok(vm.ctx.new_list(v))
}
fn eq(zelf: &Py<Self>, other: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
if zelf.is(other) {
return Ok(true);
}
if zelf.released.load() {
return Ok(false);
}
if let Some(other) = other.payload::<Self>() {
if other.released.load() {
return Ok(false);
}
}
let other = match PyBuffer::try_from_borrowed_object(vm, other) {
Ok(buf) => buf,
Err(_) => return Ok(false),
};
if !is_equiv_shape(&zelf.desc, &other.desc) {
return Ok(false);
}
let a_itemsize = zelf.desc.itemsize;
let b_itemsize = other.desc.itemsize;
let a_format_spec = &zelf.format_spec;
let b_format_spec = &Self::parse_format(&other.desc.format, vm)?;
if zelf.desc.ndim() == 0 {
let a_val = format_unpack(a_format_spec, &zelf.buffer.obj_bytes()[..a_itemsize], vm)?;
let b_val = format_unpack(b_format_spec, &other.obj_bytes()[..b_itemsize], vm)?;
return vm.bool_eq(&a_val, &b_val);
}
// TODO: optimize cmp by format
let mut ret = Ok(true);
let a_bytes = zelf.buffer.obj_bytes();
let b_bytes = other.obj_bytes();
zelf.desc.zip_eq(&other.desc, false, |a_range, b_range| {
let a_range = (a_range.start + zelf.start as isize) as usize
..(a_range.end + zelf.start as isize) as usize;
let b_range = b_range.start as usize..b_range.end as usize;
let a_val = match format_unpack(a_format_spec, &a_bytes[a_range], vm) {
Ok(val) => val,
Err(e) => {
ret = Err(e);
return true;
}
};
let b_val = match format_unpack(b_format_spec, &b_bytes[b_range], vm) {
Ok(val) => val,
Err(e) => {
ret = Err(e);
return true;
}
};
ret = vm.bool_eq(&a_val, &b_val);
if let Ok(b) = ret {
!b
} else {
true
}
});
ret
}
fn obj_bytes(&self) -> BorrowedValue<[u8]> {
if self.desc.is_contiguous() {
BorrowedValue::map(self.buffer.obj_bytes(), |x| {
&x[self.start..self.start + self.desc.len]
})
} else {
BorrowedValue::map(self.buffer.obj_bytes(), |x| &x[self.start..])
}
}
fn obj_bytes_mut(&self) -> BorrowedValueMut<[u8]> {
if self.desc.is_contiguous() {
BorrowedValueMut::map(self.buffer.obj_bytes_mut(), |x| {
&mut x[self.start..self.start + self.desc.len]
})
} else {
BorrowedValueMut::map(self.buffer.obj_bytes_mut(), |x| &mut x[self.start..])
}
}
fn as_contiguous(&self) -> Option<BorrowedValue<[u8]>> {
self.desc.is_contiguous().then(|| {
BorrowedValue::map(self.buffer.obj_bytes(), |x| {
&x[self.start..self.start + self.desc.len]
})
})
}
fn _as_contiguous_mut(&self) -> Option<BorrowedValueMut<[u8]>> {
self.desc.is_contiguous().then(|| {
BorrowedValueMut::map(self.buffer.obj_bytes_mut(), |x| {
&mut x[self.start..self.start + self.desc.len]
})
})
}
fn append_to(&self, buf: &mut Vec<u8>) {
if let Some(bytes) = self.as_contiguous() {
buf.extend_from_slice(&bytes);
} else {
buf.reserve(self.desc.len);
let bytes = &*self.buffer.obj_bytes();
self.desc.for_each_segment(true, |range| {
let start = (range.start + self.start as isize) as usize;
let end = (range.end + self.start as isize) as usize;
buf.extend_from_slice(&bytes[start..end]);
})
}
}
fn contiguous_or_collect<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
let borrowed;
let mut collected;
let v = if let Some(bytes) = self.as_contiguous() {
borrowed = bytes;
&*borrowed
} else {
collected = vec![];
self.append_to(&mut collected);
&collected
};
f(v)
}
/// clone data from memoryview
/// keep the shape, convert to contiguous
pub fn to_contiguous(&self, vm: &VirtualMachine) -> PyBuffer {
let mut data = vec![];
self.append_to(&mut data);
if self.desc.ndim() == 0 {
return VecBuffer::from(data)
.into_ref(vm)
.into_pybuffer_with_descriptor(self.desc.clone());
}
let mut dim_desc = self.desc.dim_desc.clone();
dim_desc.last_mut().unwrap().1 = self.desc.itemsize as isize;
dim_desc.last_mut().unwrap().2 = 0;
for i in (0..dim_desc.len() - 1).rev() {
dim_desc[i].1 = dim_desc[i + 1].1 * dim_desc[i + 1].0 as isize;
dim_desc[i].2 = 0;
}
let desc = BufferDescriptor {
len: self.desc.len,
readonly: self.desc.readonly,
itemsize: self.desc.itemsize,
format: self.desc.format.clone(),
dim_desc,
};
VecBuffer::from(data)
.into_ref(vm)
.into_pybuffer_with_descriptor(desc)
}
}
impl Py<PyMemoryView> {
fn setitem_by_slice(
&self,
slice: &PySlice,
src: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
if self.desc.ndim() != 1 {
return Err(vm.new_not_implemented_error("sub-view are not implemented".to_owned()));
}
let mut dest = self.new_view();
dest.init_slice(slice, 0, vm)?;
dest.init_len();
if self.is(&src) {
return if !is_equiv_structure(&self.desc, &dest.desc) {
Err(vm.new_value_error(
"memoryview assignment: lvalue and rvalue have different structures".to_owned(),
))
} else {
// assign self[:] to self
Ok(())
};
};
let src = if let Some(src) = src.downcast_ref::<PyMemoryView>() {
if self.buffer.obj.is(&src.buffer.obj) {
src.to_contiguous(vm)
} else {
AsBuffer::as_buffer(src, vm)?
}
} else {
PyBuffer::try_from_object(vm, src)?
};
if !is_equiv_structure(&src.desc, &dest.desc) {
return Err(vm.new_value_error(
"memoryview assignment: lvalue and rvalue have different structures".to_owned(),
));
}
let mut bytes_mut = dest.buffer.obj_bytes_mut();
let src_bytes = src.obj_bytes();
dest.desc.zip_eq(&src.desc, true, |a_range, b_range| {
let a_range = (a_range.start + dest.start as isize) as usize
..(a_range.end + dest.start as isize) as usize;
let b_range = b_range.start as usize..b_range.end as usize;
bytes_mut[a_range].copy_from_slice(&src_bytes[b_range]);
false
});
Ok(())
}
}
#[pyclass(with(
Py,
Hashable,
Comparable,
AsBuffer,
AsMapping,
AsSequence,
Constructor,
Iterable,
Representable
))]
impl PyMemoryView {
#[pymethod]
pub fn release(&self) {
if self.released.compare_exchange(false, true).is_ok() {
self.buffer.release();
}
}
#[pygetset]
fn obj(&self, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
self.try_not_released(vm).map(|_| self.buffer.obj.clone())
}
#[pygetset]
fn nbytes(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm).map(|_| self.desc.len)
}
#[pygetset]
fn readonly(&self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_not_released(vm).map(|_| self.desc.readonly)
}
#[pygetset]
fn itemsize(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm).map(|_| self.desc.itemsize)
}
#[pygetset]
fn ndim(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm).map(|_| self.desc.ndim())
}
#[pygetset]
fn shape(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
self.try_not_released(vm)?;
Ok(vm.ctx.new_tuple(
self.desc
.dim_desc
.iter()
.map(|(shape, _, _)| shape.to_pyobject(vm))
.collect(),
))
}
#[pygetset]
fn strides(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
self.try_not_released(vm)?;
Ok(vm.ctx.new_tuple(
self.desc
.dim_desc
.iter()
.map(|(_, stride, _)| stride.to_pyobject(vm))
.collect(),
))
}
#[pygetset]
fn suboffsets(&self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
self.try_not_released(vm)?;
Ok(vm.ctx.new_tuple(
self.desc
.dim_desc
.iter()
.map(|(_, _, suboffset)| suboffset.to_pyobject(vm))
.collect(),
))
}
#[pygetset]
fn format(&self, vm: &VirtualMachine) -> PyResult<PyStr> {
self.try_not_released(vm)
.map(|_| PyStr::from(self.desc.format.clone()))
}
#[pygetset]
fn contiguous(&self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_not_released(vm).map(|_| self.desc.is_contiguous())
}
#[pygetset]
fn c_contiguous(&self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_not_released(vm).map(|_| self.desc.is_contiguous())
}
#[pygetset]
fn f_contiguous(&self, vm: &VirtualMachine) -> PyResult<bool> {
// TODO: fortain order
self.try_not_released(vm)
.map(|_| self.desc.ndim() <= 1 && self.desc.is_contiguous())
}
#[pymethod(magic)]
fn enter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
zelf.try_not_released(vm).map(|_| zelf)
}
#[pymethod(magic)]
fn exit(&self, _args: FuncArgs) {
self.release();
}
#[pymethod(magic)]
fn getitem(zelf: PyRef<Self>, needle: PyObjectRef, vm: &VirtualMachine) -> PyResult {
zelf.try_not_released(vm)?;
if zelf.desc.ndim() == 0 {
// 0-d memoryview can be referenced using mv[...] or mv[()] only
if needle.is(&vm.ctx.ellipsis) {
return Ok(zelf.into());
}
if let Some(tuple) = needle.payload::<PyTuple>() {
if tuple.is_empty() {
return zelf.unpack_single(0, vm);
}
}
return Err(vm.new_type_error("invalid indexing of 0-dim memory".to_owned()));
}
match SubscriptNeedle::try_from_object(vm, needle)? {
SubscriptNeedle::Index(i) => zelf.getitem_by_idx(i, vm),
SubscriptNeedle::Slice(slice) => zelf.getitem_by_slice(&slice, vm),
SubscriptNeedle::MultiIndex(indices) => zelf.getitem_by_multi_idx(&indices, vm),
}
}
#[pymethod(magic)]
fn delitem(&self, _needle: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> {
if self.desc.readonly {
return Err(vm.new_type_error("cannot modify read-only memory".to_owned()));
}
Err(vm.new_type_error("cannot delete memory".to_owned()))
}
#[pymethod(magic)]
fn len(&self, vm: &VirtualMachine) -> PyResult<usize> {
self.try_not_released(vm)?;
Ok(if self.desc.ndim() == 0 {
1
} else {
// shape for dim[0]
self.desc.dim_desc[0].0
})
}
#[pymethod]
fn tobytes(&self, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
self.try_not_released(vm)?;
let mut v = vec![];
self.append_to(&mut v);
Ok(PyBytes::from(v).into_ref(vm))
}
#[pymethod]
fn tolist(&self, vm: &VirtualMachine) -> PyResult<PyListRef> {
self.try_not_released(vm)?;
@@ -714,178 +848,51 @@ impl PyMemoryView {
Ok(self.cast_to_1d(format, vm)?.into_ref(vm))
}
}
}
fn eq(zelf: &Py<Self>, other: &PyObject, vm: &VirtualMachine) -> PyResult<bool> {
if zelf.is(other) {
return Ok(true);
}
if zelf.released.load() {
return Ok(false);
}
if let Some(other) = other.payload::<Self>() {
if other.released.load() {
return Ok(false);
}
}
let other = match PyBuffer::try_from_borrowed_object(vm, other) {
Ok(buf) => buf,
Err(_) => return Ok(false),
};
if !is_equiv_shape(&zelf.desc, &other.desc) {
return Ok(false);
}
let a_itemsize = zelf.desc.itemsize;
let b_itemsize = other.desc.itemsize;
let a_format_spec = &zelf.format_spec;
let b_format_spec = &Self::parse_format(&other.desc.format, vm)?;
if zelf.desc.ndim() == 0 {
let a_val = format_unpack(a_format_spec, &zelf.buffer.obj_bytes()[..a_itemsize], vm)?;
let b_val = format_unpack(b_format_spec, &other.obj_bytes()[..b_itemsize], vm)?;
return vm.bool_eq(&a_val, &b_val);
}
// TODO: optimize cmp by format
let mut ret = Ok(true);
let a_bytes = zelf.buffer.obj_bytes();
let b_bytes = other.obj_bytes();
zelf.desc.zip_eq(&other.desc, false, |a_range, b_range| {
let a_range = (a_range.start + zelf.start as isize) as usize
..(a_range.end + zelf.start as isize) as usize;
let b_range = b_range.start as usize..b_range.end as usize;
let a_val = match format_unpack(a_format_spec, &a_bytes[a_range], vm) {
Ok(val) => val,
Err(e) => {
ret = Err(e);
return true;
}
};
let b_val = match format_unpack(b_format_spec, &b_bytes[b_range], vm) {
Ok(val) => val,
Err(e) => {
ret = Err(e);
return true;
}
};
ret = vm.bool_eq(&a_val, &b_val);
if let Ok(b) = ret {
!b
} else {
true
}
});
ret
}
#[pyclass]
impl Py<PyMemoryView> {
#[pymethod(magic)]
fn reduce_ex(zelf: PyRef<Self>, _proto: usize, vm: &VirtualMachine) -> PyResult {
Self::reduce(zelf, vm)
}
#[pymethod(magic)]
fn reduce(_zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
Err(vm.new_type_error("cannot pickle 'memoryview' object".to_owned()))
}
fn obj_bytes(&self) -> BorrowedValue<[u8]> {
if self.desc.is_contiguous() {
BorrowedValue::map(self.buffer.obj_bytes(), |x| {
&x[self.start..self.start + self.desc.len]
})
} else {
BorrowedValue::map(self.buffer.obj_bytes(), |x| &x[self.start..])
fn setitem(
&self,
needle: PyObjectRef,
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
self.try_not_released(vm)?;
if self.desc.readonly {
return Err(vm.new_type_error("cannot modify read-only memory".to_owned()));
}
}
fn obj_bytes_mut(&self) -> BorrowedValueMut<[u8]> {
if self.desc.is_contiguous() {
BorrowedValueMut::map(self.buffer.obj_bytes_mut(), |x| {
&mut x[self.start..self.start + self.desc.len]
})
} else {
BorrowedValueMut::map(self.buffer.obj_bytes_mut(), |x| &mut x[self.start..])
if value.is(&vm.ctx.none) {
return Err(vm.new_type_error("cannot delete memory".to_owned()));
}
}
fn as_contiguous(&self) -> Option<BorrowedValue<[u8]>> {
self.desc.is_contiguous().then(|| {
BorrowedValue::map(self.buffer.obj_bytes(), |x| {
&x[self.start..self.start + self.desc.len]
})
})
}
fn _as_contiguous_mut(&self) -> Option<BorrowedValueMut<[u8]>> {
self.desc.is_contiguous().then(|| {
BorrowedValueMut::map(self.buffer.obj_bytes_mut(), |x| {
&mut x[self.start..self.start + self.desc.len]
})
})
}
fn append_to(&self, buf: &mut Vec<u8>) {
if let Some(bytes) = self.as_contiguous() {
buf.extend_from_slice(&bytes);
} else {
buf.reserve(self.desc.len);
let bytes = &*self.buffer.obj_bytes();
self.desc.for_each_segment(true, |range| {
let start = (range.start + self.start as isize) as usize;
let end = (range.end + self.start as isize) as usize;
buf.extend_from_slice(&bytes[start..end]);
})
}
}
fn contiguous_or_collect<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
let borrowed;
let mut collected;
let v = if let Some(bytes) = self.as_contiguous() {
borrowed = bytes;
&*borrowed
} else {
collected = vec![];
self.append_to(&mut collected);
&collected
};
f(v)
}
/// clone data from memoryview
/// keep the shape, convert to contiguous
pub fn to_contiguous(&self, vm: &VirtualMachine) -> PyBuffer {
let mut data = vec![];
self.append_to(&mut data);
if self.desc.ndim() == 0 {
return VecBuffer::from(data)
.into_ref(vm)
.into_pybuffer_with_descriptor(self.desc.clone());
// TODO: merge branches when we got conditional if let
if needle.is(&vm.ctx.ellipsis) {
return self.pack_single(0, value, vm);
} else if let Some(tuple) = needle.payload::<PyTuple>() {
if tuple.is_empty() {
return self.pack_single(0, value, vm);
}
}
return Err(vm.new_type_error("invalid indexing of 0-dim memory".to_owned()));
}
let mut dim_desc = self.desc.dim_desc.clone();
dim_desc.last_mut().unwrap().1 = self.desc.itemsize as isize;
dim_desc.last_mut().unwrap().2 = 0;
for i in (0..dim_desc.len() - 1).rev() {
dim_desc[i].1 = dim_desc[i + 1].1 * dim_desc[i + 1].0 as isize;
dim_desc[i].2 = 0;
match SubscriptNeedle::try_from_object(vm, needle)? {
SubscriptNeedle::Index(i) => self.setitem_by_idx(i, value, vm),
SubscriptNeedle::Slice(slice) => self.setitem_by_slice(&slice, value, vm),
SubscriptNeedle::MultiIndex(indices) => self.setitem_by_multi_idx(&indices, value, vm),
}
}
let desc = BufferDescriptor {
len: self.desc.len,
readonly: self.desc.readonly,
itemsize: self.desc.itemsize,
format: self.desc.format.clone(),
dim_desc,
};
#[pymethod(magic)]
fn reduce_ex(&self, _proto: usize, vm: &VirtualMachine) -> PyResult {
self.reduce(vm)
}
VecBuffer::from(data)
.into_ref(vm)
.into_pybuffer_with_descriptor(desc)
#[pymethod(magic)]
fn reduce(&self, vm: &VirtualMachine) -> PyResult {
Err(vm.new_type_error("cannot pickle 'memoryview' object".to_owned()))
}
}
@@ -977,7 +984,7 @@ impl AsMapping for PyMemoryView {
ass_subscript: atomic_func!(|mapping, needle, value, vm| {
let zelf = PyMemoryView::mapping_downcast(mapping);
if let Some(value) = value {
PyMemoryView::setitem(zelf.to_owned(), needle.to_owned(), value, vm)
zelf.setitem(needle.to_owned(), value, vm)
} else {
Err(vm.new_type_error("cannot delete memory".to_owned()))
}
+2 -2
View File
@@ -42,8 +42,8 @@ use unic_ucd_category::GeneralCategory;
use unic_ucd_ident::{is_xid_continue, is_xid_start};
use unicode_casing::CharExt;
impl TryFromBorrowedObject for String {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for String {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
obj.try_value_with(|pystr: &PyStr| Ok(pystr.as_str().to_owned()), vm)
}
}
+66 -63
View File
@@ -355,6 +355,31 @@ impl PyType {
attributes
}
// bound method for every type
pub(crate) fn __new__(zelf: PyRef<PyType>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
let (subtype, args): (PyRef<Self>, FuncArgs) = args.bind(vm)?;
if !subtype.fast_issubclass(&zelf) {
return Err(vm.new_type_error(format!(
"{zelf}.__new__({subtype}): {subtype} is not a subtype of {zelf}",
zelf = zelf.name(),
subtype = subtype.name(),
)));
}
call_slot_new(zelf, subtype, args, vm)
}
pub fn name(&self) -> BorrowedValue<str> {
PyRwLockReadGuard::map(self.slots.name.read(), |slot_name| {
let name = slot_name.as_ref().unwrap();
if self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
name.as_str()
} else {
name.rsplit('.').next().unwrap()
}
})
.into()
}
}
impl Py<PyType> {
@@ -375,30 +400,10 @@ impl Py<PyType> {
}
#[pyclass(
with(GetAttr, SetAttr, Callable, AsNumber, Representable),
with(Py, GetAttr, SetAttr, Callable, AsNumber, Representable),
flags(BASETYPE)
)]
impl PyType {
// bound method for every type
pub(crate) fn __new__(zelf: PyRef<Self>, args: FuncArgs, vm: &VirtualMachine) -> PyResult {
let (subtype, args): (PyRef<Self>, FuncArgs) = args.bind(vm)?;
if !subtype.fast_issubclass(&zelf) {
return Err(vm.new_type_error(format!(
"{zelf}.__new__({subtype}): {subtype} is not a subtype of {zelf}",
zelf = zelf.name(),
subtype = subtype.name(),
)));
}
call_slot_new(zelf, subtype, args, vm)
}
#[pygetset(name = "__mro__")]
fn get_mro(zelf: PyRef<Self>) -> PyTuple {
let elements: Vec<PyObjectRef> =
zelf.iter_mro().map(|x| x.as_object().to_owned()).collect();
PyTuple::new_unchecked(elements.into_boxed_slice())
}
#[pygetset(magic)]
fn bases(&self, vm: &VirtualMachine) -> PyTupleRef {
vm.ctx.new_tuple(
@@ -419,48 +424,11 @@ impl PyType {
self.slots.flags.bits()
}
#[pymethod(magic)]
fn dir(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyList {
let attributes: Vec<PyObjectRef> = zelf
.get_attributes()
.into_iter()
.map(|(k, _)| k.to_object())
.collect();
PyList::from(attributes)
}
#[pymethod(magic)]
fn instancecheck(zelf: PyRef<Self>, obj: PyObjectRef) -> bool {
obj.fast_isinstance(&zelf)
}
#[pymethod(magic)]
fn subclasscheck(zelf: PyRef<Self>, subclass: PyTypeRef) -> bool {
subclass.fast_issubclass(&zelf)
}
#[pyclassmethod(magic)]
fn subclasshook(_args: FuncArgs, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.not_implemented()
}
#[pygetset]
fn __name__(&self) -> String {
self.name().to_string()
}
pub fn name(&self) -> BorrowedValue<str> {
PyRwLockReadGuard::map(self.slots.name.read(), |slot_name| {
let name = slot_name.as_ref().unwrap();
if self.slots.flags.has_feature(PyTypeFlags::HEAPTYPE) {
name.as_str()
} else {
name.rsplit('.').next().unwrap()
}
})
.into()
}
#[pygetset(magic)]
pub fn qualname(&self, vm: &VirtualMachine) -> PyObjectRef {
self.attributes
@@ -607,11 +575,6 @@ impl PyType {
)
}
#[pymethod]
fn mro(zelf: PyRef<Self>) -> Vec<PyObjectRef> {
zelf.iter_mro().map(|cls| cls.to_owned().into()).collect()
}
#[pymethod(magic)]
pub fn ror(zelf: PyObjectRef, other: PyObjectRef, vm: &VirtualMachine) -> PyObjectRef {
or_(other, zelf, vm)
@@ -906,6 +869,46 @@ impl PyType {
}
}
#[pyclass]
impl Py<PyType> {
#[pygetset(name = "__mro__")]
fn get_mro(&self) -> PyTuple {
let elements: Vec<PyObjectRef> =
self.iter_mro().map(|x| x.as_object().to_owned()).collect();
PyTuple::new_unchecked(elements.into_boxed_slice())
}
#[pymethod(magic)]
fn dir(&self) -> PyList {
let attributes: Vec<PyObjectRef> = self
.get_attributes()
.into_iter()
.map(|(k, _)| k.to_object())
.collect();
PyList::from(attributes)
}
#[pymethod(magic)]
fn instancecheck(&self, obj: PyObjectRef) -> bool {
obj.fast_isinstance(self)
}
#[pymethod(magic)]
fn subclasscheck(&self, subclass: PyTypeRef) -> bool {
subclass.fast_issubclass(self)
}
#[pyclassmethod(magic)]
fn subclasshook(_args: FuncArgs, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.not_implemented()
}
#[pymethod]
fn mro(&self) -> Vec<PyObjectRef> {
self.iter_mro().map(|cls| cls.to_owned().into()).collect()
}
}
const SIGNATURE_END_MARKER: &str = ")\n--\n\n";
fn get_signature(doc: &str) -> Option<&str> {
doc.find(SIGNATURE_END_MARKER).map(|index| &doc[..=index])
+2 -2
View File
@@ -30,8 +30,8 @@ impl From<Vec<u8>> for PyBytesInner {
}
}
impl TryFromBorrowedObject for PyBytesInner {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for PyBytesInner {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
bytes_from_object(vm, obj).map(Self::from)
}
}
+1 -13
View File
@@ -3,7 +3,7 @@
use crate::{
builtins::{PyBaseObject, PyBoundMethod, PyType, PyTypeRef},
identifier,
object::{Py, PyObjectPayload, PyObjectRef, PyRef},
object::{Py, PyObjectRef},
types::{hash_not_implemented, PyTypeFlags, PyTypeSlots},
vm::Context,
};
@@ -63,18 +63,6 @@ pub trait PyClassDef {
const UNHASHABLE: bool = false;
}
impl<T> PyClassDef for PyRef<T>
where
T: PyObjectPayload + PyClassDef,
{
const NAME: &'static str = T::NAME;
const MODULE_NAME: Option<&'static str> = T::MODULE_NAME;
const TP_NAME: &'static str = T::TP_NAME;
const DOC: Option<&'static str> = T::DOC;
const BASICSIZE: usize = T::BASICSIZE;
const UNHASHABLE: bool = T::UNHASHABLE;
}
pub trait PyClassImpl: PyClassDef {
const TP_FLAGS: PyTypeFlags = PyTypeFlags::DEFAULT;
+23 -8
View File
@@ -1,7 +1,7 @@
use crate::{
builtins::PyFloat,
object::{AsObject, PyObject, PyObjectRef, PyPayload, PyRef, PyResult},
vm::VirtualMachine,
Py, VirtualMachine,
};
use num_traits::ToPrimitive;
@@ -15,7 +15,7 @@ pub trait TryFromObject: Sized {
}
/// Rust-side only version of TryFromObject to reduce unnecessary Rc::clone
impl<T: TryFromBorrowedObject> TryFromObject for T {
impl<T: for<'a> TryFromBorrowedObject<'a>> TryFromObject for T {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
TryFromBorrowedObject::try_from_borrowed_object(vm, &obj)
}
@@ -31,9 +31,9 @@ impl PyObjectRef {
}
impl PyObject {
pub fn try_to_value<T>(&self, vm: &VirtualMachine) -> PyResult<T>
pub fn try_to_value<'a, T: 'a>(&'a self, vm: &VirtualMachine) -> PyResult<T>
where
T: TryFromBorrowedObject,
T: TryFromBorrowedObject<'a>,
{
T::try_from_borrowed_object(vm, self)
}
@@ -55,9 +55,12 @@ impl PyObject {
}
/// Lower-cost variation of `TryFromObject`
pub trait TryFromBorrowedObject: Sized {
pub trait TryFromBorrowedObject<'a>: Sized
where
Self: 'a,
{
/// Attempt to convert a Python object to a value of this type.
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self>;
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self>;
}
impl<T> TryFromObject for PyRef<T>
@@ -93,12 +96,24 @@ impl<T: TryFromObject> TryFromObject for Option<T> {
}
}
impl<T: TryFromObject> TryFromBorrowedObject for Vec<T> {
fn try_from_borrowed_object(vm: &VirtualMachine, value: &PyObject) -> PyResult<Self> {
impl<'a, T: 'a + TryFromObject> TryFromBorrowedObject<'a> for Vec<T> {
fn try_from_borrowed_object(vm: &VirtualMachine, value: &'a PyObject) -> PyResult<Self> {
vm.extract_elements_with(value, |obj| T::try_from_object(vm, obj))
}
}
impl<'a, T: PyPayload> TryFromBorrowedObject<'a> for &'a Py<T> {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let class = T::class(vm);
if obj.fast_isinstance(class) {
obj.downcast_ref()
.ok_or_else(|| vm.new_downcast_runtime_error(class, &obj))
} else {
Err(vm.new_downcast_type_error(class, &obj))
}
}
}
impl TryFromObject for std::time::Duration {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
use std::time::Duration;
+41 -37
View File
@@ -164,24 +164,20 @@ impl Frame {
temporary_refs: PyMutex::new(vec![]),
}
}
}
impl FrameRef {
#[inline(always)]
fn with_exec<R>(&self, f: impl FnOnce(ExecutingFrame) -> R) -> R {
let mut state = self.state.lock();
let exec = ExecutingFrame {
code: &self.code,
fastlocals: &self.fastlocals,
cells_frees: &self.cells_frees,
locals: &self.locals,
globals: &self.globals,
builtins: &self.builtins,
lasti: &self.lasti,
object: self,
state: &mut state,
};
f(exec)
pub fn current_location(&self) -> bytecode::Location {
self.code.locations[self.lasti() as usize - 1]
}
pub fn lasti(&self) -> u32 {
#[cfg(feature = "threading")]
{
self.lasti.load(atomic::Ordering::Relaxed)
}
#[cfg(not(feature = "threading"))]
{
self.lasti.get()
}
}
pub fn locals(&self, vm: &VirtualMachine) -> PyResult<ArgMapping> {
@@ -221,6 +217,25 @@ impl FrameRef {
}
Ok(locals.clone())
}
}
impl Py<Frame> {
#[inline(always)]
fn with_exec<R>(&self, f: impl FnOnce(ExecutingFrame) -> R) -> R {
let mut state = self.state.lock();
let exec = ExecutingFrame {
code: &self.code,
fastlocals: &self.fastlocals,
cells_frees: &self.cells_frees,
locals: &self.locals,
globals: &self.globals,
builtins: &self.builtins,
lasti: &self.lasti,
object: self,
state: &mut state,
};
f(exec)
}
// #[cfg_attr(feature = "flame-it", flame("Frame"))]
pub fn run(&self, vm: &VirtualMachine) -> PyResult<ExecutionResult> {
@@ -250,34 +265,19 @@ impl FrameRef {
self.with_exec(|mut exec| exec.gen_throw(vm, exc_type, exc_val, exc_tb))
}
pub fn current_location(&self) -> bytecode::Location {
self.code.locations[self.lasti() as usize - 1]
}
pub fn yield_from_target(&self) -> Option<PyObjectRef> {
self.with_exec(|exec| exec.yield_from_target().map(PyObject::to_owned))
}
pub fn lasti(&self) -> u32 {
#[cfg(feature = "threading")]
{
self.lasti.load(atomic::Ordering::Relaxed)
}
#[cfg(not(feature = "threading"))]
{
self.lasti.get()
}
}
pub fn is_internal_frame(&self) -> bool {
let code = self.clone().f_code();
let code = self.f_code();
let filename = code.co_filename();
filename.as_str().contains("importlib") && filename.as_str().contains("_bootstrap")
}
pub fn next_external_frame(&self, vm: &VirtualMachine) -> Option<FrameRef> {
self.clone().f_back(vm).map(|mut back| loop {
self.f_back(vm).map(|mut back| loop {
back = if let Some(back) = back.to_owned().f_back(vm) {
back
} else {
@@ -300,7 +300,7 @@ struct ExecutingFrame<'a> {
locals: &'a ArgMapping,
globals: &'a PyDictRef,
builtins: &'a PyDictRef,
object: &'a FrameRef,
object: &'a Py<Frame>,
lasti: &'a Lasti,
state: &'a mut FrameState,
}
@@ -376,8 +376,12 @@ impl ExecutingFrame<'_> {
let loc = frame.code.locations[idx];
let next = exception.traceback();
let new_traceback =
PyTraceback::new(next, frame.object.clone(), frame.lasti(), loc.row());
let new_traceback = PyTraceback::new(
next,
frame.object.to_owned(),
frame.lasti(),
loc.row(),
);
vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, loc.row());
exception.set_traceback(Some(new_traceback.into_ref(vm)));
+4 -4
View File
@@ -65,8 +65,8 @@ impl From<ArgBytesLike> for PyBuffer {
}
}
impl TryFromBorrowedObject for ArgBytesLike {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for ArgBytesLike {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let buffer = PyBuffer::try_from_borrowed_object(vm, obj)?;
if buffer.desc.is_contiguous() {
Ok(Self(buffer))
@@ -107,8 +107,8 @@ impl From<ArgMemoryBuffer> for PyBuffer {
}
}
impl TryFromBorrowedObject for ArgMemoryBuffer {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for ArgMemoryBuffer {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let buffer = PyBuffer::try_from_borrowed_object(vm, obj)?;
if !buffer.desc.is_contiguous() {
Err(vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()))
+32 -1
View File
@@ -1,6 +1,7 @@
use super::{FromArgs, FuncArgs};
use crate::{
convert::ToPyResult, object::PyThreadingConstraint, PyPayload, PyRef, PyResult, VirtualMachine,
convert::ToPyResult, object::PyThreadingConstraint, Py, PyPayload, PyRef, PyResult,
VirtualMachine,
};
use std::marker::PhantomData;
@@ -59,6 +60,8 @@ use sealed::PyNativeFuncInternal;
#[doc(hidden)]
pub struct OwnedParam<T>(PhantomData<T>);
#[doc(hidden)]
pub struct BorrowedParam<T>(PhantomData<T>);
#[doc(hidden)]
pub struct RefParam<T>(PhantomData<T>);
// This is the "magic" that allows rust functions of varying signatures to
@@ -80,6 +83,20 @@ macro_rules! into_py_native_func_tuple {
}
}
impl<F, S, $($T,)* R> PyNativeFuncInternal<(BorrowedParam<S>, $(OwnedParam<$T>,)*), R, VirtualMachine> for F
where
F: Fn(&Py<S>, $($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
S: PyPayload,
$($T: FromArgs,)*
R: ToPyResult,
{
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
(self)(&zelf, $($n,)* vm).to_pyresult(vm)
}
}
impl<F, S, $($T,)* R> PyNativeFuncInternal<(RefParam<S>, $(OwnedParam<$T>,)*), R, VirtualMachine> for F
where
F: Fn(&S, $($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
@@ -107,6 +124,20 @@ macro_rules! into_py_native_func_tuple {
}
}
impl<F, S, $($T,)* R> PyNativeFuncInternal<(BorrowedParam<S>, $(OwnedParam<$T>,)*), R, ()> for F
where
F: Fn(&Py<S>, $($T,)*) -> R + PyThreadingConstraint + 'static,
S: PyPayload,
$($T: FromArgs,)*
R: ToPyResult,
{
fn call_(&self, vm: &VirtualMachine, args: FuncArgs) -> PyResult {
let (zelf, $($n,)*) = args.bind::<(PyRef<S>, $($T,)*)>(vm)?;
(self)(&zelf, $($n,)*).to_pyresult(vm)
}
}
impl<F, S, $($T,)* R> PyNativeFuncInternal<(RefParam<S>, $(OwnedParam<$T>,)*), R, ()> for F
where
F: Fn(&S, $($T,)*) -> R + PyThreadingConstraint + 'static,
+54 -2
View File
@@ -3,9 +3,9 @@
*/
use crate::{
convert::ToPyResult,
function::{OwnedParam, RefParam},
function::{BorrowedParam, OwnedParam, RefParam},
object::PyThreadingConstraint,
PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
Py, PyObjectRef, PyPayload, PyRef, PyResult, TryFromObject, VirtualMachine,
};
#[derive(result_like::OptionLike, is_macro::Is, Debug)]
@@ -74,6 +74,18 @@ where
}
}
impl<F, S, R> IntoPyGetterFunc<(BorrowedParam<S>, R, VirtualMachine)> for F
where
F: Fn(&Py<S>, &VirtualMachine) -> R + 'static + Send + Sync,
S: PyPayload,
R: ToPyResult,
{
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
(self)(&zelf, vm).to_pyresult(vm)
}
}
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R, VirtualMachine)> for F
where
F: Fn(&S, &VirtualMachine) -> R + 'static + Send + Sync,
@@ -98,6 +110,18 @@ where
}
}
impl<F, S, R> IntoPyGetterFunc<(BorrowedParam<S>, R)> for F
where
F: Fn(&Py<S>) -> R + 'static + Send + Sync,
S: PyPayload,
R: ToPyResult,
{
fn get(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
(self)(&zelf).to_pyresult(vm)
}
}
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R)> for F
where
F: Fn(&S) -> R + 'static + Send + Sync,
@@ -149,6 +173,20 @@ where
}
}
impl<F, S, V, R> IntoPySetterFunc<(BorrowedParam<S>, V, R, VirtualMachine)> for F
where
F: Fn(&Py<S>, V, &VirtualMachine) -> R + 'static + Send + Sync,
S: PyPayload,
V: FromPySetterValue,
R: IntoPyNoResult,
{
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
let value = V::from_setter_value(vm, value)?;
(self)(&zelf, value, vm).into_noresult()
}
}
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R, VirtualMachine)> for F
where
F: Fn(&S, V, &VirtualMachine) -> R + 'static + Send + Sync,
@@ -177,6 +215,20 @@ where
}
}
impl<F, S, V, R> IntoPySetterFunc<(BorrowedParam<S>, V, R)> for F
where
F: Fn(&Py<S>, V) -> R + 'static + Send + Sync,
S: PyPayload,
V: FromPySetterValue,
R: IntoPyNoResult,
{
fn set(&self, obj: PyObjectRef, value: PySetterValue, vm: &VirtualMachine) -> PyResult<()> {
let zelf = PyRef::<S>::try_from_object(vm, obj)?;
let value = V::from_setter_value(vm, value)?;
(self)(&zelf, value).into_noresult()
}
}
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R)> for F
where
F: Fn(&S, V) -> R + 'static + Send + Sync,
+4 -3
View File
@@ -13,7 +13,8 @@ pub use argument::{
};
pub use arithmetic::{PyArithmeticValue, PyComparisonValue};
pub use buffer::{ArgAsciiBuffer, ArgBytesLike, ArgMemoryBuffer, ArgStrOrBytesLike};
pub use builtin::{IntoPyNativeFunc, OwnedParam, PyNativeFunc, RefParam};
pub(self) use builtin::{BorrowedParam, OwnedParam, RefParam};
pub use builtin::{IntoPyNativeFunc, PyNativeFunc};
pub use either::Either;
pub use getset::PySetterValue;
pub(super) use getset::{IntoPyGetterFunc, IntoPySetterFunc, PyGetterFunc, PySetterFunc};
@@ -28,8 +29,8 @@ pub enum ArgByteOrder {
Little,
}
impl TryFromBorrowedObject for ArgByteOrder {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for ArgByteOrder {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
obj.try_value_with(
|s: &PyStr| match s.as_str() {
"big" => Ok(Self::Big),
+1 -1
View File
@@ -385,7 +385,7 @@ impl Drop for PyWeak {
}
}
impl PyRef<PyWeak> {
impl Py<PyWeak> {
#[inline(always)]
pub fn upgrade(&self) -> Option<PyObjectRef> {
PyWeak::upgrade(self)
+2 -2
View File
@@ -136,8 +136,8 @@ impl PyBuffer {
}
}
impl TryFromBorrowedObject for PyBuffer {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for PyBuffer {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
let cls = obj.class();
let as_buffer = cls.mro_find_map(|cls| cls.slots.as_buffer);
if let Some(f) = as_buffer {
+51 -67
View File
@@ -3065,8 +3065,6 @@ mod _io {
closed: AtomicCell<bool>,
}
type StringIORef = PyRef<StringIO>;
#[derive(FromArgs)]
struct StringIONewArgs {
#[pyarg(positional, optional)]
@@ -3100,7 +3098,6 @@ mod _io {
}
}
#[pyclass(flags(BASETYPE, HAS_DICT), with(PyRef, Constructor))]
impl StringIO {
fn buffer(&self, vm: &VirtualMachine) -> PyResult<PyRwLockWriteGuard<'_, BufferedIO>> {
if !self.closed.load() {
@@ -3109,7 +3106,10 @@ mod _io {
Err(io_closed_error(vm))
}
}
}
#[pyclass(flags(BASETYPE, HAS_DICT), with(Constructor))]
impl StringIO {
#[pymethod]
fn readable(&self) -> bool {
true
@@ -3132,34 +3132,28 @@ mod _io {
fn close(&self) {
self.closed.store(true);
}
}
#[pyclass]
impl StringIORef {
//write string to underlying vector
// write string to underlying vector
#[pymethod]
fn write(self, data: PyStrRef, vm: &VirtualMachine) -> PyResult {
fn write(&self, data: PyStrRef, vm: &VirtualMachine) -> PyResult<u64> {
let bytes = data.as_str().as_bytes();
match self.buffer(vm)?.write(bytes) {
Some(value) => Ok(vm.ctx.new_int(value).into()),
None => Err(vm.new_type_error("Error Writing String".to_owned())),
}
self.buffer(vm)?
.write(bytes)
.ok_or_else(|| vm.new_type_error("Error Writing String".to_owned()))
}
//return the entire contents of the underlying
// return the entire contents of the underlying
#[pymethod]
fn getvalue(self, vm: &VirtualMachine) -> PyResult {
match String::from_utf8(self.buffer(vm)?.getvalue()) {
Ok(result) => Ok(vm.ctx.new_str(result).into()),
Err(_) => Err(vm.new_value_error("Error Retrieving Value".to_owned())),
}
fn getvalue(&self, vm: &VirtualMachine) -> PyResult<String> {
let bytes = self.buffer(vm)?.getvalue();
String::from_utf8(bytes)
.map_err(|_| vm.new_value_error("Error Retrieving Value".to_owned()))
}
//skip to the jth position
// skip to the jth position
#[pymethod]
fn seek(
self,
&self,
offset: PyObjectRef,
how: OptionalArg<i32>,
vm: &VirtualMachine,
@@ -3169,38 +3163,34 @@ mod _io {
.map_err(|err| os_err(vm, err))
}
//Read k bytes from the object and return.
//If k is undefined || k == -1, then we read all bytes until the end of the file.
//This also increments the stream position by the value of k
// Read k bytes from the object and return.
// If k is undefined || k == -1, then we read all bytes until the end of the file.
// This also increments the stream position by the value of k
#[pymethod]
fn read(self, size: OptionalSize, vm: &VirtualMachine) -> PyResult {
let data = match self.buffer(vm)?.read(size.to_usize()) {
Some(value) => value,
None => Vec::new(),
};
fn read(&self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<String> {
let data = self.buffer(vm)?.read(size.to_usize()).unwrap_or_default();
let value = String::from_utf8(data)
.map_err(|_| vm.new_value_error("Error Retrieving Value".to_owned()))?;
Ok(vm.ctx.new_str(value).into())
Ok(value)
}
#[pymethod]
fn tell(self, vm: &VirtualMachine) -> PyResult<u64> {
fn tell(&self, vm: &VirtualMachine) -> PyResult<u64> {
Ok(self.buffer(vm)?.tell())
}
#[pymethod]
fn readline(self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<String> {
fn readline(&self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<String> {
// TODO size should correspond to the number of characters, at the moments its the number of
// bytes.
match String::from_utf8(self.buffer(vm)?.readline(size.to_usize(), vm)?) {
Ok(value) => Ok(value),
Err(_) => Err(vm.new_value_error("Error Retrieving Value".to_owned())),
}
let input = self.buffer(vm)?.readline(size.to_usize(), vm)?;
String::from_utf8(input)
.map_err(|_| vm.new_value_error("Error Retrieving Value".to_owned()))
}
#[pymethod]
fn truncate(self, pos: OptionalSize, vm: &VirtualMachine) -> PyResult<usize> {
fn truncate(&self, pos: OptionalSize, vm: &VirtualMachine) -> PyResult<usize> {
let mut buffer = self.buffer(vm)?;
let pos = pos.try_usize(vm)?;
Ok(buffer.truncate(pos))
@@ -3216,8 +3206,6 @@ mod _io {
exports: AtomicCell<usize>,
}
type BytesIORef = PyRef<BytesIO>;
impl Constructor for BytesIO {
type Args = OptionalArg<Option<PyBytesRef>>;
@@ -3236,7 +3224,6 @@ mod _io {
}
}
#[pyclass(flags(BASETYPE, HAS_DICT), with(PyRef, Constructor))]
impl BytesIO {
fn buffer(&self, vm: &VirtualMachine) -> PyResult<PyRwLockWriteGuard<'_, BufferedIO>> {
if !self.closed.load() {
@@ -3245,7 +3232,10 @@ mod _io {
Err(io_closed_error(vm))
}
}
}
#[pyclass(flags(BASETYPE, HAS_DICT), with(PyRef, Constructor))]
impl BytesIO {
#[pymethod]
fn readable(&self) -> bool {
true
@@ -3258,37 +3248,33 @@ mod _io {
fn seekable(&self) -> bool {
true
}
}
#[pyclass]
impl BytesIORef {
#[pymethod]
fn write(self, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult<u64> {
fn write(&self, data: ArgBytesLike, vm: &VirtualMachine) -> PyResult<u64> {
let mut buffer = self.try_resizable(vm)?;
match data.with_ref(|b| buffer.write(b)) {
Some(value) => Ok(value),
None => Err(vm.new_type_error("Error Writing Bytes".to_owned())),
}
data.with_ref(|b| buffer.write(b))
.ok_or_else(|| vm.new_type_error("Error Writing Bytes".to_owned()))
}
//Retrieves the entire bytes object value from the underlying buffer
// Retrieves the entire bytes object value from the underlying buffer
#[pymethod]
fn getvalue(self, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
Ok(vm.ctx.new_bytes(self.buffer(vm)?.getvalue()))
fn getvalue(&self, vm: &VirtualMachine) -> PyResult<PyBytesRef> {
let bytes = self.buffer(vm)?.getvalue();
Ok(vm.ctx.new_bytes(bytes))
}
//Takes an integer k (bytes) and returns them from the underlying buffer
//If k is undefined || k == -1, then we read all bytes until the end of the file.
//This also increments the stream position by the value of k
// Takes an integer k (bytes) and returns them from the underlying buffer
// If k is undefined || k == -1, then we read all bytes until the end of the file.
// This also increments the stream position by the value of k
#[pymethod]
#[pymethod(name = "read1")]
fn read(self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
fn read(&self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
let buf = self.buffer(vm)?.read(size.to_usize()).unwrap_or_default();
Ok(buf)
}
#[pymethod]
fn readinto(self, obj: ArgMemoryBuffer, vm: &VirtualMachine) -> PyResult<usize> {
fn readinto(&self, obj: ArgMemoryBuffer, vm: &VirtualMachine) -> PyResult<usize> {
let mut buf = self.buffer(vm)?;
let ret = buf
.cursor
@@ -3301,7 +3287,7 @@ mod _io {
//skip to the jth position
#[pymethod]
fn seek(
self,
&self,
offset: PyObjectRef,
how: OptionalArg<i32>,
vm: &VirtualMachine,
@@ -3312,22 +3298,17 @@ mod _io {
}
#[pymethod]
fn seekable(self) -> bool {
true
}
#[pymethod]
fn tell(self, vm: &VirtualMachine) -> PyResult<u64> {
fn tell(&self, vm: &VirtualMachine) -> PyResult<u64> {
Ok(self.buffer(vm)?.tell())
}
#[pymethod]
fn readline(self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
fn readline(&self, size: OptionalSize, vm: &VirtualMachine) -> PyResult<Vec<u8>> {
self.buffer(vm)?.readline(size.to_usize(), vm)
}
#[pymethod]
fn truncate(self, pos: OptionalSize, vm: &VirtualMachine) -> PyResult<usize> {
fn truncate(&self, pos: OptionalSize, vm: &VirtualMachine) -> PyResult<usize> {
if self.closed.load() {
return Err(io_closed_error(vm));
}
@@ -3337,17 +3318,20 @@ mod _io {
}
#[pygetset]
fn closed(self) -> bool {
fn closed(&self) -> bool {
self.closed.load()
}
#[pymethod]
fn close(self, vm: &VirtualMachine) -> PyResult<()> {
fn close(&self, vm: &VirtualMachine) -> PyResult<()> {
drop(self.try_resizable(vm)?);
self.closed.store(true);
Ok(())
}
}
#[pyclass]
impl PyRef<BytesIO> {
#[pymethod]
fn getbuffer(self, vm: &VirtualMachine) -> PyResult<PyMemoryView> {
let len = self.buffer.read().cursor.get_ref().len();
+2 -2
View File
@@ -435,8 +435,8 @@ mod unix {
#[pyattr]
use libc::{CLOCK_PROF, CLOCK_UPTIME};
impl TryFromBorrowedObject for ClockId {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObject) -> PyResult<Self> {
impl<'a> TryFromBorrowedObject<'a> for ClockId {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &'a PyObject) -> PyResult<Self> {
obj.try_to_value(vm).map(ClockId::from_raw)
}
}