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