rustify_derive/
params.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::collections::HashMap;

use crate::Error;
use proc_macro2::Span;
use syn::{Expr, Ident, LitStr, Type};

/// Used for building the parameter list for the derive function
#[derive(Default, Debug)]
pub struct ParametersBuilder {
    pub path: Option<LitStr>,
    pub method: Option<Expr>,
    pub response: Option<Type>,
    pub request_type: Option<Expr>,
    pub response_type: Option<Expr>,
    pub builder: Option<bool>,
}

/// Represents all valid parameters that can be passed to the derive function
#[derive(Debug)]
pub struct Parameters {
    pub path: LitStr,
    pub method: Expr,
    pub response: Type,
    pub request_type: Expr,
    pub response_type: Expr,
    pub builder: bool,
}

impl Parameters {
    /// Given a map of identities to literal strings, builds a new instance of
    /// [Parameters] using the contents of the map.
    ///
    /// The only required parameter is `path` and not providing it will cause
    /// the function to fail. All other parameters are optional and will have
    /// sane defaults provided if they are not found in the map.
    pub fn new(map: HashMap<Ident, LitStr>) -> Result<Parameters, Error> {
        let mut builder = ParametersBuilder::default();
        for key in map.keys() {
            match key.to_string().as_str() {
                "path" => builder.path = Some(map[key].clone()),
                "method" => {
                    builder.method = Some(parse(&map[key])?);
                }
                "response" => {
                    builder.response = Some(parse(&map[key])?);
                }
                "request_type" => {
                    builder.request_type = Some(parse(&map[key])?);
                }
                "response_type" => {
                    builder.response_type = Some(parse(&map[key])?);
                }
                "builder" => {
                    builder.builder = Some(true);
                }
                _ => {
                    return Err(Error::new(key.span(), "Unknown parameter"));
                }
            }
        }

        let params = Parameters {
            path: match builder.path {
                Some(p) => p,
                None => {
                    return Err(Error::new(
                        Span::call_site(),
                        "Missing required parameter: path",
                    ))
                }
            },
            method: builder
                .method
                .unwrap_or_else(|| syn::parse_str("GET").unwrap()),
            response: builder
                .response
                .unwrap_or_else(|| syn::parse_str("()").unwrap()),
            request_type: builder
                .request_type
                .unwrap_or_else(|| syn::parse_str("JSON").unwrap()),
            response_type: builder
                .response_type
                .unwrap_or_else(|| syn::parse_str("JSON").unwrap()),
            builder: builder.builder.unwrap_or(false),
        };

        Ok(params)
    }
}

/// Parses a [LitStr] into `T` and returns an error if it fails
fn parse<T: syn::parse::Parse>(value: &LitStr) -> Result<T, Error> {
    value
        .parse()
        .map_err(|_| Error::new(value.span(), "Unable to parse value"))
}