use std::fmt::{self, Display, Write};
use crate::{
Attribute, BaseType, Constructor, Destructor, Doc, Formatter, Method, Type, Visibility,
};
#[derive(Debug, Clone)]
pub struct Class {
name: String,
doc: Option<Doc>,
base: Option<(Visibility, String)>,
constructors: Vec<Constructor>,
destructor: Option<Destructor>,
methods: Vec<Method>,
attributes: Vec<Attribute>,
}
impl Class {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
doc: None,
base: None,
destructor: None,
constructors: Vec::new(),
methods: Vec::new(),
attributes: Vec::new(),
}
}
pub fn to_type(&self) -> Type {
Type::new(BaseType::Class(self.name.clone()))
}
pub fn push_doc_str(&mut self, doc: &str) -> &mut Self {
if let Some(d) = &mut self.doc {
d.add_text(doc);
} else {
self.doc = Some(Doc::with_str(doc));
}
self
}
pub fn doc(&mut self, doc: Doc) -> &mut Self {
self.doc = Some(doc);
self
}
pub fn set_base(&mut self, base: &str, visibility: Visibility) -> &mut Self {
self.base = Some((visibility, base.to_string()));
self
}
pub fn new_attribute(&mut self, name: &str, ty: Type) -> &mut Attribute {
self.attributes.push(Attribute::new(name, ty));
self.attributes.last_mut().unwrap()
}
pub fn push_attribute(&mut self, field: Attribute) -> &mut Self {
self.attributes.push(field);
self
}
pub fn attribute_by_name(&self, name: &str) -> Option<&Attribute> {
self.attributes.iter().find(|f| f.name() == name)
}
pub fn attribute_by_name_mut(&mut self, name: &str) -> Option<&mut Attribute> {
self.attributes.iter_mut().find(|f| f.name() == name)
}
pub fn attribute_by_idx(&self, idx: usize) -> Option<&Attribute> {
self.attributes.get(idx)
}
pub fn attribute_by_idx_mut(&mut self, idx: usize) -> Option<&mut Attribute> {
self.attributes.get_mut(idx)
}
pub fn new_method(&mut self, name: &str, ty: Type) -> &mut Method {
self.methods.push(Method::new(name, ty));
self.methods.last_mut().unwrap()
}
pub fn push_method(&mut self, method: Method) -> &mut Self {
self.methods.push(method);
self
}
pub fn method_by_name(&self, name: &str) -> Option<&Method> {
self.methods.iter().find(|f| f.name() == name)
}
pub fn method_by_name_mut(&mut self, name: &str) -> Option<&mut Method> {
self.methods.iter_mut().find(|f| f.name() == name)
}
pub fn new_constructor(&mut self) -> &mut Constructor {
self.constructors.push(Constructor::new(self.name.as_str()));
self.constructors.last_mut().unwrap()
}
pub fn new_destructor(&mut self) -> &mut Destructor {
self.destructor = Some(Destructor::new(self.name.as_str()));
self.destructor.as_mut().unwrap()
}
pub fn do_fmt_class_scope(&self, fmt: &mut Formatter<'_>, decl_only: bool) -> fmt::Result {
if let Some(ref docs) = self.doc {
docs.fmt(fmt)?;
}
if !decl_only {
self.constructors.iter().for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
self.attributes.iter().filter(|a| a.is_static()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
self.methods.iter().for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
return Ok(());
}
write!(fmt, "class {}", self.name)?;
if let Some(p) = &self.base {
write!(fmt, " : {} {}", p.0, p.1)?;
}
let pub_attr = self.attributes.iter().filter(|a| a.is_public()).count();
let pub_methods = self.methods.iter().filter(|a| a.is_public()).count();
let pub_constructors = self.constructors.iter().filter(|a| a.is_public()).count();
let prot_attr = self.attributes.iter().filter(|a| a.is_protected()).count();
let prot_methods = self.methods.iter().filter(|a| a.is_protected()).count();
let prot_constructors = self.constructors.iter().filter(|a| a.is_protected()).count();
let priv_attr = self.attributes.iter().filter(|a| a.is_private()).count();
let priv_methods = self.methods.iter().filter(|a| a.is_private()).count();
let priv_constructors = self.constructors.iter().filter(|a| a.is_private()).count();
if self.destructor.is_none()
&& pub_attr
+ pub_methods
+ pub_constructors
+ prot_attr
+ prot_methods
+ prot_constructors
+ priv_attr
+ priv_methods
+ priv_constructors
== 0
{
return writeln!(fmt, " {{ }};");
}
fmt.block(|fmt| {
if self.destructor.is_some() || pub_attr + pub_methods + pub_constructors > 0 {
writeln!(fmt, "\npublic:")?;
}
if pub_constructors > 0 {
self.constructors.iter().filter(|m| m.is_public()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if let Some(d) = &self.destructor {
d.do_fmt(fmt, decl_only)?;
}
if pub_attr > 0 {
self.attributes.iter().filter(|a| a.is_public()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if pub_methods > 0 {
self.methods.iter().filter(|m| m.is_public()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if prot_attr + prot_attr + prot_constructors > 0 {
writeln!(fmt, "\nprotected:")?;
}
if prot_constructors > 0 {
self.constructors.iter().filter(|m| m.is_protected()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if prot_attr > 0 {
self.attributes.iter().filter(|a| a.is_protected()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if prot_methods > 0 {
self.methods.iter().filter(|m| m.is_protected()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if priv_attr + priv_attr + priv_constructors > 0 {
writeln!(fmt, "\nprivate:")?;
}
if priv_constructors > 0 {
self.constructors.iter().filter(|m| m.is_private()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if priv_attr > 0 {
self.attributes.iter().filter(|a| a.is_private()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
if priv_methods > 0 {
self.methods.iter().filter(|m| m.is_private()).for_each(|m| {
m.do_fmt(fmt, decl_only).expect("format failed");
});
}
Ok(())
})?;
writeln!(fmt, ";")
}
pub fn do_fmt(&self, fmt: &mut Formatter<'_>, decl_only: bool) -> fmt::Result {
fmt.scope(self.name.as_str(), |fmt| {
self.do_fmt_class_scope(fmt, decl_only).expect("failed to format the class")
});
Ok(())
}
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.do_fmt(fmt, false)
}
pub fn fmt_decl(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.do_fmt(fmt, true)
}
pub fn fmt_def(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.do_fmt(fmt, false)
}
}
impl Display for Class {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut ret = String::new();
self.fmt_def(&mut Formatter::new(&mut ret)).unwrap();
write!(f, "{ret}")?;
let mut ret = String::new();
self.fmt_decl(&mut Formatter::new(&mut ret)).unwrap();
write!(f, "{ret}")
}
}