doubter_impl/
config.rs

1use std::fmt;
2use std::str::FromStr;
3
4use proc_macro2::Span;
5use syn;
6use syn::parse;
7use syn::parse::{Parse, ParseStream};
8use syn::punctuated::Punctuated;
9use syn::{Ident, Lit};
10
11#[derive(Debug, Copy, Clone)]
12pub enum Mode {
13    Raw,
14    Extract,
15}
16
17#[derive(Debug)]
18pub struct Config {
19    pub includes: Vec<String>,
20    pub mode: Option<Mode>,
21    pub use_external_doc: bool,
22}
23
24impl FromStr for Config {
25    type Err = parse::Error;
26
27    fn from_str(s: &str) -> Result<Self, Self::Err> {
28        syn::parse_str(s)
29    }
30}
31
32impl Parse for Config {
33    fn parse(input: ParseStream) -> parse::Result<Self> {
34        let fields = Punctuated::<Field, Token![,]>::parse_terminated(input)?;
35
36        let mut includes = vec![];
37        let mut mode = None;
38        let mut use_external_doc = false;
39
40        for field in fields {
41            match &*field.ident.to_string() {
42                "include" => match field.value {
43                    Lit::Str(s) => includes.push(s.value()),
44                    _ => return Err(parse_error("unsupported literal type in 'include' field.")),
45                },
46                "mode" => match field.value {
47                    Lit::Str(s) => match s.value().trim() {
48                        "raw" => mode = Some(Mode::Raw),
49                        "extract" => mode = Some(Mode::Extract),
50                        s => return Err(parse_error(format!("invalid mode: {:?}", s))),
51                    },
52                    _ => return Err(parse_error("unsupported literal type in 'mode' field.")),
53                },
54                "use_external_doc" => match field.value {
55                    Lit::Str(s) => match s.value().trim() {
56                        "on" | "true" | "yes" => use_external_doc = true,
57                        "off" | "false" | "no" => use_external_doc = false,
58                        s => {
59                            return Err(parse_error(format!(
60                                "invalid value in `use_external_doc`: {}",
61                                s
62                            )))
63                        }
64                    },
65                    Lit::Bool(b) => use_external_doc = b.value,
66                    _ => {
67                        return Err(parse_error(
68                            "unsupported literal type in 'use_external_doc' field.",
69                        ))
70                    }
71                },
72                s => return Err(parse_error(format!("invalid key: {:?}", s))),
73            }
74        }
75
76        Ok(Config {
77            includes,
78            mode,
79            use_external_doc,
80        })
81    }
82}
83
84fn parse_error<D>(message: D) -> parse::Error
85where
86    D: fmt::Display,
87{
88    parse::Error::new(Span::call_site(), message)
89}
90
91#[derive(Debug)]
92struct Field {
93    ident: Ident,
94    eq: Token![=],
95    value: Lit,
96}
97
98impl Parse for Field {
99    fn parse(input: ParseStream) -> parse::Result<Self> {
100        Ok(Field {
101            ident: input.parse()?,
102            eq: input.parse()?,
103            value: input.parse()?,
104        })
105    }
106}