Skip to main content

virtue_next/generate/
impl.rs

1use super::FnBuilder;
2use super::GenConst;
3use super::Generator;
4use super::Parent;
5use super::StreamBuilder;
6use super::generate_item::FnParent;
7use crate::parse::GenericConstraints;
8use crate::parse::Generics;
9use crate::prelude::Delimiter;
10use crate::prelude::Result;
11
12#[must_use]
13/// A helper struct for implementing functions for a given struct or enum.
14pub struct Impl<'a, P: Parent> {
15    parent: &'a mut P,
16    outer_attr: Vec<StreamBuilder>,
17    inner_attr: Vec<StreamBuilder>,
18    name: String,
19    // pub(super) group: StreamBuilder,
20    consts: Vec<StreamBuilder>,
21    custom_generic_constraints: Option<GenericConstraints>,
22    fns: Vec<(StreamBuilder, StreamBuilder)>,
23}
24
25impl<'a, P: Parent> Impl<'a, P> {
26    pub(super) fn with_parent_name(parent: &'a mut P) -> Self {
27        Self {
28            outer_attr: Vec::new(),
29            inner_attr: Vec::new(),
30            name: parent.name().to_string(),
31            parent,
32            consts: Vec::new(),
33            custom_generic_constraints: None,
34            fns: Vec::new(),
35        }
36    }
37
38    pub(super) fn new(
39        parent: &'a mut P,
40        name: impl Into<String>,
41    ) -> Self {
42        Self {
43            outer_attr: Vec::new(),
44            inner_attr: Vec::new(),
45            parent,
46            name: name.into(),
47            consts: Vec::new(),
48            custom_generic_constraints: None,
49            fns: Vec::new(),
50        }
51    }
52
53    /// Add a outer attribute to the trait implementation
54    ///
55    /// # Errors
56    ///
57    /// Returns an error if parsing fails.
58    pub fn impl_outer_attr(
59        &mut self,
60        attr: impl AsRef<str>,
61    ) -> Result {
62        let mut builder = StreamBuilder::new();
63        builder.punct('#').group(Delimiter::Bracket, |builder| {
64            builder.push_parsed(attr)?;
65            Ok(())
66        })?;
67        self.outer_attr.push(builder);
68        Ok(())
69    }
70
71    /// Add a inner attribute to the trait implementation
72    ///
73    /// # Errors
74    ///
75    /// Returns an error if parsing fails.
76    pub fn impl_inner_attr(
77        &mut self,
78        attr: impl AsRef<str>,
79    ) -> Result {
80        let mut builder = StreamBuilder::new();
81        builder
82            .punct('#')
83            .punct('!')
84            .group(Delimiter::Brace, |builder| {
85                builder.push_parsed(attr)?;
86                Ok(())
87            })?;
88        self.inner_attr.push(builder);
89        Ok(())
90    }
91
92    /// Add a function to the trait implementation.
93    ///
94    /// `generator.impl().generate_fn("bar")` results in code like:
95    ///
96    /// ```ignore
97    /// impl <struct or enum> {
98    ///     fn bar() {}
99    /// }
100    /// ```
101    ///
102    /// See [`FnBuilder`] for more options, as well as information on how to fill the function body.
103    pub fn generate_fn(
104        &mut self,
105        name: impl Into<String>,
106    ) -> FnBuilder<'_, Self> {
107        FnBuilder::new(self, name)
108    }
109
110    /// Add a const to the trait implementation
111    /// ```
112    /// # use virtue::prelude::Generator;
113    /// # let mut generator = Generator::with_name("Bar");
114    /// generator
115    ///     .impl_for("Foo")
116    ///     .generate_const("BAR", "u8")
117    ///     .with_value(|b| {
118    ///         b.push_parsed("5")?;
119    ///         Ok(())
120    ///     })?;
121    /// # generator.assert_eq("impl Foo for Bar { const BAR : u8 = 5 ; }");
122    /// # Ok::<_, virtue::Error>(())
123    /// ```
124    ///
125    /// Generates:
126    /// ```ignore
127    /// impl Foo for <struct or enum> {
128    ///     const BAR: u8 = 5;
129    /// }
130    pub fn generate_const(
131        &mut self,
132        name: impl Into<String>,
133        ty: impl Into<String>,
134    ) -> GenConst<'_> {
135        GenConst::new(&mut self.consts, name, ty)
136    }
137}
138
139impl Impl<'_, Generator> {
140    /// Modify the generic constraints of a type.
141    /// This can be used to add additional type constraints to your implementation.
142    ///
143    /// ```ignore
144    /// // Your derive:
145    /// #[derive(YourTrait)]
146    /// pub struct Foo<B> {
147    ///     ...
148    /// }
149    ///
150    /// // With this code:
151    /// generator
152    ///     .r#impl()
153    ///     .modify_generic_constraints(|generics, constraints| {
154    ///         for g in generics.iter_generics() {
155    ///             constraints.push_generic(g, "YourTrait");
156    ///         }
157    ///     })
158    ///
159    /// // will generate:
160    /// impl<B> Foo<B>
161    ///     where B: YourTrait // <-
162    /// {
163    /// }
164    /// ```
165    ///
166    /// Note that this function is only implemented when you call `.r#impl` on [`Generator`].
167    pub fn modify_generic_constraints<CB>(
168        &mut self,
169        cb: CB,
170    ) -> &mut Self
171    where
172        CB: FnOnce(&Generics, &mut GenericConstraints),
173    {
174        if let Some(generics) = self.parent.generics() {
175            let constraints = self.custom_generic_constraints.get_or_insert_with(|| {
176                self.parent
177                    .generic_constraints()
178                    .cloned()
179                    .unwrap_or_default()
180            });
181            cb(generics, constraints);
182        }
183        self
184    }
185}
186
187impl<P: Parent> FnParent for Impl<'_, P> {
188    fn append(
189        &mut self,
190        fn_definition: StreamBuilder,
191        fn_body: StreamBuilder,
192    ) -> Result {
193        self.fns.push((fn_definition, fn_body));
194        Ok(())
195    }
196}
197
198impl<P: Parent> Drop for Impl<'_, P> {
199    fn drop(&mut self) {
200        if std::thread::panicking() {
201            return;
202        }
203        let mut builder = StreamBuilder::new();
204        for attr in std::mem::take(&mut self.outer_attr) {
205            builder.append(attr);
206        }
207        builder.ident_str("impl");
208
209        if let Some(generics) = self.parent.generics() {
210            builder.append(generics.impl_generics());
211        }
212        builder.push_parsed(&self.name).unwrap();
213
214        if let Some(generics) = self.parent.generics() {
215            builder.append(generics.type_generics());
216        }
217        match self.custom_generic_constraints.take() {
218            | Some(generic_constraints) => {
219                builder.append(generic_constraints.where_clause());
220            },
221            | _ => {
222                if let Some(generic_constraints) = self.parent.generic_constraints() {
223                    builder.append(generic_constraints.where_clause());
224                }
225            },
226        }
227
228        builder
229            .group(Delimiter::Brace, |builder| {
230                for attr in std::mem::take(&mut self.inner_attr) {
231                    builder.append(attr);
232                }
233                for r#const in std::mem::take(&mut self.consts) {
234                    builder.append(r#const);
235                }
236                for (fn_def, fn_body) in std::mem::take(&mut self.fns) {
237                    builder.append(fn_def);
238                    builder
239                        .group(Delimiter::Brace, |body| {
240                            *body = fn_body;
241                            Ok(())
242                        })
243                        .unwrap();
244                }
245                Ok(())
246            })
247            .unwrap();
248
249        self.parent.append(builder);
250    }
251}