From bf252cf5560ae30e11fdb025471baa8352c3b0cb Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Sun, 27 Aug 2017 13:09:04 -0700 Subject: [PATCH 1/2] Handle enum discriminants for C-style enums. --- enum_index_derive/src/lib.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/enum_index_derive/src/lib.rs b/enum_index_derive/src/lib.rs index a7eb5f8..1583069 100644 --- a/enum_index_derive/src/lib.rs +++ b/enum_index_derive/src/lib.rs @@ -77,6 +77,14 @@ fn impl_index_enum(ast: &syn::DeriveInput) -> quote::Tokens { for variant in variants { use syn::VariantData::*; let ident = &variant.ident; + match variant.discriminant { + None => {}, + Some(syn::ConstExpr::Lit(syn::Lit::Int(i, _))) => { + index = i as usize; + }, + Some(_) => panic!("Unhandled enum discriminant!"), + }; + match variant.data { Unit => { index_matches.push(quote! { #index => Some(#name::#ident) }); From 3146a3cb7624bf89e30d2dceff9aea3b6261deb9 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Tue, 28 Jan 2020 13:54:35 -0800 Subject: [PATCH 2/2] Upgrade to latest proc macro stuff. --- enum_index_derive/Cargo.toml | 5 ++-- enum_index_derive/src/lib.rs | 58 +++++++++++++++++------------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/enum_index_derive/Cargo.toml b/enum_index_derive/Cargo.toml index 70cf724..3ff480d 100644 --- a/enum_index_derive/Cargo.toml +++ b/enum_index_derive/Cargo.toml @@ -12,8 +12,9 @@ homepage = "https://github.com/regresscheck/enum_index" readme = "../README.md" [dependencies] -syn = "0.11.11" -quote = "0.3.15" +syn = "1" +proc-macro2 = "1" +quote = "1" [lib] proc-macro = true diff --git a/enum_index_derive/src/lib.rs b/enum_index_derive/src/lib.rs index 1583069..72a6ece 100644 --- a/enum_index_derive/src/lib.rs +++ b/enum_index_derive/src/lib.rs @@ -2,44 +2,44 @@ extern crate syn; #[macro_use] extern crate quote; extern crate proc_macro; -use proc_macro::TokenStream; +extern crate proc_macro2; +use quote::format_ident; +use syn::{parse_macro_input, DeriveInput}; #[proc_macro_derive(EnumIndex)] -pub fn enum_index(input: TokenStream) -> TokenStream { - let s = input.to_string(); - let ast = syn::parse_derive_input(&s).unwrap(); +pub fn enum_index(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = parse_macro_input!(input as DeriveInput); let tokens = impl_enum_index(&ast); - tokens.parse().unwrap() + proc_macro::TokenStream::from(tokens) } -fn impl_enum_index(ast: &syn::DeriveInput) -> quote::Tokens { +fn impl_enum_index(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let name = &ast.ident; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - let variants = match ast.body { - syn::Body::Enum(ref v) => v, + let variants = match ast.data { + syn::Data::Enum(ref v) => &v.variants, _ => panic!("EnumIndex can be only implemented for Enums") }; let mut matches = Vec::new(); for variant in variants { - use syn::VariantData::*; + use syn::Fields::*; let ident = &variant.ident; - let params = match variant.data { - Unit => quote::Ident::from(""), - Tuple(..) => quote::Ident::from("(..)"), - Struct(..) => quote::Ident::from("{..}") + let params = match variant.fields { + Unit => format_ident!(""), + Unnamed(..) => format_ident!("(..)"), + Named(..) => format_ident!("{{..}}") }; let index = matches.len(); matches.push(quote!{ #name::#ident #params => #index}); } - quote!{ impl #impl_generics enum_index::EnumIndex for #name #ty_generics #where_clause { fn enum_index(&self) -> usize { @@ -53,21 +53,20 @@ fn impl_enum_index(ast: &syn::DeriveInput) -> quote::Tokens { #[proc_macro_derive(IndexEnum)] -pub fn index_enum(input: TokenStream) -> TokenStream { - let s = input.to_string(); - let ast = syn::parse_derive_input(&s).unwrap(); +pub fn index_enum(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = parse_macro_input!(input as DeriveInput); let tokens = impl_index_enum(&ast); - tokens.parse().unwrap() + proc_macro::TokenStream::from(tokens) } -fn impl_index_enum(ast: &syn::DeriveInput) -> quote::Tokens { +fn impl_index_enum(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { let name = &ast.ident; let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); - let variants = match ast.body { - syn::Body::Enum(ref v) => v, + let variants = match ast.data { + syn::Data::Enum(ref v) => &v.variants, _ => panic!("IndexEnum can be only implemented for Enums") }; @@ -75,23 +74,23 @@ fn impl_index_enum(ast: &syn::DeriveInput) -> quote::Tokens { let mut index : usize = 0; for variant in variants { - use syn::VariantData::*; + use syn::Fields::*; let ident = &variant.ident; match variant.discriminant { None => {}, - Some(syn::ConstExpr::Lit(syn::Lit::Int(i, _))) => { - index = i as usize; + Some((_, syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(ref i), .. }))) => { + index = i.base10_parse::().unwrap(); }, Some(_) => panic!("Unhandled enum discriminant!"), }; - match variant.data { + match variant.fields { Unit => { index_matches.push(quote! { #index => Some(#name::#ident) }); }, - Tuple(ref fields) => { + Unnamed(ref fields) => { let mut initialized_fields = Vec::new(); - for field in fields { + for field in &fields.unnamed { let field_type = &field.ty; initialized_fields.push(quote! { #field_type::default()} ); } @@ -99,9 +98,9 @@ fn impl_index_enum(ast: &syn::DeriveInput) -> quote::Tokens { #index => Some(#name::#ident(#(#initialized_fields),*)) }); } - Struct(ref fields) => { + Named(ref fields) => { let mut initialized_fields = Vec::new(); - for field in fields { + for field in &fields.named { let field_name = &field.ident; let field_type = &field.ty; initialized_fields.push(quote! { #field_name: #field_type::default()}); @@ -112,7 +111,6 @@ fn impl_index_enum(ast: &syn::DeriveInput) -> quote::Tokens { index += 1; } - quote!{ impl #impl_generics enum_index::IndexEnum for #name #ty_generics #where_clause { fn index_enum(index: usize) -> Option {