1use syn::token;
4
5use super::helpers::{ident, make_abi, try_parse_path};
6use super::{ToSyn, ToSynError};
7use crate::pure::ast::{PureImpl, PureImplItem};
8
9impl ToSyn for PureImpl {
10 type Output = syn::ItemImpl;
11
12 fn to_syn(&self) -> Result<syn::ItemImpl, ToSynError> {
13 Ok(syn::ItemImpl {
14 attrs: self
15 .attrs
16 .iter()
17 .map(|a| a.to_syn())
18 .collect::<Result<Vec<_>, _>>()?,
19 defaultness: None,
20 unsafety: if self.is_unsafe {
21 Some(token::Unsafe::default())
22 } else {
23 None
24 },
25 impl_token: token::Impl::default(),
26 generics: self.generics.to_syn()?,
27 trait_: self
28 .trait_
29 .as_ref()
30 .map(|t| Ok((None, try_parse_path(t)?, token::For::default())))
31 .transpose()?,
32 self_ty: Box::new(syn::parse_str(&self.self_ty).map_err(|e| {
33 ToSynError::ParseType {
34 input: self.self_ty.clone(),
35 message: e.to_string(),
36 }
37 })?),
38 brace_token: token::Brace::default(),
39 items: self
40 .items
41 .iter()
42 .map(|i| i.to_syn())
43 .collect::<Result<Vec<_>, _>>()?,
44 })
45 }
46}
47
48impl ToSyn for PureImplItem {
49 type Output = syn::ImplItem;
50
51 fn to_syn(&self) -> Result<syn::ImplItem, ToSynError> {
52 Ok(match self {
53 PureImplItem::Fn(f) => syn::ImplItem::Fn(syn::ImplItemFn {
54 attrs: f
55 .attrs
56 .iter()
57 .map(|a| a.to_syn())
58 .collect::<Result<Vec<_>, _>>()?,
59 vis: f.vis.to_syn()?,
60 defaultness: None,
61 sig: syn::Signature {
62 constness: if f.is_const {
63 Some(token::Const::default())
64 } else {
65 None
66 },
67 asyncness: if f.is_async {
68 Some(token::Async::default())
69 } else {
70 None
71 },
72 unsafety: if f.is_unsafe {
73 Some(token::Unsafe::default())
74 } else {
75 None
76 },
77 abi: f.abi.as_ref().map(|a| make_abi(a)),
78 fn_token: token::Fn::default(),
79 ident: ident(&f.name),
80 generics: f.generics.to_syn()?,
81 paren_token: token::Paren::default(),
82 inputs: f
83 .params
84 .iter()
85 .map(|p| p.to_syn())
86 .collect::<Result<_, _>>()?,
87 variadic: None,
88 output: match &f.ret {
89 Some(ty) => {
90 syn::ReturnType::Type(token::RArrow::default(), Box::new(ty.to_syn()?))
91 }
92 None => syn::ReturnType::Default,
93 },
94 },
95 block: f.body.to_syn()?,
96 }),
97 PureImplItem::Const(c) => syn::ImplItem::Const(syn::ImplItemConst {
98 attrs: c
99 .attrs
100 .iter()
101 .map(|a| a.to_syn())
102 .collect::<Result<Vec<_>, _>>()?,
103 vis: c.vis.to_syn()?,
104 defaultness: None,
105 const_token: token::Const::default(),
106 ident: ident(&c.name),
107 generics: syn::Generics::default(),
108 colon_token: token::Colon::default(),
109 ty: c.ty.to_syn()?,
110 eq_token: token::Eq::default(),
111 expr: c
112 .value
113 .as_ref()
114 .ok_or_else(|| ToSynError::MissingValue {
115 context: format!("ImplItemConst '{}' must have a value", c.name),
116 })?
117 .to_syn()?,
118 semi_token: token::Semi::default(),
119 }),
120 PureImplItem::Type(t) => syn::ImplItem::Type(syn::ImplItemType {
121 attrs: t
122 .attrs
123 .iter()
124 .map(|a| a.to_syn())
125 .collect::<Result<Vec<_>, _>>()?,
126 vis: t.vis.to_syn()?,
127 defaultness: None,
128 type_token: token::Type::default(),
129 ident: ident(&t.name),
130 generics: t.generics.to_syn()?,
131 eq_token: token::Eq::default(),
132 ty: t.ty.to_syn()?,
133 semi_token: token::Semi::default(),
134 }),
135 PureImplItem::Other(s) => syn::parse_str(s).map_err(|e| ToSynError::Other {
136 message: format!("Failed to parse impl item '{}': {}", s, e),
137 })?,
138 })
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::pure::ast::{PureBlock, PureFn, PureGenerics, PureType, PureVis};
146 use quote::ToTokens;
147
148 #[test]
149 fn test_pure_impl_inherent() {
150 let impl_block = PureImpl {
151 attrs: vec![],
152 generics: PureGenerics::default(),
153 is_unsafe: false,
154 trait_: None,
155 self_ty: "Foo".to_string(),
156 items: vec![],
157 };
158 let syn_impl = impl_block.to_syn().unwrap();
159 let output = syn_impl.to_token_stream().to_string();
160 assert!(output.contains("impl"), "Output: {}", output);
161 assert!(output.contains("Foo"), "Output: {}", output);
162 }
163
164 #[test]
165 fn test_pure_impl_trait() {
166 let impl_block = PureImpl {
167 attrs: vec![],
168 generics: PureGenerics::default(),
169 is_unsafe: false,
170 trait_: Some("Clone".to_string()),
171 self_ty: "Foo".to_string(),
172 items: vec![],
173 };
174 let syn_impl = impl_block.to_syn().unwrap();
175 let output = syn_impl.to_token_stream().to_string();
176 assert!(output.contains("Clone"), "Output: {}", output);
177 assert!(output.contains("for"), "Output: {}", output);
178 }
179
180 #[test]
181 fn test_pure_impl_with_method() {
182 let impl_block = PureImpl {
183 attrs: vec![],
184 generics: PureGenerics::default(),
185 is_unsafe: false,
186 trait_: None,
187 self_ty: "Foo".to_string(),
188 items: vec![PureImplItem::Fn(PureFn {
189 attrs: vec![],
190 vis: PureVis::Public,
191 is_async: false,
192 is_async_inferred: false,
193 is_const: false,
194 is_unsafe: false,
195 abi: None,
196 name: "new".to_string(),
197 generics: PureGenerics::default(),
198 params: vec![],
199 ret: Some(PureType::Path("Self".to_string())),
200 body: PureBlock::default(),
201 })],
202 };
203 let syn_impl = impl_block.to_syn().unwrap();
204 let output = syn_impl.to_token_stream().to_string();
205 assert!(output.contains("new"), "Output: {}", output);
206 assert!(output.contains("Self"), "Output: {}", output);
207 }
208}