calyx_frontend/
attributes.rs

1use super::Attribute;
2use crate::InlineAttributes;
3use calyx_utils::{CalyxResult, GPosIdx, WithPos};
4use linked_hash_map::LinkedHashMap;
5use std::convert::TryFrom;
6
7#[derive(Debug, Clone, Default)]
8/// Attribute information stored on the Heap
9struct HeapAttrInfo {
10    attrs: LinkedHashMap<Attribute, u64>,
11    span: GPosIdx,
12}
13
14/// Attributes associated with a specific IR structure.
15#[derive(Default, Debug, Clone)]
16#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
17pub struct Attributes {
18    /// Inlined attributes
19    inl: InlineAttributes,
20    /// Attributes stored on the heap
21    hinfo: Box<HeapAttrInfo>,
22}
23
24impl TryFrom<Vec<(Attribute, u64)>> for Attributes {
25    type Error = calyx_utils::Error;
26
27    fn try_from(v: Vec<(Attribute, u64)>) -> CalyxResult<Self> {
28        let mut attrs = Attributes::default();
29        for (k, v) in v {
30            if attrs.has(k) {
31                return Err(Self::Error::malformed_structure(format!(
32                    "Multiple entries for attribute: {}",
33                    k
34                )));
35            }
36            attrs.insert(k, v);
37        }
38        Ok(attrs)
39    }
40}
41
42impl WithPos for Attributes {
43    fn copy_span(&self) -> GPosIdx {
44        self.hinfo.span
45    }
46}
47
48/// Structs that can return an [`Attributes`] instance.
49pub trait GetAttributes {
50    /// Returns an [`Attributes`] instance
51    fn get_attributes(&self) -> &Attributes;
52
53    /// Returns a mutable [`Attributes`] instance
54    fn get_mut_attributes(&mut self) -> &mut Attributes;
55}
56
57impl Attributes {
58    /// Add a new attribute
59    pub fn insert<A>(&mut self, key: A, val: u64)
60    where
61        A: Into<Attribute>,
62    {
63        match key.into() {
64            Attribute::Bool(b) => {
65                assert!(
66                    val == 1,
67                    "{} is a boolean attribute and can only have a value of 1",
68                    b.as_ref(),
69                );
70                self.inl.insert(b);
71            }
72            attr => {
73                self.hinfo.attrs.insert(attr, val);
74            }
75        }
76    }
77
78    /// Get the value associated with an attribute key
79    pub fn get<A>(&self, key: A) -> Option<u64>
80    where
81        A: Into<Attribute>,
82    {
83        match key.into() {
84            Attribute::Bool(b) => {
85                if self.inl.has(b) {
86                    Some(1)
87                } else {
88                    None
89                }
90            }
91            attr => self.hinfo.attrs.get(&attr).cloned(),
92        }
93    }
94
95    /// Check if an attribute key has been set
96    pub fn has<A>(&self, key: A) -> bool
97    where
98        A: Into<Attribute>,
99    {
100        match key.into() {
101            Attribute::Bool(b) => self.inl.has(b),
102            attr => self.hinfo.attrs.contains_key(&attr),
103        }
104    }
105
106    /// Returns true if there are no attributes
107    pub fn is_empty(&self) -> bool {
108        self.inl.is_empty() && self.hinfo.attrs.is_empty()
109    }
110
111    /// Remove attribute with the name `key`
112    pub fn remove<A>(&mut self, key: A)
113    where
114        A: Into<Attribute>,
115    {
116        match key.into() {
117            Attribute::Bool(b) => {
118                self.inl.remove(b);
119            }
120            attr => {
121                self.hinfo.attrs.remove(&attr);
122            }
123        }
124    }
125
126    /// Set the span information
127    pub fn add_span(mut self, span: GPosIdx) -> Self {
128        self.hinfo.span = span;
129        self
130    }
131
132    pub fn to_string_with<F>(&self, sep: &'static str, fmt: F) -> String
133    where
134        F: Fn(String, u64) -> String,
135    {
136        if self.is_empty() {
137            return String::default();
138        }
139
140        self.hinfo
141            .attrs
142            .iter()
143            .map(|(k, v)| fmt(k.to_string(), *v))
144            .chain(self.inl.iter().map(|k| fmt(k.as_ref().to_string(), 1)))
145            .collect::<Vec<_>>()
146            .join(sep)
147    }
148}
149
150#[cfg(feature = "serialize")]
151impl serde::Serialize for HeapAttrInfo {
152    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
153    where
154        S: serde::Serializer,
155    {
156        ser.collect_map(self.to_owned().attrs.iter())
157    }
158}