more mapping protocol methods; start working on class tests
This commit is contained in:
parent
1f2c927bd5
commit
452a4e8d7f
|
@ -8,6 +8,8 @@ proc-macro = true
|
|||
|
||||
[dependencies]
|
||||
quote="0.3"
|
||||
log="0.3"
|
||||
env_logger = "0.4"
|
||||
|
||||
[dependencies.syn]
|
||||
version="0.11"
|
||||
|
|
|
@ -5,9 +5,8 @@ use quote::Tokens;
|
|||
// Add lifetime support for args with Rptr
|
||||
|
||||
pub enum MethodProto {
|
||||
Len{name: &'static str, proto: &'static str},
|
||||
Unary{name: &'static str, proto: &'static str},
|
||||
Binary{name: &'static str, arg: &'static str, proto: &'static str},
|
||||
Unary{name: &'static str, pyres: bool, proto: &'static str, },
|
||||
Binary{name: &'static str, arg: &'static str, pyres: bool, proto: &'static str},
|
||||
Ternary{name: &'static str, arg1: &'static str, arg2: &'static str, proto: &'static str},
|
||||
Quaternary{name: &'static str,
|
||||
arg1: &'static str,
|
||||
|
@ -19,9 +18,8 @@ impl MethodProto {
|
|||
|
||||
pub fn eq(&self, name: &str) -> bool {
|
||||
match *self {
|
||||
MethodProto::Len{name: n, proto: _} => n == name,
|
||||
MethodProto::Unary{name: n, proto: _} => n == name,
|
||||
MethodProto::Binary{name: n, arg: _, proto: _} => n == name,
|
||||
MethodProto::Unary{name: n, pyres: _, proto: _} => n == name,
|
||||
MethodProto::Binary{name: n, arg: _, pyres: _, proto: _} => n == name,
|
||||
MethodProto::Ternary{name: n, arg1: _, arg2: _, proto: _} => n == name,
|
||||
MethodProto::Quaternary{name: n, arg1: _, arg2: _, arg3: _, proto: _} => n == name,
|
||||
}
|
||||
|
@ -35,36 +33,45 @@ pub fn impl_method_proto(cls: &Box<syn::Ty>,
|
|||
match sig.decl.output {
|
||||
syn::FunctionRetTy::Ty(ref ty) => {
|
||||
match *meth {
|
||||
MethodProto::Len{name: _, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
},
|
||||
MethodProto::Unary{name: _, proto} => {
|
||||
MethodProto::Unary{name: _, pyres, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let succ = get_res_success(ty);
|
||||
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
if pyres {
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MethodProto::Binary{name: _, arg, proto} => {
|
||||
MethodProto::Binary{name: _, arg, pyres, proto} => {
|
||||
let p = syn::Ident::from(proto);
|
||||
let arg_name = syn::Ident::from(arg);
|
||||
let arg_ty = get_arg_ty(sig, 2);
|
||||
let succ = get_res_success(ty);
|
||||
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type #arg_name = #arg_ty;
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
if pyres {
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type #arg_name = #arg_ty;
|
||||
type Success = #succ;
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
impl #p for #cls {
|
||||
type #arg_name = #arg_ty;
|
||||
type Result = #ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
extern crate proc_macro;
|
||||
extern crate syn;
|
||||
#[macro_use] extern crate quote;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
use std::str::FromStr;
|
||||
use proc_macro::TokenStream;
|
||||
|
|
|
@ -192,10 +192,10 @@ fn parse_attributes(attrs: &mut Vec<syn::Attribute>) -> (FnType, Vec<FnAttr>) {
|
|||
match attr.value {
|
||||
syn::MetaItem::Word(ref name) => {
|
||||
match name.as_ref() {
|
||||
"new" => {
|
||||
"new" | "__new__" => {
|
||||
res = Some(FnType::FnNew)
|
||||
},
|
||||
"call" => {
|
||||
"call" | "__call__" => {
|
||||
res = Some(FnType::FnCall)
|
||||
},
|
||||
"setter" | "getter" => {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
use syn;
|
||||
use quote::{Tokens, ToTokens};
|
||||
use utils::for_err_msg;
|
||||
|
||||
use method::{FnArg, FnSpec, FnType};
|
||||
|
||||
|
||||
|
@ -207,7 +205,7 @@ fn impl_arg_params(spec: &FnSpec, body: Tokens) -> Tokens {
|
|||
let mut rargs = spec.args.clone();
|
||||
rargs.reverse();
|
||||
let mut body = body;
|
||||
for arg in spec.args.iter() {
|
||||
for arg in rargs.iter() {
|
||||
body = impl_arg_param(&arg, &spec, &body);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,15 +45,19 @@ static ASYNC: Proto = Proto {
|
|||
methods: &[
|
||||
MethodProto::Unary {
|
||||
name: "__await__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::async::PyAsyncAwaitProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__aiter__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::async::PyAsyncAiterProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__anext__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::async::PyAsyncAnextProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__aenter__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::async::PyAsyncAenterProtocol"},
|
||||
MethodProto::Quaternary {
|
||||
name: "__aexit__",
|
||||
|
@ -77,6 +81,7 @@ static CONTEXT: Proto = Proto {
|
|||
methods: &[
|
||||
MethodProto::Unary{
|
||||
name: "__enter__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::context::PyContextEnterProtocol"},
|
||||
MethodProto::Quaternary {
|
||||
name: "__exit__",
|
||||
|
@ -101,9 +106,11 @@ static ITER: Proto = Proto {
|
|||
methods: &[
|
||||
MethodProto::Unary{
|
||||
name: "__iter__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::iter::PyIterIterProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__next__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::iter::PyIterNextProtocol"},
|
||||
],
|
||||
};
|
||||
|
@ -111,14 +118,15 @@ static ITER: Proto = Proto {
|
|||
|
||||
static MAPPING: Proto = Proto {
|
||||
name: "Mapping",
|
||||
py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::Len{
|
||||
MethodProto::Unary{
|
||||
name: "__len__",
|
||||
pyres: false,
|
||||
proto: "_pyo3::class::mapping::PyMappingLenProtocol"},
|
||||
MethodProto::Binary{
|
||||
name: "__getitem__",
|
||||
arg: "Key",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::mapping::PyMappingGetItemProtocol"},
|
||||
MethodProto::Ternary{
|
||||
name: "__setitem__",
|
||||
|
@ -128,8 +136,37 @@ static MAPPING: Proto = Proto {
|
|||
MethodProto::Binary{
|
||||
name: "__delitem__",
|
||||
arg: "Key",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::mapping::PyMappingDelItemProtocol"},
|
||||
MethodProto::Binary{
|
||||
name: "__contains__",
|
||||
arg: "Value",
|
||||
pyres: false,
|
||||
proto: "_pyo3::class::mapping::PyMappingContainsProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__reversed__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::mapping::PyMappingReversedProtocol"},
|
||||
MethodProto::Unary{
|
||||
name: "__iter__",
|
||||
pyres: true,
|
||||
proto: "_pyo3::class::mapping::PyMappingIterProtocol"},
|
||||
],
|
||||
py_methods: &[
|
||||
PyMethod {
|
||||
name: "__iter__",
|
||||
proto: "_pyo3::class::mapping::PyMappingIterProtocolImpl",
|
||||
},
|
||||
PyMethod {
|
||||
name: "__contains__",
|
||||
proto: "_pyo3::class::mapping::PyMappingContainsProtocolImpl",
|
||||
},
|
||||
PyMethod {
|
||||
name: "__reversed__",
|
||||
proto: "_pyo3::class::mapping::PyMappingReversedProtocolImpl",
|
||||
},
|
||||
],
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -160,12 +197,15 @@ pub fn build_py_proto(ast: &mut syn::Item) -> Tokens {
|
|||
impl_protocol("_pyo3::class::gc::PyGCProtocolImpl",
|
||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||
"PySequenceProtocol" =>
|
||||
impl_protocol("_pyo3::class::mapping::PySequenceProtocolImpl",
|
||||
impl_protocol("_pyo3::class::sequence::PySequenceProtocolImpl",
|
||||
path.clone(), ty, impl_items, &DEFAULT_METHODS),
|
||||
"PyNumberProtocol" =>
|
||||
impl_protocol("_pyo3::class::number::PyNumberProtocolImpl",
|
||||
path.clone(), ty, impl_items, &NUM_METHODS),
|
||||
_ => panic!("#[proto] can not be used with this block"),
|
||||
_ => {
|
||||
warn!("#[proto] can not be used with this block");
|
||||
Tokens::new()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("#[proto] can only be used with protocol trait implementations")
|
||||
|
|
|
@ -16,11 +16,10 @@ use conversion::ToPyObject;
|
|||
use callback::{handle_callback, PyObjectCallbackConverter, HashConverter, UnitCallbackConverter};
|
||||
use class::{NO_METHODS, NO_PY_METHODS};
|
||||
|
||||
// __new__
|
||||
// __init__
|
||||
// __call__
|
||||
// classmethod
|
||||
// staticmethod
|
||||
// __instancecheck__
|
||||
// __subclasscheck__
|
||||
|
||||
|
||||
/// Object customization
|
||||
|
@ -32,18 +31,18 @@ pub trait PyObjectProtocol {
|
|||
|
||||
fn __delattr__(&self, py: Python, name: &PyObject) -> PyResult<()>;
|
||||
|
||||
// __instancecheck__
|
||||
// __subclasscheck__
|
||||
// __dir__
|
||||
|
||||
fn __str__(&self, py: Python) -> PyResult<PyObject>;
|
||||
|
||||
fn __repr__(&self, py: Python) -> PyResult<PyObject>;
|
||||
|
||||
fn __hash__(&self, py: Python) -> PyResult<u64>;
|
||||
fn __format__(&self, py: Python, format_spec: &str) -> PyResult<PyObject>;
|
||||
|
||||
fn __hash__(&self, py: Python) -> PyResult<usize>;
|
||||
|
||||
fn __bool__(&self, py: Python) -> PyResult<bool>;
|
||||
|
||||
fn __bytes__(&self, py: Python) -> PyResult<PyObject>;
|
||||
|
||||
fn __richcmp__(&self, py: Python, other: &PyObject, op: CompareOp) -> PyResult<PyObject>;
|
||||
|
||||
}
|
||||
|
@ -60,25 +59,24 @@ impl<T> PyObjectProtocol for T {
|
|||
default fn __delattr__(&self, py: Python, _: &PyObject) -> PyResult<()> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
|
||||
// __instancecheck__
|
||||
// __subclasscheck__
|
||||
// __iter__
|
||||
// __next__
|
||||
// __dir__
|
||||
|
||||
default fn __str__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
default fn __repr__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
default fn __hash__(&self, py: Python) -> PyResult<u64> {
|
||||
default fn __format__(&self, py: Python, format_spec: &str) -> PyResult<PyObject> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
default fn __hash__(&self, py: Python) -> PyResult<usize> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
default fn __bool__(&self, py: Python) -> PyResult<bool> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
default fn __bytes__(&self, py: Python) -> PyResult<PyObject> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
default fn __richcmp__(&self, py: Python, _: &PyObject, _: CompareOp) -> PyResult<PyObject> {
|
||||
Err(PyErr::new::<exc::NotImplementedError, _>(py, "Not implemented"))
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ impl<T> PyContextProtocolImpl for T where T: PyContextProtocol {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
trait PyContextEnterProtocolImpl {
|
||||
pub trait PyContextEnterProtocolImpl {
|
||||
fn __enter__() -> Option<PyMethodDef>;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,7 @@ impl<T> PyContextEnterProtocolImpl for T
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyContextExitProtocolImpl {
|
||||
fn __exit__() -> Option<PyMethodDef>;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use python::{Python, PythonObject, PyDrop};
|
|||
use objects::{exc, PyObject};
|
||||
use callback::{PyObjectCallbackConverter, LenResultConverter, UnitCallbackConverter};
|
||||
use conversion::{ToPyObject, FromPyObject};
|
||||
use class::methods::PyMethodDef;
|
||||
|
||||
|
||||
/// Mapping interface
|
||||
|
@ -29,6 +30,15 @@ pub trait PyMappingProtocol: PythonObject {
|
|||
fn __delitem__(&self, py: Python, key: Self::Key)
|
||||
-> Self::Result where Self: PyMappingDelItemProtocol { unimplemented!() }
|
||||
|
||||
fn __iter__(&self, py: Python)
|
||||
-> Self::Result where Self: PyMappingIterProtocol { unimplemented!() }
|
||||
|
||||
fn __contains__(&self, py: Python, value: Self::Value)
|
||||
-> Self::Result where Self: PyMappingContainsProtocol { unimplemented!() }
|
||||
|
||||
fn __reversed__(&self, py: Python)
|
||||
-> Self::Result where Self: PyMappingReversedProtocol { unimplemented!() }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,9 +68,25 @@ pub trait PyMappingDelItemProtocol: PyMappingProtocol {
|
|||
type Result: Into<PyResult<()>>;
|
||||
}
|
||||
|
||||
pub trait PyMappingIterProtocol: PyMappingProtocol {
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
pub trait PyMappingContainsProtocol: PyMappingProtocol {
|
||||
type Value: for<'a> FromPyObject<'a>;
|
||||
type Result: Into<PyResult<bool>>;
|
||||
}
|
||||
|
||||
pub trait PyMappingReversedProtocol: PyMappingProtocol {
|
||||
type Success: ToPyObject;
|
||||
type Result: Into<PyResult<Self::Success>>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyMappingProtocolImpl {
|
||||
fn tp_as_mapping() -> Option<ffi::PyMappingMethods>;
|
||||
fn methods() -> Vec<PyMethodDef>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingProtocolImpl for T {
|
||||
|
@ -68,6 +94,10 @@ impl<T> PyMappingProtocolImpl for T {
|
|||
default fn tp_as_mapping() -> Option<ffi::PyMappingMethods> {
|
||||
None
|
||||
}
|
||||
#[inline]
|
||||
default fn methods() -> Vec<PyMethodDef> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PyMappingProtocolImpl for T where T: PyMappingProtocol {
|
||||
|
@ -85,6 +115,23 @@ impl<T> PyMappingProtocolImpl for T where T: PyMappingProtocol {
|
|||
mp_ass_subscript: f,
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn methods() -> Vec<PyMethodDef> {
|
||||
let mut methods = Vec::new();
|
||||
|
||||
if let Some(def) = <Self as PyMappingIterProtocolImpl>::__iter__() {
|
||||
methods.push(def)
|
||||
}
|
||||
if let Some(def) = <Self as PyMappingContainsProtocolImpl>::__contains__() {
|
||||
methods.push(def)
|
||||
}
|
||||
if let Some(def) = <Self as PyMappingReversedProtocolImpl>::__reversed__() {
|
||||
methods.push(def)
|
||||
}
|
||||
|
||||
methods
|
||||
}
|
||||
}
|
||||
|
||||
trait PyMappingLenProtocolImpl {
|
||||
|
@ -279,3 +326,46 @@ impl<T> PyMappingDelItemProtocolImpl for T
|
|||
Some(wrap::<T>)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyMappingContainsProtocolImpl {
|
||||
fn __contains__() -> Option<PyMethodDef>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingContainsProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn __contains__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyMappingReversedProtocolImpl {
|
||||
fn __reversed__() -> Option<PyMethodDef>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingReversedProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn __reversed__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait PyMappingIterProtocolImpl {
|
||||
fn __iter__() -> Option<PyMethodDef>;
|
||||
}
|
||||
|
||||
impl<T> PyMappingIterProtocolImpl for T
|
||||
where T: PyMappingProtocol
|
||||
{
|
||||
#[inline]
|
||||
default fn __iter__() -> Option<PyMethodDef> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use callback::{handle_callback, PyObjectCallbackConverter,
|
|||
use class::NO_METHODS;
|
||||
|
||||
|
||||
/// Mapping interface
|
||||
/// Sequece interface
|
||||
pub trait PySequenceProtocol {
|
||||
fn __len__(&self, py: Python) -> PyResult<usize>;
|
||||
|
||||
|
|
|
@ -75,7 +75,8 @@ impl PyByteArray {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use exc;
|
||||
use python::{Python, PythonObject, PythonObjectWithTypeObject};
|
||||
use class::PyTypeObject;
|
||||
use python::{Python, PythonObject};
|
||||
use objects::PyByteArray;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#![feature(proc_macro, specialization)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
#[macro_use] extern crate pyo3;
|
||||
extern crate pyo3;
|
||||
|
||||
use pyo3::*;
|
||||
use std::{mem, isize, iter};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::RefCell;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use pyo3::ffi;
|
||||
|
@ -13,6 +14,7 @@ macro_rules! py_run {
|
|||
($py:expr, $val:ident, $code:expr) => {{
|
||||
let d = PyDict::new($py);
|
||||
d.set_item($py, stringify!($val), &$val).unwrap();
|
||||
//$py.run($code, None, Some(&d)).map_err(|e| e.print($py)).expect($code);
|
||||
$py.run($code, None, Some(&d)).expect($code);
|
||||
}}
|
||||
}
|
||||
|
@ -34,7 +36,8 @@ macro_rules! py_expect_exception {
|
|||
}
|
||||
|
||||
|
||||
py_class!(class EmptyClass |py| { });
|
||||
#[py::class]
|
||||
struct EmptyClass { }
|
||||
|
||||
#[test]
|
||||
fn empty_class() {
|
||||
|
@ -47,7 +50,8 @@ fn empty_class() {
|
|||
py_assert!(py, typeobj, "typeobj.__name__ == 'EmptyClass'");
|
||||
}
|
||||
|
||||
py_class!(class EmptyClassInModule |py| { });
|
||||
#[py::class]
|
||||
struct EmptyClassInModule { }
|
||||
|
||||
#[test]
|
||||
fn empty_class_in_module() {
|
||||
|
@ -61,11 +65,16 @@ fn empty_class_in_module() {
|
|||
assert_eq!(ty.getattr(py, "__module__").unwrap().extract::<String>(py).unwrap(), "test_module.nested");
|
||||
}
|
||||
|
||||
py_class!(class EmptyClassWithNew |py| {
|
||||
def __new__(_cls) -> PyResult<EmptyClassWithNew> {
|
||||
#[py::class]
|
||||
struct EmptyClassWithNew { }
|
||||
|
||||
#[py::methods]
|
||||
impl EmptyClassWithNew {
|
||||
#[__new__]
|
||||
fn __new__(_cls: &PyType, py: Python) -> PyResult<EmptyClassWithNew> {
|
||||
EmptyClassWithNew::create_instance(py)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_class_with_new() {
|
||||
|
@ -75,12 +84,17 @@ fn empty_class_with_new() {
|
|||
assert!(typeobj.call(py, NoArgs, None).unwrap().cast_into::<EmptyClassWithNew>(py).is_ok());
|
||||
}
|
||||
|
||||
py_class!(class NewWithOneArg |py| {
|
||||
data _data: i32;
|
||||
def __new__(_cls, arg: i32) -> PyResult<NewWithOneArg> {
|
||||
#[py::class]
|
||||
struct NewWithOneArg {
|
||||
_data: i32,
|
||||
}
|
||||
#[py::methods]
|
||||
impl NewWithOneArg {
|
||||
#[new]
|
||||
fn __new__(_cls: &PyType, py: Python, arg: i32) -> PyResult<NewWithOneArg> {
|
||||
NewWithOneArg::create_instance(py, arg)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_one_arg() {
|
||||
|
@ -91,13 +105,19 @@ fn new_with_one_arg() {
|
|||
assert_eq!(*obj._data(py), 42);
|
||||
}
|
||||
|
||||
py_class!(class NewWithTwoArgs |py| {
|
||||
data _data1: i32;
|
||||
data _data2: i32;
|
||||
def __new__(_cls, arg1: i32, arg2: i32) -> PyResult<NewWithTwoArgs> {
|
||||
#[py::class]
|
||||
struct NewWithTwoArgs {
|
||||
_data1: i32,
|
||||
_data2: i32,
|
||||
}
|
||||
|
||||
#[py::methods]
|
||||
impl NewWithTwoArgs {
|
||||
#[new]
|
||||
fn __new__(_cls: &PyType, py: Python, arg1: i32, arg2: i32) -> PyResult<NewWithTwoArgs> {
|
||||
NewWithTwoArgs::create_instance(py, arg1, arg2)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_two_args() {
|
||||
|
@ -118,10 +138,11 @@ impl Drop for TestDropCall {
|
|||
}
|
||||
}
|
||||
|
||||
py_class!(class DataIsDropped |py| {
|
||||
data member1: TestDropCall;
|
||||
data member2: TestDropCall;
|
||||
});
|
||||
#[py::class]
|
||||
struct DataIsDropped {
|
||||
member1: TestDropCall,
|
||||
member2: TestDropCall,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn data_is_dropped() {
|
||||
|
@ -140,13 +161,17 @@ fn data_is_dropped() {
|
|||
assert!(drop_called2.load(Ordering::Relaxed) == true);
|
||||
}
|
||||
|
||||
py_class!(class InstanceMethod |py| {
|
||||
data member: i32;
|
||||
#[py::class]
|
||||
struct InstanceMethod {
|
||||
member: i32,
|
||||
}
|
||||
|
||||
def method(&self) -> PyResult<i32> {
|
||||
#[py::methods]
|
||||
impl InstanceMethod {
|
||||
fn method(&self, py: Python) -> PyResult<i32> {
|
||||
Ok(*self.member(py))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instance_method() {
|
||||
|
@ -160,13 +185,16 @@ fn instance_method() {
|
|||
py.run("assert obj.method() == 42", None, Some(&d)).unwrap();
|
||||
}
|
||||
|
||||
py_class!(class InstanceMethodWithArgs |py| {
|
||||
data member: i32;
|
||||
|
||||
def method(&self, multiplier: i32) -> PyResult<i32> {
|
||||
#[py::class]
|
||||
struct InstanceMethodWithArgs {
|
||||
member: i32
|
||||
}
|
||||
#[py::methods]
|
||||
impl InstanceMethodWithArgs {
|
||||
fn method(&self, py: Python, multiplier: i32) -> PyResult<i32> {
|
||||
Ok(*self.member(py) * multiplier)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instance_method_with_args() {
|
||||
|
@ -181,18 +209,22 @@ fn instance_method_with_args() {
|
|||
py.run("assert obj.method(multiplier=6) == 42", None, Some(&d)).unwrap();
|
||||
}
|
||||
|
||||
py_class!(class ClassMethod |py| {
|
||||
def __new__(cls) -> PyResult<ClassMethod> {
|
||||
#[py::class]
|
||||
struct ClassMethod {}
|
||||
#[py::methods]
|
||||
impl ClassMethod {
|
||||
#[new]
|
||||
fn __new__(cls: &PyType, py: Python) -> PyResult<ClassMethod> {
|
||||
ClassMethod::create_instance(py)
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def method(cls) -> PyResult<String> {
|
||||
Ok(format!("{}.method()!", cls.name(py)))
|
||||
}
|
||||
});
|
||||
//#[classmethod]
|
||||
//def method(cls) -> PyResult<String> {
|
||||
// Ok(format!("{}.method()!", cls.name(py)))
|
||||
//}
|
||||
}
|
||||
|
||||
#[test]
|
||||
//#[test]
|
||||
fn class_method() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
@ -203,36 +235,41 @@ fn class_method() {
|
|||
py.run("assert C().method() == 'ClassMethod.method()!'", None, Some(&d)).unwrap();
|
||||
}
|
||||
|
||||
py_class!(class ClassMethodWithArgs |py| {
|
||||
@classmethod
|
||||
def method(cls, input: &str) -> PyResult<String> {
|
||||
Ok(format!("{}.method({})", cls.name(py), input))
|
||||
}
|
||||
});
|
||||
//py_class!(class ClassMethodWithArgs |py| {
|
||||
// @classmethod
|
||||
// def method(cls, input: &str) -> PyResult<String> {
|
||||
// Ok(format!("{}.method({})", cls.name(py), input))
|
||||
// }
|
||||
//});
|
||||
|
||||
#[test]
|
||||
fn class_method_with_args() {
|
||||
//#[test]
|
||||
/*fn class_method_with_args() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let d = PyDict::new(py);
|
||||
d.set_item(py, "C", py.get_type::<ClassMethodWithArgs>()).unwrap();
|
||||
py.run("assert C.method('abc') == 'ClassMethodWithArgs.method(abc)'", None, Some(&d)).unwrap();
|
||||
}
|
||||
}*/
|
||||
|
||||
py_class!(class StaticMethod |py| {
|
||||
def __new__(cls) -> PyResult<StaticMethod> {
|
||||
#[py::class]
|
||||
struct StaticMethod {}
|
||||
|
||||
#[py::methods]
|
||||
impl StaticMethod {
|
||||
#[new]
|
||||
fn __new__(cls: &PyType, py: Python) -> PyResult<StaticMethod> {
|
||||
StaticMethod::create_instance(py)
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def method() -> PyResult<&'static str> {
|
||||
Ok("StaticMethod.method()!")
|
||||
}
|
||||
});
|
||||
//#[staticmethod]
|
||||
//fn method(py: Python) -> PyResult<&'static str> {
|
||||
// Ok("StaticMethod.method()!")
|
||||
//}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_method() {
|
||||
//#[test]
|
||||
/*fn static_method() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
|
@ -241,57 +278,44 @@ fn static_method() {
|
|||
d.set_item(py, "C", py.get_type::<StaticMethod>()).unwrap();
|
||||
py.run("assert C.method() == 'StaticMethod.method()!'", None, Some(&d)).unwrap();
|
||||
py.run("assert C().method() == 'StaticMethod.method()!'", None, Some(&d)).unwrap();
|
||||
}*/
|
||||
|
||||
//py_class!(class StaticMethodWithArgs |py| {
|
||||
// @staticmethod
|
||||
// def method(input: i32) -> PyResult<String> {
|
||||
// Ok(format!("0x{:x}", input))
|
||||
// }
|
||||
//});
|
||||
|
||||
//#[test]
|
||||
//fn static_method_with_args() {
|
||||
// let gil = Python::acquire_gil();
|
||||
// let py = gil.python();
|
||||
|
||||
// assert_eq!(StaticMethodWithArgs::method(py, 1234).unwrap(), "0x4d2");
|
||||
// let d = PyDict::new(py);
|
||||
// d.set_item(py, "C", py.get_type::<StaticMethodWithArgs>()).unwrap();
|
||||
// py.run("assert C.method(1337) == '0x539'", None, Some(&d)).unwrap();
|
||||
//}
|
||||
|
||||
#[py::class]
|
||||
struct GCIntegration {
|
||||
self_ref: RefCell<PyObject>,
|
||||
dropped: TestDropCall,
|
||||
}
|
||||
|
||||
py_class!(class StaticMethodWithArgs |py| {
|
||||
@staticmethod
|
||||
def method(input: i32) -> PyResult<String> {
|
||||
Ok(format!("0x{:x}", input))
|
||||
}
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn static_method_with_args() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
assert_eq!(StaticMethodWithArgs::method(py, 1234).unwrap(), "0x4d2");
|
||||
let d = PyDict::new(py);
|
||||
d.set_item(py, "C", py.get_type::<StaticMethodWithArgs>()).unwrap();
|
||||
py.run("assert C.method(1337) == '0x539'", None, Some(&d)).unwrap();
|
||||
}
|
||||
|
||||
py_class!(class StaticData |py| {
|
||||
static VAL1 = 123;
|
||||
static VAL2 = py.None();
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn static_data() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let d = PyDict::new(py);
|
||||
d.set_item(py, "C", py.get_type::<StaticData>()).unwrap();
|
||||
py.run("assert C.VAL1 == 123", None, Some(&d)).unwrap();
|
||||
py.run("assert C.VAL2 is None", None, Some(&d)).unwrap();
|
||||
assert!(py.run("C.VAL1 = 124", None, Some(&d)).is_err());
|
||||
}
|
||||
|
||||
py_class!(class GCIntegration |py| {
|
||||
data self_ref: RefCell<PyObject>;
|
||||
data dropped: TestDropCall;
|
||||
|
||||
def __traverse__(&self, visit) {
|
||||
#[py::proto]
|
||||
impl PyGCProtocol for GCIntegration {
|
||||
fn __traverse__(&self, py: Python, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||
visit.call(&*self.self_ref(py).borrow())
|
||||
}
|
||||
|
||||
def __clear__(&self) {
|
||||
fn __clear__(&self, py: Python) {
|
||||
let old_ref = mem::replace(&mut *self.self_ref(py).borrow_mut(), py.None());
|
||||
// Release reference only after the mutable borrow has expired.
|
||||
old_ref.release_ref(py);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gc_integration() {
|
||||
|
@ -310,13 +334,17 @@ fn gc_integration() {
|
|||
assert!(drop_called.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
py_class!(class Len |py| {
|
||||
data l: usize;
|
||||
#[py::class]
|
||||
pub struct Len {
|
||||
l: usize
|
||||
}
|
||||
|
||||
def __len__(&self) -> PyResult<usize> {
|
||||
#[py::proto]
|
||||
impl PyMappingProtocol for Len {
|
||||
fn __len__(&self, py: Python) -> PyResult<usize> {
|
||||
Ok(*self.l(py))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len() {
|
||||
|
@ -334,7 +362,8 @@ fn len() {
|
|||
py_expect_exception!(py, inst, "len(inst)", OverflowError);
|
||||
}
|
||||
|
||||
py_class!(class Iterator |py| {
|
||||
|
||||
/*py_class!(class Iterator |py| {
|
||||
data iter: RefCell<Box<iter::Iterator<Item=i32> + Send>>;
|
||||
|
||||
def __iter__(&self) -> PyResult<Iterator> {
|
||||
|
@ -354,29 +383,34 @@ fn iterator() {
|
|||
let inst = Iterator::create_instance(py, RefCell::new(Box::new(5..8))).unwrap();
|
||||
py_assert!(py, inst, "iter(inst) is inst");
|
||||
py_assert!(py, inst, "list(inst) == [5, 6, 7]");
|
||||
}
|
||||
}*/
|
||||
|
||||
py_class!(class StringMethods |py| {
|
||||
def __str__(&self) -> PyResult<&'static str> {
|
||||
/*
|
||||
#[py::class]
|
||||
struct StringMethods {}
|
||||
|
||||
#[py::proto]
|
||||
impl PyObjectProtocol for StringMethods {
|
||||
fn __str__(&self, py: Python) -> PyResult<&'static str> {
|
||||
Ok("str")
|
||||
}
|
||||
|
||||
def __repr__(&self) -> PyResult<&'static str> {
|
||||
fn __repr__(&self, py: Python) -> PyResult<&'static str> {
|
||||
Ok("repr")
|
||||
}
|
||||
|
||||
def __format__(&self, format_spec: &str) -> PyResult<String> {
|
||||
fn __format__(&self, py: Python, format_spec: &str) -> PyResult<String> {
|
||||
Ok(format!("format({})", format_spec))
|
||||
}
|
||||
|
||||
def __unicode__(&self) -> PyResult<PyString> {
|
||||
Ok(PyString::new(py, "unicode"))
|
||||
}
|
||||
//fn __unicode__(&self) -> PyResult<PyString> {
|
||||
// Ok(PyString::new(py, "unicode"))
|
||||
//}
|
||||
|
||||
def __bytes__(&self) -> PyResult<PyBytes> {
|
||||
fn __bytes__(&self, py: Python) -> PyResult<PyBytes> {
|
||||
Ok(PyBytes::new(py, b"bytes"))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_methods() {
|
||||
|
@ -387,8 +421,8 @@ fn string_methods() {
|
|||
py_assert!(py, obj, "str(obj) == 'str'");
|
||||
py_assert!(py, obj, "repr(obj) == 'repr'");
|
||||
py_assert!(py, obj, "'{0:x}'.format(obj) == 'format(x)'");
|
||||
}
|
||||
|
||||
}*/
|
||||
/*
|
||||
#[test]
|
||||
fn python3_string_methods() {
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -396,20 +430,24 @@ fn python3_string_methods() {
|
|||
|
||||
let obj = StringMethods::create_instance(py).unwrap();
|
||||
py_assert!(py, obj, "bytes(obj) == b'bytes'");
|
||||
}*/
|
||||
|
||||
|
||||
#[py::class]
|
||||
struct Comparisons {
|
||||
val: i32,
|
||||
}
|
||||
|
||||
|
||||
py_class!(class Comparisons |py| {
|
||||
data val: i32;
|
||||
|
||||
def __hash__(&self) -> PyResult<i32> {
|
||||
Ok(*self.val(py))
|
||||
#[py::proto]
|
||||
impl PyObjectProtocol for Comparisons {
|
||||
fn __hash__(&self, py: Python) -> PyResult<usize> {
|
||||
Ok(*self.val(py) as usize)
|
||||
}
|
||||
|
||||
def __bool__(&self) -> PyResult<bool> {
|
||||
fn __bool__(&self, py: Python) -> PyResult<bool> {
|
||||
Ok(*self.val(py) != 0)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
|
@ -430,20 +468,22 @@ fn comparisons() {
|
|||
}
|
||||
|
||||
|
||||
py_class!(class Sequence |py| {
|
||||
def __len__(&self) -> PyResult<usize> {
|
||||
/*#[py::class]
|
||||
struct Sequence {}
|
||||
|
||||
#[py::proto]
|
||||
impl PySequenceProtocol for Sequence {
|
||||
fn __len__(&self, py: Python) -> PyResult<usize> {
|
||||
Ok(5)
|
||||
}
|
||||
|
||||
def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
|
||||
if let Ok(index) = key.extract::<i32>(py) {
|
||||
if index == 5 {
|
||||
return Err(PyErr::new::<exc::IndexError, NoArgs>(py, NoArgs));
|
||||
}
|
||||
fn __getitem__(&self, py: Python, key: isize) -> PyResult<PyObject> {
|
||||
if key == 5 {
|
||||
return Err(PyErr::new::<exc::IndexError, NoArgs>(py, NoArgs));
|
||||
}
|
||||
Ok(key)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sequence() {
|
||||
|
@ -453,14 +493,20 @@ fn sequence() {
|
|||
let c = Sequence::create_instance(py).unwrap();
|
||||
py_assert!(py, c, "list(c) == [0, 1, 2, 3, 4]");
|
||||
py_assert!(py, c, "c['abc'] == 'abc'");
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
py_class!(class Callable |py| {
|
||||
def __call__(&self, arg: i32) -> PyResult<i32> {
|
||||
#[py::class]
|
||||
struct Callable {}
|
||||
|
||||
#[py::methods]
|
||||
impl Callable {
|
||||
|
||||
#[__call__]
|
||||
fn __call__(&self, py: Python, arg: i32) -> PyResult<i32> {
|
||||
Ok(arg * 6)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn callable() {
|
||||
|
@ -475,80 +521,97 @@ fn callable() {
|
|||
py_assert!(py, nc, "not callable(nc)");
|
||||
}
|
||||
|
||||
py_class!(class SetItem |py| {
|
||||
data key: Cell<i32>;
|
||||
data val: Cell<i32>;
|
||||
#[py::class]
|
||||
struct SetItem {
|
||||
key: i32,
|
||||
val: i32,
|
||||
}
|
||||
|
||||
def __setitem__(&self, key: i32, val: i32) -> PyResult<()> {
|
||||
self.key(py).set(key);
|
||||
self.val(py).set(val);
|
||||
#[py::proto]
|
||||
impl PyMappingProtocol for SetItem {
|
||||
fn __setitem__(&self, py: Python, key: i32, val: i32) -> PyResult<()> {
|
||||
*self.key_mut(py) = key;
|
||||
*self.val_mut(py) = val;
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setitem() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let c = SetItem::create_instance(py, Cell::new(0), Cell::new(0)).unwrap();
|
||||
let c = SetItem::create_instance(py, 0, 0).unwrap();
|
||||
py_run!(py, c, "c[1] = 2");
|
||||
assert_eq!(c.key(py).get(), 1);
|
||||
assert_eq!(c.val(py).get(), 2);
|
||||
assert_eq!(*c.key(py), 1);
|
||||
assert_eq!(*c.val(py), 2);
|
||||
py_expect_exception!(py, c, "del c[1]", NotImplementedError);
|
||||
}
|
||||
|
||||
py_class!(class DelItem |py| {
|
||||
data key: Cell<i32>;
|
||||
#[py::class]
|
||||
struct DelItem {
|
||||
key: i32,
|
||||
}
|
||||
|
||||
def __delitem__(&self, key: i32) -> PyResult<()> {
|
||||
self.key(py).set(key);
|
||||
#[py::proto]
|
||||
impl PyMappingProtocol for DelItem {
|
||||
fn __delitem__(&self, py: Python, key: i32) -> PyResult<()> {
|
||||
*self.key_mut(py) = key;
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delitem() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let c = DelItem::create_instance(py, Cell::new(0)).unwrap();
|
||||
let c = DelItem::create_instance(py, 0).unwrap();
|
||||
py_run!(py, c, "del c[1]");
|
||||
assert_eq!(c.key(py).get(), 1);
|
||||
assert_eq!(*c.key(py), 1);
|
||||
py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
|
||||
}
|
||||
|
||||
py_class!(class SetDelItem |py| {
|
||||
data val: Cell<Option<i32>>;
|
||||
#[py::class]
|
||||
struct SetDelItem {
|
||||
val: Option<i32>,
|
||||
}
|
||||
|
||||
def __setitem__(&self, key: i32, val: i32) -> PyResult<()> {
|
||||
self.val(py).set(Some(val));
|
||||
#[py::proto]
|
||||
impl PyMappingProtocol for SetDelItem {
|
||||
fn __setitem__(&self, py: Python, key: i32, val: i32) -> PyResult<()> {
|
||||
*self.val_mut(py) = Some(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
def __delitem__(&self, key: i32) -> PyResult<()> {
|
||||
self.val(py).set(None);
|
||||
fn __delitem__(&self, py: Python, key: i32) -> PyResult<()> {
|
||||
*self.val_mut(py) = None;
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setdelitem() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let c = SetDelItem::create_instance(py, Cell::new(None)).unwrap();
|
||||
let c = SetDelItem::create_instance(py, None).unwrap();
|
||||
py_run!(py, c, "c[1] = 2");
|
||||
assert_eq!(c.val(py).get(), Some(2));
|
||||
assert_eq!(*c.val(py), Some(2));
|
||||
py_run!(py, c, "del c[1]");
|
||||
assert_eq!(c.val(py).get(), None);
|
||||
assert_eq!(*c.val(py), None);
|
||||
}
|
||||
|
||||
py_class!(class Reversed |py| {
|
||||
def __reversed__(&self) -> PyResult<&'static str> {
|
||||
#[py::class]
|
||||
struct Reversed {}
|
||||
|
||||
#[py::proto]
|
||||
impl PyMappingProtocol for Reversed{
|
||||
fn __reversed__(&self, py: Python) -> PyResult<&'static str> {
|
||||
println!("__reversed__");
|
||||
Ok("I am reversed")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reversed() {
|
||||
|
@ -559,11 +622,15 @@ fn reversed() {
|
|||
py_run!(py, c, "assert reversed(c) == 'I am reversed'");
|
||||
}
|
||||
|
||||
py_class!(class Contains |py| {
|
||||
def __contains__(&self, item: i32) -> PyResult<bool> {
|
||||
/*#[py::class]
|
||||
struct Contains {}
|
||||
|
||||
#[py::proto]
|
||||
impl PyMappingProtocol for Contains {
|
||||
fn __contains__(&self, py: Python, item: i32) -> PyResult<bool> {
|
||||
Ok(item >= 0)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contains() {
|
||||
|
@ -574,8 +641,9 @@ fn contains() {
|
|||
py_run!(py, c, "assert 1 in c");
|
||||
py_run!(py, c, "assert -1 not in c");
|
||||
py_run!(py, c, "assert 'wrong type' not in c");
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
py_class!(class UnaryArithmetic |py| {
|
||||
def __neg__(&self) -> PyResult<&'static str> {
|
||||
Ok("neg")
|
||||
|
@ -604,45 +672,53 @@ fn unary_arithmetic() {
|
|||
py_run!(py, c, "assert +c == 'pos'");
|
||||
py_run!(py, c, "assert abs(c) == 'abs'");
|
||||
py_run!(py, c, "assert ~c == 'invert'");
|
||||
}
|
||||
}*/
|
||||
|
||||
py_class!(class BinaryArithmetic |py| {
|
||||
/*
|
||||
#[py::class]
|
||||
struct BinaryArithmetic {}
|
||||
|
||||
#[py::proto]
|
||||
impl PyObjectProtocol for BinaryArithmetic {
|
||||
def __repr__(&self) -> PyResult<&'static str> {
|
||||
Ok("BA")
|
||||
}
|
||||
}
|
||||
|
||||
def __add__(lhs, rhs) -> PyResult<String> {
|
||||
#[py::proto]
|
||||
impl PyNumberProtocol for BinaryArithmetic {
|
||||
fn __add__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} + {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __sub__(lhs, rhs) -> PyResult<String> {
|
||||
fn __sub__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} - {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __mul__(lhs, rhs) -> PyResult<String> {
|
||||
fn __mul__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} * {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __lshift__(lhs, rhs) -> PyResult<String> {
|
||||
fn __lshift__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} << {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __rshift__(lhs, rhs) -> PyResult<String> {
|
||||
fn __rshift__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} >> {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __and__(lhs, rhs) -> PyResult<String> {
|
||||
fn __and__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} & {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __xor__(lhs, rhs) -> PyResult<String> {
|
||||
fn __xor__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} ^ {:?}", lhs, rhs))
|
||||
}
|
||||
|
||||
def __or__(lhs, rhs) -> PyResult<String> {
|
||||
fn __or__(lhs, rhs) -> PyResult<String> {
|
||||
Ok(format!("{:?} | {:?}", lhs, rhs))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binary_arithmetic() {
|
||||
|
@ -668,8 +744,9 @@ fn binary_arithmetic() {
|
|||
py_run!(py, c, "assert 1 ^ c == '1 ^ BA'");
|
||||
py_run!(py, c, "assert c | 1 == 'BA | 1'");
|
||||
py_run!(py, c, "assert 1 | c == '1 | BA'");
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
py_class!(class RichComparisons |py| {
|
||||
def __repr__(&self) -> PyResult<&'static str> {
|
||||
Ok("RC")
|
||||
|
@ -753,54 +830,62 @@ fn rich_comparisons_python_3_type_error() {
|
|||
py_expect_exception!(py, c2, "c2 >= 1", TypeError);
|
||||
py_expect_exception!(py, c2, "1 >= c2", TypeError);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
#[py::class]
|
||||
struct InPlaceOperations {
|
||||
value: u32
|
||||
}
|
||||
|
||||
py_class!(class InPlaceOperations |py| {
|
||||
data value: Cell<u32>;
|
||||
|
||||
def __repr__(&self) -> PyResult<String> {
|
||||
#[py::proto]
|
||||
impl PyObjectProtocol for InPlaceOperations {
|
||||
fn __repr__(&self, py: Python) -> PyResult<String> {
|
||||
Ok(format!("IPO({:?})", self.value(py).get()))
|
||||
}
|
||||
}
|
||||
|
||||
def __iadd__(&self, other: u32) -> PyResult<Self> {
|
||||
#[py::proto]
|
||||
impl PyNumberProtocol for InPlaceOperations {
|
||||
fn __iadd__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() + other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __isub__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __isub__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() - other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __imul__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __imul__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() * other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __ilshift__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __ilshift__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() << other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __irshift__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __irshift__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() >> other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __iand__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __iand__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() & other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __ixor__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __ixor__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() ^ other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
|
||||
def __ior__(&self, other: u32) -> PyResult<Self> {
|
||||
fn __ior__(&self, py: Python, other: u32) -> PyResult<Self> {
|
||||
self.value(py).set(self.value(py).get() | other);
|
||||
Ok(self.clone_ref(py))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inplace_operations() {
|
||||
|
@ -831,60 +916,74 @@ fn inplace_operations() {
|
|||
let c = InPlaceOperations::create_instance(py, Cell::new(12)).unwrap();
|
||||
py_run!(py, c, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'");
|
||||
}
|
||||
*/
|
||||
|
||||
py_class!(class ContextManager |py| {
|
||||
data exit_called : Cell<bool>;
|
||||
#[py::class]
|
||||
struct ContextManager {
|
||||
exit_called: bool
|
||||
}
|
||||
|
||||
def __enter__(&self) -> PyResult<i32> {
|
||||
#[py::proto]
|
||||
impl PyContextProtocol for ContextManager {
|
||||
|
||||
fn __enter__(&self, py: Python) -> PyResult<i32> {
|
||||
Ok(42)
|
||||
}
|
||||
|
||||
def __exit__(&self, ty: Option<PyType>, value: PyObject, traceback: PyObject) -> PyResult<bool> {
|
||||
self.exit_called(py).set(true);
|
||||
fn __exit__(&self, py: Python,
|
||||
ty: Option<PyType>,
|
||||
value: Option<PyObject>,
|
||||
traceback: Option<PyObject>) -> PyResult<bool> {
|
||||
*self.exit_called_mut(py) = true;
|
||||
if ty == Some(py.get_type::<exc::ValueError>()) {
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_manager() {
|
||||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let c = ContextManager::create_instance(py, Cell::new(false)).unwrap();
|
||||
let c = ContextManager::create_instance(py, false).unwrap();
|
||||
py_run!(py, c, "with c as x:\n assert x == 42");
|
||||
assert!(c.exit_called(py).get());
|
||||
assert!(*c.exit_called(py));
|
||||
|
||||
c.exit_called(py).set(false);
|
||||
*c.exit_called_mut(py) = false;
|
||||
py_run!(py, c, "with c as x:\n raise ValueError");
|
||||
assert!(c.exit_called(py).get());
|
||||
assert!(*c.exit_called(py));
|
||||
|
||||
c.exit_called(py).set(false);
|
||||
*c.exit_called_mut(py) = false;
|
||||
py_expect_exception!(py, c, "with c as x:\n raise NotImplementedError", NotImplementedError);
|
||||
assert!(c.exit_called(py).get());
|
||||
assert!(*c.exit_called(py));
|
||||
}
|
||||
|
||||
|
||||
py_class!(class ClassWithProperties |py| {
|
||||
data num: Cell<i32>;
|
||||
#[py::class]
|
||||
struct ClassWithProperties {
|
||||
num: i32
|
||||
}
|
||||
|
||||
def get_num(&self) -> PyResult<i32> {
|
||||
Ok(self.num(py).get())
|
||||
#[py::methods]
|
||||
impl ClassWithProperties {
|
||||
|
||||
fn get_num(&self, py: Python) -> PyResult<i32> {
|
||||
Ok(*self.num(py))
|
||||
}
|
||||
|
||||
property DATA {
|
||||
get(&slf) -> PyResult<i32> {
|
||||
Ok(slf.num(py).get())
|
||||
}
|
||||
set(&slf, value: i32) -> PyResult<()> {
|
||||
slf.num(py).set(value);
|
||||
Ok(())
|
||||
}
|
||||
#[getter(DATA)]
|
||||
fn get_data(&self, py: Python) -> PyResult<i32> {
|
||||
Ok(*self.num(py))
|
||||
}
|
||||
});
|
||||
#[setter(DATA)]
|
||||
fn set(&self, py: Python, value: i32) -> PyResult<()> {
|
||||
*self.num_mut(py) = value;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
|
@ -892,7 +991,7 @@ fn class_with_properties() {
|
|||
let gil = Python::acquire_gil();
|
||||
let py = gil.python();
|
||||
|
||||
let inst = ClassWithProperties::create_instance(py, Cell::new(10)).unwrap();
|
||||
let inst = ClassWithProperties::create_instance(py, 10).unwrap();
|
||||
|
||||
py_run!(py, inst, "assert inst.get_num() == 10");
|
||||
py_run!(py, inst, "assert inst.get_num() == inst.DATA");
|
||||
|
|
Loading…
Reference in a new issue