use std::fmt::{self, Display, Write};
use crate::{Doc, Expr, Formatter, Type, Visibility};
#[derive(Debug, Clone)]
pub struct Attribute {
name: String,
visibility: Visibility,
ty: Type,
width: Option<u8>,
value: Option<Expr>,
is_static: bool,
doc: Option<Doc>,
}
impl Attribute {
pub fn new(name: &str, ty: Type) -> Self {
Attribute::with_string(String::from(name), ty)
}
pub fn with_string(name: String, ty: Type) -> Self {
Attribute {
name,
ty,
visibility: Visibility::Default,
width: None,
value: None,
is_static: false,
doc: None,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn to_type(&self) -> Type {
self.ty.clone()
}
pub fn as_type(&self) -> &Type {
&self.ty
}
pub fn to_expr(&self) -> Expr {
Expr::Variable {
name: self.name.clone(),
ty: self.ty.clone(),
}
}
pub fn visibility(&self) -> Visibility {
self.visibility
}
pub fn is_public(&self) -> bool {
self.visibility == Visibility::Public
}
pub fn is_protected(&self) -> bool {
self.visibility == Visibility::Protected
}
pub fn is_private(&self) -> bool {
self.visibility == Visibility::Private || self.visibility == Visibility::Default
}
pub fn set_visibility(&mut self, vis: Visibility) -> &mut Self {
self.visibility = vis;
self
}
pub fn set_public(&mut self) -> &mut Self {
self.set_visibility(Visibility::Public)
}
pub fn set_protected(&mut self) -> &mut Self {
self.set_visibility(Visibility::Protected)
}
pub fn set_private(&mut self) -> &mut Self {
self.set_visibility(Visibility::Private)
}
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 set_doc(&mut self, doc: Doc) -> &mut Self {
self.doc = Some(doc);
self
}
pub fn set_bitfield_width(&mut self, width: u8) -> &mut Self {
if self.ty.is_integer() {
self.width = Some(width);
}
self
}
pub fn is_bitfield(&self) -> bool {
self.width.is_some()
}
pub fn toggle_static(&mut self, val: bool) -> &mut Self {
self.is_static = val;
self
}
pub fn set_static(&mut self) -> &mut Self {
self.toggle_static(true)
}
pub fn is_static(&self) -> bool {
self.is_static
}
pub fn set_value(&mut self, val: Expr) -> &mut Self {
self.value = Some(val);
self
}
pub fn value(&self) -> Option<&Expr> {
self.value.as_ref()
}
pub fn fmt_decl(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
if let Some(ref docs) = self.doc {
docs.fmt(fmt)?;
}
if self.is_static {
write!(fmt, "static ")?;
}
self.ty.fmt(fmt)?;
write!(fmt, " {}", self.name)?;
if self.ty.is_array() {
write!(fmt, "[{}]", self.ty.get_array_size())?;
}
if let Some(w) = self.width {
write!(fmt, " : {w}")?;
}
writeln!(fmt, ";")
}
pub fn fmt_def(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
if !self.is_static {
return Ok(());
}
if let Some(ref docs) = self.doc {
docs.fmt(fmt)?;
}
if self.is_static {
write!(fmt, "static ")?;
}
self.ty.fmt(fmt)?;
write!(fmt, " {}", self.name)?;
if self.ty.is_array() {
write!(fmt, "[{}]", self.ty.get_array_size())?;
}
if let Some(w) = self.width {
write!(fmt, " : {w}")?;
}
if let Some(v) = &self.value {
write!(fmt, " = {v}")?;
}
writeln!(fmt, ";")
}
pub fn do_fmt(&self, fmt: &mut Formatter<'_>, decl_only: bool) -> fmt::Result {
if let Some(ref docs) = self.doc {
docs.fmt(fmt)?;
}
if self.is_static {
write!(fmt, "static ")?;
}
self.ty.fmt(fmt)?;
write!(fmt, " {}", self.name)?;
if self.ty.is_array() {
write!(fmt, "[{}]", self.ty.get_array_size())?;
}
if let Some(w) = self.width {
write!(fmt, " : {w}")?;
}
if let Some(v) = &self.value {
if !decl_only {
write!(fmt, " = {v}")?;
}
}
writeln!(fmt, ";")
}
pub fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
self.do_fmt(fmt, false)
}
}
impl Display for Attribute {
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}")
}
}