2018-07-02 17:41:01 +00:00
|
|
|
// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
|
|
|
|
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
|
|
|
|
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
2020-01-31 11:05:12 +00:00
|
|
|
/*
|
2018-07-02 18:31:23 +00:00
|
|
|
use proc_macro2;
|
2020-01-31 11:05:12 +00:00
|
|
|
use quote;
|
2018-07-02 18:31:23 +00:00
|
|
|
use syn;
|
2020-01-31 11:05:12 +00:00
|
|
|
use syn::punctuated;
|
|
|
|
use syn::token;
|
2017-11-12 18:02:56 +00:00
|
|
|
|
2020-01-07 10:17:23 +00:00
|
|
|
pub fn derive_arg_enum(_ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
2020-01-31 11:05:12 +00:00
|
|
|
let from_str_block = impl_from_str(ast)?;
|
|
|
|
let variants_block = impl_variants(ast)?;
|
2018-07-02 17:41:01 +00:00
|
|
|
|
2020-01-31 11:05:12 +00:00
|
|
|
quote! {
|
|
|
|
#from_str_block
|
|
|
|
#variants_block
|
|
|
|
}
|
2017-11-12 18:02:56 +00:00
|
|
|
}
|
|
|
|
|
2018-07-02 18:31:23 +00:00
|
|
|
fn impl_from_str(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
2017-11-12 18:02:56 +00:00
|
|
|
let ident = &ast.ident;
|
2017-11-15 17:49:55 +00:00
|
|
|
let is_case_sensitive = ast.attrs.iter().any(|v| v.name() == "case_sensitive");
|
2018-07-02 18:31:23 +00:00
|
|
|
let variants = variants(ast)?;
|
2017-11-12 18:02:56 +00:00
|
|
|
|
2018-07-02 17:41:01 +00:00
|
|
|
let strings = variants
|
|
|
|
.iter()
|
2017-11-12 18:02:56 +00:00
|
|
|
.map(|ref variant| String::from(variant.ident.as_ref()))
|
|
|
|
.collect::<Vec<_>>();
|
2018-07-02 17:41:01 +00:00
|
|
|
|
2017-11-15 17:49:55 +00:00
|
|
|
// All of these need to be iterators.
|
2017-11-12 18:02:56 +00:00
|
|
|
let ident_slice = [ident.clone()];
|
|
|
|
let idents = ident_slice.iter().cycle();
|
|
|
|
|
|
|
|
let for_error_message = strings.clone();
|
|
|
|
|
2017-11-15 17:49:55 +00:00
|
|
|
let condition_function_slice = [match is_case_sensitive {
|
|
|
|
true => quote! { str::eq },
|
|
|
|
false => quote! { ::std::ascii::AsciiExt::eq_ignore_ascii_case },
|
|
|
|
}];
|
|
|
|
let condition_function = condition_function_slice.iter().cycle();
|
|
|
|
|
2017-11-12 18:02:56 +00:00
|
|
|
Ok(quote! {
|
|
|
|
impl ::std::str::FromStr for #ident {
|
|
|
|
type Err = String;
|
|
|
|
|
|
|
|
fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
|
|
|
|
match input {
|
2017-11-15 17:49:55 +00:00
|
|
|
#(val if #condition_function(val, #strings) => Ok(#idents::#variants),)*
|
2017-11-12 18:02:56 +00:00
|
|
|
_ => Err({
|
|
|
|
let v = #for_error_message;
|
|
|
|
format!("valid values: {}",
|
|
|
|
v.join(" ,"))
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-07-02 18:31:23 +00:00
|
|
|
fn impl_variants(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
|
2017-11-12 18:02:56 +00:00
|
|
|
let ident = &ast.ident;
|
2018-07-02 18:31:23 +00:00
|
|
|
let variants = variants(ast)?
|
2017-11-12 18:02:56 +00:00
|
|
|
.iter()
|
|
|
|
.map(|ref variant| String::from(variant.ident.as_ref()))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
let length = variants.len();
|
|
|
|
|
|
|
|
Ok(quote! {
|
|
|
|
impl #ident {
|
|
|
|
fn variants() -> [&'static str; #length] {
|
|
|
|
#variants
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2018-07-02 17:41:01 +00:00
|
|
|
}
|
2018-07-02 18:31:23 +00:00
|
|
|
|
|
|
|
fn variants(ast: &syn::DeriveInput) -> &punctuated::Punctuated<syn::Variant, token::Comma> {
|
|
|
|
use syn::Data::*;
|
|
|
|
|
|
|
|
match ast.data {
|
|
|
|
Enum(ref data) => data.variants,
|
|
|
|
_ => panic!("Only enums are supported for deriving the ArgEnum trait"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|