rustify_derive/
params.rs

1use std::collections::HashMap;
2
3use crate::Error;
4use proc_macro2::Span;
5use syn::{Expr, Ident, LitStr, Type};
6
7/// Used for building the parameter list for the derive function
8#[derive(Default, Debug)]
9pub struct ParametersBuilder {
10    pub path: Option<LitStr>,
11    pub method: Option<Expr>,
12    pub response: Option<Type>,
13    pub request_type: Option<Expr>,
14    pub response_type: Option<Expr>,
15    pub builder: Option<bool>,
16}
17
18/// Represents all valid parameters that can be passed to the derive function
19#[derive(Debug)]
20pub struct Parameters {
21    pub path: LitStr,
22    pub method: Expr,
23    pub response: Type,
24    pub request_type: Expr,
25    pub response_type: Expr,
26    pub builder: bool,
27}
28
29impl Parameters {
30    /// Given a map of identities to literal strings, builds a new instance of
31    /// [Parameters] using the contents of the map.
32    ///
33    /// The only required parameter is `path` and not providing it will cause
34    /// the function to fail. All other parameters are optional and will have
35    /// sane defaults provided if they are not found in the map.
36    pub fn new(map: HashMap<Ident, LitStr>) -> Result<Parameters, Error> {
37        let mut builder = ParametersBuilder::default();
38        for key in map.keys() {
39            match key.to_string().as_str() {
40                "path" => builder.path = Some(map[key].clone()),
41                "method" => {
42                    builder.method = Some(parse(&map[key])?);
43                }
44                "response" => {
45                    builder.response = Some(parse(&map[key])?);
46                }
47                "request_type" => {
48                    builder.request_type = Some(parse(&map[key])?);
49                }
50                "response_type" => {
51                    builder.response_type = Some(parse(&map[key])?);
52                }
53                "builder" => {
54                    builder.builder = Some(true);
55                }
56                _ => {
57                    return Err(Error::new(key.span(), "Unknown parameter"));
58                }
59            }
60        }
61
62        let params = Parameters {
63            path: match builder.path {
64                Some(p) => p,
65                None => {
66                    return Err(Error::new(
67                        Span::call_site(),
68                        "Missing required parameter: path",
69                    ))
70                }
71            },
72            method: builder
73                .method
74                .unwrap_or_else(|| syn::parse_str("GET").unwrap()),
75            response: builder
76                .response
77                .unwrap_or_else(|| syn::parse_str("()").unwrap()),
78            request_type: builder
79                .request_type
80                .unwrap_or_else(|| syn::parse_str("JSON").unwrap()),
81            response_type: builder
82                .response_type
83                .unwrap_or_else(|| syn::parse_str("JSON").unwrap()),
84            builder: builder.builder.unwrap_or(false),
85        };
86
87        Ok(params)
88    }
89}
90
91/// Parses a [LitStr] into `T` and returns an error if it fails
92fn parse<T: syn::parse::Parse>(value: &LitStr) -> Result<T, Error> {
93    value
94        .parse()
95        .map_err(|_| Error::new(value.span(), "Unable to parse value"))
96}