From 8d46a96068a7f5df96112ec5b2678b5929cfddfa Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sat, 22 Aug 2020 15:14:11 +0900 Subject: [PATCH] use meta item rather than parent name --- derive/src/pyclass.rs | 56 +++++++++++++++++++-------------- derive/src/pymodule.rs | 30 +++++++++--------- derive/src/util.rs | 71 +++++++++++++++++++++++++----------------- 3 files changed, 90 insertions(+), 67 deletions(-) diff --git a/derive/src/pyclass.rs b/derive/src/pyclass.rs index 430260819..089e1ab12 100644 --- a/derive/src/pyclass.rs +++ b/derive/src/pyclass.rs @@ -90,35 +90,38 @@ impl Class { } fn extract_method( - ident: &Ident, - nested: PunctuatedNestedMeta, + item: &Ident, + (meta, nested): (&Ident, PunctuatedNestedMeta), ) -> Result { - let item_meta = MethodItemMeta::from_nested("pymethod", &ident, nested.into_iter())?; + let item_meta = + MethodItemMeta::from_nested(item.clone(), meta.clone(), nested.into_iter())?; Ok(ClassItem::Method { - item_ident: ident.clone(), + item_ident: item.clone(), py_name: item_meta.method_name()?, }) } fn extract_classmethod( - ident: &Ident, - nested: PunctuatedNestedMeta, + item: &Ident, + (meta, nested): (&Ident, PunctuatedNestedMeta), ) -> Result { - let item_meta = MethodItemMeta::from_nested("pyclassmethod", &ident, nested.into_iter())?; + let item_meta = + MethodItemMeta::from_nested(item.clone(), meta.clone(), nested.into_iter())?; Ok(ClassItem::ClassMethod { - item_ident: ident.clone(), + item_ident: item.clone(), py_name: item_meta.method_name()?, }) } fn extract_property( - ident: &Ident, - nested: PunctuatedNestedMeta, + item: &Ident, + (meta, nested): (&Ident, PunctuatedNestedMeta), ) -> Result { - let item_meta = PropertyItemMeta::from_nested("pyproperty", &ident, nested.into_iter())?; + let item_meta = + PropertyItemMeta::from_nested(item.clone(), meta.clone(), nested.into_iter())?; Ok(ClassItem::Property { + item_ident: item.clone(), py_name: item_meta.property_name()?, - item_ident: ident.clone(), setter: item_meta.setter()?, }) } @@ -159,9 +162,13 @@ impl Class { }; let item = match name.to_string().as_str() { - "pymethod" => Self::extract_method(item.ident, attr.promoted_nested()?)?, - "pyclassmethod" => Self::extract_classmethod(item.ident, attr.promoted_nested()?)?, - "pyproperty" => Self::extract_property(item.ident, attr.promoted_nested()?)?, + "pymethod" => Self::extract_method(item.ident, attr.ident_and_promoted_nested()?)?, + "pyclassmethod" => { + Self::extract_classmethod(item.ident, attr.ident_and_promoted_nested()?)? + } + "pyproperty" => { + Self::extract_property(item.ident, attr.ident_and_promoted_nested()?)? + } "pyslot" => Self::extract_slot(item.ident, attr.promoted_nested()?)?, _ => { continue; @@ -208,7 +215,7 @@ impl MethodItemMeta { Ok(if let Some(name) = name { name } else { - let name = inner.ident.to_string(); + let name = inner.item_name(); if magic { format!("__{}__", name) } else { @@ -241,24 +248,24 @@ impl PropertyItemMeta { Ok(if let Some(name) = name { name } else { - let sig_name = inner.ident.to_string(); + let sig_name = inner.item_name(); let name = if setter { if let Some(name) = sig_name.strip_prefix("set_") { if name.is_empty() { bail_span!( - &inner.ident, + &inner.meta_ident, "A #[{}(setter)] fn with a set_* name must \ have something after \"set_\"", - inner.parent_type + inner.meta_name() ) } name.to_string() } else { bail_span!( - &inner.ident, + &inner.meta_ident, "A #[{}(setter)] fn must either have a `name` \ parameter or a fn name along the lines of \"set_*\"", - inner.parent_type + inner.meta_name() ) } } else { @@ -572,7 +579,8 @@ pub fn impl_pyclass(attr: AttributeArgs, item: Item) -> Result Result m, other => bail_span!(other, "#[pymodule] can only be on a module declaration"), }; + let fake_ident = Ident::new("pymodule", module_item.span()); let module_meta = - SimpleItemMeta::from_nested("pymodule", &module_item.ident, attr.into_iter())?; + SimpleItemMeta::from_nested(module_item.ident.clone(), fake_ident, attr.into_iter())?; let mut module_context = Module { name: module_meta.simple_name()?, items: ItemNursery::default(), @@ -260,8 +261,8 @@ impl ModuleItem for FunctionItem { }; let item_attr = attrs.remove(self.index()); let item_meta = SimpleItemMeta::from_nested( - "pyfunction", - &args.ident, + args.ident.clone(), + item_attr.get_ident().unwrap().clone(), item_attr.promoted_nested()?.into_iter(), )?; @@ -309,14 +310,10 @@ impl ModuleItem for ClassItem { )); } } - let static_name = match self.attr_name() { - "pyclass" => "pyclass", - "pystruct_sequence" => "pystruct_sequence", - _ => unreachable!(), - }; + let class_meta = ClassItemMeta::from_nested( - static_name, - &args.ident, + args.ident.clone(), + class_attr.get_ident().unwrap().clone(), class_attr.promoted_nested()?.into_iter(), )?; let module_name = args.module.name.clone(); @@ -328,8 +325,12 @@ impl ModuleItem for ClassItem { }; for attr_index in self.pyattrs.iter().rev() { let attr_attr = attrs.remove(*attr_index); - let nested = attr_attr.promoted_nested()?; - let item_meta = SimpleItemMeta::from_nested("pyattr", &args.ident, nested.into_iter())?; + let (meta_ident, nested) = attr_attr.ident_and_promoted_nested()?; + let item_meta = SimpleItemMeta::from_nested( + args.ident.clone(), + meta_ident.clone(), + nested.into_iter(), + )?; let py_name = item_meta .optional_name() @@ -356,8 +357,9 @@ impl ModuleItem for AttributeItem { fn gen_module_item(&self, args: ModuleItemArgs<'_>) -> Result<()> { let ident = &args.ident; let get_py_name = |attrs: &mut Vec| -> Result<_> { - let nested = attrs[self.inner.index].promoted_nested()?; - let item_meta = SimpleItemMeta::from_nested("pyattr", &ident, nested.into_iter())?; + let (meta_ident, nested) = attrs[self.inner.index].ident_and_promoted_nested()?; + let item_meta = + SimpleItemMeta::from_nested(ident.clone(), meta_ident.clone(), nested.into_iter())?; let py_name = item_meta.simple_name()?; Ok(py_name) }; diff --git a/derive/src/util.rs b/derive/src/util.rs index b9803d28b..7dff1113b 100644 --- a/derive/src/util.rs +++ b/derive/src/util.rs @@ -68,22 +68,22 @@ pub(crate) trait ContentItem { } pub(crate) struct ItemMetaInner { - pub ident: Ident, - pub parent_type: &'static str, - pub meta: HashMap, + pub item_ident: Ident, + pub meta_ident: Ident, + pub meta_map: HashMap, } impl ItemMetaInner { pub fn from_nested( - parent_type: &'static str, - ident: &Ident, + item_ident: Ident, + meta_ident: Ident, nested: I, allowed_names: &[&'static str], ) -> Result where I: std::iter::Iterator, { - let (named_map, lits) = nested.into_unique_map_and_lits(|path| { + let (meta_map, lits) = nested.into_unique_map_and_lits(|path| { if let Some(ident) = path.get_ident() { let name = ident.to_string(); if allowed_names.contains(&name.as_str()) { @@ -93,7 +93,7 @@ impl ItemMetaInner { ident, format!( "#[{}({})] is not one of allowed attributes {}", - parent_type, + meta_ident.to_string(), name, allowed_names.join(", ") ), @@ -105,20 +105,28 @@ impl ItemMetaInner { })?; if !lits.is_empty() { return Err(syn::Error::new_spanned( - ident, - format!("#[{}(..)] cannot contain literal", parent_type), + &meta_ident, + format!("#[{}(..)] cannot contain literal", meta_ident.to_string()), )); } Ok(Self { - ident: ident.clone(), - parent_type, - meta: named_map, + item_ident, + meta_ident, + meta_map, }) } + pub fn item_name(&self) -> String { + self.item_ident.to_string() + } + + pub fn meta_name(&self) -> String { + self.meta_ident.to_string() + } + pub fn _optional_str(&self, key: &str) -> Result> { - let value = if let Some((_, meta)) = self.meta.get(key) { + let value = if let Some((_, meta)) = self.meta_map.get(key) { match meta { Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(lit), @@ -129,7 +137,8 @@ impl ItemMetaInner { other, format!( "#[{}({} = ...)] must exist as a string", - self.parent_type, key + self.meta_name(), + key ), )); } @@ -141,7 +150,7 @@ impl ItemMetaInner { } pub fn _bool(&self, key: &str) -> Result { - let value = if let Some((_, meta)) = self.meta.get(key) { + let value = if let Some((_, meta)) = self.meta_map.get(key) { match meta { Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Bool(lit), @@ -151,7 +160,7 @@ impl ItemMetaInner { other => { return Err(syn::Error::new_spanned( other, - format!("#[{}({})] is expected", self.parent_type, key), + format!("#[{}({})] is expected", self.meta_name(), key), )) } } @@ -165,13 +174,13 @@ impl ItemMetaInner { pub(crate) trait ItemMeta: Sized { const ALLOWED_NAMES: &'static [&'static str]; - fn from_nested(parent_type: &'static str, ident: &Ident, nested: I) -> Result + fn from_nested(item_ident: Ident, meta_ident: Ident, nested: I) -> Result where I: std::iter::Iterator, { Ok(Self::from_inner(ItemMetaInner::from_nested( - parent_type, - ident, + item_ident, + meta_ident, nested, Self::ALLOWED_NAMES, )?)) @@ -184,7 +193,7 @@ pub(crate) trait ItemMeta: Sized { let inner = self.inner(); Ok(inner ._optional_str("name")? - .unwrap_or_else(|| inner.ident.to_string())) + .unwrap_or_else(|| inner.item_name())) } fn optional_name(&self) -> Option { @@ -221,22 +230,22 @@ impl ClassItemMeta { pub fn class_name(&self) -> Result { const KEY: &str = "name"; let inner = self.inner(); - let value = if let Some((_, meta)) = inner.meta.get(KEY) { + let value = if let Some((_, meta)) = inner.meta_map.get(KEY) { match meta { Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(lit), .. }) => Some(lit.value()), - Meta::Path(_) => Some(inner.ident.to_string()), + Meta::Path(_) => Some(inner.item_name()), _ => None, } } else { None }.ok_or_else(|| syn::Error::new_spanned( - &inner.ident, + &inner.meta_ident, format!( "#[{attr_name}(name = ...)] must exist as a string. Try #[{attr_name}(name)] to use rust type name.", - attr_name=inner.parent_type + attr_name=inner.meta_name() ), ))?; Ok(value) @@ -245,7 +254,7 @@ impl ClassItemMeta { pub fn module(&self) -> Result> { const KEY: &str = "module"; let inner = self.inner(); - let value = if let Some((_, meta)) = inner.meta.get(KEY) { + let value = if let Some((_, meta)) = inner.meta_map.get(KEY) { match meta { Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(lit), @@ -262,12 +271,12 @@ impl ClassItemMeta { other => Err(other.span()), } } else { - Err(inner.ident.span()) + Err(inner.item_ident.span()) }.map_err(|span| syn::Error::new( span, format!( "#[{attr_name}(module = ...)] must exist as a string or false. Try #[{attr_name}(module=false)] for built-in types.", - attr_name=inner.parent_type + attr_name=inner.meta_name() ), ))?; Ok(value) @@ -277,10 +286,10 @@ impl ClassItemMeta { let inner = self.inner(); let value = self.module().ok().flatten(). ok_or_else(|| syn::Error::new_spanned( - &inner.ident, + &inner.meta_ident, format!( "#[{attr_name}(module = ...)] must exist as a string. Built-in module is not allowed here.", - attr_name=inner.parent_type + attr_name=inner.meta_name() ), ))?; Ok(value) @@ -293,6 +302,7 @@ pub(crate) fn path_eq(path: &Path, s: &str) -> bool { pub(crate) trait AttributeExt: SynAttributeExt { fn promoted_nested(&self) -> Result; + fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)>; fn try_remove_name(&mut self, name: &str) -> Result>; fn fill_nested_meta(&mut self, name: &str, new_item: F) -> Result<()> where @@ -315,6 +325,9 @@ impl AttributeExt for Attribute { })?; Ok(list.nested) } + fn ident_and_promoted_nested(&self) -> Result<(&Ident, PunctuatedNestedMeta)> { + Ok((self.get_ident().unwrap(), self.promoted_nested()?)) + } fn try_remove_name(&mut self, item_name: &str) -> Result> { self.try_meta_mut(|meta| {