Skip to content

Object protocol #3306

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions vm/src/bytesinner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ impl TryFromBorrowedObject for PyBytesInner {
#[derive(FromArgs)]
pub struct ByteInnerNewOptions {
#[pyarg(any, optional)]
source: OptionalArg<PyObjectRef>,
pub source: OptionalArg<PyObjectRef>,
#[pyarg(any, optional)]
encoding: OptionalArg<PyStrRef>,
pub encoding: OptionalArg<PyStrRef>,
#[pyarg(any, optional)]
errors: OptionalArg<PyStrRef>,
pub errors: OptionalArg<PyStrRef>,
}

impl ByteInnerNewOptions {
Expand Down
10 changes: 0 additions & 10 deletions vm/src/protocol/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,6 @@ impl TryFromObject for PyIter<PyObjectRef> {
}
}

impl PyObjectRef {
/// Takes an object and returns an iterator for it.
/// This is typically a new iterator but if the argument is an iterator, this
/// returns itself.
pub fn get_iter(self, vm: &VirtualMachine) -> PyResult<PyIter> {
// PyObject_GetIter
PyIter::try_from_object(vm, self)
}
}

pub enum PyIterReturn<T = PyObjectRef> {
Return(T),
StopIteration(Option<PyObjectRef>),
Expand Down
1 change: 1 addition & 0 deletions vm/src/protocol/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod buffer;
mod iter;
mod mapping;
mod object;

pub use buffer::{BufferInternal, BufferOptions, BufferResizeGuard, PyBuffer};
pub use iter::{PyIter, PyIterIter, PyIterReturn};
Expand Down
148 changes: 148 additions & 0 deletions vm/src/protocol/object.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//! Object Protocol
//! https://docs.python.org/3/c-api/object.html

use crate::{
builtins::{pystr::IntoPyStrRef, PyBytes, PyInt, PyStrRef},
bytesinner::ByteInnerNewOptions,
common::{hash::PyHash, str::to_ascii},
function::OptionalArg,
protocol::PyIter,
pyref_type_error,
types::{Constructor, PyComparisonOp},
PyObjectRef, PyResult, TryFromObject, VirtualMachine,
};

// RustPython doesn't need these items
// PyObject *Py_NotImplemented
// Py_RETURN_NOTIMPLEMENTED

impl PyObjectRef {
// int PyObject_Print(PyObject *o, FILE *fp, int flags)

pub fn has_attr(self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult<bool> {
self.get_attr(attr_name, vm).map(|o| vm.is_none(&o))
}

pub fn get_attr(self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult {
vm.get_attribute(self, attr_name)
}

// PyObject *PyObject_GenericGetAttr(PyObject *o, PyObject *name)

pub fn set_attr(
&self,
attr_name: impl IntoPyStrRef,
attr_value: impl Into<PyObjectRef>,
vm: &VirtualMachine,
) -> PyResult<()> {
vm.set_attr(self, attr_name, attr_value)
}

// int PyObject_GenericSetAttr(PyObject *o, PyObject *name, PyObject *value)

pub fn del_attr(&self, attr_name: impl IntoPyStrRef, vm: &VirtualMachine) -> PyResult<()> {
vm.del_attr(self, attr_name)
}

// PyObject *PyObject_GenericGetDict(PyObject *o, void *context)
// int PyObject_GenericSetDict(PyObject *o, PyObject *value, void *context)

pub fn rich_compare(self, other: Self, opid: PyComparisonOp, vm: &VirtualMachine) -> PyResult {
vm.obj_cmp(self, other, opid)
}

pub fn rich_compare_bool(
&self,
other: &Self,
opid: PyComparisonOp,
vm: &VirtualMachine,
) -> PyResult<bool> {
vm.bool_cmp(self, other, opid)
}

pub fn repr(&self, vm: &VirtualMachine) -> PyResult<PyStrRef> {
vm.to_repr(self)
}

pub fn ascii(&self, vm: &VirtualMachine) -> PyResult<ascii::AsciiString> {
let repr = vm.to_repr(self)?;
let ascii = to_ascii(repr.as_str());
Ok(ascii)
}

pub fn str(&self, vm: &VirtualMachine) -> PyResult<PyStrRef> {
vm.to_str(self)
}

pub fn bytes(self, vm: &VirtualMachine) -> PyResult {
let bytes_type = &vm.ctx.types.bytes_type;
match self.downcast_exact::<PyInt>(vm) {
Ok(int) => Err(pyref_type_error(vm, bytes_type, int.as_object())),
Err(obj) => PyBytes::py_new(
bytes_type.clone(),
ByteInnerNewOptions {
source: OptionalArg::Present(obj),
encoding: OptionalArg::Missing,
errors: OptionalArg::Missing,
},
vm,
),
}
}

pub fn is_subclass(&self, cls: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
vm.issubclass(self, cls)
}

pub fn is_instance(&self, cls: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
vm.isinstance(self, cls)
}

pub fn hash(&self, vm: &VirtualMachine) -> PyResult<PyHash> {
vm._hash(self)
}

// const hash_not_implemented: fn(&PyObjectRef, &VirtualMachine) ->PyResult<PyHash> = crate::types::Unhashable::slot_hash;

pub fn is_true(self, vm: &VirtualMachine) -> PyResult<bool> {
self.try_to_bool(vm)
}

pub fn not(self, vm: &VirtualMachine) -> PyResult<bool> {
self.is_true(vm).map(|x| !x)
}

// type protocol
// PyObject *PyObject_Type(PyObject *o)

// int PyObject_TypeCheck(PyObject *o, PyTypeObject *type)

pub fn length(&self, vm: &VirtualMachine) -> PyResult<usize> {
vm.obj_len(self)
}

pub fn length_hint(
self,
defaultvalue: Option<usize>,
vm: &VirtualMachine,
) -> PyResult<Option<usize>> {
Ok(vm.length_hint(self)?.or(defaultvalue))
}

// item protocol
// PyObject *PyObject_GetItem(PyObject *o, PyObject *key)
// int PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v)
// int PyObject_DelItem(PyObject *o, PyObject *key)

// PyObject *PyObject_Dir(PyObject *o)

/// Takes an object and returns an iterator for it.
/// This is typically a new iterator but if the argument is an iterator, this
/// returns itself.
pub fn get_iter(self, vm: &VirtualMachine) -> PyResult<PyIter> {
// PyObject_GetIter
PyIter::try_from_object(vm, self)
}

// PyObject *PyObject_GetAIter(PyObject *o)
}
2 changes: 2 additions & 0 deletions vm/src/types/slot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,8 @@ where
fn slot_hash(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult<PyHash> {
Err(vm.new_type_error(format!("unhashable type: '{}'", zelf.class().name())))
}

#[cold]
fn hash(_zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<PyHash> {
unreachable!("slot_hash is implemented for unhashable types");
}
Expand Down