| // Copyright 2022 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| use std::collections::HashSet; |
| |
| use proc_macro2::{Ident, Span}; |
| use quote::ToTokens; |
| use syn::{parse::Parse, Error, Token, Visibility}; |
| |
| pub struct Config { |
| pub allow_alias: bool, |
| pub repr_visibility: Visibility, |
| } |
| |
| impl Parse for Config { |
| fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { |
| let mut out = Self { |
| allow_alias: false, |
| repr_visibility: Visibility::Public(Token)), |
| }; |
| let mut seen_names = HashSet::new(); |
| while !input.is_empty() { |
| let name: Ident = input.parse()?; |
| let name_string = name.to_token_stream().to_string(); |
| let has_value = input.peek(Token![=]); |
| if has_value { |
| let _eq_token: Token![=] = input.parse()?; |
| } |
| match name_string.as_str() { |
| "allow_alias" => { |
| if has_value { |
| let allow_alias: syn::LitBool = input.parse()?; |
| out.allow_alias = allow_alias.value; |
| } else { |
| out.allow_alias = true; |
| } |
| } |
| name_str @ "inner_vis" if !has_value => { |
| return Err(Error::new( |
| name.span(), |
| format!("Option `{name_str}` requires a value"), |
| )) |
| } |
| "inner_vis" => { |
| out.repr_visibility = input.parse()?; |
| if matches!(out.repr_visibility, syn::Visibility::Inherited) { |
| return Err(input.error("Expected visibility")); |
| } |
| } |
| unknown_name => { |
| return Err(Error::new( |
| name.span(), |
| format!("Unknown option `{unknown_name}`"), |
| )); |
| } |
| } |
| if !input.is_empty() { |
| let _comma: Token![,] = input.parse()?; |
| } |
| if !seen_names.insert(name_string) { |
| return Err(Error::new( |
| name.span(), |
| format!( |
| "Option `{name}` listed more than once", |
| name = name.to_token_stream() |
| ), |
| )); |
| } |
| } |
| Ok(out) |
| } |
| } |