ligen_ir/macro_attributes/attributes/
mod.rs

1pub mod attribute;
2
3#[cfg(any(test, feature = "mocks"))]
4pub mod mock;
5
6use std::fmt::{Display, Formatter};
7pub use attribute::*;
8
9use crate::Path;
10use crate::Literal;
11use crate::prelude::*;
12
13#[derive(Shrinkwrap, Default, Debug, PartialEq, Clone, Serialize, Deserialize)]
14#[shrinkwrap(mutable)]
15/// Attributes representation.
16pub struct Attributes {
17    /// attributes field
18    pub attributes: Vec<Attribute>,
19}
20
21impl Attributes {
22    /// Get the group identified by `path`.
23    pub fn get_subgroup<P: Into<Path>>(&self, path: P) -> Option<&Attributes> {
24        let path = path.into();
25        let mut group = self;
26        for segment in path.segments {
27            if let Some(new_group) = group.get_group(segment) {
28                group = new_group
29            } else {
30                return None;
31            }
32        }
33        Some(group)
34    }
35
36    /// Get a literal from the `path`.
37    pub fn get_literal_from_path<P: Into<Path>>(&self, path: P) -> Option<&Literal> {
38        let mut path = path.into();
39        path
40            .pop_back()
41            .and_then(|last| {
42                self
43                    .get_subgroup(path.segments)
44                    .and_then(|group| group.get_named(last))
45            })
46    }
47
48    /// Get the group identified by `name`.
49    pub fn get_group<I: Into<Path>>(&self, name: I) -> Option<&Attributes> {
50        let name = name.into();
51        self
52            .attributes
53            .iter()
54            .find_map(|attribute| {
55                if let Attribute::Group(group) = attribute {
56                    if group.path == name {
57                        Some(&group.attributes)
58                    } else {
59                        None
60                    }
61                } else {
62                    None
63                }
64            })
65    }
66
67    /// Get named attribute e.g.: name = "literal"
68    pub fn get_named<I: Into<Path>>(&self, name: I) -> Option<&Literal> {
69        let name = name.into();
70        self
71            .attributes
72            .iter()
73            .find_map(|attribute| {
74                if let Attribute::Named(named) = attribute {
75                    if named.path == name {
76                        Some(&named.literal)
77                    } else {
78                        None
79                    }
80                } else {
81                    None
82                }
83            })
84    }
85
86    /// Check if `Attributes` contains the specified `attribute`.
87    pub fn contains(&self, attribute: &Attribute) -> bool {
88        self
89            .attributes
90            .iter()
91            .any(|inner_attribute| *inner_attribute == *attribute)
92    }
93
94    /// Check if the attributes list has an ignore attribute.
95    pub fn has_ignore_attribute(&self) -> bool {
96        self.contains(&Attribute::Group(Group::new("ligen", Group::from("ignore"))))
97    }
98}
99
100impl From<Group> for Attributes {
101    fn from(group: Group) -> Self {
102        Self { attributes: vec![group.into()] }
103    }
104}
105
106impl From<Named> for Attributes {
107    fn from(named: Named) -> Self {
108        Self { attributes: vec![named.into()] }
109    }
110}
111
112impl<L: Into<Literal>> From<L> for Attributes {
113    fn from(literal: L) -> Self {
114        Self { attributes: vec![literal.into().into()] }
115    }
116}
117
118impl<A: Into<Attribute>> From<Vec<A>> for Attributes {
119    fn from(attributes: Vec<A>) -> Self {
120        let attributes = attributes
121            .into_iter()
122            .map(|attribute| attribute.into())
123            .collect();
124        Self { attributes }
125    }
126}
127
128impl From<Attribute> for Attributes {
129    fn from(attribute: Attribute) -> Self {
130        let attributes = vec![attribute];
131        Self { attributes }
132    }
133}
134
135impl Display for Attributes {
136    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137        f.write_str(self.attributes.iter().map(|attribute| attribute.to_string()).collect::<Vec<_>>().join(",").as_str())
138    }
139}
140
141#[cfg(test)]
142mod test {
143    use crate::macro_attributes::attributes::mock;
144    use crate::*;
145
146    #[test]
147    fn get_literals() {
148        let attributes = mock::parse_literals();
149        assert_eq!(attributes.get_literal_from_path(vec!["c", "int"]), Some(&Literal::String("sized".into())));
150        assert_eq!(attributes.get_literal_from_path(vec!["c", "marshal_as", "name"]), Some(&Literal::String("hello".into())));
151        assert_eq!(attributes.get_literal_from_path(vec!["c", "marshal_as", "uuid"]), Some(&Literal::Integer(5)));
152    }
153}