fix sequence protocol; convert buffer protocol

This commit is contained in:
Nikolay Kim 2017-05-29 15:08:19 -07:00
parent 51ac8c9c78
commit ad38688378
17 changed files with 121 additions and 131 deletions

View File

@ -110,6 +110,21 @@ pub const ASYNC: Proto = Proto {
],
};
pub const BUFFER: Proto = Proto {
name: "Buffer",
methods: &[
MethodProto::Unary{
name: "bf_getbuffer",
pyres: false,
proto: "::pyo3::class::buffer::PyBufferGetBufferProtocol"},
MethodProto::Unary{
name: "bf_releasebuffer",
pyres: false,
proto: "::pyo3::class::buffer::PyBufferReleaseBufferProtocol"},
],
py_methods: &[],
};
pub const CONTEXT: Proto = Proto {
name: "Context",
methods: &[
@ -134,6 +149,8 @@ pub const CONTEXT: Proto = Proto {
],
};
pub const DESCR: Proto = Proto {
name: "Descriptor",
methods: &[

View File

@ -41,8 +41,7 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
"PyDescrProtocol" =>
impl_proto_impl(ty, impl_items, &defs::DESCR),
"PyBufferProtocol" =>
impl_protocol("_pyo3::class::buffer::PyBufferProtocolImpl",
path.clone(), ty, impl_items, &DEFAULT_METHODS),
impl_proto_impl(ty, impl_items, &defs::BUFFER),
"PyGCProtocol" =>
impl_protocol("_pyo3::class::gc::PyGCProtocolImpl",
path.clone(), ty, impl_items, &DEFAULT_METHODS),

View File

@ -10,80 +10,76 @@ use std::os::raw::c_int;
use ffi;
use err::PyResult;
use python::Python;
use objects::PyObject;
use typeob::PyTypeInfo;
use callback::{handle, UnitCallbackConverter};
use class::NO_METHODS;
use callback::UnitCallbackConverter;
/// Buffer protocol interface
pub trait PyBufferProtocol<'p> : PyTypeInfo {
#[allow(unused_variables)]
pub trait PyBufferProtocol<'p> : PyTypeInfo + Sized + 'static
{
fn bf_getbuffer(&'p self, py: Python<'p>,
view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()>;
view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
where Self: PyBufferGetBufferProtocol<'p> { unimplemented!() }
fn bf_releasebuffer(&'p self, py: Python<'p>, view: *mut ffi::Py_buffer) -> PyResult<()>;
fn bf_releasebuffer(&'p self, py: Python<'p>, view: *mut ffi::Py_buffer) -> Self::Result
where Self: PyBufferReleaseBufferProtocol<'p> { unimplemented!() }
}
pub trait PyBufferGetBufferProtocol<'p>: PyBufferProtocol<'p> {
type Result: Into<PyResult<()>>;
}
pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
type Result: Into<PyResult<()>>;
}
#[doc(hidden)]
pub trait PyBufferProtocolImpl {
fn methods() -> &'static [&'static str];
fn tp_as_buffer() -> Option<ffi::PyBufferProcs>;
}
impl<T> PyBufferProtocolImpl for T {
default fn methods() -> &'static [&'static str] {
NO_METHODS
default fn tp_as_buffer() -> Option<ffi::PyBufferProcs> { None }
}
impl<'p, T> PyBufferProtocolImpl for T where T: PyBufferProtocol<'p> {
#[inline]
fn tp_as_buffer() -> Option<ffi::PyBufferProcs> {
Some(ffi::PyBufferProcs{
bf_getbuffer: Self::cb_bf_getbuffer(),
bf_releasebuffer: None,
})
}
}
impl<'p, T> PyBufferProtocol<'p> for T where T: PyTypeInfo {
trait PyBufferGetBufferProtocolImpl {
fn cb_bf_getbuffer() -> Option<ffi::getbufferproc>;
}
default fn bf_getbuffer(&'p self, _py: Python<'p>,
_view: *mut ffi::Py_buffer, _flags: c_int) -> PyResult<()> {
Ok(())
}
default fn bf_releasebuffer(&'p self, _py: Python<'p>,
_view: *mut ffi::Py_buffer) -> PyResult<()> {
Ok(())
impl<'p, T> PyBufferGetBufferProtocolImpl for T where T: PyBufferProtocol<'p>
{
#[inline]
default fn cb_bf_getbuffer() -> Option<ffi::getbufferproc> {
None
}
}
impl ffi::PyBufferProcs {
/// Construct PyBufferProcs struct for PyTypeObject.tp_as_buffer
pub fn new<'p, T>() -> Option<ffi::PyBufferProcs>
where T: PyBufferProtocol<'p> + PyBufferProtocolImpl
{
let methods = T::methods();
if methods.is_empty() {
return None
impl<T> PyBufferGetBufferProtocolImpl for T where T: for<'p> PyBufferGetBufferProtocol<'p>
{
#[inline]
fn cb_bf_getbuffer() -> Option<ffi::getbufferproc> {
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg1: *mut ffi::Py_buffer,
arg2: c_int) -> c_int
where T: for<'p> PyBufferGetBufferProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".buffer_get::<PyBufferProtocol>()");
::callback::cb_unary::<T, _, _, _>(LOCATION, slf, UnitCallbackConverter, |py, slf| {
slf.bf_getbuffer(py, arg1, arg2).into()
})
}
let mut buf_procs: ffi::PyBufferProcs = ffi::PyBufferProcs_INIT;
for name in methods {
match name {
&"bf_getbuffer" => {
buf_procs.bf_getbuffer = {
unsafe extern "C" fn wrap<'p, T>(slf: *mut ffi::PyObject,
arg1: *mut ffi::Py_buffer,
arg2: c_int) -> c_int
where T: PyBufferProtocol<'p>
{
const LOCATION: &'static str = concat!(stringify!(T), ".buffer_get::<PyBufferProtocol>()");
handle(LOCATION, UnitCallbackConverter, |py| {
let slf = PyObject::from_borrowed_ptr(py, slf);
slf.bf_getbuffer(py, arg1, arg2)
})
}
Some(wrap::<T>)
}
},
_ => ()
}
}
Some(buf_procs)
Some(wrap::<T>)
}
}

View File

@ -53,7 +53,7 @@ macro_rules! py_unary_func_self {
($trait:ident, $class:ident :: $f:ident, $res_type:ty, $conv:ty) => {{
unsafe extern "C" fn wrap<T>(slf: *mut $crate::ffi::PyObject)
-> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + $crate::ToPyObject + $crate::IntoPyObject
where T: for<'p> $trait<'p>
{
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");
@ -221,7 +221,7 @@ macro_rules! py_ssizearg_func {
#[allow(unused_mut)]
unsafe extern "C" fn wrap<T>(slf: *mut ffi::PyObject,
arg: $crate::Py_ssize_t) -> *mut $crate::ffi::PyObject
where T: for<'p> $trait<'p> + ToPyObject + IntoPyObject
where T: for<'p> $trait<'p>
{
const LOCATION: &'static str = concat!(stringify!($class), ".", stringify!($f), "()");

View File

@ -34,6 +34,7 @@ pub static NO_PY_METHODS: &'static [PyMethodDefType] = &[];
use ffi;
use typeob::PyTypeInfo;
use python::ToPythonPointer;
use token::PythonObjectWithToken;
#[derive(Debug)]
pub enum CompareOp {
@ -47,7 +48,7 @@ pub enum CompareOp {
pub trait PyCustomObject : PyTypeInfo + Sized {}
impl<'p, T> ToPythonPointer for T where T: PyCustomObject {
impl<'p, T> ToPythonPointer for T where T: PyCustomObject + PythonObjectWithToken {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <T as PyTypeInfo>::offset();

View File

@ -83,12 +83,12 @@ pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
type Result: Into<PyResult<Self::Success>>;
}
pub trait PySequenceInplaceConcatProtocol<'p>: PySequenceProtocol<'p> + ToPyObject {
pub trait PySequenceInplaceConcatProtocol<'p>: PySequenceProtocol<'p> + IntoPyObject {
type Other: FromPyObject<'p>;
type Result: Into<PyResult<Self>>;
}
pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + ToPyObject {
pub trait PySequenceInplaceRepeatProtocol<'p>: PySequenceProtocol<'p> + IntoPyObject {
type Result: Into<PyResult<Self>>;
}
@ -113,7 +113,6 @@ impl<'p, T> PySequenceProtocolImpl for T where T: PySequenceProtocol<'p> {
Self::sq_ass_item()
};
Some(ffi::PySequenceMethods {
sq_length: Self::sq_length(),
sq_concat: Self::sq_concat(),
@ -161,8 +160,7 @@ impl<'p, T> PySequenceGetItemProtocolImpl for T where T: PySequenceProtocol<'p>
}
}
impl<T> PySequenceGetItemProtocolImpl for T
where T: for<'p> PySequenceGetItemProtocol<'p> + ToPyObject + IntoPyObject
impl<T> PySequenceGetItemProtocolImpl for T where T: for<'p> PySequenceGetItemProtocol<'p>
{
#[inline]
fn sq_item() -> Option<ffi::ssizeargfunc> {
@ -365,8 +363,7 @@ impl<'p, T> PySequenceRepeatProtocolImpl for T
}
}
impl<T> PySequenceRepeatProtocolImpl for T
where T: for<'p> PySequenceRepeatProtocol<'p> + ToPyObject + IntoPyObject
impl<T> PySequenceRepeatProtocolImpl for T where T: for<'p> PySequenceRepeatProtocol<'p>
{
#[inline]
fn sq_repeat() -> Option<ffi::ssizeargfunc> {
@ -388,7 +385,7 @@ impl<'p, T> PySequenceInplaceConcatProtocolImpl for T where T: PySequenceProtoco
}
impl<T> PySequenceInplaceConcatProtocolImpl for T
where T: for<'p> PySequenceInplaceConcatProtocol<'p> + ToPyObject + IntoPyObject
where T: for<'p> PySequenceInplaceConcatProtocol<'p>
{
#[inline]
fn sq_inplace_concat() -> Option<ffi::binaryfunc> {
@ -410,7 +407,7 @@ impl<'p, T> PySequenceInplaceRepeatProtocolImpl for T where T: PySequenceProtoco
}
impl<T> PySequenceInplaceRepeatProtocolImpl for T
where T: for<'p> PySequenceInplaceRepeatProtocol<'p> + ToPyObject + IntoPyObject
where T: for<'p> PySequenceInplaceRepeatProtocol<'p>
{
#[inline]
fn sq_inplace_repeat() -> Option<ffi::ssizeargfunc> {

View File

@ -1,5 +1,6 @@
use std;
use std::ffi::CString;
use std::os::raw::c_char;
use libc;
use ffi;
@ -34,7 +35,7 @@ let gil = Python::acquire_gil();
let py = gil.python();
let ctx = PyDict::new(py);
ctx.set_item(py, "CustomError", py.get_type::<CustomError>()).unwrap();
ctx.set_item("CustomError", py.get_type::<CustomError>()).unwrap();
py.run("assert str(CustomError) == \"<class 'mymodule.CustomError'>\"", None, Some(&ctx)).unwrap();
py.run("assert CustomError('oops').args == ('oops',)", None, Some(&ctx)).unwrap();
@ -46,7 +47,7 @@ macro_rules! py_exception {
($module: ident, $name: ident, $base: ty) => {
pub struct $name;
pyobject_newtype!($name);
pyobject_nativetype!($name);
impl $name {
pub fn new<'p, T: $crate::ToPyObject>(py: $crate::Python<'p>, args: T) -> $crate::PyErr {
@ -56,11 +57,7 @@ macro_rules! py_exception {
impl $crate::PyTypeObject for $name {
#[inline]
fn type_name() -> &'static str {
"$name"
}
#[inline]
fn type_object(py: $crate::Python) -> $crate::PyType {
fn type_object<'p>(py: $crate::Python<'p>) -> $crate::PyType<'p> {
unsafe {
static mut type_object: *mut $crate::ffi::PyTypeObject = 0 as *mut $crate::ffi::PyTypeObject;
@ -68,8 +65,7 @@ macro_rules! py_exception {
type_object = $crate::PyErr::new_type(
py,
concat!(stringify!($module), ".", stringify!($name)),
Some($crate::PythonObject::into_object(py.get_type::<$base>())),
None).as_type_ptr();
Some(py.get_type::<$base>()), None);
}
$crate::PyType::from_type_ptr(py, type_object)
@ -136,25 +132,26 @@ impl PyErr {
///
/// `base` can be an existing exception type to subclass, or a tuple of classes
/// `dict` specifies an optional dictionary of class variables and methods
/*pub fn new_type(py: Python, name: &str,
base: Option<PyObject>, dict: Option<PyObject>) -> PyType {
pub fn new_type<'p>(py: Python<'p>, name: &str,
base: Option<PyObject<'p>>, dict: Option<PyObject<'p>>) -> PyType<'p> {
let base: *mut ffi::PyObject = match base {
None => ptr::null_mut(),
Some(obj) => obj.steal_ptr()
None => std::ptr::null_mut(),
Some(obj) => obj.into_ptr()
};
let dict: *mut ffi::PyObject = match dict {
None => ptr::null_mut(),
None => std::ptr::null_mut(),
Some(obj) => obj.into_ptr(),
};
unsafe {
let null_terminated_name = CString::new(name).unwrap();
let ptr: *mut ffi::PyObject = ffi::PyErr_NewException(
null_terminated_name.as_ptr() as *mut c_char, base, dict);
PyObject::from_borrowed_ptr(py, ptr).unchecked_cast_into::<PyType>()
let ptr = ffi::PyErr_NewException(
null_terminated_name.as_ptr() as *mut c_char,
base, dict) as *mut ffi::PyTypeObject;
PyType::from_type_ptr(py, ptr)
}
}*/
}
/// Retrieves the current error from the Python interpreter's global state.
/// The error is cleared from the Python interpreter.

View File

@ -1,12 +1,9 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use ffi;
use ppptr::pptr;
use pyptr::PyPtr;
use token::PyObjectMarker;
use typeob::PyTypeInfo;
use objects::PyObject;
use python::ToPythonPointer;
pub trait PyBaseObject : PyTypeInfo + Sized {}

View File

@ -105,7 +105,7 @@ impl<'p> PyDict<'p> {
//}
/// Returns the list of (key, value) pairs in this dictionary.
pub fn items(&self) -> Vec<(&PyObject, &PyObject)> {
pub fn items(&self) -> Vec<(PyObject<'p>, PyObject<'p>)> {
// Note that we don't provide an iterator because
// PyDict_Next() is unsafe to use when the dictionary might be changed
// by other python code.
@ -116,7 +116,8 @@ impl<'p> PyDict<'p> {
let mut key: *mut ffi::PyObject = mem::uninitialized();
let mut value: *mut ffi::PyObject = mem::uninitialized();
while ffi::PyDict_Next(self.as_ptr(), &mut pos, &mut key, &mut value) != 0 {
vec.push((token.from_owned_ptr(key), token.from_owned_ptr(value)));
vec.push((PyObject::from_owned_ptr(token, key),
PyObject::from_owned_ptr(token, value)));
}
}
vec
@ -273,7 +274,7 @@ mod test {
#[test]
fn test_items() {
let gil = Python::acquire_gil();
let gil = Python::acquire_gil();
let py = gil.python();
let mut v = HashMap::new();
v.insert(7, 32);

View File

@ -8,10 +8,11 @@ use std::os::raw::c_char;
use std::ffi::{CStr, CString};
use ::pptr;
use conversion::ToPyTuple;
use pyptr::PyPtr;
use python::{ToPythonPointer, Python};
use token::PythonObjectWithGilToken;
use objects::{PyDict, PyType, exc};
use objects::{PyObject, PyDict, PyType, exc};
use objectprotocol::ObjectProtocol;
use err::{PyResult, PyErr};
@ -79,6 +80,15 @@ impl<'p> PyModule<'p> {
unsafe { self.str_from_ptr(ffi::PyModule_GetFilename(self.as_ptr())) }
}
/// Calls a function in the module.
/// This is equivalent to the Python expression: `getattr(module, name)(*args, **kwargs)`
pub fn call<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>)
-> PyResult<PyObject<'p>>
where A: ToPyTuple
{
self.getattr(name)?.call(args, kwargs)
}
/// Adds a new extension type to the module.
///
/// This is a convenience function that initializes the `class`,

View File

@ -162,6 +162,7 @@ tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
///
/// # Example
/// ```
/// use pyo3::ObjectProtocol;
/// let gil = pyo3::Python::acquire_gil();
/// let py = gil.python();
/// let os = py.import("os").unwrap();

View File

@ -499,11 +499,11 @@ impl<'p, T> Py<'p, T> where T: PyTypeInfo
}
}
//impl<'p, T> PythonObjectWithGilToken<'p> for Py<'p, T> {
// fn gil(&self) -> Python<'p> {
// self.py
// }
//}
impl<'p, T> PythonObjectWithGilToken<'p> for Py<'p, T> {
fn gil(&self) -> Python<'p> {
self.py
}
}
impl<'p, T> ToPythonPointer for Py<'p, T> {
/// Gets the underlying FFI pointer, returns a borrowed pointer.

View File

@ -9,7 +9,7 @@ use std::os::raw::c_int;
use ffi;
use typeob::{PyTypeInfo, PyTypeObject, PyObjectAlloc};
use token::{PyObjectMarker, PythonToken, PythonObjectWithGilToken};
use token::{PyObjectMarker, PythonToken};
use objects::{PyObject, PyType, PyBool, PyDict, PyModule};
use err::{PyErr, PyResult, PyDowncastError};
use pyptr::{Py, PyPtr};
@ -254,33 +254,6 @@ impl<'p> Python<'p> {
{
f(Python(PhantomData))
}
/// Convert raw pointer into referece
#[inline]
pub unsafe fn from_owned_ptr<P>(self, ptr: *mut ffi::PyObject) -> &'p P
{
std::mem::transmute(ptr)
}
#[inline]
pub unsafe fn from_owned_ptr_opt<P>(self, ptr: *mut ffi::PyObject) -> Option<&'p P>
{
if ptr.is_null() {
None
} else {
Some(std::mem::transmute(ptr))
}
}
#[inline]
pub unsafe fn from_owned_ptr_or_panic<P>(self, ptr: *mut ffi::PyObject) -> &'p P
{
if ptr.is_null() {
::err::panic_after_error();
} else {
std::mem::transmute(ptr)
}
}
}
#[cfg(test)]

View File

@ -96,6 +96,7 @@ pub struct GILGuard {
/// The Drop implementation for GILGuard will release the GIL.
impl Drop for GILGuard {
fn drop(&mut self) {
println!("RELEASE");
unsafe { ffi::PyGILState_Release(self.gstate) }
}
}
@ -107,6 +108,7 @@ impl GILGuard {
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
pub fn acquire() -> GILGuard {
::pythonrun::prepare_freethreaded_python();
println!("ACQUIRE");
let gstate = unsafe { ffi::PyGILState_Ensure() }; // acquire GIL
GILGuard { gstate: gstate, no_send: marker::PhantomData }
}

View File

@ -248,7 +248,7 @@ pub fn initialize_type<'p, T>(py: Python<'p>, module_name: Option<&str>, type_na
}
// buffer protocol
if let Some(meth) = ffi::PyBufferProcs::new::<T>() {
if let Some(meth) = <T as class::buffer::PyBufferProtocolImpl>::tp_as_buffer() {
static mut BUFFER_PROCS: ffi::PyBufferProcs = ffi::PyBufferProcs_INIT;
*(unsafe { &mut BUFFER_PROCS }) = meth;
type_object.tp_as_buffer = unsafe { &mut BUFFER_PROCS };

View File

@ -19,7 +19,6 @@ struct TestClass {
impl class::PyBufferProtocol for TestClass {
fn bf_getbuffer(&self, py: Python, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
if view == ptr::null_mut() {
return Err(PyErr::new::<exc::BufferError, _>(py, "View is null"))
}
@ -75,6 +74,5 @@ fn test_buffer() {
let d = PyDict::new(py);
let _ = d.set_item("ob", t);
py.run("assert bytes(ob) == b' 23'", None, Some(&d)).unwrap();
}

View File

@ -477,7 +477,9 @@ fn comparisons() {
#[py::class]
struct Sequence {token: PythonToken<Sequence>}
struct Sequence {
#[token]
token: PythonToken<Sequence>}
#[py::proto]
impl PySequenceProtocol for Sequence {
@ -619,7 +621,6 @@ struct Reversed {token: PythonToken<Reversed>}
#[py::proto]
impl PyMappingProtocol for Reversed{
fn __reversed__(&self, py: Python) -> PyResult<&'static str> {
println!("__reversed__");
Ok("I am reversed")
}
}