diff --git a/.gitignore b/.gitignore index 58f7b09..2f3f8f7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ flamegraph.svg perf.data perf.data.old -/target +**/target diff --git a/Cargo.lock b/Cargo.lock index 17351b0..7c85499 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,11 +145,21 @@ dependencies = [ "alpm", "anyhow", "clap", + "pacdef_macro", "path-absolutize", "regex", "serde_json", ] +[[package]] +name = "pacdef_macro" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "path-absolutize" version = "3.0.14" @@ -174,6 +184,24 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + [[package]] name = "regex" version = "1.7.1" @@ -220,6 +248,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -235,6 +274,12 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 6f0ec82..39aa187 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ clap = "3.*" path-absolutize = "*" regex = "1.7.1" serde_json = "1.0.91" +pacdef_macro = {path = "pacdef_macro/"} [profile.release] lto = "fat" diff --git a/pacdef_macro/Cargo.lock b/pacdef_macro/Cargo.lock new file mode 100644 index 0000000..9b7c0bb --- /dev/null +++ b/pacdef_macro/Cargo.lock @@ -0,0 +1,47 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "pacdef_macro" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" diff --git a/pacdef_macro/Cargo.toml b/pacdef_macro/Cargo.toml new file mode 100644 index 0000000..f9e77b6 --- /dev/null +++ b/pacdef_macro/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pacdef_macro" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +proc-macro2 = "1.0.49" +quote = "1.0.23" +syn = "1.0.107" + +[lib] +proc-macro = true diff --git a/pacdef_macro/src/lib.rs b/pacdef_macro/src/lib.rs new file mode 100644 index 0000000..fd3d881 --- /dev/null +++ b/pacdef_macro/src/lib.rs @@ -0,0 +1,74 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::DeriveInput; + +#[proc_macro_derive(Register)] +pub fn register(input: TokenStream) -> TokenStream { + let input = syn::parse::(input).unwrap(); + let name = &input.ident; + let enum_data = if let syn::Data::Enum(enum_data) = &input.data { + enum_data + } else { + panic!("`Register` can only be used on enums"); + }; + let first_variant = &enum_data.variants[0].ident; + + let variant_matches_backend = enum_data.variants.iter().map(|variant| { + let variant_name = &variant.ident; + quote! { + Self::#variant_name => Box::new(#variant_name::new()), + } + }); + + let variant_matches_next = enum_data.variants.iter().enumerate().map(|(i, variant)| { + let variant_name = &variant.ident; + if i == enum_data.variants.len() - 1 { + quote! { + Self::#variant_name => None, + } + } else { + let next_variant = &enum_data.variants[i + 1].ident; + quote! { + Self::#variant_name => Some(Self::#next_variant), + } + } + }); + + let variant_imports = enum_data.variants.iter().map(|variant| { + let variant_name = &variant.ident; + // let variant_module = variant_name.clone(); + + let variant_module = proc_macro2::Ident::new( + &variant_name.to_string().to_lowercase(), + proc_macro2::Span::call_site(), + ); + + quote! { + pub(crate) use #variant_module::#variant_name; + + } + }); + + let expanded = quote! { + #(#variant_imports)* + + impl #name { + pub fn iter() -> BackendIter { + BackendIter { + next: Some(Self::#first_variant), + } + } + fn get_backend(&self) -> Box { + match self { + #(#variant_matches_backend)* + } + } + fn next(&self) -> Option { + match self { + #(#variant_matches_next)* + } + } + } + }; + TokenStream::from(expanded) +} diff --git a/src/backend/macros.rs b/src/backend/macros.rs index b450746..29bf2ac 100644 --- a/src/backend/macros.rs +++ b/src/backend/macros.rs @@ -41,34 +41,3 @@ macro_rules! impl_backend_constants { } }; } - -#[macro_export] -macro_rules! register_backends { - ($first:ident, $($name:ident),*) => { - #[derive(Debug)] - pub(crate) enum Backends { - $first, - $( - $name, - )* - } - - impl Backends { - pub fn iter() -> BackendIter { - BackendIter { - next: Some(Backends::$first), - } - } - - fn get_backend(&self) -> Box { - match self { - Self::$first => Box::new($first::new()), - $( - Self::$name => Box::new($name::new()), - )* - } - } - - } - } -} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 0e1f54d..4f6344d 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -9,28 +9,18 @@ use std::process::Command; use anyhow::{Context, Result}; -use crate::register_backends; use crate::{Group, Package}; +use pacdef_macro::Register; pub(crate) use todo_per_backend::ToDoPerBackend; pub(in crate::backend) type Switches = &'static [&'static str]; pub(in crate::backend) type Text = &'static str; -register_backends!(Pacman, Rust); - -// TODO find a way to include this in the `register_backends!` macro -pub(crate) use pacman::Pacman; -pub(crate) use rust::Rust; - -// TODO find a way to include this in the `register_backends!` macro -impl Backends { - fn next(&self) -> Option { - match self { - Self::Pacman => Some(Self::Rust), - Self::Rust => None, - } - } +#[derive(Debug, Register)] +pub(crate) enum Backends { + Pacman, + Rust, } #[derive(Debug)] diff --git a/src/lib.rs b/src/lib.rs index bf7d31e..b4c1340 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,3 +12,5 @@ mod ui; pub use crate::core::Pacdef; pub use crate::grouping::Group; pub(crate) use crate::grouping::Package; + +extern crate pacdef_macro;