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 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 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}