Skip to content

Commit

Permalink
update to syn 2.0 and refactor attribute handling
Browse files Browse the repository at this point in the history
  • Loading branch information
ranfdev committed May 11, 2023
1 parent 53532d2 commit da9c950
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 237 deletions.
2 changes: 1 addition & 1 deletion glib-macros/Cargo.toml
Expand Up @@ -17,7 +17,7 @@ heck = "0.4"
proc-macro-error = "1.0"
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full"] }
syn = { version = "2.0", features = ["full"] }
proc-macro-crate = "1.0"

[lib]
Expand Down
33 changes: 22 additions & 11 deletions glib-macros/src/boxed_derive.rs
Expand Up @@ -4,7 +4,7 @@ use proc_macro2::{Ident, TokenStream};
use proc_macro_error::abort_call_site;
use quote::quote;

use crate::utils::{crate_ident_new, find_attribute_meta, find_nested_meta, parse_name};
use crate::utils::{crate_ident_new, parse_nested_meta_items, NestedMetaItem};

fn gen_option_to_ptr() -> TokenStream {
quote! {
Expand Down Expand Up @@ -94,18 +94,29 @@ fn gen_impl_to_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenS
pub fn impl_boxed(input: &syn::DeriveInput) -> TokenStream {
let name = &input.ident;

let gtype_name = match parse_name(input, "boxed_type") {
Ok(name) => name,
Err(e) => abort_call_site!(
"{}: #[derive(glib::Boxed)] requires #[boxed_type(name = \"BoxedTypeName\")]",
e
),
let mut gtype_name = NestedMetaItem::<syn::LitStr>::new("name")
.required()
.value_required();
let mut nullable = NestedMetaItem::<syn::LitBool>::new("nullable").value_optional();

let found = parse_nested_meta_items(
&input.attrs,
"boxed_type",
&mut [&mut gtype_name, &mut nullable],
);

match found {
None => {
abort_call_site!(
"#[derive(glib::Boxed)] requires #[boxed_type(name = \"BoxedTypeName\")]"
)
}
Some((_, Err(e))) => return e.to_compile_error(),
Some((_, Ok(()))) => (),
};

let meta = find_attribute_meta(&input.attrs, "boxed_type")
.unwrap()
.unwrap();
let nullable = find_nested_meta(&meta, "nullable").is_some();
let gtype_name = gtype_name.value.unwrap();
let nullable = nullable.found || nullable.value.map(|b| b.value()).unwrap_or(false);

let crate_ident = crate_ident_new();

Expand Down
49 changes: 24 additions & 25 deletions glib-macros/src/enum_derive.rs
Expand Up @@ -6,9 +6,7 @@ use proc_macro_error::abort_call_site;
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Data, Ident, Variant};

use crate::utils::{
crate_ident_new, gen_enum_from_glib, parse_item_attributes, parse_name, ItemAttribute,
};
use crate::utils::{crate_ident_new, gen_enum_from_glib, parse_nested_meta_items, NestedMetaItem};

// Generate glib::gobject_ffi::GEnumValue structs mapping the enum such as:
// glib::gobject_ffi::GEnumValue {
Expand All @@ -29,21 +27,17 @@ fn gen_enum_values(
let mut value_name = name.to_string().to_upper_camel_case();
let mut value_nick = name.to_string().to_kebab_case();

let attrs = parse_item_attributes("enum_value", &v.attrs);
let attrs = match attrs {
Ok(attrs) => attrs,
Err(e) => abort_call_site!(
"{}: derive(glib::Enum) enum supports only the following optional attributes: #[enum_value(name = \"The Cat\", nick = \"chat\")]",
e
),
};

attrs.into_iter().for_each(|attr|
match attr {
ItemAttribute::Name(n) => value_name = n,
ItemAttribute::Nick(n) => value_nick = n,
}
);
let mut name_attr = NestedMetaItem::<syn::LitStr>::new("name").value_required();
let mut nick = NestedMetaItem::<syn::LitStr>::new("nick").value_required();

let found =
parse_nested_meta_items(&v.attrs, "enum_value", &mut [&mut name_attr, &mut nick]);
if let Some((_, Err(e))) = found {
return e.to_compile_error();
}

value_name = name_attr.value.map(|s| s.value()).unwrap_or(value_name);
value_nick = nick.value.map(|s| s.value()).unwrap_or(value_nick);

let value_name = format!("{value_name}\0");
let value_nick = format!("{value_nick}\0");
Expand Down Expand Up @@ -73,14 +67,19 @@ pub fn impl_enum(input: &syn::DeriveInput) -> TokenStream {
_ => abort_call_site!("#[derive(glib::Enum)] only supports enums"),
};

let gtype_name = match parse_name(input, "enum_type") {
Ok(name) => name,
Err(e) => abort_call_site!(
"{}: #[derive(glib::Enum)] requires #[enum_type(name = \"EnumTypeName\")]",
e
),
};
let mut gtype_name = NestedMetaItem::<syn::LitStr>::new("name")
.required()
.value_required();
let found = parse_nested_meta_items(&input.attrs, "enum_type", &mut [&mut gtype_name]);

match found {
None => {
abort_call_site!("#[derive(glib::Enum)] requires #[enum_type(name = \"EnumTypeName\")]")
}
Some((_, Err(e))) => return e.to_compile_error(),
Some((attr, _)) => attr,
};
let gtype_name = gtype_name.value.unwrap();
let from_glib = gen_enum_from_glib(name, enum_variants);
let (enum_values, nb_enum_values) = gen_enum_values(name, enum_variants);

Expand Down
23 changes: 15 additions & 8 deletions glib-macros/src/error_domain_derive.rs
Expand Up @@ -5,7 +5,7 @@ use proc_macro_error::abort_call_site;
use quote::quote;
use syn::Data;

use crate::utils::{crate_ident_new, gen_enum_from_glib, parse_name};
use crate::utils::{crate_ident_new, gen_enum_from_glib, parse_nested_meta_items, NestedMetaItem};

pub fn impl_error_domain(input: &syn::DeriveInput) -> TokenStream {
let name = &input.ident;
Expand All @@ -15,14 +15,21 @@ pub fn impl_error_domain(input: &syn::DeriveInput) -> TokenStream {
_ => abort_call_site!("#[derive(glib::ErrorDomain)] only supports enums"),
};

let domain_name = match parse_name(input, "error_domain") {
Ok(name) => name,
Err(e) => abort_call_site!(
"{}: #[derive(glib::ErrorDomain)] requires #[error_domain(name = \"domain-name\")]",
e
),
};
let mut domain_name = NestedMetaItem::<syn::LitStr>::new("name")
.required()
.value_required();
let found = parse_nested_meta_items(&input.attrs, "error_domain", &mut [&mut domain_name]);

match found {
None => {
abort_call_site!(
"#[derive(glib::ErrorDomain)] requires #[error_domain(name = \"domain-name\")]"
)
}
Some((_, Err(e))) => return e.to_compile_error(),
_ => (),
};
let domain_name = domain_name.value.unwrap();
let crate_ident = crate_ident_new();

let from_glib = gen_enum_from_glib(name, enum_variants);
Expand Down
106 changes: 56 additions & 50 deletions glib-macros/src/flags_attribute.rs
Expand Up @@ -6,21 +6,38 @@ use proc_macro_error::abort_call_site;
use quote::{quote, quote_spanned};
use syn::{
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, DeriveInput, Ident,
NestedMeta, Variant, Visibility,
Variant, Visibility,
};

use crate::utils::{
crate_ident_new, find_attribute_meta, find_nested_meta, parse_item_attributes,
parse_name_attribute, ItemAttribute,
};
use crate::utils::{crate_ident_new, parse_nested_meta_items, NestedMetaItem};

pub struct AttrInput {
pub enum_name: syn::LitStr,
}
struct FlagsDesc {
variant: Variant,
name: Option<String>,
nick: Option<String>,
skip: bool,
}
impl FlagsDesc {
fn from_attrs(variant: Variant, attrs: &[Attribute]) -> syn::Result<Self> {
let mut name = NestedMetaItem::<syn::LitStr>::new("name").value_required();
let mut nick = NestedMetaItem::<syn::LitStr>::new("nick").value_required();
let mut skip = NestedMetaItem::<syn::LitBool>::new("skip").value_optional();

// Flag is not registered if it has the #[flags_value(skip)] meta
fn attribute_has_skip(attrs: &[Attribute]) -> bool {
let meta = find_attribute_meta(attrs, "flags_value").unwrap();
let found =
parse_nested_meta_items(attrs, "flags_value", &mut [&mut name, &mut nick, &mut skip]);

match meta {
None => false,
Some(meta) => find_nested_meta(&meta, "skip").is_some(),
if let Some((_, Err(e))) = found {
return Err(e);
}
Ok(Self {
variant,
name: name.value.map(|s| s.value()),
nick: nick.value.map(|s| s.value()),
skip: skip.found || skip.value.map(|b| b.value()).unwrap_or(false),
})
}
}

Expand All @@ -38,39 +55,35 @@ fn gen_flags_values(

// start at one as GFlagsValue array is null-terminated
let mut n = 1;
let recurse = enum_variants.iter().filter(|v| { !attribute_has_skip(&v.attrs) } ).map(|v| {
let name = &v.ident;
let mut value_name = name.to_string().to_upper_camel_case();
let mut value_nick = name.to_string().to_kebab_case();

let attrs = parse_item_attributes("flags_value", &v.attrs);
let attrs = match attrs {
Ok(attrs) => attrs,
Err(e) => abort_call_site!(
"{}: #[glib::flags] supports only the following optional attributes: #[flags_value(name = \"The Name\", nick = \"the-nick\")] or #[flags_value(skip)]",
e
),
};

attrs.into_iter().for_each(|attr|
match attr {
ItemAttribute::Name(n) => value_name = n,
ItemAttribute::Nick(n) => value_nick = n,
let recurse = enum_variants
.iter()
.map(|v| FlagsDesc::from_attrs(v.clone(), &v.attrs).unwrap())
.filter(|desc| !desc.skip)
.map(|desc| {
let v = desc.variant;
let name = &v.ident;
let mut value_name = name.to_string().to_upper_camel_case();
let mut value_nick = name.to_string().to_kebab_case();

if let Some(n) = desc.name {
value_name = n;
}
if let Some(n) = desc.nick {
value_nick = n;
}
);

let value_name = format!("{value_name}\0");
let value_nick = format!("{value_nick}\0");
let value_name = format!("{value_name}\0");
let value_nick = format!("{value_nick}\0");

n += 1;
quote_spanned! {v.span()=>
#crate_ident::gobject_ffi::GFlagsValue {
value: #enum_name::#name.bits(),
value_name: #value_name as *const _ as *const _,
value_nick: #value_nick as *const _ as *const _,
},
}
});
n += 1;
quote_spanned! {v.span()=>
#crate_ident::gobject_ffi::GFlagsValue {
value: #enum_name::#name.bits(),
value_name: #value_name as *const _ as *const _,
value_nick: #value_nick as *const _ as *const _,
},
}
});
(
quote! {
#(#recurse)*
Expand Down Expand Up @@ -104,15 +117,8 @@ fn gen_bitflags(
}
}

pub fn impl_flags(attrs: &NestedMeta, input: &DeriveInput) -> TokenStream {
let gtype_name = match parse_name_attribute(attrs) {
Ok(name) => name,
Err(e) => abort_call_site!(
"{}: [glib::flags] requires #[glib::flags(name = \"FlagsTypeName\")]",
e
),
};

pub fn impl_flags(attrs: AttrInput, input: &DeriveInput) -> TokenStream {
let gtype_name = attrs.enum_name.value();
let name = &input.ident;
let visibility = &input.vis;

Expand Down
18 changes: 15 additions & 3 deletions glib-macros/src/lib.rs
Expand Up @@ -16,9 +16,11 @@ mod variant_derive;

mod utils;

use flags_attribute::AttrInput;
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use syn::{parse_macro_input, DeriveInput, NestedMeta};
use syn::{parse_macro_input, DeriveInput};
use utils::{parse_nested_meta_items_from_stream, NestedMetaItem};

/// Macro for passing variables as strong or weak references into a closure.
///
Expand Down Expand Up @@ -498,9 +500,19 @@ pub fn enum_derive(input: TokenStream) -> TokenStream {
#[proc_macro_attribute]
#[proc_macro_error]
pub fn flags(attr: TokenStream, item: TokenStream) -> TokenStream {
let attr_meta = parse_macro_input!(attr as NestedMeta);
let mut name = NestedMetaItem::<syn::LitStr>::new("name")
.required()
.value_required();

if let Err(e) = parse_nested_meta_items_from_stream(attr.into(), &mut [&mut name]) {
return e.to_compile_error().into();
}

let attr_meta = AttrInput {
enum_name: name.value.unwrap(),
};
let input = parse_macro_input!(item as DeriveInput);
let gen = flags_attribute::impl_flags(&attr_meta, &input);
let gen = flags_attribute::impl_flags(attr_meta, &input);
gen.into()
}

Expand Down
2 changes: 1 addition & 1 deletion glib-macros/src/object_subclass_attribute.rs
Expand Up @@ -15,7 +15,7 @@ pub fn impl_object_subclass(input: &syn::ItemImpl) -> TokenStream {
let mut has_class = false;
for item in &input.items {
match item {
syn::ImplItem::Method(method) => {
syn::ImplItem::Fn(method) => {
let name = &method.sig.ident;
if name == "new" || name == "with_class" {
has_new = true;
Expand Down
6 changes: 3 additions & 3 deletions glib-macros/src/properties.rs
Expand Up @@ -42,7 +42,7 @@ impl Parse for PropsMacroInput {
let wrapper_ty = derive_input
.attrs
.iter()
.find(|x| x.path.is_ident("properties"))
.find(|x| x.path().is_ident("properties"))
.ok_or_else(|| {
syn::Error::new(
derive_input.span(),
Expand Down Expand Up @@ -141,7 +141,7 @@ impl Parse for PropAttr {
"builder" => {
let content;
parenthesized!(content in input);
let required = content.parse_terminated(syn::Expr::parse)?;
let required = content.parse_terminated(syn::Expr::parse, Token![,])?;
let rest: TokenStream2 = input.parse()?;
PropAttr::Builder(required, rest)
}
Expand Down Expand Up @@ -502,7 +502,7 @@ fn parse_fields(fields: syn::Fields) -> syn::Result<Vec<PropDesc>> {
} = field;
attrs
.into_iter()
.filter(|a| a.path.is_ident("property"))
.filter(|a| a.path().is_ident("property"))
.map(move |prop_attrs| {
let span = prop_attrs.span();
PropDesc::new(
Expand Down

0 comments on commit da9c950

Please sign in to comment.