ligen_ir/macro_attributes/attributes/
mod.rs1pub 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)]
15pub struct Attributes {
17 pub attributes: Vec<Attribute>,
19}
20
21impl Attributes {
22 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 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 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 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 pub fn contains(&self, attribute: &Attribute) -> bool {
88 self
89 .attributes
90 .iter()
91 .any(|inner_attribute| *inner_attribute == *attribute)
92 }
93
94 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}