1#[macro_use]
4mod r#macro;
5mod array;
6mod attribute_like;
7mod bool;
8mod dense_elements;
9mod dense_i32_array;
10mod dense_i64_array;
11mod flat_symbol_ref;
12mod float;
13mod integer;
14mod string;
15mod r#type;
16
17pub use self::{
18 array::ArrayAttribute, attribute_like::AttributeLike, bool::BoolAttribute,
19 dense_elements::DenseElementsAttribute, dense_i32_array::DenseI32ArrayAttribute,
20 dense_i64_array::DenseI64ArrayAttribute, flat_symbol_ref::FlatSymbolRefAttribute,
21 float::FloatAttribute, integer::IntegerAttribute, r#type::TypeAttribute,
22 string::StringAttribute,
23};
24use crate::{context::Context, string_ref::StringRef, utility::print_callback};
25use mlir_sys::{
26 mlirAttributeEqual, mlirAttributeGetNull, mlirAttributeParseGet, mlirAttributePrint,
27 mlirUnitAttrGet, MlirAttribute,
28};
29use std::{
30 ffi::c_void,
31 fmt::{self, Debug, Display, Formatter},
32 marker::PhantomData,
33};
34
35#[derive(Clone, Copy)]
38pub struct Attribute<'c> {
39 raw: MlirAttribute,
40 _context: PhantomData<&'c Context>,
41}
42
43impl<'c> Attribute<'c> {
44 pub fn parse(context: &'c Context, source: &str) -> Option<Self> {
46 unsafe {
47 Self::from_option_raw(mlirAttributeParseGet(
48 context.to_raw(),
49 StringRef::new(source).to_raw(),
50 ))
51 }
52 }
53
54 pub fn unit(context: &'c Context) -> Self {
56 unsafe { Self::from_raw(mlirUnitAttrGet(context.to_raw())) }
57 }
58
59 pub(crate) unsafe fn null() -> Self {
60 unsafe { Self::from_raw(mlirAttributeGetNull()) }
61 }
62
63 pub unsafe fn from_raw(raw: MlirAttribute) -> Self {
69 Self {
70 raw,
71 _context: Default::default(),
72 }
73 }
74
75 pub unsafe fn from_option_raw(raw: MlirAttribute) -> Option<Self> {
81 if raw.ptr.is_null() {
82 None
83 } else {
84 Some(Self::from_raw(raw))
85 }
86 }
87}
88
89impl<'c> AttributeLike<'c> for Attribute<'c> {
90 fn to_raw(&self) -> MlirAttribute {
91 self.raw
92 }
93}
94
95impl PartialEq for Attribute<'_> {
96 fn eq(&self, other: &Self) -> bool {
97 unsafe { mlirAttributeEqual(self.raw, other.raw) }
98 }
99}
100
101impl Eq for Attribute<'_> {}
102
103impl Display for Attribute<'_> {
104 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
105 let mut data = (formatter, Ok(()));
106
107 unsafe {
108 mlirAttributePrint(
109 self.raw,
110 Some(print_callback),
111 &mut data as *mut _ as *mut c_void,
112 );
113 }
114
115 data.1
116 }
117}
118
119impl Debug for Attribute<'_> {
120 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
121 Display::fmt(self, formatter)
122 }
123}
124
125from_subtypes!(
126 Attribute,
127 ArrayAttribute,
128 BoolAttribute,
129 DenseElementsAttribute,
130 DenseI32ArrayAttribute,
131 DenseI64ArrayAttribute,
132 FlatSymbolRefAttribute,
133 FloatAttribute,
134 IntegerAttribute,
135 StringAttribute,
136 TypeAttribute,
137);
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142 use crate::{
143 ir::{Type, TypeLike},
144 test::create_test_context,
145 };
146
147 #[test]
148 fn parse() {
149 let context = create_test_context();
150 for attribute in ["unit", "i32", r#""foo""#] {
151 assert!(Attribute::parse(&context, attribute).is_some());
152 }
153 }
154
155 #[test]
156 fn parse_none() {
157 assert!(Attribute::parse(&Context::new(), "z").is_none());
162 }
163
164 #[test]
165 fn context() {
166 let context = create_test_context();
167 Attribute::parse(&context, "unit").unwrap().context();
168 }
169
170 #[test]
171 fn r#type() {
172 let context = Context::new();
173
174 assert_eq!(
175 Attribute::parse(&context, "unit").unwrap().r#type(),
176 Type::none(&context)
177 );
178 }
179
180 #[ignore]
182 #[test]
183 fn type_id() {
184 let context = Context::new();
185
186 assert_eq!(
187 Attribute::parse(&context, "42 : index").unwrap().type_id(),
188 Type::index(&context).id()
189 );
190 }
191
192 #[test]
193 fn is_array() {
194 let context = create_test_context();
195 assert!(Attribute::parse(&context, "[]").unwrap().is_array());
196 }
197
198 #[test]
199 fn is_bool() {
200 let context = create_test_context();
201 assert!(Attribute::parse(&context, "false").unwrap().is_bool());
202 }
203
204 #[test]
205 fn is_dense_elements() {
206 let context = create_test_context();
207 assert!(Attribute::parse(&context, "dense<10> : tensor<2xi8>")
208 .unwrap()
209 .is_dense_elements());
210 }
211
212 #[test]
213 fn is_dense_int_elements() {
214 let context = create_test_context();
215 assert!(Attribute::parse(&context, "dense<42> : tensor<42xi8>")
216 .unwrap()
217 .is_dense_int_elements());
218 }
219
220 #[test]
221 fn is_dense_fp_elements() {
222 let context = create_test_context();
223 assert!(Attribute::parse(&context, "dense<42.0> : tensor<42xf32>")
224 .unwrap()
225 .is_dense_fp_elements());
226 }
227
228 #[test]
229 fn is_elements() {
230 let context = create_test_context();
231 assert!(Attribute::parse(
232 &context,
233 "sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>"
234 )
235 .unwrap()
236 .is_elements());
237 }
238
239 #[test]
240 fn is_integer() {
241 let context = create_test_context();
242 assert!(Attribute::parse(&context, "42").unwrap().is_integer());
243 }
244
245 #[test]
246 fn is_integer_set() {
247 let context = create_test_context();
248 assert!(
249 Attribute::parse(&context, "affine_set<(d0) : (d0 - 2 >= 0)>")
250 .unwrap()
251 .is_integer_set()
252 );
253 }
254
255 #[ignore]
257 #[test]
258 fn is_opaque() {
259 let context = create_test_context();
260 assert!(Attribute::parse(&context, "#foo<\"bar\">")
261 .unwrap()
262 .is_opaque());
263 }
264
265 #[test]
266 fn is_sparse_elements() {
267 let context = create_test_context();
268 assert!(Attribute::parse(
269 &context,
270 "sparse<[[0, 0], [1, 2]], [1, 5]> : tensor<3x4xi32>"
271 )
272 .unwrap()
273 .is_sparse_elements());
274 }
275
276 #[test]
277 fn is_string() {
278 let context = create_test_context();
279 assert!(Attribute::parse(&context, "\"foo\"").unwrap().is_string());
280 }
281
282 #[test]
283 fn is_type() {
284 let context = create_test_context();
285 assert!(Attribute::parse(&context, "index").unwrap().is_type());
286 }
287
288 #[test]
289 fn is_unit() {
290 let context = create_test_context();
291 assert!(Attribute::parse(&context, "unit").unwrap().is_unit());
292 }
293
294 #[test]
295 fn is_symbol() {
296 let context = create_test_context();
297 assert!(Attribute::parse(&context, "@foo").unwrap().is_symbol_ref());
298 }
299
300 #[test]
301 fn equal() {
302 let context = create_test_context();
303 let attribute = Attribute::parse(&context, "unit").unwrap();
304
305 assert_eq!(attribute, attribute);
306 }
307
308 #[test]
309 fn not_equal() {
310 let context = create_test_context();
311
312 assert_ne!(
313 Attribute::parse(&context, "unit").unwrap(),
314 Attribute::parse(&context, "42").unwrap()
315 );
316 }
317
318 #[test]
319 fn display() {
320 let context = create_test_context();
321 assert_eq!(
322 Attribute::parse(&context, "unit").unwrap().to_string(),
323 "unit"
324 );
325 }
326}