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