1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
use proc_macro::{self, TokenStream}; use quote::quote; use syn::{ parse_macro_input, DataEnum, Data, DeriveInput, Fields }; #[proc_macro_derive(QuickFrom, attributes(quick_from))] pub fn simple_from(input: TokenStream) -> TokenStream { let DeriveInput{ident, data, ..} = parse_macro_input!(input); let variants = if let Data::Enum(DataEnum{variants, ..}) = data { variants } else { return quote!{ compile_error!("SimpleFrom only accepts enums") }.into() }; let mut out = TokenStream::new(); for variant in variants { let has_attr = variant.attrs.iter().find(|attr| { attr.path.get_ident().map_or(false, |id| { id == "quick_from" }) }).is_some(); if !has_attr { continue } let enum_type = &ident; let var_name = variant.ident; let var_type = if let Fields::Unnamed(fields) = variant.fields { if fields.unnamed.len() != 1 { return quote!{ compile_error!("SimpleFrom #[from] variant must have \ exactly one unnamed field") }.into() } fields.unnamed.first().unwrap().ty.clone() } else { return quote!{ compile_error!("SimpleFrom #[from] variant must have \ exactly one unnamed field") }.into() }; let x : TokenStream = quote!{ impl From<#var_type> for #enum_type { fn from(x : #var_type) -> Self { Self::#var_name(x) } } }.into(); out.extend(x); } out.into() }