use calyx_utils::{CalyxResult, Error, Id};
use std::str::FromStr;
use strum::EnumCount;
use strum_macros::{AsRefStr, EnumCount, EnumString, FromRepr};
pub const DEPRECATED_ATTRIBUTES: &[&str] = &[];
#[derive(
EnumCount,
FromRepr,
AsRefStr,
EnumString,
Clone,
Copy,
Hash,
PartialEq,
Eq,
Debug,
)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[repr(u8)]
pub enum BoolAttr {
#[strum(serialize = "toplevel")]
TopLevel,
#[strum(serialize = "external")]
External,
#[strum(serialize = "nointerface")]
NoInterface,
#[strum(serialize = "reset")]
Reset,
#[strum(serialize = "clk")]
Clk,
#[strum(serialize = "stable")]
Stable,
#[strum(serialize = "data")]
Data,
#[strum(serialize = "control")]
Control,
#[strum(serialize = "share")]
Share,
#[strum(serialize = "state_share")]
StateShare,
#[strum(serialize = "generated")]
Generated,
#[strum(serialize = "new_fsm")]
NewFSM,
#[strum(serialize = "inline")]
Inline,
}
impl From<BoolAttr> for Attribute {
fn from(attr: BoolAttr) -> Self {
Attribute::Bool(attr)
}
}
impl std::fmt::Display for BoolAttr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_ref())
}
}
#[derive(AsRefStr, EnumString, Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum NumAttr {
#[strum(serialize = "go")]
Go,
#[strum(serialize = "done")]
Done,
#[strum(serialize = "read_together")]
ReadTogether,
#[strum(serialize = "write_together")]
WriteTogether,
#[strum(serialize = "sync")]
Sync,
#[strum(serialize = "bound")]
Bound,
#[strum(serialize = "static")]
Static,
#[strum(serialize = "pos")]
Pos,
#[strum(serialize = "promote_static")]
PromoteStatic,
}
impl From<NumAttr> for Attribute {
fn from(attr: NumAttr) -> Self {
Attribute::Num(attr)
}
}
impl std::fmt::Display for NumAttr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_ref())
}
}
#[derive(AsRefStr, Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[allow(non_camel_case_types)]
pub enum InternalAttr {
DEAD,
NODE_ID,
BEGIN_ID,
END_ID,
ST_ID,
LOOP,
START,
END,
}
impl From<InternalAttr> for Attribute {
fn from(attr: InternalAttr) -> Self {
Attribute::Internal(attr)
}
}
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub enum Attribute {
Bool(BoolAttr),
Num(NumAttr),
Internal(InternalAttr),
Unknown(Id),
}
impl std::fmt::Display for Attribute {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Attribute::Bool(b) => write!(f, "{}", b.as_ref()),
Attribute::Num(n) => write!(f, "{}", n.as_ref()),
Attribute::Internal(i) => write!(f, "{}", i.as_ref()),
Attribute::Unknown(s) => write!(f, "{}", s),
}
}
}
impl FromStr for Attribute {
type Err = Error;
fn from_str(s: &str) -> CalyxResult<Self> {
if let Ok(b) = BoolAttr::from_str(s) {
Ok(Attribute::Bool(b))
} else if let Ok(n) = NumAttr::from_str(s) {
Ok(Attribute::Num(n))
} else {
if s.to_uppercase() == s {
return Err(Error::misc(format!("Invalid attribute: {}. All caps attributes are reserved for internal use.", s)));
}
Ok(Attribute::Unknown(s.into()))
}
}
}
#[derive(Default, Debug, Clone)]
pub(super) struct InlineAttributes {
attrs: u16,
}
impl InlineAttributes {
pub const fn is_empty(&self) -> bool {
self.attrs == 0
}
pub fn insert(&mut self, attr: BoolAttr) {
self.attrs |= 1 << attr as u8;
}
pub fn has(&self, attr: BoolAttr) -> bool {
self.attrs & (1 << (attr as u8)) != 0
}
pub fn remove(&mut self, attr: BoolAttr) {
self.attrs &= !(1 << attr as u8);
}
pub(super) fn iter(&self) -> impl Iterator<Item = BoolAttr> + '_ {
(0..(BoolAttr::COUNT as u8)).filter_map(|idx| {
if self.attrs & (1 << idx) != 0 {
Some(BoolAttr::from_repr(idx).unwrap())
} else {
None
}
})
}
}
#[cfg(feature = "serialize")]
impl serde::Serialize for InlineAttributes {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.to_owned().attrs.serialize(ser)
}
}