codegen_rs/
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
16    /// Impl level generics
17    generics: Vec<String>,
18
19    /// If implementing a trait
20    impl_trait: Option<Type>,
21
22    /// Associated types
23    assoc_tys: Vec<Field>,
24
25    /// Bounds
26    bounds: Vec<Bound>,
27
28    fns: Vec<Function>,
29
30    macros: Vec<String>,
31}
32
33impl Impl {
34    /// Return a new impl definition
35    pub fn new<T>(target: T) -> Self
36    where
37        T: Into<Type>,
38    {
39        Self {
40            target: target.into(),
41            generics: vec![],
42            impl_trait: None,
43            assoc_tys: vec![],
44            bounds: vec![],
45            fns: vec![],
46            macros: vec![],
47        }
48    }
49
50    /// Add a generic to the impl block.
51    ///
52    /// This adds the generic for the block (`impl<T>`) and not the target type.
53    pub fn generic(&mut self, name: &str) -> &mut Self {
54        self.generics.push(name.to_string());
55        self
56    }
57
58    /// Add a generic to the target type.
59    pub fn target_generic<T>(&mut self, ty: T) -> &mut Self
60    where
61        T: Into<Type>,
62    {
63        self.target.generic(ty);
64        self
65    }
66
67    /// Set the trait that the impl block is implementing.
68    pub fn impl_trait<T>(&mut self, ty: T) -> &mut Self
69    where
70        T: Into<Type>,
71    {
72        self.impl_trait = Some(ty.into());
73        self
74    }
75
76    /// Add a macro to the impl block (e.g. `"#[async_trait]"`)
77    pub fn r#macro(&mut self, r#macro: &str) -> &mut Self {
78        self.macros.push(r#macro.to_string());
79        self
80    }
81
82    /// Set an associated type.
83    pub fn associate_type<T>(&mut self, name: &str, ty: T) -> &mut Self
84    where
85        T: Into<Type>,
86    {
87        self.assoc_tys.push(Field {
88            name: name.to_string(),
89            ty: ty.into(),
90            documentation: Vec::new(),
91            annotation: Vec::new(),
92        });
93
94        self
95    }
96
97    /// Add a `where` bound to the impl block.
98    pub fn bound<T>(&mut self, name: &str, ty: T) -> &mut Self
99    where
100        T: Into<Type>,
101    {
102        self.bounds.push(Bound {
103            name: name.to_string(),
104            bound: vec![ty.into()],
105        });
106        self
107    }
108
109    /// Push a new function definition, returning a mutable reference to it.
110    pub fn new_fn(&mut self, name: &str) -> &mut Function {
111        self.push_fn(Function::new(name));
112        self.fns.last_mut().unwrap()
113    }
114
115    /// Push a function definition.
116    pub fn push_fn(&mut self, item: Function) -> &mut Self {
117        self.fns.push(item);
118        self
119    }
120
121    /// Formats the impl block using the given formatter.
122    pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
123        for m in self.macros.iter() {
124            writeln!(fmt, "{}", m)?;
125        }
126        write!(fmt, "impl")?;
127        fmt_generics(&self.generics[..], fmt)?;
128
129        if let Some(ref t) = self.impl_trait {
130            write!(fmt, " ")?;
131            t.fmt(fmt)?;
132            write!(fmt, " for")?;
133        }
134
135        write!(fmt, " ")?;
136        self.target.fmt(fmt)?;
137
138        fmt_bounds(&self.bounds, fmt)?;
139
140        fmt.block(|fmt| {
141            // format associated types
142            if !self.assoc_tys.is_empty() {
143                for ty in &self.assoc_tys {
144                    write!(fmt, "type {} = ", ty.name)?;
145                    ty.ty.fmt(fmt)?;
146                    writeln!(fmt, ";")?;
147                }
148            }
149
150            for (i, func) in self.fns.iter().enumerate() {
151                if i != 0 || !self.assoc_tys.is_empty() {
152                    writeln!(fmt)?;
153                }
154
155                func.fmt(false, fmt)?;
156            }
157
158            Ok(())
159        })
160    }
161}