move_syn/
functions.rs

1use unsynn::*;
2
3use crate::{Generics, MaybeRefType, kw};
4
5cfg_if::cfg_if!(if #[cfg(feature = "fun-args")] {
6    unsynn! {
7        pub struct Function {
8            entry: Option<kw::Entry>,
9            fun_kw: kw::Fun,
10            ident: Ident,
11            generics: Option<Generics>,
12            args: FunctionArgs,
13            ret: Option<FunctionReturn>,
14            body: BraceGroup,
15        }
16
17        struct FunctionArgs(ParenthesisGroupContaining<CommaDelimitedVec<FunctionArg>>);
18
19        /// E.g., `name: T`, `mut name: T`, `name: &T`, `name: &mut T`.
20        struct FunctionArg {
21            mut_: Option<kw::Mut>,
22            ident: Ident,
23            colon: Colon,
24            type_: MaybeRefType,
25        }
26
27        enum ReturnType {
28            One(MaybeRefType),
29            Many(ParenthesisGroupContaining<CommaDelimitedVec<MaybeRefType>>)
30        }
31   }
32} else {
33    unsynn! {
34        pub struct Function {
35            entry: Option<kw::Entry>,
36            fun_kw: kw::Fun,
37            ident: Ident,
38            generics: Option<Generics>,
39            args: ParenthesisGroup,
40            ret: Option<FunctionReturn>,
41            body: BraceGroup,
42        }
43
44        enum ReturnType {
45            One(MaybeRefType),
46            Many(ParenthesisGroup)
47        }
48    }
49});
50
51unsynn! {
52    /// `: T`, `: &T`, `: &mut T`, `: (...)`
53    struct FunctionReturn {
54        colon: Colon,
55        type_: ReturnType,
56    }
57}
58
59impl Function {
60    pub const fn ident(&self) -> &Ident {
61        &self.ident
62    }
63
64    pub const fn is_entry(&self) -> bool {
65        self.entry.is_some()
66    }
67}
68
69#[cfg(feature = "fun-args")]
70impl Function {
71    pub fn n_returns(&self) -> usize {
72        self.ret
73            .as_ref()
74            .map(|ret| match &ret.type_ {
75                ReturnType::One(_) => 1,
76                ReturnType::Many(group) => group.content.len(),
77            })
78            .unwrap_or_default()
79    }
80
81    pub fn signature_string(&self, named_args: bool) -> String {
82        let Self {
83            entry,
84            fun_kw,
85            ident,
86            generics,
87            args: FunctionArgs(ParenthesisGroupContaining { content: args }),
88            ret,
89            body: _,
90        } = self;
91
92        fn to_string(t: &impl ToTokens) -> String {
93            t.tokens_to_string()
94        }
95
96        let fun = to_string(fun_kw);
97        let maybe_entry = entry
98            .as_ref()
99            .map(|e| to_string(e) + " ")
100            .unwrap_or_default();
101        let generics = generics.as_ref().map(to_string).unwrap_or_default();
102
103        let args = args
104            .iter()
105            .map(|d| {
106                let type_ = to_string(&d.value.type_);
107                if named_args {
108                    format!("{}: {type_}", d.value.ident)
109                } else {
110                    type_
111                }
112            })
113            .reduce(|a, b| a + ", " + &b)
114            .unwrap_or_default();
115
116        let ret = ret.as_ref().map(to_string).unwrap_or_default();
117        format!("{maybe_entry}{fun} {ident}{generics}({args}){ret}")
118            .replace(" ,", ",")
119            .replace(",)", ")")
120            .replace(" <", "<")
121            .replace("< ", "<")
122            .replace(" >", ">")
123            .replace(" :", ":")
124            .replace(":: ", "::")
125            .replace("& ", "&")
126    }
127}