use super::Attribute;
use crate::InlineAttributes;
use calyx_utils::{CalyxResult, GPosIdx, WithPos};
use linked_hash_map::LinkedHashMap;
use std::convert::TryFrom;
#[derive(Debug, Clone, Default)]
struct HeapAttrInfo {
attrs: LinkedHashMap<Attribute, u64>,
span: GPosIdx,
}
#[derive(Default, Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
pub struct Attributes {
inl: InlineAttributes,
hinfo: Box<HeapAttrInfo>,
}
impl TryFrom<Vec<(Attribute, u64)>> for Attributes {
type Error = calyx_utils::Error;
fn try_from(v: Vec<(Attribute, u64)>) -> CalyxResult<Self> {
let mut attrs = Attributes::default();
for (k, v) in v {
if attrs.has(k) {
return Err(Self::Error::malformed_structure(format!(
"Multiple entries for attribute: {}",
k
)));
}
attrs.insert(k, v);
}
Ok(attrs)
}
}
impl WithPos for Attributes {
fn copy_span(&self) -> GPosIdx {
self.hinfo.span
}
}
pub trait GetAttributes {
fn get_attributes(&self) -> &Attributes;
fn get_mut_attributes(&mut self) -> &mut Attributes;
}
impl Attributes {
pub fn insert<A>(&mut self, key: A, val: u64)
where
A: Into<Attribute>,
{
match key.into() {
Attribute::Bool(b) => {
assert!(
val == 1,
"{} is a boolean attribute and can only have a value of 1",
b.as_ref(),
);
self.inl.insert(b);
}
attr => {
self.hinfo.attrs.insert(attr, val);
}
}
}
pub fn get<A>(&self, key: A) -> Option<u64>
where
A: Into<Attribute>,
{
match key.into() {
Attribute::Bool(b) => {
if self.inl.has(b) {
Some(1)
} else {
None
}
}
attr => self.hinfo.attrs.get(&attr).cloned(),
}
}
pub fn has<A>(&self, key: A) -> bool
where
A: Into<Attribute>,
{
match key.into() {
Attribute::Bool(b) => self.inl.has(b),
attr => self.hinfo.attrs.contains_key(&attr),
}
}
pub fn is_empty(&self) -> bool {
self.inl.is_empty() && self.hinfo.attrs.is_empty()
}
pub fn remove<A>(&mut self, key: A)
where
A: Into<Attribute>,
{
match key.into() {
Attribute::Bool(b) => {
self.inl.remove(b);
}
attr => {
self.hinfo.attrs.remove(&attr);
}
}
}
pub fn add_span(mut self, span: GPosIdx) -> Self {
self.hinfo.span = span;
self
}
pub fn to_string_with<F>(&self, sep: &'static str, fmt: F) -> String
where
F: Fn(String, u64) -> String,
{
if self.is_empty() {
return String::default();
}
self.hinfo
.attrs
.iter()
.map(|(k, v)| fmt(k.to_string(), *v))
.chain(self.inl.iter().map(|k| fmt(k.as_ref().to_string(), 1)))
.collect::<Vec<_>>()
.join(sep)
}
}
#[cfg(feature = "serialize")]
impl serde::Serialize for HeapAttrInfo {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
ser.collect_map(self.to_owned().attrs.iter())
}
}