119625d8cSopenharmony_ci// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>, 219625d8cSopenharmony_ci// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and 319625d8cSopenharmony_ci// Ana Hobden (@hoverbear) <operator@hoverbear.org> 419625d8cSopenharmony_ci// 519625d8cSopenharmony_ci// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 619625d8cSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 719625d8cSopenharmony_ci// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 819625d8cSopenharmony_ci// option. This file may not be copied, modified, or distributed 919625d8cSopenharmony_ci// except according to those terms. 1019625d8cSopenharmony_ci// 1119625d8cSopenharmony_ci// This work was derived from Structopt (https://github.com/TeXitoi/structopt) 1219625d8cSopenharmony_ci// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the 1319625d8cSopenharmony_ci// MIT/Apache 2.0 license. 1419625d8cSopenharmony_ci 1519625d8cSopenharmony_ciuse proc_macro2::TokenStream; 1619625d8cSopenharmony_ciuse quote::quote; 1719625d8cSopenharmony_ciuse syn::Ident; 1819625d8cSopenharmony_ciuse syn::Variant; 1919625d8cSopenharmony_ciuse syn::{ 2019625d8cSopenharmony_ci self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields, 2119625d8cSopenharmony_ci Generics, 2219625d8cSopenharmony_ci}; 2319625d8cSopenharmony_ci 2419625d8cSopenharmony_ciuse crate::derives::{args, into_app, subcommand}; 2519625d8cSopenharmony_ciuse crate::item::Item; 2619625d8cSopenharmony_ciuse crate::item::Name; 2719625d8cSopenharmony_ci 2819625d8cSopenharmony_cipub fn derive_parser(input: &DeriveInput) -> Result<TokenStream, syn::Error> { 2919625d8cSopenharmony_ci let ident = &input.ident; 3019625d8cSopenharmony_ci let pkg_name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default(); 3119625d8cSopenharmony_ci 3219625d8cSopenharmony_ci match input.data { 3319625d8cSopenharmony_ci Data::Struct(DataStruct { 3419625d8cSopenharmony_ci fields: Fields::Named(ref fields), 3519625d8cSopenharmony_ci .. 3619625d8cSopenharmony_ci }) => { 3719625d8cSopenharmony_ci let name = Name::Assigned(quote!(#pkg_name)); 3819625d8cSopenharmony_ci let item = Item::from_args_struct(input, name)?; 3919625d8cSopenharmony_ci let fields = fields 4019625d8cSopenharmony_ci .named 4119625d8cSopenharmony_ci .iter() 4219625d8cSopenharmony_ci .map(|field| { 4319625d8cSopenharmony_ci let item = Item::from_args_field(field, item.casing(), item.env_casing())?; 4419625d8cSopenharmony_ci Ok((field, item)) 4519625d8cSopenharmony_ci }) 4619625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 4719625d8cSopenharmony_ci gen_for_struct(&item, ident, &input.generics, &fields) 4819625d8cSopenharmony_ci } 4919625d8cSopenharmony_ci Data::Struct(DataStruct { 5019625d8cSopenharmony_ci fields: Fields::Unit, 5119625d8cSopenharmony_ci .. 5219625d8cSopenharmony_ci }) => { 5319625d8cSopenharmony_ci let name = Name::Assigned(quote!(#pkg_name)); 5419625d8cSopenharmony_ci let item = Item::from_args_struct(input, name)?; 5519625d8cSopenharmony_ci let fields = Punctuated::<Field, Comma>::new(); 5619625d8cSopenharmony_ci let fields = fields 5719625d8cSopenharmony_ci .iter() 5819625d8cSopenharmony_ci .map(|field| { 5919625d8cSopenharmony_ci let item = Item::from_args_field(field, item.casing(), item.env_casing())?; 6019625d8cSopenharmony_ci Ok((field, item)) 6119625d8cSopenharmony_ci }) 6219625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 6319625d8cSopenharmony_ci gen_for_struct(&item, ident, &input.generics, &fields) 6419625d8cSopenharmony_ci } 6519625d8cSopenharmony_ci Data::Enum(ref e) => { 6619625d8cSopenharmony_ci let name = Name::Assigned(quote!(#pkg_name)); 6719625d8cSopenharmony_ci let item = Item::from_subcommand_enum(input, name)?; 6819625d8cSopenharmony_ci let variants = e 6919625d8cSopenharmony_ci .variants 7019625d8cSopenharmony_ci .iter() 7119625d8cSopenharmony_ci .map(|variant| { 7219625d8cSopenharmony_ci let item = 7319625d8cSopenharmony_ci Item::from_subcommand_variant(variant, item.casing(), item.env_casing())?; 7419625d8cSopenharmony_ci Ok((variant, item)) 7519625d8cSopenharmony_ci }) 7619625d8cSopenharmony_ci .collect::<Result<Vec<_>, syn::Error>>()?; 7719625d8cSopenharmony_ci gen_for_enum(&item, ident, &input.generics, &variants) 7819625d8cSopenharmony_ci } 7919625d8cSopenharmony_ci _ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"), 8019625d8cSopenharmony_ci } 8119625d8cSopenharmony_ci} 8219625d8cSopenharmony_ci 8319625d8cSopenharmony_cifn gen_for_struct( 8419625d8cSopenharmony_ci item: &Item, 8519625d8cSopenharmony_ci item_name: &Ident, 8619625d8cSopenharmony_ci generics: &Generics, 8719625d8cSopenharmony_ci fields: &[(&Field, Item)], 8819625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 8919625d8cSopenharmony_ci let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 9019625d8cSopenharmony_ci 9119625d8cSopenharmony_ci let into_app = into_app::gen_for_struct(item, item_name, generics)?; 9219625d8cSopenharmony_ci let args = args::gen_for_struct(item, item_name, generics, fields)?; 9319625d8cSopenharmony_ci 9419625d8cSopenharmony_ci Ok(quote! { 9519625d8cSopenharmony_ci impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {} 9619625d8cSopenharmony_ci 9719625d8cSopenharmony_ci #into_app 9819625d8cSopenharmony_ci #args 9919625d8cSopenharmony_ci }) 10019625d8cSopenharmony_ci} 10119625d8cSopenharmony_ci 10219625d8cSopenharmony_cifn gen_for_enum( 10319625d8cSopenharmony_ci item: &Item, 10419625d8cSopenharmony_ci item_name: &Ident, 10519625d8cSopenharmony_ci generics: &Generics, 10619625d8cSopenharmony_ci variants: &[(&Variant, Item)], 10719625d8cSopenharmony_ci) -> Result<TokenStream, syn::Error> { 10819625d8cSopenharmony_ci let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); 10919625d8cSopenharmony_ci 11019625d8cSopenharmony_ci let into_app = into_app::gen_for_enum(item, item_name, generics)?; 11119625d8cSopenharmony_ci let subcommand = subcommand::gen_for_enum(item, item_name, generics, variants)?; 11219625d8cSopenharmony_ci 11319625d8cSopenharmony_ci Ok(quote! { 11419625d8cSopenharmony_ci impl #impl_generics clap::Parser for #item_name #ty_generics #where_clause {} 11519625d8cSopenharmony_ci 11619625d8cSopenharmony_ci #into_app 11719625d8cSopenharmony_ci #subcommand 11819625d8cSopenharmony_ci }) 11919625d8cSopenharmony_ci} 120