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}