Skip to content

Commit

Permalink
Generate getters/setters
Browse files Browse the repository at this point in the history
  • Loading branch information
messense committed Aug 2, 2017
1 parent e44365b commit b10089d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 4 deletions.
66 changes: 62 additions & 4 deletions pyo3cls/src/py_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,33 @@ use syn;
use quote::{Tokens, ToTokens};

use utils;
use method::FnType;


pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
let (params, flags, base) = parse_attribute(attr);
let doc = utils::get_doc(&ast.attrs, true);
let mut token: Option<syn::Ident> = None;

let mut descriptors = Vec::new();
match ast.body {
syn::Body::Struct(syn::VariantData::Struct(ref mut fields)) => {
for field in fields.iter() {
for field in fields.iter_mut() {
if is_python_token(field) {
token = field.ident.clone();
break
} else {
let field_descs = parse_descriptors(field);
if !field_descs.is_empty() {
descriptors.push((field.clone(), field_descs));
}
}
}
},
_ => panic!("#[class] can only be used with normal structs"),
}

let dummy_const = syn::Ident::new(format!("_IMPL_PYO3_CLS_{}", ast.ident));
let tokens = impl_class(&ast.ident, &base, token, doc, params, flags);
let tokens = impl_class(&ast.ident, &base, token, doc, params, flags, descriptors);

quote! {
#[allow(non_upper_case_globals, unused_attributes,
Expand All @@ -41,9 +47,53 @@ pub fn build_py_class(ast: &mut syn::DeriveInput, attr: String) -> Tokens {
}
}

fn parse_descriptors(item: &mut syn::Field) -> Vec<FnType> {
let mut descs = Vec::new();
let mut new_attrs = Vec::new();
for attr in item.attrs.iter() {
match attr.value {
syn::MetaItem::List(ref name, ref metas) => {
match name.as_ref() {
"prop" => {
for meta in metas.iter() {
match *meta {
syn::NestedMetaItem::MetaItem(ref metaitem) => {
match metaitem.name() {
"getter" => {
descs.push(FnType::Getter(None));
}
"setter" => {
descs.push(FnType::Setter(None));
}
_ => {
panic!("Only getter and setter supported");
}
}
}
_ => ()
}
}
}
_ => {
new_attrs.push(attr.clone());
}
}
}
_ => {
new_attrs.push(attr.clone());
}
}
}
item.attrs.clear();
item.attrs.extend(new_attrs);
descs
}

fn impl_class(cls: &syn::Ident, base: &syn::Ident,
token: Option<syn::Ident>, doc: syn::Lit,
params: HashMap<&'static str, syn::Ident>, flags: Vec<syn::Ident>) -> Tokens {
params: HashMap<&'static str, syn::Ident>,
flags: Vec<syn::Ident>,
descriptors: Vec<(syn::Field, Vec<FnType>)>) -> Tokens {
let cls_name = match params.get("name") {
Some(name) => quote! { #name }.as_str().to_string(),
None => quote! { #cls }.as_str().to_string()
Expand Down Expand Up @@ -145,6 +195,14 @@ fn impl_class(cls: &syn::Ident, base: &syn::Ident,
}
};

let extra = if !descriptors.is_empty() {
Some(quote! {
#extra
})
} else {
extra
};

// insert space for weak ref
let mut has_weakref = false;
let mut has_dict = false;
Expand Down
6 changes: 6 additions & 0 deletions tests/test_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1280,3 +1280,9 @@ fn weakref_dunder_dict_support() {
let inst = Py::new_ref(py, |t| WeakRefDunderDictSupport{token: t}).unwrap();
py_run!(py, inst, "import weakref; assert weakref.ref(inst)() is inst; inst.a = 1; assert inst.a == 1");
}

#[py::class]
struct GetterSetter {
#[prop(getter, setter)]
num: i32,
}

0 comments on commit b10089d

Please sign in to comment.