Skip to content

Commit

Permalink
glib-macros: port attribute parsing to use deluxe crate
Browse files Browse the repository at this point in the history
  • Loading branch information
jf2048 committed Feb 7, 2023
1 parent e73ff61 commit b1b0d1b
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 327 deletions.
1 change: 1 addition & 0 deletions glib-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", features = ["full"], default-features = false }
proc-macro-crate = "1.0"
deluxe = "0.3.2"

[lib]
proc-macro = true
Expand Down
32 changes: 17 additions & 15 deletions glib-macros/src/boxed_derive.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
// Take a look at the license at the top of the repository in the LICENSE file.

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;

fn gen_option_to_ptr() -> TokenStream {
quote! {
Expand Down Expand Up @@ -91,21 +90,22 @@ fn gen_impl_to_value_optional(name: &Ident, crate_ident: &TokenStream) -> TokenS
}
}

pub fn impl_boxed(input: &syn::DeriveInput) -> TokenStream {
let name = &input.ident;
#[derive(deluxe::ExtractAttributes, Default)]
#[deluxe(attributes(boxed_type))]
struct BoxedType {
name: String,
#[deluxe(default)]
nullable: bool,
}

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
),
};
pub fn impl_boxed(mut input: syn::DeriveInput) -> TokenStream {
let name = &input.ident;

let meta = find_attribute_meta(&input.attrs, "boxed_type")
.unwrap()
.unwrap();
let nullable = find_nested_meta(&meta, "nullable").is_some();
let errors = deluxe::Errors::new();
let BoxedType {
name: gtype_name,
nullable,
} = deluxe::extract_attributes_optional(&mut input.attrs, &errors);

let crate_ident = crate_ident_new();

Expand All @@ -121,6 +121,8 @@ pub fn impl_boxed(input: &syn::DeriveInput) -> TokenStream {
};

quote! {
#errors

impl #crate_ident::subclass::boxed::BoxedType for #name {
const NAME: &'static str = #gtype_name;
}
Expand Down
83 changes: 42 additions & 41 deletions glib-macros/src/enum_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ 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};

#[derive(deluxe::ExtractAttributes, Default)]
#[deluxe(attributes(enum_type))]
struct EnumType {
name: String,
}

#[derive(deluxe::ExtractAttributes, Default)]
#[deluxe(attributes(enum_value), default)]
struct EnumValue {
name: Option<String>,
nick: Option<String>,
}

// Generate glib::gobject_ffi::GEnumValue structs mapping the enum such as:
// glib::gobject_ffi::GEnumValue {
Expand All @@ -18,35 +29,24 @@ use crate::utils::{
// },
fn gen_enum_values(
enum_name: &Ident,
enum_variants: &Punctuated<Variant, Comma>,
enum_variants: &mut Punctuated<Variant, Comma>,
errors: &deluxe::Errors,
) -> (TokenStream, usize) {
let crate_ident = crate_ident_new();

// start at one as GEnumValue array is null-terminated
let mut n = 1;
let recurse = enum_variants.iter().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("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 recurse = enum_variants.iter_mut().map(|v| {
let EnumValue {
name: value_name,
nick: value_nick,
} = deluxe::extract_attributes_optional(v, errors);

let value_name = format!("{value_name}\0");
let value_nick = format!("{value_nick}\0");
let name = &v.ident;
let mut value_name = value_name.unwrap_or_else(|| name.to_string().to_upper_camel_case());
let mut value_nick = value_nick.unwrap_or_else(|| name.to_string().to_kebab_case());
value_name.push('\0');
value_nick.push('\0');

n += 1;
quote_spanned! {v.span()=>
Expand All @@ -65,28 +65,27 @@ fn gen_enum_values(
)
}

pub fn impl_enum(input: &syn::DeriveInput) -> TokenStream {
let name = &input.ident;

let enum_variants = match input.data {
Data::Enum(ref e) => &e.variants,
pub fn impl_enum(mut input: syn::DeriveInput) -> TokenStream {
let enum_variants = match &mut input.data {
Data::Enum(e) => &mut e.variants,
_ => 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 errors = deluxe::Errors::new();
let EnumType {
name: mut gtype_name,
} = deluxe::extract_attributes_optional(&mut input.attrs, &errors);
gtype_name.push('\0');

let name = &input.ident;
let from_glib = gen_enum_from_glib(name, enum_variants);
let (enum_values, nb_enum_values) = gen_enum_values(name, enum_variants);
let (enum_values, nb_enum_values) = gen_enum_values(name, enum_variants, &errors);

let crate_ident = crate_ident_new();

quote! {
#errors

impl #crate_ident::translate::IntoGlib for #name {
type GlibType = i32;

Expand Down Expand Up @@ -175,9 +174,11 @@ pub fn impl_enum(input: &syn::DeriveInput) -> TokenStream {
},
];

let name = ::std::ffi::CString::new(#gtype_name).expect("CString::new failed");
unsafe {
let type_ = #crate_ident::gobject_ffi::g_enum_register_static(name.as_ptr(), VALUES.as_ptr());
let type_ = #crate_ident::gobject_ffi::g_enum_register_static(
#gtype_name.as_ptr() as *const _,
VALUES.as_ptr(),
);
let type_: #crate_ident::Type = #crate_ident::translate::from_glib(type_);
assert!(type_.is_valid());
TYPE = type_;
Expand Down
30 changes: 18 additions & 12 deletions glib-macros/src/error_domain_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,43 @@ 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};

pub fn impl_error_domain(input: &syn::DeriveInput) -> TokenStream {
#[derive(deluxe::ExtractAttributes, Default)]
#[deluxe(attributes(error_domain))]
struct ErrorDomainType {
name: String,
}

pub fn impl_error_domain(mut input: syn::DeriveInput) -> TokenStream {
let name = &input.ident;

let enum_variants = match input.data {
Data::Enum(ref e) => &e.variants,
let enum_variants = match &mut input.data {
Data::Enum(e) => &mut e.variants,
_ => 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 errors = deluxe::Errors::new();
let ErrorDomainType {
name: mut domain_name,
} = deluxe::extract_attributes_optional(&mut input.attrs, &errors);
domain_name.push('\0');

let crate_ident = crate_ident_new();

let from_glib = gen_enum_from_glib(name, enum_variants);

quote! {
#errors

impl #crate_ident::error::ErrorDomain for #name {
#[inline]
fn domain() -> #crate_ident::Quark {
use #crate_ident::translate::from_glib;

static QUARK: #crate_ident::once_cell::sync::Lazy<#crate_ident::Quark> =
#crate_ident::once_cell::sync::Lazy::new(|| unsafe {
from_glib(#crate_ident::ffi::g_quark_from_static_string(concat!(#domain_name, "\0") as *const str as *const _))
from_glib(#crate_ident::ffi::g_quark_from_static_string(#domain_name.as_ptr() as *const _))
});
*QUARK
}
Expand Down
Loading

0 comments on commit b1b0d1b

Please sign in to comment.