use super::FnBuilder;
use super::GenConst;
use super::Generator;
use super::Parent;
use super::StreamBuilder;
use super::generate_item::FnParent;
use crate::parse::GenericConstraints;
use crate::parse::Generics;
use crate::prelude::Delimiter;
use crate::prelude::Result;
#[must_use]
pub struct Impl<'a, P: Parent> {
parent: &'a mut P,
outer_attr: Vec<StreamBuilder>,
inner_attr: Vec<StreamBuilder>,
name: String,
consts: Vec<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 {
outer_attr: Vec::new(),
inner_attr: Vec::new(),
name: parent.name().to_string(),
parent,
consts: Vec::new(),
custom_generic_constraints: None,
fns: Vec::new(),
}
}
pub(super) fn new(
parent: &'a mut P,
name: impl Into<String>,
) -> Self {
Self {
outer_attr: Vec::new(),
inner_attr: Vec::new(),
parent,
name: name.into(),
consts: Vec::new(),
custom_generic_constraints: None,
fns: Vec::new(),
}
}
pub fn impl_outer_attr(
&mut self,
attr: impl AsRef<str>,
) -> Result {
let mut builder = StreamBuilder::new();
builder.punct('#').group(Delimiter::Bracket, |builder| {
builder.push_parsed(attr)?;
Ok(())
})?;
self.outer_attr.push(builder);
Ok(())
}
pub fn impl_inner_attr(
&mut self,
attr: impl AsRef<str>,
) -> Result {
let mut builder = StreamBuilder::new();
builder
.punct('#')
.punct('!')
.group(Delimiter::Brace, |builder| {
builder.push_parsed(attr)?;
Ok(())
})?;
self.inner_attr.push(builder);
Ok(())
}
pub fn generate_fn(
&mut self,
name: impl Into<String>,
) -> FnBuilder<'_, Self> {
FnBuilder::new(self, name)
}
pub fn generate_const(
&mut self,
name: impl Into<String>,
ty: impl Into<String>,
) -> GenConst<'_> {
GenConst::new(&mut self.consts, name, ty)
}
}
impl Impl<'_, 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 constraints = self.custom_generic_constraints.get_or_insert_with(|| {
self.parent
.generic_constraints()
.cloned()
.unwrap_or_default()
});
cb(generics, constraints);
}
self
}
}
impl<P: Parent> FnParent for Impl<'_, P> {
fn append(
&mut self,
fn_definition: StreamBuilder,
fn_body: StreamBuilder,
) -> Result {
self.fns.push((fn_definition, fn_body));
Ok(())
}
}
impl<P: Parent> Drop for Impl<'_, P> {
fn drop(&mut self) {
if std::thread::panicking() {
return;
}
let mut builder = StreamBuilder::new();
for attr in std::mem::take(&mut self.outer_attr) {
builder.append(attr);
}
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());
}
match self.custom_generic_constraints.take() {
| Some(generic_constraints) => {
builder.append(generic_constraints.where_clause());
},
| _ => {
if let Some(generic_constraints) = self.parent.generic_constraints() {
builder.append(generic_constraints.where_clause());
}
},
}
builder
.group(Delimiter::Brace, |builder| {
for attr in std::mem::take(&mut self.inner_attr) {
builder.append(attr);
}
for r#const in std::mem::take(&mut self.consts) {
builder.append(r#const);
}
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);
}
}