1use alloc::{boxed::Box, vec::Vec};
4
5use super::*;
6pub use crate::{
7 ast_enum::{Expr, Member, RangeLimits},
8 ast_struct::{
9 ExprArray, ExprAssign, ExprAsync, ExprAwait, ExprBinary, ExprBlock, ExprBreak, ExprCall,
10 ExprCast, ExprClosure, ExprConst, ExprContinue, ExprField, ExprForLoop, ExprGroup, ExprIf,
11 ExprIndex, ExprInfer, ExprLet, ExprLit, ExprLoop, ExprMacro, ExprMatch, ExprMethodCall,
12 ExprParen, ExprPath, ExprRange, ExprReference, ExprRepeat, ExprReturn, ExprStruct, ExprTry,
13 ExprTryBlock, ExprTuple, ExprUnary, ExprUnsafe, ExprWhile, ExprYield, FieldValue, Index,
14 Label,
15 },
16};
17
18ast_struct! {
19 pub struct Arm {
21 #[serde(default, skip_serializing_if = "Vec::is_empty")]
22 pub(crate) attrs: Vec<Attribute>,
23 pub(crate) pat: Pat,
24 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub(crate) guard: Option<Box<Expr>>,
26 pub(crate) body: Box<Expr>,
27 }
30}
31
32pub(crate) fn requires_terminator(expr: &Expr) -> bool {
34 match expr {
36 Expr::If(_)
37 | Expr::Match(_)
38 | Expr::Block(_) | Expr::Unsafe(_) | Expr::While(_)
40 | Expr::Loop(_)
41 | Expr::ForLoop(_)
42 | Expr::TryBlock(_)
43 | Expr::Const(_) => false,
44 Expr::Array(_)
45 | Expr::Assign(_)
46 | Expr::Async(_)
47 | Expr::Await(_)
48 | Expr::Binary(_)
49 | Expr::Break(_)
50 | Expr::Call(_)
51 | Expr::Cast(_)
52 | Expr::Closure(_)
53 | Expr::Continue(_)
54 | Expr::Field(_)
55 | Expr::Group(_)
56 | Expr::Index(_)
57 | Expr::Infer(_)
58 | Expr::Let(_)
59 | Expr::Lit(_)
60 | Expr::Macro(_)
61 | Expr::MethodCall(_)
62 | Expr::Paren(_)
63 | Expr::Path(_)
64 | Expr::Range(_)
65 | Expr::Reference(_)
66 | Expr::Repeat(_)
67 | Expr::Return(_)
68 | Expr::Struct(_)
69 | Expr::Try(_)
70 | Expr::Tuple(_)
71 | Expr::Unary(_)
72 | Expr::Yield(_)
73 | Expr::Verbatim(_) => true
74 }
75}
76
77mod convert {
78 use super::*;
79
80 syn_trait_impl!(syn::ExprMatch);
82 fn from_syn_arms(other: &[syn::Arm]) -> Vec<Arm> {
83 let last = other.len().saturating_sub(1);
84 other
85 .iter()
86 .enumerate()
87 .map(|(i, other)| {
88 let body = other.body.map_into();
89 if i < last && requires_terminator(&body) {
90 assert!(other.comma.is_some(), "expected `,`");
91 }
92
93 Arm {
94 attrs: other.attrs.map_into(),
95 pat: other.pat.ref_into(),
96 guard: other.guard.ref_map(|(_, x)| x.map_into()),
97 body,
98 }
99 })
100 .collect()
101 }
102 impl From<&syn::ExprMatch> for ExprMatch {
103 fn from(other: &syn::ExprMatch) -> Self {
104 Self {
105 attrs: other.attrs.map_into(),
106 expr: other.expr.map_into(),
107 arms: from_syn_arms(&other.arms),
108 }
109 }
110 }
111 impl From<&ExprMatch> for syn::ExprMatch {
112 fn from(other: &ExprMatch) -> Self {
113 Self {
114 attrs: other.attrs.map_into(),
115 match_token: default(),
116 expr: other.expr.map_into(),
117 brace_token: default(),
118 arms: other.arms.map_into(),
119 }
120 }
121 }
122
123 syn_trait_impl!(syn::Arm);
125 impl From<&syn::Arm> for Arm {
126 fn from(other: &syn::Arm) -> Self {
127 let body = other.body.map_into();
128 if requires_terminator(&body) {
129 assert!(other.comma.is_some(), "expected `,`");
130 }
131
132 Self {
133 attrs: other.attrs.map_into(),
134 pat: other.pat.ref_into(),
135 guard: other.guard.ref_map(|(_, x)| x.map_into()),
136 body,
137 }
138 }
139 }
140 impl From<&Arm> for syn::Arm {
141 fn from(other: &Arm) -> Self {
142 Self {
143 attrs: other.attrs.map_into(),
144 pat: other.pat.ref_into(),
145 guard: other.guard.ref_map(|x| (default(), x.map_into())),
146 fat_arrow_token: default(),
147 body: other.body.map_into(),
148 comma: default_or_none(requires_terminator(&other.body)),
149 }
150 }
151 }
152}