{"id":16752682,"url":"https://github.com/azriel91/proc_macro_roids","last_synced_at":"2025-03-17T02:31:05.046Z","repository":{"id":60775596,"uuid":"178779319","full_name":"azriel91/proc_macro_roids","owner":"azriel91","description":"Traits and functions to make writing proc macros more ergonomic.","archived":false,"fork":false,"pushed_at":"2023-06-27T04:42:41.000Z","size":145,"stargazers_count":21,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-05-01T23:23:55.643Z","etag":null,"topics":["macro","proc-macro","rust"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/azriel91.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-01T03:30:33.000Z","updated_at":"2023-08-06T09:32:17.000Z","dependencies_parsed_at":"2024-10-13T02:47:50.151Z","dependency_job_id":"4498f034-913d-4a4c-8980-d30cef8d8bf3","html_url":"https://github.com/azriel91/proc_macro_roids","commit_stats":{"total_commits":69,"total_committers":1,"mean_commits":69.0,"dds":0.0,"last_synced_commit":"740fc0c0e19837b5aa0b6efab59bdec504fd30c2"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azriel91%2Fproc_macro_roids","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azriel91%2Fproc_macro_roids/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azriel91%2Fproc_macro_roids/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/azriel91%2Fproc_macro_roids/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/azriel91","download_url":"https://codeload.github.com/azriel91/proc_macro_roids/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243836993,"owners_count":20355811,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["macro","proc-macro","rust"],"created_at":"2024-10-13T02:47:47.836Z","updated_at":"2025-03-17T02:31:04.587Z","avatar_url":"https://github.com/azriel91.png","language":"Rust","readme":"# 💊 Proc Macro Roids\n\n[![Crates.io](https://img.shields.io/crates/v/proc_macro_roids.svg)](https://crates.io/crates/proc_macro_roids)\n[![docs.rs](https://img.shields.io/docsrs/proc_macro_roids)](https://docs.rs/proc_macro_roids)\n[![CI](https://github.com/azriel91/proc_macro_roids/workflows/CI/badge.svg)](https://github.com/azriel91/proc_macro_roids/actions/workflows/ci.yml)\n[![Coverage Status](https://codecov.io/gh/azriel91/proc_macro_roids/branch/main/graph/badge.svg)](https://codecov.io/gh/azriel91/proc_macro_roids)\n\nTraits and functions to make writing proc macros more ergonomic.\n\n```toml\nproc_macro_roids = \"0.8.0\"\n```\n\nMakes writing procedural macros much easier:\n\n```rust\nextern crate proc_macro;\n\nuse proc_macro::TokenStream;\nuse proc_macro2::Span;\nuse proc_macro_roids::{DeriveInputStructExt, FieldExt, IdentExt};\nuse quote::quote;\nuse syn::{parse_macro_input, parse_quote, DeriveInput, Ident};\n\n/// Derives a `Super` enum with a variant for each struct field:\n///\n/// ```rust,edition2021\n/// use std::marker::PhantomData;\n/// use super_derive::Super;\n///\n/// #[derive(Super)]\n/// pub struct Man\u003cT\u003e {\n///     #[super_derive(skip)]\n///     name: String,\n///     power_level: u64,\n///     marker: PhantomData\u003cT\u003e,\n/// }\n/// ```\n///\n/// Generates:\n///\n/// ```rust,ignore\n/// pub enum SuperMan {\n///     U64(u64),\n/// }\n/// ```\n#[proc_macro_derive(Super, attributes(super_derive))]\npub fn system_desc_derive(input: TokenStream) -\u003e TokenStream {\n    let ast = parse_macro_input!(input as DeriveInput);\n    let enum_name = ast.ident.prepend(\"Super\");\n    let fields = ast.fields();\n    let relevant_fields = fields\n        .iter()\n        .filter(|field| !field.is_phantom_data())\n        .filter(|field| !field.contains_tag(\u0026parse_quote!(super_derive), \u0026parse_quote!(skip)));\n\n    let variants = relevant_fields\n        .map(|field| {\n            let type_name = field.type_name();\n            let variant_name = type_name.to_string().to_uppercase();\n            let variant_name = Ident::new(\u0026variant_name, Span::call_site());\n            quote! {\n                #variant_name(#type_name)\n            }\n        })\n        .collect::\u003cVec\u003c_\u003e\u003e();\n\n    let token_stream2 = quote! {\n        pub enum #enum_name {\n            #(#variants,)*\n        }\n    };\n\n    token_stream2.into()\n}\n```\n\n## Examples\n\n\u003cdetails\u003e\n\n\u003csummary\u003e1. Append additional `#[derive(..)]`s.\u003c/summary\u003e\n\nThis works for function-like or attribute proc macros.\n\n```rust\nextern crate proc_macro;\n\nuse proc_macro::TokenStream;\nuse proc_macro_roids::DeriveInputExt;\nuse quote::quote;\nuse syn::{parse_macro_input, parse_quote, DeriveInput};\n\n#[proc_macro_attribute]\npub fn copy(_args: TokenStream, item: TokenStream) -\u003e TokenStream {\n    // Example input:\n    //\n    // #[derive(Debug)]\n    // struct Struct;\n    let mut ast = parse_macro_input!(item as DeriveInput);\n\n    // Append the derives.\n    let derives = parse_quote!(Clone, Copy);\n    ast.append_derives(derives);\n\n    // Example output:\n    //\n    // #[derive(Debug, Clone, Copy)]\n    // struct Struct;\n    TokenStream::from(quote! { #ast })\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e2. Append named fields.\u003c/summary\u003e\n\nThis works for structs with named fields or unit structs.\n\n```rust\nextern crate proc_macro;\n\nuse proc_macro::TokenStream;\nuse proc_macro_roids::FieldsNamedAppend;\nuse quote::quote;\nuse syn::{parse_macro_input, parse_quote, DeriveInput, FieldsNamed};\n\n/// Example usage:\n///\n/// ```rust\n/// use macro_crate::append_cd;\n///\n/// #[append_cd]\n/// struct StructNamed { a: u32, b: i32 }\n/// ```\n#[proc_macro_attribute]\npub fn append_cd(_args: TokenStream, item: TokenStream) -\u003e TokenStream {\n    // Example input:\n    //\n    // struct StructNamed { a: u32, b: i32 }\n    let mut ast = parse_macro_input!(item as DeriveInput);\n\n    // Append the fields.\n    let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });\n    ast.append_named(fields_additional);\n\n    // Example output:\n    //\n    // struct StructNamed { a: u32, b: i32, c: i64, d: usize }\n    TokenStream::from(quote! { #ast })\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e3. Append unnamed fields (tuples).\u003c/summary\u003e\n\nThis works for structs with unnamed fields or unit structs.\n\n```rust\nextern crate proc_macro;\n\nuse proc_macro::TokenStream;\nuse proc_macro_roids::FieldsUnnamedAppend;\nuse quote::quote;\nuse syn::{parse_macro_input, parse_quote, DeriveInput, FieldsUnnamed};\n\n/// Example usage:\n///\n/// ```rust\n/// use macro_crate::append_i64_usize;\n///\n/// #[append_i64_usize]\n/// struct StructUnit;\n/// ```\n#[proc_macro_attribute]\npub fn append_i64_usize(_args: TokenStream, item: TokenStream) -\u003e TokenStream {\n    // Example input:\n    //\n    // struct StructUnit;\n    let mut ast = parse_macro_input!(item as DeriveInput);\n\n    // Append the fields.\n    let fields_additional: FieldsUnnamed = parse_quote!((i64, usize));\n    ast.append_unnamed(fields_additional);\n\n    // Example output:\n    //\n    // struct StructUnit(i64, usize);\n    TokenStream::from(quote! { #ast })\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e4. Get newtype inner `Field`.\u003c/summary\u003e\n\nThis works for structs with unnamed fields or unit structs.\n\n```rust\nextern crate proc_macro;\n\nuse proc_macro::TokenStream;\nuse proc_macro_roids::DeriveInputNewtypeExt;\nuse quote::quote;\nuse syn::{parse_macro_input, parse_quote, DeriveInput, Type};\n\n#[proc_macro_derive(Deref)]\npub fn derive_deref(item: TokenStream) -\u003e TokenStream {\n    // Example input:\n    //\n    // #[derive(Deref)]\n    // struct Newtype(u32);\n    let mut ast = parse_macro_input!(item as DeriveInput);\n\n    // Get the inner field type.\n    let inner_type = ast.inner_type();\n\n    // Implement `Deref`\n    let type_name = \u0026ast.ident;\n    let token_stream_2 = quote! {\n        #ast\n\n        impl std::ops::Deref for #type_name {\n            type Target = #inner_type;\n            fn deref(\u0026self) -\u003e \u0026Self::Target {\n                \u0026self.0\n            }\n        }\n    }\n    TokenStream::from(token_stream_2)\n}\n```\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\n\u003csummary\u003e5. `Ident` concatenation.\u003c/summary\u003e\n\n```rust,edition2021\nuse proc_macro_roids::IdentExt;\nuse proc_macro2::Span;\nuse syn::Ident;\n\n# fn main() {\nlet one = Ident::new(\"One\", Span::call_site());\nassert_eq!(Ident::new(\"OneSuffix\", Span::call_site()), one.append(\"Suffix\"));\nassert_eq!(Ident::new(\"PrefixOne\", Span::call_site()), one.prepend(\"Prefix\"));\n\nlet two = Ident::new(\"Two\", Span::call_site());\nassert_eq!(Ident::new(\"OneTwo\", Span::call_site()), one.append(\u0026two));\nassert_eq!(Ident::new(\"TwoOne\", Span::call_site()), one.prepend(\u0026two));\n# }\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e6. Accessing struct fields.\u003c/summary\u003e\n\n```rust,edition2021\nuse proc_macro_roids::DeriveInputStructExt;\nuse syn::{parse_quote, DeriveInput, Fields};\n\n# fn main() {\nlet ast: DeriveInput = parse_quote! {\n    struct Named {}\n};\n\nif let Fields::Named(..) = ast.fields() {\n    // do something\n}\n# }\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e7. Inspecting `Field`s.\u003c/summary\u003e\n\n```rust,edition2021\nuse proc_macro_roids::FieldExt;\nuse proc_macro2::Span;\nuse syn::{parse_quote, Fields, FieldsNamed, Lit, LitStr, Meta, MetaNameValue, NestedMeta};\n\nlet fields_named: FieldsNamed = parse_quote! {{\n    #[my::derive(tag::name(param = \"value\"))]\n    pub name: PhantomData\u003cT\u003e,\n}};\nlet fields = Fields::from(fields_named);\nlet field = fields.iter().next().expect(\"Expected field to exist.\");\n\nassert_eq!(field.type_name(), \"PhantomData\");\nassert!(field.is_phantom_data());\nassert!(field.contains_tag(\u0026parse_quote!(my::derive), \u0026parse_quote!(tag::name)));\nassert_eq!(\n    field.tag_parameter(\n        \u0026parse_quote!(my::derive),\n        \u0026parse_quote!(tag::name),\n    ).expect(\"Expected parameter to exist.\"),\n    NestedMeta::Meta(Meta::NameValue(MetaNameValue {\n        path: parse_quote!(param),\n        eq_token: Default::default(),\n        lit: Lit::Str(LitStr::new(\"value\", Span::call_site())),\n    })),\n);\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e8. (De)constructing `Fields`.\u003c/summary\u003e\n\n```rust,edition2021\n# use std::str::FromStr;\n#\nuse proc_macro_roids::{DeriveInputStructExt, FieldsExt};\n# use proc_macro2::{Span, TokenStream};\n# use syn::{parse_quote, DeriveInput};\n# use quote::quote;\n#\n// Need to generate code that instantiates `MyEnum::Struct`:\n// enum MyEnum {\n//     Struct {\n//         field_0: u32,\n//         field_1: u32,\n//     }\n// }\n\nlet ast: DeriveInput = parse_quote! {\n    struct Struct {\n        field_0: u32,\n        field_1: u32,\n    }\n};\nlet fields = ast.fields();\nlet construction_form = fields.construction_form();\nlet tokens = quote! { MyEnum::Struct #construction_form };\n\nlet expected = TokenStream::from_str(\"MyEnum::Struct { field_0, field_1, }\").unwrap();\nassert_eq!(expected.to_string(), tokens.to_string());\n```\n\n\u003c/details\u003e\n\n---\n\n**Note:** The *roids* name is chosen because, although these functions make it easy to perform\ncertain operations, they may not always be good ideas =D!\n\n## License\n\nLicensed under either of\n\n* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)\n* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)\n\nat your option.\n\n\n### Contribution\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazriel91%2Fproc_macro_roids","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fazriel91%2Fproc_macro_roids","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fazriel91%2Fproc_macro_roids/lists"}