pyo3/pyo3cls/src/py_class.rs

152 lines
5.1 KiB
Rust
Raw Normal View History

2017-05-16 05:24:06 +00:00
// Copyright (c) 2017-present PyO3 Project and Contributors
use syn;
use quote::Tokens;
2017-05-16 05:24:06 +00:00
pub fn build_py_class(ast: &mut syn::DeriveInput) -> Tokens {
2017-05-25 03:31:51 +00:00
let base = syn::Ident::from("_pyo3::PyObject");
2017-05-28 05:45:48 +00:00
let mut token: Option<syn::Ident> = None;
2017-05-17 06:43:39 +00:00
match ast.body {
2017-05-28 05:45:48 +00:00
syn::Body::Struct(syn::VariantData::Struct(ref mut fields)) => {
for field in fields.iter_mut() {
let mut attrs = vec![];
for attr in field.attrs.iter() {
match attr.value {
syn::MetaItem::Word(ref a) => {
if a.as_ref() == "token" {
token = field.ident.clone();
continue
}
},
_ => (),
}
attrs.push(attr.clone());
}
field.attrs = attrs;
}
},
_ => panic!("#[class] can only be used with notmal structs"),
2017-05-17 06:43:39 +00:00
}
2017-05-16 05:24:06 +00:00
let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident));
2017-05-28 05:45:48 +00:00
let tokens = impl_class(&ast.ident, &base, token);
2017-05-16 05:24:06 +00:00
quote! {
#[feature(specialization)]
#[allow(non_upper_case_globals, unused_attributes,
unused_qualifications, unused_variables, non_camel_case_types)]
2017-05-16 05:24:06 +00:00
const #dummy_const: () = {
2017-05-18 18:15:06 +00:00
extern crate pyo3 as _pyo3;
2017-05-16 05:24:06 +00:00
#tokens
};
}
}
2017-05-28 05:45:48 +00:00
fn impl_class(cls: &syn::Ident, base: &syn::Ident, token: Option<syn::Ident>) -> Tokens {
2017-05-18 23:57:39 +00:00
let cls_name = quote! { #cls }.as_str().to_string();
2017-05-28 05:45:48 +00:00
let extra = if let Some(token) = token {
Some(quote! {
2017-05-29 04:19:29 +00:00
impl _pyo3::PythonObjectWithToken for #cls {
2017-05-29 20:30:38 +00:00
fn token<'p>(&'p self) -> _pyo3::python::Python<'p> {
self.#token.token()
2017-05-28 05:45:48 +00:00
}
}
2017-05-28 15:57:34 +00:00
impl std::fmt::Debug for #cls {
2017-05-28 05:45:48 +00:00
fn fmt(&self, f : &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
2017-05-28 15:57:34 +00:00
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
let repr = unsafe {
2017-05-29 04:19:29 +00:00
PyString::downcast_from_owned_ptr(
2017-05-28 15:57:34 +00:00
self.token(), _pyo3::ffi::PyObject_Repr(ptr))
2017-05-29 04:19:29 +00:00
.map_err(|_| std::fmt::Error)?
};
2017-05-28 15:57:34 +00:00
f.write_str(&repr.to_string_lossy())
2017-05-28 05:45:48 +00:00
}
}
impl std::fmt::Display for #cls {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
2017-05-28 15:57:34 +00:00
let ptr = <#cls as _pyo3::python::ToPythonPointer>::as_ptr(self);
2017-05-29 04:19:29 +00:00
let str_obj = unsafe {
PyString::downcast_from_owned_ptr(
self.token(), _pyo3::ffi::PyObject_Str(ptr))
.map_err(|_| std::fmt::Error)?
};
f.write_str(&str_obj.to_string_lossy())
2017-05-28 05:45:48 +00:00
}
2017-05-28 15:57:34 +00:00
}
2017-05-28 05:45:48 +00:00
})
} else {
None
};
2017-05-17 06:43:39 +00:00
quote! {
2017-05-25 05:43:07 +00:00
impl _pyo3::typeob::PyTypeInfo for #cls {
type Type = #cls;
2017-05-22 05:22:45 +00:00
#[inline]
fn size() -> usize {
Self::offset() as usize + std::mem::size_of::<#cls>()
2017-05-22 05:22:45 +00:00
}
2017-05-17 06:43:39 +00:00
2017-05-22 05:22:45 +00:00
#[inline]
fn offset() -> isize {
2017-05-22 05:22:45 +00:00
let align = std::mem::align_of::<#cls>();
2017-05-25 05:43:07 +00:00
let bs = <#base as _pyo3::typeob::PyTypeInfo>::size();
2017-05-17 06:43:39 +00:00
2017-05-22 05:22:45 +00:00
// round base_size up to next multiple of align
((bs + align - 1) / align * align) as isize
2017-05-17 06:43:39 +00:00
}
2017-05-18 23:57:39 +00:00
#[inline]
fn type_name() -> &'static str { #cls_name }
2017-05-17 06:43:39 +00:00
#[inline]
2017-05-19 04:35:08 +00:00
fn type_object() -> &'static mut _pyo3::ffi::PyTypeObject {
2017-05-18 18:15:06 +00:00
static mut TYPE_OBJECT: _pyo3::ffi::PyTypeObject = _pyo3::ffi::PyTypeObject_INIT;
2017-05-19 04:35:08 +00:00
unsafe { &mut TYPE_OBJECT }
2017-05-17 06:43:39 +00:00
}
}
2017-05-25 05:43:07 +00:00
impl<'p> _pyo3::python::PyDowncastFrom<'p> for #cls
{
fn downcast_from(py: &'p _pyo3::PyObject<'p>)
-> Result<&'p #cls, _pyo3::PyDowncastError<'p>>
{
unsafe {
let checked = ffi::PyObject_TypeCheck(
py.as_ptr(), <#cls as _pyo3::typeob::PyTypeInfo>::type_object()) != 0;
if checked {
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
let ptr = (py.as_ptr() as *mut u8).offset(offset) as *mut #cls;
Ok(ptr.as_ref().unwrap())
} else {
2017-05-29 20:30:38 +00:00
Err(_pyo3::PyDowncastError(py.gil(), None))
}
}
}
}
2017-05-30 05:59:03 +00:00
impl _pyo3::python::ToPythonPointer for #cls {
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
let offset = <#cls as _pyo3::typeob::PyTypeInfo>::offset();
unsafe {
{self as *const _ as *mut u8}.offset(-offset) as *mut ffi::PyObject
}
}
}
2017-05-29 20:30:38 +00:00
impl _pyo3::class::PyCustomObject for #cls {
}
2017-05-28 05:45:48 +00:00
#extra
2017-05-16 05:24:06 +00:00
}
}