1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
use super::{generate_fn::FnParent, FnBuilder, Generator, Parent, StreamBuilder};
use crate::{
parse::{GenericConstraints, Generics},
prelude::{Delimiter, Result},
};
#[must_use]
/// A helper struct for implementing functions for a given struct or enum.
pub struct Impl<'a, P: Parent> {
parent: &'a mut P,
name: String,
// pub(super) group: StreamBuilder,
custom_generic_constraints: Option<GenericConstraints>,
fns: Vec<(StreamBuilder, StreamBuilder)>,
}
impl<'a, P: Parent> Impl<'a, P> {
pub(super) fn with_parent_name(parent: &'a mut P) -> Self {
Self {
name: parent.name().to_string(),
parent,
custom_generic_constraints: None,
fns: Vec::new(),
}
}
pub(super) fn new(parent: &'a mut P, name: impl Into<String>) -> Self {
Self {
parent,
name: name.into(),
custom_generic_constraints: None,
fns: Vec::new(),
}
}
/// Add a function to the trait implementation.
///
/// `generator.impl().generate_fn("bar")` results in code like:
///
/// ```ignore
/// impl <struct or enum> {
/// fn bar() {}
/// }
/// ```
///
/// See [`FnBuilder`] for more options, as well as information on how to fill the function body.
pub fn generate_fn(&mut self, name: impl Into<String>) -> FnBuilder<Self> {
FnBuilder::new(self, name)
}
}
impl<'a> Impl<'a, Generator> {
/// Modify the generic constraints of a type.
/// This can be used to add additional type constraints to your implementation.
///
/// ```ignore
/// // Your derive:
/// #[derive(YourTrait)]
/// pub struct Foo<B> {
/// ...
/// }
///
/// // With this code:
/// generator
/// .r#impl()
/// .modify_generic_constraints(|generics, constraints| {
/// for g in generics.iter_generics() {
/// constraints.push_generic(g, "YourTrait");
/// }
/// })
///
/// // will generate:
/// impl<B> Foo<B>
/// where B: YourTrait // <-
/// {
/// }
/// ```
///
/// Note that this function is only implemented when you call `.r#impl` on [`Generator`].
pub fn modify_generic_constraints<CB>(&mut self, cb: CB) -> &mut Self
where
CB: FnOnce(&Generics, &mut GenericConstraints),
{
if let Some(generics) = self.parent.generics() {
let mut constraints = self
.parent
.generic_constraints()
.cloned()
.unwrap_or_default();
cb(generics, &mut constraints);
self.custom_generic_constraints = Some(constraints)
}
self
}
}
impl<'a, P: Parent> FnParent for Impl<'a, P> {
fn append(&mut self, fn_definition: StreamBuilder, fn_body: StreamBuilder) -> Result {
self.fns.push((fn_definition, fn_body));
Ok(())
}
}
impl<'a, P: Parent> Drop for Impl<'a, P> {
fn drop(&mut self) {
if std::thread::panicking() {
return;
}
let mut builder = StreamBuilder::new();
builder.ident_str("impl");
if let Some(generics) = self.parent.generics() {
builder.append(generics.impl_generics());
}
builder.push_parsed(&self.name).unwrap();
if let Some(generics) = self.parent.generics() {
builder.append(generics.type_generics());
}
if let Some(generic_constraints) = self.custom_generic_constraints.take() {
builder.append(generic_constraints.where_clause());
} else if let Some(generic_constraints) = self.parent.generic_constraints() {
builder.append(generic_constraints.where_clause());
}
builder
.group(Delimiter::Brace, |builder| {
for (fn_def, fn_body) in std::mem::take(&mut self.fns) {
builder.append(fn_def);
builder
.group(Delimiter::Brace, |body| {
*body = fn_body;
Ok(())
})
.unwrap();
}
Ok(())
})
.unwrap();
self.parent.append(builder);
}
}