diff --git a/python3-sys/src/descrobject.rs b/python3-sys/src/descrobject.rs index 5fc9f1b3..b39fc673 100644 --- a/python3-sys/src/descrobject.rs +++ b/python3-sys/src/descrobject.rs @@ -1,8 +1,9 @@ use libc::{c_char, c_int, c_void}; use crate::methodobject::PyMethodDef; -use crate::object::{PyObject, PyTypeObject}; +use crate::object::*; use crate::structmember::PyMemberDef; +use crate::pyport::Py_ssize_t; pub type getter = unsafe extern "C" fn(slf: *mut PyObject, closure: *mut c_void) -> *mut PyObject; @@ -32,6 +33,18 @@ impl Clone for PyGetSetDef { } } + +#[inline(always)] +pub unsafe fn PyDictProxy_Check(op: *mut PyObject) -> c_int { + PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC) +} + +#[inline(always)] +pub unsafe fn PyDictProxy_CheckExact(op: *mut PyObject) -> c_int { + (Py_TYPE(op) == &mut PyDictProxy_Type) as c_int +} + + #[cfg_attr(windows, link(name = "pythonXY"))] extern "C" { pub static mut PyClassMethodDescr_Type: PyTypeObject; diff --git a/src/objects/descrobject.rs b/src/objects/descrobject.rs new file mode 100644 index 00000000..0ef1289f --- /dev/null +++ b/src/objects/descrobject.rs @@ -0,0 +1,64 @@ +use std::ptr; + +use crate::conversion::ToPyObject; +use crate::err::{self, PyErr, PyResult}; +use crate::ffi; +use crate::objects::{PyObject, PyTuple}; +use crate::python::{Python, PythonObject, ToPythonPointer}; + +/// Represents a read-only Python dictionary +pub struct PyDictProxy(PyObject); + +pyobject_newtype!(PyDictProxy, PyDictProxy_Check, PyDictProxy_Type); + +impl PyDictProxy { + #[inline] + pub fn len(&self, _py: Python) -> usize { + unsafe { ffi::PyObject_Size(self.0.as_ptr()) as usize } + } + + pub fn get_item(&self, py: Python, key: K) -> Option + where + K: ToPyObject, + { + key.with_borrowed_ptr(py, |key| unsafe { + PyObject::from_borrowed_ptr_opt(py, ffi::PyObject_GetItem(self.0.as_ptr(), key)) + }) + } + + pub fn contains(&self, py: Python, key: K) -> PyResult + where + K: ToPyObject, + { + key.with_borrowed_ptr(py, |key| unsafe { + match ffi::PyMapping_HasKey(self.0.as_ptr(), key) { + 1 => Ok(true), + 0 => Ok(false), + _ => Err(PyErr::fetch(py)), + } + }) + } + + pub fn keys(&self, py: Python) -> PyObject { + // Returns a PySequence object + unsafe { + PyObject::from_borrowed_ptr(py, ffi::PyMapping_Keys(self.0.as_ptr())) + } + } + + pub fn values(&self, py: Python) -> PyObject { + // Returns a PySequence object + unsafe { + PyObject::from_borrowed_ptr(py, ffi::PyMapping_Values(self.0.as_ptr())) + } + } + + pub fn items(&self, py: Python) -> PyObject { + // Returns a PySequence object + unsafe { + PyObject::from_borrowed_ptr(py, ffi::PyMapping_Items(self.0.as_ptr())) + } + } +} + + diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 98fa040f..1174b33d 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -39,6 +39,7 @@ pub use self::num::{PyFloat, PyLong}; pub use self::sequence::PySequence; pub use self::set::PySet; pub use self::tuple::{NoArgs, PyTuple}; +pub use self::descrobject::PyDictProxy; #[macro_export] macro_rules! pyobject_newtype( @@ -146,6 +147,7 @@ mod set; mod string; mod tuple; mod typeobject; +mod descrobject; #[cfg(feature = "python27-sys")] pub mod oldstyle;