rust_codegen/impl.rs
1use std::fmt::{self, Write};
2
3use crate::bound::Bound;
4use crate::field::Field;
5use crate::formatter::{fmt_bounds, fmt_generics, Formatter};
6use crate::function::Function;
7
8use crate::r#type::Type;
9
10/// Defines an impl block.
11#[derive(Debug, Clone)]
12pub struct Impl {
13 /// The struct being implemented.
14 target: Type,
15 /// Impl level generics.
16 generics: Vec<String>,
17 /// If implementing a trait.
18 impl_trait: Option<Type>,
19 /// Associated types.
20 assoc_tys: Vec<Field>,
21 /// The bounds of the impl block.
22 bounds: Vec<Bound>,
23 /// The functions for the impl block.
24 fns: Vec<Function>,
25 /// The macros for the impl block.
26 macros: Vec<String>,
27}
28
29impl Impl {
30 /// Returns a new impl definition.
31 ///
32 /// # Arguments
33 ///
34 /// * `target` - The impl's target.
35 ///
36 /// # Examples
37 ///
38 /// ```
39 /// use rust_codegen::Impl;
40 ///
41 /// let foo_impl = Impl::new("Foo");
42 /// ```
43 pub fn new<T>(target: T) -> Self
44 where
45 T: Into<Type>,
46 {
47 Impl {
48 target: target.into(),
49 generics: vec![],
50 impl_trait: None,
51 assoc_tys: vec![],
52 bounds: vec![],
53 fns: vec![],
54 macros: vec![],
55 }
56 }
57
58 /// Add a generic to the impl block.
59 ///
60 /// This adds the generic for the block (`impl<T>`) and not the target
61 /// type.
62 ///
63 /// # Arguments
64 ///
65 /// * `name` - The name of the generic.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// use rust_codegen::Impl;
71 ///
72 /// let mut foo_impl = Impl::new("Foo");
73 /// foo_impl.generic("T");
74 /// ```
75 pub fn generic(&mut self, name: &str) -> &mut Self {
76 self.generics.push(name.to_string());
77 self
78 }
79
80 /// Add a generic to the target type.
81 ///
82 /// # Arguments
83 ///
84 /// * `ty` - The generic type to add to the target.
85 ///
86 /// # Examples
87 ///
88 /// ```
89 /// use rust_codegen::Impl;
90 ///
91 /// let mut foo_impl = Impl::new("Foo");
92 /// foo_impl.target_generic("T");
93 /// ```
94 pub fn target_generic<T>(&mut self, ty: T) -> &mut Self
95 where
96 T: Into<Type>,
97 {
98 self.target.generic(ty);
99 self
100 }
101
102 /// Set the trait that the impl block is implementing.
103 ///
104 /// # Arguments
105 ///
106 /// * `ty` - The trait that the impl block is implementing.
107 ///
108 /// # Examples
109 ///
110 /// ```
111 /// use rust_codegen::Impl;
112 ///
113 /// let mut foo_impl = Impl::new("Foo");
114 /// foo_impl.impl_trait("T");
115 /// ```
116 pub fn impl_trait<T>(&mut self, ty: T) -> &mut Self
117 where
118 T: Into<Type>,
119 {
120 self.impl_trait = Some(ty.into());
121 self
122 }
123
124 /// Add a macro to the impl block (e.g. `"#[async_trait]"`)
125 ///
126 /// # Arguments
127 ///
128 /// * `macro` - The macro to add.
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use rust_codegen::Impl;
134 ///
135 /// let mut foo_impl = Impl::new("Foo");
136 /// foo_impl.r#macro("async_trait");
137 /// ```
138 pub fn r#macro(&mut self, r#macro: &str) -> &mut Self {
139 self.macros.push(r#macro.to_string());
140 self
141 }
142
143 /// Set an associated type.
144 ///
145 /// # Arguments
146 ///
147 /// * `name` - The name of the associated type.
148 /// * `ty` - The type of the associated type.
149 ///
150 /// # Examples
151 ///
152 /// ```
153 /// use rust_codegen::*;
154 ///
155 /// let mut scope = Scope::new();
156 ///
157 /// let trait_foo = scope.new_trait("Foo");
158 /// let mut impl_bar = Impl::new("Bar");
159 ///
160 /// impl_bar.associate_type("A", "Foo");
161 /// ```
162 pub fn associate_type<T>(&mut self, name: &str, ty: T) -> &mut Self
163 where
164 T: Into<Type>,
165 {
166 self.assoc_tys.push(Field {
167 name: name.to_string(),
168 ty: ty.into(),
169 documentation: Vec::new(),
170 annotation: Vec::new(),
171 });
172
173 self
174 }
175
176 /// Add a `where` bound to the impl block.
177 ///
178 /// # Arguments
179 ///
180 /// * `name` - The name of the bound.
181 /// * `ty` - The type of the bound.
182 ///
183 /// # Examples
184 ///
185 /// ```
186 /// use rust_codegen::Impl;
187 ///
188 /// let mut foo_impl = Impl::new("Foo");
189 /// foo_impl.bound("T", "Default");
190 pub fn bound<T>(&mut self, name: &str, ty: T) -> &mut Self
191 where
192 T: Into<Type>,
193 {
194 self.bounds.push(Bound {
195 name: name.to_string(),
196 bound: vec![ty.into()],
197 });
198 self
199 }
200
201 /// Push a new function definition, returning a mutable reference to it.
202 ///
203 /// # Arguments
204 ///
205 /// * `name` - The name of the function.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use rust_codegen::Impl;
211 ///
212 /// let mut foo_impl = Impl::new("Foo");
213 /// foo_impl.new_fn("bar_fn");
214 pub fn new_fn(&mut self, name: &str) -> &mut Function {
215 self.push_fn(Function::new(name));
216 self.fns.last_mut().unwrap()
217 }
218
219 /// Push a function definition.
220 ///
221 /// # Arguments
222 ///
223 /// * `item` - The function definition to push.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// use rust_codegen::{Function,Impl};
229 ///
230 /// let mut foo_impl = Impl::new("Foo");
231 /// let bar_fn = Function::new("bar");
232 ///
233 /// foo_impl.push_fn(bar_fn);
234 pub fn push_fn(&mut self, item: Function) -> &mut Self {
235 self.fns.push(item);
236 self
237 }
238
239 /// Formats the impl block using the given formatter.
240 ///
241 /// # Arguments
242 ///
243 /// * `fmt` - The formatter to use.
244 ///
245 /// # Examples
246 ///
247 /// ```
248 /// use rust_codegen::*;
249 ///
250 /// let mut dest = String::new();
251 /// let mut fmt = Formatter::new(&mut dest);
252 ///
253 /// let mut foo_impl = Impl::new("Foo");
254 /// foo_impl.fmt( &mut fmt);
255 /// ```
256 pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
257 for m in self.macros.iter() {
258 write!(fmt, "{}\n", m)?;
259 }
260 write!(fmt, "impl")?;
261 fmt_generics(&self.generics[..], fmt)?;
262
263 if let Some(ref t) = self.impl_trait {
264 write!(fmt, " ")?;
265 t.fmt(fmt)?;
266 write!(fmt, " for")?;
267 }
268
269 write!(fmt, " ")?;
270 self.target.fmt(fmt)?;
271
272 fmt_bounds(&self.bounds, fmt)?;
273
274 fmt.block(|fmt| {
275 // format associated types
276 if !self.assoc_tys.is_empty() {
277 for ty in &self.assoc_tys {
278 write!(fmt, "type {} = ", ty.name)?;
279 ty.ty.fmt(fmt)?;
280 write!(fmt, ";\n")?;
281 }
282 }
283
284 for (i, func) in self.fns.iter().enumerate() {
285 if i != 0 || !self.assoc_tys.is_empty() {
286 write!(fmt, "\n")?;
287 }
288
289 func.fmt(false, fmt)?;
290 }
291
292 Ok(())
293 })
294 }
295}