use std::fmt::{self, Write};
use crate::bound::Bound;
use crate::field::Field;
use crate::formatter::{fmt_bounds, fmt_generics, Formatter};
use crate::function::Function;
use crate::r#type::Type;
#[derive(Debug, Clone)]
pub struct Impl {
target: Type,
generics: Vec<String>,
impl_trait: Option<Type>,
assoc_csts: Vec<Field>,
assoc_tys: Vec<Field>,
bounds: Vec<Bound>,
fns: Vec<Function>,
macros: Vec<String>,
}
impl Impl {
pub fn new<T>(target: T) -> Self
where
T: Into<Type>,
{
Impl {
target: target.into(),
generics: vec![],
impl_trait: None,
assoc_csts: vec![],
assoc_tys: vec![],
bounds: vec![],
fns: vec![],
macros: vec![],
}
}
pub fn generic(&mut self, name: &str) -> &mut Self {
self.generics.push(name.to_string());
self
}
pub fn target_generic<T>(&mut self, ty: T) -> &mut Self
where
T: Into<Type>,
{
self.target.generic(ty);
self
}
pub fn impl_trait<T>(&mut self, ty: T) -> &mut Self
where
T: Into<Type>,
{
self.impl_trait = Some(ty.into());
self
}
pub fn r#macro(&mut self, r#macro: &str) -> &mut Self {
self.macros.push(r#macro.to_string());
self
}
pub fn associate_const<T>(
&mut self,
name: impl Into<String>,
ty: T,
value: impl Into<String>,
visibility: impl Into<String>,
) -> &mut Self
where
T: Into<Type>,
{
self.assoc_csts.push(Field {
name: name.into(),
ty: ty.into(),
documentation: String::new(),
annotation: Vec::new(),
value: value.into(),
visibility: Some(visibility.into()),
});
self
}
pub fn associate_type<T>(&mut self, name: &str, ty: T) -> &mut Self
where
T: Into<Type>,
{
self.assoc_tys.push(Field {
name: name.to_string(),
ty: ty.into(),
documentation: String::new(),
annotation: Vec::new(),
value: String::new(),
visibility: None,
});
self
}
pub fn bound<T>(&mut self, name: &str, ty: T) -> &mut Self
where
T: Into<Type>,
{
self.bounds.push(Bound {
name: name.to_string(),
bound: vec![ty.into()],
});
self
}
pub fn new_fn(&mut self, name: &str) -> &mut Function {
self.push_fn(Function::new(name));
self.fns.last_mut().unwrap()
}
pub fn push_fn(&mut self, item: Function) -> &mut Self {
self.fns.push(item);
self
}
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
for m in self.macros.iter() {
write!(fmt, "{}\n", m)?;
}
write!(fmt, "impl")?;
fmt_generics(&self.generics[..], fmt)?;
if let Some(ref t) = self.impl_trait {
write!(fmt, " ")?;
t.fmt(fmt)?;
write!(fmt, " for")?;
}
write!(fmt, " ")?;
self.target.fmt(fmt)?;
fmt_bounds(&self.bounds, fmt)?;
fmt.block(|fmt| {
if !self.assoc_csts.is_empty() {
for cst in &self.assoc_csts {
if let Some(vis) = &cst.visibility {
write!(fmt, "{} ", vis)?;
}
write!(fmt, "const {}: ", cst.name)?;
cst.ty.fmt(fmt)?;
write!(fmt, " = {};\n", cst.value)?;
}
}
if !self.assoc_tys.is_empty() {
for ty in &self.assoc_tys {
write!(fmt, "type {} = ", ty.name)?;
ty.ty.fmt(fmt)?;
write!(fmt, ";\n")?;
}
}
for (i, func) in self.fns.iter().enumerate() {
if i != 0 || !self.assoc_tys.is_empty() {
write!(fmt, "\n")?;
}
func.fmt(false, fmt)?;
}
Ok(())
})
}
}