Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update syn: v2.0 #1096

Merged
merged 1 commit into from May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 {
Ok(None) => {
abort_call_site!(
"#[derive(glib::Boxed)] requires #[boxed_type(name = \"BoxedTypeName\")]"
)
}
Err(e) => return e.to_compile_error(),
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 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 {
Ok(None) => {
abort_call_site!("#[derive(glib::Enum)] requires #[enum_type(name = \"EnumTypeName\")]")
}
Err(e) => return e.to_compile_error(),
Ok(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 {
Ok(None) => {
abort_call_site!(
"#[derive(glib::ErrorDomain)] requires #[error_domain(name = \"domain-name\")]"
)
}
Err(e) => return e.to_compile_error(),
Ok(_) => (),
};
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
104 changes: 53 additions & 51 deletions glib-macros/src/flags_attribute.rs
Expand Up @@ -6,21 +6,34 @@ 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,
};

// 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();
use crate::utils::{crate_ident_new, parse_nested_meta_items, NestedMetaItem};

match meta {
None => false,
Some(meta) => find_nested_meta(&meta, "skip").is_some(),
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();

parse_nested_meta_items(attrs, "flags_value", &mut [&mut name, &mut nick, &mut skip])?;

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 +51,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 +113,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 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 @@
#[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 Expand Up @@ -870,7 +882,7 @@
///
/// ## Using Rust keywords as property names
/// You might hit a roadblock when declaring properties with this macro because you want to use a name that happens to be a Rust keyword. This may happen with names like `loop`, which is a pretty common name when creating things like animation handlers.
/// To use those names, you can make use of the raw identifier feature of Rust. Simply prefix the identifier name with `r#` in the struct declaration. Internally, those `r#`s are stripped so you can use its expected name in [`ObjectExt::property`] or within GtkBuilder template files.

Check warning on line 885 in glib-macros/src/lib.rs

View workflow job for this annotation

GitHub Actions / build

unresolved link to `ObjectExt::property`
///
/// # Generated wrapper methods
/// The following methods are generated on the wrapper type specified on `#[properties(wrapper_type = ...)]`:
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