Skip to main content

rustidy_ast/item/
function.rs

1//! Fn statements
2
3// Imports
4use {
5	crate::{
6		attr::{self, WithOuterAttributes},
7		expr::BlockExpression,
8		lifetime::Lifetime,
9		pat::PatternNoTopAlt,
10		token,
11		ty::{Type, TypePath},
12		util::{FmtSingleOrIndent, Parenthesized},
13	},
14	rustidy_ast_literal::{LiteralExpression, RawStringLiteral, StringLiteral},
15	rustidy_ast_util::{Delimited, Follows, Identifier, PunctuatedTrailing, delimited, punct},
16	rustidy_format::{Format, Formattable, WhitespaceFormat},
17	rustidy_parse::{Parse, ParsePeeked},
18	rustidy_print::Print,
19	rustidy_util::Whitespace,
20};
21
22/// `Function`
23#[derive(PartialEq, Eq, Clone, Debug)]
24#[derive(serde::Serialize, serde::Deserialize)]
25#[derive(Parse, Formattable, Format, Print)]
26#[parse(name = "a function")]
27pub struct Function {
28	pub qualifiers: FunctionQualifiers,
29	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.qualifiers.has_any()))]
30	pub fn_:        token::Fn,
31	#[parse(fatal)]
32	#[format(prefix_ws = Whitespace::SINGLE)]
33	pub ident:      Identifier,
34	#[format(prefix_ws = Whitespace::REMOVE)]
35	pub generics:   Option<GenericParams>,
36	#[format(prefix_ws = Whitespace::REMOVE)]
37	#[format(args = delimited::fmt_remove_or_indent_if_non_blank(
38		60,
39		FmtSingleOrIndent::Single,
40		FmtSingleOrIndent::Indent
41	))]
42	pub params:     Parenthesized<Option<FunctionParameters>>,
43	#[format(prefix_ws = Whitespace::SINGLE)]
44	pub ret:        Option<FunctionReturnType>,
45	#[format(prefix_ws = Whitespace::INDENT)]
46	pub where_:     Option<WhereClause>,
47	#[format(prefix_ws = match self.body.is_semi() {
48		true => Whitespace::REMOVE,
49		false => match self.where_.is_some() {
50			true => Whitespace::INDENT,
51			false => Whitespace::SINGLE,
52		}
53	})]
54	pub body:       FunctionBody,
55}
56
57#[derive(PartialEq, Eq, Clone, Debug)]
58#[derive(strum::EnumIs)]
59#[derive(serde::Serialize, serde::Deserialize)]
60#[derive(Parse, Formattable, Format, Print)]
61pub enum FunctionBody {
62	Expr(BlockExpression),
63	Semi(token::Semi),
64}
65
66/// `FunctionQualifiers`
67#[derive(PartialEq, Eq, Clone, Debug)]
68#[derive(serde::Serialize, serde::Deserialize)]
69#[derive(Parse, Formattable, Format, Print)]
70#[parse(name = "function qualifiers")]
71pub struct FunctionQualifiers {
72	pub const_:  Option<token::Const>,
73	#[format(prefix_ws(if_ = self.const_.is_some(), expr = Whitespace::SINGLE))]
74	pub async_:  Option<token::Async>,
75	#[format(prefix_ws(if_ = self.const_.is_some() || self.async_.is_some(), expr = Whitespace::SINGLE))]
76	pub safety:  Option<ItemSafety>,
77	#[format(prefix_ws(
78		if_ = self.const_.is_some() || self.async_.is_some() || self.safety.is_some(),
79		expr = Whitespace::SINGLE
80	))]
81	pub extern_: Option<ExternAbi>,
82}
83
84impl FunctionQualifiers {
85	/// Returns if any qualifiers exist
86	#[must_use]
87	pub const fn has_any(&self) -> bool {
88		self.const_.is_some() || self.async_.is_some() || self.safety.is_some() || self.extern_.is_some()
89	}
90}
91
92#[derive(PartialEq, Eq, Clone, Debug)]
93#[derive(serde::Serialize, serde::Deserialize)]
94#[derive(Parse, Formattable, Format, Print)]
95pub struct ExternAbi {
96	pub extern_: token::Extern,
97	#[format(prefix_ws = Whitespace::SINGLE)]
98	pub abi:     Option<Abi>,
99}
100
101/// `Abi`
102#[derive(PartialEq, Eq, Clone, Debug)]
103#[derive(serde::Serialize, serde::Deserialize)]
104#[derive(Parse, Formattable, Format, Print)]
105pub enum Abi {
106	String(StringLiteral),
107	RawString(RawStringLiteral),
108}
109
110/// `ItemSafety`
111#[derive(PartialEq, Eq, Clone, Debug)]
112#[derive(serde::Serialize, serde::Deserialize)]
113#[derive(Parse, Formattable, Format, Print)]
114pub enum ItemSafety {
115	Safe(token::Safe),
116	Unsafe(token::Unsafe),
117}
118
119/// `FunctionParameters`
120#[derive(PartialEq, Eq, Clone, Debug)]
121#[derive(serde::Serialize, serde::Deserialize)]
122#[derive(Parse, Formattable, Format, Print)]
123#[parse(name = "function parameters")]
124#[format(args(ty = "FmtSingleOrIndent"))]
125pub enum FunctionParameters {
126	#[format(args = args)]
127	Full(FunctionParametersFull),
128	#[parse(peek = (SelfParam, Option::<token::Comma>, Follows::<token::ParenClose>))]
129	OnlySelf(FunctionParametersOnlySelf),
130}
131
132#[derive(PartialEq, Eq, Clone, Debug)]
133#[derive(serde::Serialize, serde::Deserialize)]
134#[derive(Parse, Formattable, Format, Print)]
135pub struct FunctionParametersOnlySelf {
136	pub self_:          SelfParam,
137	#[format(prefix_ws = Whitespace::REMOVE)]
138	pub trailing_comma: Option<token::Comma>,
139}
140
141impl ParsePeeked<(SelfParam, Option<token::Comma>, Follows<token::ParenClose>)> for FunctionParametersOnlySelf {
142	fn parse_from_with_peeked(
143		_parser: &mut rustidy_parse::Parser,
144		(self_, trailing_comma, _): (SelfParam, Option<token::Comma>, Follows<token::ParenClose>),
145	) -> Result<Self, Self::Error> {
146		Ok(Self { self_, trailing_comma })
147	}
148}
149
150#[derive(PartialEq, Eq, Clone, Debug)]
151#[derive(serde::Serialize, serde::Deserialize)]
152#[derive(Parse, Formattable, Format, Print)]
153#[format(args(ty = "FmtSingleOrIndent"))]
154pub struct FunctionParametersFull {
155	pub self_: Option<FunctionParametersFullSelf>,
156	#[format(prefix_ws(if_ = self.self_.is_some(), expr = args.prefix_ws()))]
157	#[format(args = punct::fmt(args.prefix_ws(), Whitespace::REMOVE))]
158	pub rest:  PunctuatedTrailing<FunctionParam, token::Comma>,
159}
160
161#[derive(PartialEq, Eq, Clone, Debug)]
162#[derive(serde::Serialize, serde::Deserialize)]
163#[derive(Parse, Formattable, Format, Print)]
164pub struct FunctionParametersFullSelf {
165	pub self_: SelfParam,
166	#[format(prefix_ws = Whitespace::REMOVE)]
167	pub comma: token::Comma,
168}
169
170/// `FunctionParam`
171#[derive(PartialEq, Eq, Clone, Debug)]
172#[derive(serde::Serialize, serde::Deserialize)]
173#[derive(Parse, Formattable, Format, Print)]
174pub struct FunctionParam(
175	#[format(args = attr::with::fmt(Whitespace::SINGLE))]
176	pub WithOuterAttributes<FunctionParamInner>,
177);
178
179#[derive(PartialEq, Eq, Clone, Debug)]
180#[derive(serde::Serialize, serde::Deserialize)]
181#[derive(Parse, Formattable, Format, Print)]
182pub enum FunctionParamInner {
183	Pattern(FunctionParamPattern),
184	CVariadic(token::DotDotDot),
185	Type(Type),
186}
187
188/// `FunctionParamPattern`
189#[derive(PartialEq, Eq, Clone, Debug)]
190#[derive(serde::Serialize, serde::Deserialize)]
191#[derive(Parse, Formattable, Format, Print)]
192pub struct FunctionParamPattern {
193	pub pat:   PatternNoTopAlt,
194	#[format(prefix_ws = Whitespace::REMOVE)]
195	pub colon: token::Colon,
196	#[parse(fatal)]
197	#[format(prefix_ws = Whitespace::SINGLE)]
198	pub ty:    Type,
199}
200
201/// `SelfParam`
202#[derive(PartialEq, Eq, Clone, Debug)]
203#[derive(serde::Serialize, serde::Deserialize)]
204#[derive(Parse, Formattable, Format, Print)]
205pub struct SelfParam(
206	#[format(args = attr::with::fmt(Whitespace::SINGLE))]
207	pub WithOuterAttributes<ShorthandOrTypedSelf>,
208);
209
210#[derive(PartialEq, Eq, Clone, Debug)]
211#[derive(serde::Serialize, serde::Deserialize)]
212#[derive(Parse, Formattable, Format, Print)]
213pub enum ShorthandOrTypedSelf {
214	Typed(TypedSelf),
215	Shorthand(ShorthandSelf),
216}
217
218/// `ShorthandSelf`
219#[derive(PartialEq, Eq, Clone, Debug)]
220#[derive(serde::Serialize, serde::Deserialize)]
221#[derive(Parse, Formattable, Format, Print)]
222pub struct ShorthandSelf {
223	pub ref_:  Option<ShorthandSelfRef>,
224	#[format(prefix_ws(if_ = let Some(ref_) = &self.ref_, expr = match ref_.lifetime.is_some() {
225		true => Whitespace::SINGLE,
226		false => Whitespace::REMOVE,
227	}))]
228	pub mut_:  Option<token::Mut>,
229	#[format(prefix_ws(if_ = self.ref_.is_some() || self.mut_.is_some(), expr = match self
230		.ref_
231		.as_ref()
232		.is_some_and(|ref_| ref_.lifetime.is_some()) || self.mut_.is_some() {
233		true => Whitespace::SINGLE,
234		false => Whitespace::REMOVE,
235	}))]
236	pub self_: token::SelfLower,
237}
238
239#[derive(PartialEq, Eq, Clone, Debug)]
240#[derive(serde::Serialize, serde::Deserialize)]
241#[derive(Parse, Formattable, Format, Print)]
242pub struct ShorthandSelfRef {
243	pub ref_:     token::And,
244	#[parse(fatal)]
245	#[format(prefix_ws = Whitespace::REMOVE)]
246	pub lifetime: Option<Lifetime>,
247}
248
249/// `TypedSelf`
250#[derive(PartialEq, Eq, Clone, Debug)]
251#[derive(serde::Serialize, serde::Deserialize)]
252#[derive(Parse, Formattable, Format, Print)]
253pub struct TypedSelf {
254	pub mut_:  Option<token::Mut>,
255	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.mut_.is_some()))]
256	pub self_: token::SelfLower,
257	#[format(prefix_ws = Whitespace::REMOVE)]
258	pub colon: token::Colon,
259	#[format(prefix_ws = Whitespace::SINGLE)]
260	pub ty:    Type,
261}
262
263/// `FunctionReturnType`
264#[derive(PartialEq, Eq, Clone, Debug)]
265#[derive(serde::Serialize, serde::Deserialize)]
266#[derive(Parse, Formattable, Format, Print)]
267#[parse(name = "function return type")]
268pub struct FunctionReturnType {
269	pub arrow: token::RArrow,
270	#[parse(fatal)]
271	#[format(prefix_ws = Whitespace::SINGLE)]
272	pub ty:    Type,
273}
274
275/// `GenericParams`
276#[derive(PartialEq, Eq, Clone, Debug)]
277#[derive(serde::Serialize, serde::Deserialize)]
278#[derive(Parse, Formattable, Format, Print)]
279#[parse(name = "generic parameters")]
280pub struct GenericParams(
281	#[format(args = delimited::FmtRemove)]
282	pub Delimited<Option<GenericParamsInner>, token::Lt, token::Gt>,
283);
284
285#[derive(PartialEq, Eq, Clone, Debug)]
286#[derive(serde::Serialize, serde::Deserialize)]
287#[derive(Parse, Formattable, Format, Print)]
288#[parse(name = "generic parameters")]
289pub struct GenericParamsInner(
290	#[format(args = punct::fmt(Whitespace::SINGLE, Whitespace::REMOVE))]
291	pub PunctuatedTrailing<GenericParam, token::Comma>,
292);
293
294/// `GenericParam`
295#[derive(PartialEq, Eq, Clone, Debug)]
296#[derive(serde::Serialize, serde::Deserialize)]
297#[derive(Parse, Formattable, Format, Print)]
298pub struct GenericParam(
299	#[format(args = attr::with::fmt(Whitespace::SINGLE))]
300	pub WithOuterAttributes<GenericParamInner>,
301);
302
303#[derive(PartialEq, Eq, Clone, Debug)]
304#[derive(serde::Serialize, serde::Deserialize)]
305#[derive(Parse, Formattable, Format, Print)]
306pub enum GenericParamInner {
307	Lifetime(LifetimeParam),
308	Type(TypeParam),
309	Const(ConstParam),
310}
311
312/// `LifetimeParam`
313#[derive(PartialEq, Eq, Clone, Debug)]
314#[derive(serde::Serialize, serde::Deserialize)]
315#[derive(Parse, Formattable, Format, Print)]
316#[parse(name = "a lifetime parameter")]
317pub struct LifetimeParam {
318	pub lifetime: Lifetime,
319	#[format(prefix_ws = Whitespace::REMOVE)]
320	pub bounds:   Option<LifetimeParamBounds>,
321}
322
323#[derive(PartialEq, Eq, Clone, Debug)]
324#[derive(serde::Serialize, serde::Deserialize)]
325#[derive(Parse, Formattable, Format, Print)]
326pub struct LifetimeParamBounds {
327	pub colon:  token::Colon,
328	#[format(prefix_ws = Whitespace::SINGLE)]
329	pub bounds: Option<LifetimeBounds>,
330}
331
332/// `LifetimeBounds`
333#[derive(PartialEq, Eq, Clone, Debug)]
334#[derive(serde::Serialize, serde::Deserialize)]
335#[derive(Parse, Formattable, Format, Print)]
336pub struct LifetimeBounds(
337	#[format(args = punct::fmt(Whitespace::SINGLE, Whitespace::SINGLE))]
338	PunctuatedTrailing<Lifetime, token::Plus>,
339);
340
341/// `TypeParam`
342#[derive(PartialEq, Eq, Clone, Debug)]
343#[derive(serde::Serialize, serde::Deserialize)]
344#[derive(Parse, Formattable, Format, Print)]
345#[parse(name = "a type parameter")]
346pub struct TypeParam {
347	pub ident:  Identifier,
348	#[format(prefix_ws = Whitespace::REMOVE)]
349	pub bounds: Option<TypeParamColonBounds>,
350	#[format(prefix_ws = Whitespace::SINGLE)]
351	pub eq_ty:  Option<TypeParamEqType>,
352}
353
354#[derive(PartialEq, Eq, Clone, Debug)]
355#[derive(serde::Serialize, serde::Deserialize)]
356#[derive(Parse, Formattable, Format, Print)]
357pub struct TypeParamColonBounds {
358	pub colon:  token::Colon,
359	#[format(prefix_ws = Whitespace::SINGLE)]
360	pub bounds: Option<TypeParamBounds>,
361}
362
363#[derive(PartialEq, Eq, Clone, Debug)]
364#[derive(serde::Serialize, serde::Deserialize)]
365#[derive(Parse, Formattable, Format, Print)]
366pub struct TypeParamEqType {
367	pub eq: token::Eq,
368	#[format(prefix_ws = Whitespace::SINGLE)]
369	pub ty: Box<Type>,
370}
371
372/// `TypeParamBounds`
373#[derive(PartialEq, Eq, Clone, Debug)]
374#[derive(serde::Serialize, serde::Deserialize)]
375#[derive(Parse, Formattable, Format, Print)]
376pub struct TypeParamBounds(
377	#[format(args = punct::fmt(Whitespace::SINGLE, Whitespace::SINGLE))]
378	pub PunctuatedTrailing<TypeParamBound, token::Plus>,
379);
380
381/// `TypeParamBound`
382#[derive(PartialEq, Eq, Clone, Debug)]
383#[derive(serde::Serialize, serde::Deserialize)]
384#[derive(Parse, Formattable, Format, Print)]
385pub enum TypeParamBound {
386	Lifetime(Lifetime),
387	Trait(TraitBound),
388	UseBound(UseBound),
389}
390
391/// `TraitBound`
392#[derive(PartialEq, Eq, Clone, Debug)]
393#[derive(serde::Serialize, serde::Deserialize)]
394#[derive(Parse, Formattable, Format, Print)]
395pub enum TraitBound {
396	#[format(args = delimited::fmt_preserve())]
397	Parenthesized(Parenthesized<TraitBoundInner>),
398	Normal(TraitBoundInner),
399}
400
401#[derive(PartialEq, Eq, Clone, Debug)]
402#[derive(serde::Serialize, serde::Deserialize)]
403#[derive(Parse, Formattable, Format, Print)]
404pub struct TraitBoundInner {
405	pub prefix: Option<TraitBoundInnerPrefix>,
406	#[format(prefix_ws(if_ = let Some(prefix) = &self.prefix, expr = match prefix {
407		TraitBoundInnerPrefix::Question(_) => Whitespace::REMOVE,
408		TraitBoundInnerPrefix::ForLifetimes(_) => Whitespace::SINGLE,
409	}))]
410	pub path:   TypePath,
411}
412
413#[derive(PartialEq, Eq, Clone, Debug)]
414#[derive(serde::Serialize, serde::Deserialize)]
415#[derive(Parse, Formattable, Format, Print)]
416pub enum TraitBoundInnerPrefix {
417	Question(token::Question),
418	ForLifetimes(Box<ForLifetimes>),
419}
420
421/// `WhereClause`
422#[derive(PartialEq, Eq, Clone, Debug)]
423#[derive(serde::Serialize, serde::Deserialize)]
424#[derive(Parse, Formattable, Format, Print)]
425pub struct WhereClause {
426	pub where_: token::Where,
427	// TODO: The reference says that this can't have a trailing comma,
428	//       but the compiler accepts it, so we do to.
429	#[format(prefix_ws = Whitespace::INDENT)]
430	#[format(indent)]
431	#[format(args = punct::fmt(Whitespace::INDENT, Whitespace::REMOVE))]
432	pub items:  Option<PunctuatedTrailing<WhereClauseItem, token::Comma>>,
433}
434
435/// `WhereClauseItem`
436#[derive(PartialEq, Eq, Clone, Debug)]
437#[derive(serde::Serialize, serde::Deserialize)]
438#[derive(Parse, Formattable, Format, Print)]
439pub enum WhereClauseItem {
440	Lifetime(LifetimeWhereClauseItem),
441	Type(TypeBoundWhereClauseItem),
442}
443
444/// `LifetimeWhereClauseItem`
445#[derive(PartialEq, Eq, Clone, Debug)]
446#[derive(serde::Serialize, serde::Deserialize)]
447#[derive(Parse, Formattable, Format, Print)]
448pub struct LifetimeWhereClauseItem {
449	pub lifetime: Lifetime,
450	#[format(prefix_ws = Whitespace::REMOVE)]
451	pub colon:    token::Colon,
452	#[parse(fatal)]
453	#[format(prefix_ws = Whitespace::SINGLE)]
454	pub bounds:   LifetimeBounds,
455}
456
457/// `TypeBoundWhereClauseItem`
458#[derive(PartialEq, Eq, Clone, Debug)]
459#[derive(serde::Serialize, serde::Deserialize)]
460#[derive(Parse, Formattable, Format, Print)]
461pub struct TypeBoundWhereClauseItem {
462	pub for_lifetimes: Option<ForLifetimes>,
463	#[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.for_lifetimes.is_some()))]
464	pub ty:            Type,
465	#[format(prefix_ws = Whitespace::REMOVE)]
466	pub colon:         token::Colon,
467	#[parse(fatal)]
468	#[format(prefix_ws = Whitespace::SINGLE)]
469	pub bounds:        Option<TypeParamBounds>,
470}
471
472/// `ForLifetimes`
473#[derive(PartialEq, Eq, Clone, Debug)]
474#[derive(serde::Serialize, serde::Deserialize)]
475#[derive(Parse, Formattable, Format, Print)]
476pub struct ForLifetimes {
477	pub for_:   token::For,
478	#[format(prefix_ws = Whitespace::REMOVE)]
479	pub params: GenericParams,
480}
481
482/// `ConstParam`
483#[derive(PartialEq, Eq, Clone, Debug)]
484#[derive(serde::Serialize, serde::Deserialize)]
485#[derive(Parse, Formattable, Format, Print)]
486pub struct ConstParam {
487	pub const_: token::Const,
488	#[format(prefix_ws = Whitespace::SINGLE)]
489	pub ident:  Identifier,
490	#[format(prefix_ws = Whitespace::REMOVE)]
491	pub colon:  token::Colon,
492	#[format(prefix_ws = Whitespace::SINGLE)]
493	pub ty:     Box<Type>,
494	#[format(prefix_ws = Whitespace::SINGLE)]
495	pub eq:     Option<ConstParamEq>,
496}
497
498#[derive(PartialEq, Eq, Clone, Debug)]
499#[derive(serde::Serialize, serde::Deserialize)]
500#[derive(Parse, Formattable, Format, Print)]
501pub struct ConstParamEq {
502	eq:   token::Eq,
503	#[format(prefix_ws = Whitespace::SINGLE)]
504	rest: ConstParamEqRest,
505}
506
507#[derive(PartialEq, Eq, Clone, Debug)]
508#[derive(serde::Serialize, serde::Deserialize)]
509#[derive(Parse, Formattable, Format, Print)]
510pub enum ConstParamEqRest {
511	Eq(Box<BlockExpression>),
512	Ident(Identifier),
513	Literal(ConstParamEqRestLiteral),
514}
515
516#[derive(PartialEq, Eq, Clone, Debug)]
517#[derive(serde::Serialize, serde::Deserialize)]
518#[derive(Parse, Formattable, Format, Print)]
519pub struct ConstParamEqRestLiteral {
520	neg:  Option<token::Minus>,
521	#[format(prefix_ws = Whitespace::REMOVE)]
522	expr: Box<LiteralExpression>,
523}
524
525/// `UseBound`
526#[derive(PartialEq, Eq, Clone, Debug)]
527#[derive(serde::Serialize, serde::Deserialize)]
528#[derive(Parse, Formattable, Format, Print)]
529pub struct UseBound {
530	pub use_: token::Use,
531	#[parse(fatal)]
532	pub args: UseBoundGenericArgs,
533}
534
535/// `UseBoundGenericArgs`
536#[derive(PartialEq, Eq, Clone, Debug)]
537#[derive(serde::Serialize, serde::Deserialize)]
538#[derive(Parse, Formattable, Format, Print)]
539pub struct UseBoundGenericArgs(
540	#[format(args = delimited::fmt_preserve())]
541	pub Delimited<UseBoundGenericArgsInner, token::Lt, token::Gt>,
542);
543
544#[derive(PartialEq, Eq, Clone, Debug)]
545#[derive(serde::Serialize, serde::Deserialize)]
546#[derive(Parse, Formattable, Format, Print)]
547pub struct UseBoundGenericArgsInner(
548	#[format(args = punct::fmt(Whitespace::PRESERVE, Whitespace::PRESERVE))]
549	pub PunctuatedTrailing<UseBoundGenericArg, token::Comma>,
550);
551
552/// `UseBoundGenericArg`
553#[derive(PartialEq, Eq, Clone, Debug)]
554#[derive(serde::Serialize, serde::Deserialize)]
555#[derive(Parse, Formattable, Format, Print)]
556pub enum UseBoundGenericArg {
557	Lifetime(Lifetime),
558	Identifier(Identifier),
559	SelfUpper(token::SelfUpper),
560}