Traits and functions to make writing proc macros more ergonomic.
toml
proc_macro_roids = "0.7.0"
Makes writing procedural macros much easier:
```rust extern crate proc_macro;
use procmacro::TokenStream; use procmacro2::Span; use procmacroroids::{DeriveInputStructExt, FieldExt, IdentExt}; use quote::quote; use syn::{parsemacroinput, parse_quote, DeriveInput, Ident};
/// Derives a Super
enum with a variant for each struct field:
///
/// rust,edition2018
/// use std::marker::PhantomData;
/// use super_derive::Super;
///
/// #[derive(Super)]
/// pub struct Man<T> {
/// #[super_derive(skip)]
/// name: String,
/// power_level: u64,
/// marker: PhantomData<T>,
/// }
///
///
/// Generates:
///
/// rust,ignore
/// pub enum SuperMan {
/// U64(u64),
/// }
///
pub fn systemdescderive(input: TokenStream) -> TokenStream { let ast = parsemacroinput!(input as DeriveInput); let enumname = ast.ident.prepend("Super"); let fields = ast.fields(); let relevantfields = fields .iter() .filter(|field| !field.isphantomdata()) .filter(|field| !field.containstag(&parsequote!(superderive), &parsequote!(skip)));
let variants = relevant_fields
.map(|field| {
let type_name = field.type_name();
let variant_name = type_name.to_string().to_uppercase();
let variant_name = Ident::new(&variant_name, Span::call_site());
quote! {
#variant_name(#type_name)
}
})
.collect::<Vec<_>>();
let token_stream2 = quote! {
pub enum #enum_name {
#(#variants,)*
}
};
token_stream2.into()
} ```
#[derive(..)]
s.
This works for function-like or attribute proc macros.
```rust extern crate proc_macro;
use procmacro::TokenStream; use procmacroroids::DeriveInputExt; use quote::quote; use syn::{parsemacroinput, parsequote, DeriveInput};
pub fn copy(args: TokenStream, item: TokenStream) -> TokenStream { // Example input: // // #[derive(Debug)] // struct Struct; let mut ast = parsemacro_input!(item as DeriveInput);
// Append the derives.
let derives = parse_quote!(Clone, Copy);
ast.append_derives(derives);
// Example output:
//
// #[derive(Debug, Clone, Copy)]
// struct Struct;
TokenStream::from(quote! { #ast })
} ```
This works for structs with named fields or unit structs.
```rust extern crate proc_macro;
use procmacro::TokenStream; use procmacroroids::FieldsNamedAppend; use quote::quote; use syn::{parsemacroinput, parsequote, DeriveInput, FieldsNamed};
/// Example usage:
///
/// rust
/// use macro_crate::append_cd;
///
/// #[append_cd]
/// struct StructNamed { a: u32, b: i32 }
///
pub fn appendcd(args: TokenStream, item: TokenStream) -> TokenStream { // Example input: // // struct StructNamed { a: u32, b: i32 } let mut ast = parsemacroinput!(item as DeriveInput);
// Append the fields.
let fields_additional: FieldsNamed = parse_quote!({ c: i64, d: usize });
ast.append_named(fields_additional);
// Example output:
//
// struct StructNamed { a: u32, b: i32, c: i64, d: usize }
TokenStream::from(quote! { #ast })
} ```
This works for structs with unnamed fields or unit structs.
```rust extern crate proc_macro;
use procmacro::TokenStream; use procmacroroids::FieldsUnnamedAppend; use quote::quote; use syn::{parsemacroinput, parsequote, DeriveInput, FieldsUnnamed};
/// Example usage:
///
/// rust
/// use macro_crate::append_i64_usize;
///
/// #[append_i64_usize]
/// struct StructUnit;
///
pub fn appendi64usize(args: TokenStream, item: TokenStream) -> TokenStream { // Example input: // // struct StructUnit; let mut ast = parsemacro_input!(item as DeriveInput);
// Append the fields.
let fields_additional: FieldsUnnamed = parse_quote!((i64, usize));
ast.append_unnamed(fields_additional);
// Example output:
//
// struct StructUnit(i64, usize);
TokenStream::from(quote! { #ast })
} ```
Field
.
This works for structs with unnamed fields or unit structs.
```rust extern crate proc_macro;
use procmacro::TokenStream; use procmacroroids::DeriveInputNewtypeExt; use quote::quote; use syn::{parsemacroinput, parsequote, DeriveInput, Type};
pub fn derivederef(item: TokenStream) -> TokenStream { // Example input: // // #[derive(Deref)] // struct Newtype(u32); let mut ast = parsemacro_input!(item as DeriveInput);
// Get the inner field.
let inner_field = ast.inner_type();
// Implement `Deref`
let type_name = &ast.ident;
let token_stream_2 = quote! {
#ast
impl std::ops::Deref for #type_name {
type Target = #inner_type;
fn deref(&self) -> &Self::Target {
&self.0
}
}
}
TokenStream::from(token_stream_2)
} ```
Ident
concatenation.
```rust,edition2018 use procmacroroids::IdentExt; use proc_macro2::Span; use syn::Ident;
let one = Ident::new("One", Span::callsite()); asserteq!(Ident::new("OneSuffix", Span::callsite()), one.append("Suffix")); asserteq!(Ident::new("PrefixOne", Span::call_site()), one.prepend("Prefix"));
let two = Ident::new("Two", Span::callsite()); asserteq!(Ident::new("OneTwo", Span::callsite()), one.append(&two)); asserteq!(Ident::new("TwoOne", Span::call_site()), one.prepend(&two));
```
```rust,edition2018 use procmacroroids::DeriveInputStructExt; use syn::{parse_quote, DeriveInput, Fields};
let ast: DeriveInput = parse_quote! { struct Named {} };
if let Fields::Named(..) = ast.fields() { // do something }
```
Field
s.
```rust,edition2018 use procmacroroids::FieldExt; use procmacro2::Span; use syn::{parsequote, Fields, FieldsNamed, Lit, LitStr, Meta, MetaNameValue, NestedMeta};
let fieldsnamed: FieldsNamed = parsequote! {{
#[my::derive(tag::name(param = "value"))]
pub name: PhantomData
asserteq!(field.typename(), "PhantomData"); assert!(field.isphantomdata()); assert!(field.containstag(&parsequote!(my::derive), &parsequote!(tag::name))); asserteq!( field.tagparameter( &parsequote!(my::derive), &parsequote!(tag::name), ).expect("Expected parameter to exist."), NestedMeta::Meta(Meta::NameValue(MetaNameValue { path: parsequote!(param), eqtoken: Default::default(), lit: Lit::Str(LitStr::new("value", Span::callsite())), })), ); ```
Fields
.
```rust,edition2018
# use procmacroroids::{DeriveInputStructExt, FieldsExt};
#
// Need to generate code that instantiates MyEnum::Struct
:
// enum MyEnum {
// Struct {
// field0: u32,
// field1: u32,
// }
// }
let ast: DeriveInput = parsequote! { struct Struct { field0: u32, field1: u32, } }; let fields = ast.fields(); let constructionform = fields.constructionform(); let tokens = quote! { MyEnum::Struct #constructionform };
let expected = TokenStream::fromstr("MyEnum::Struct { field0, field1, }").unwrap(); asserteq!(expected.tostring(), tokens.tostring()); ```
Note: The roids name is chosen because, although these functions make it easy to perform certain operations, they may not always be good ideas =D!
Licensed under either of
at your option.
Unless 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.