use std::fmt::{self, Display, Write};
use crate::{Doc, Field, Formatter, Type};
#[derive(Debug, Clone)]
pub struct Struct {
name: String,
fields: Vec<Field>,
doc: Option<Doc>,
attributes: Vec<String>,
}
impl Struct {
pub fn new(name: &str) -> Self {
Self {
name: String::from(name),
fields: Vec::new(),
doc: None,
attributes: Vec::new(),
}
}
pub fn with_fields(name: &str, fields: Vec<Field>) -> Self {
Self {
name: String::from(name),
fields,
doc: None,
attributes: Vec::new(),
}
}
pub fn to_type(&self) -> Type {
Type::new_struct(&self.name)
}
pub fn doc(&mut self, doc: Doc) -> &mut Self {
self.doc = Some(doc);
self
}
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 new_field(&mut self, name: &str, ty: Type) -> &mut Field {
self.fields.push(Field::new(name, ty));
self.fields.last_mut().unwrap()
}
pub fn push_field(&mut self, item: Field) -> &mut Self {
self.fields.push(item);
self
}
pub fn field_by_name(&self, name: &str) -> Option<&Field> {
self.fields.iter().find(|f| f.name() == name)
}
pub fn field_by_name_mut(&mut self, name: &str) -> Option<&mut Field> {
self.fields.iter_mut().find(|f| f.name() == name)
}
pub fn field_by_idx(&self, idx: usize) -> Option<&Field> {
self.fields.get(idx)
}
pub fn field_by_idx_mut(&mut self, idx: usize) -> Option<&mut Field> {
self.fields.get_mut(idx)
}
pub fn push_attribute(&mut self, attr: String) -> &mut Self {
self.attributes.push(attr);
self
}
pub fn fmt_decl(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "struct {}; // forward declaration", self.name)
}
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
if let Some(ref docs) = self.doc {
docs.fmt(fmt)?;
}
write!(fmt, "struct {}", self.name)?;
if !self.fields.is_empty() {
fmt.block(|fmt| {
for field in &self.fields {
field.fmt(fmt)?;
}
Ok(())
})?;
if !self.attributes.is_empty() {
write!(fmt, "__attribute__() // TODO")?;
}
}
writeln!(fmt, ";")
}
}
impl Display for Struct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut ret = String::new();
self.fmt(&mut Formatter::new(&mut ret)).unwrap();
write!(f, "{ret}")
}
}