1use crate::{
2 diagnostic::{Diagnostic, DiagnosticHandlerId},
3 dialect::{Dialect, DialectRegistry},
4 logical_result::LogicalResult,
5 string_ref::StringRef,
6};
7use mlir_sys::{
8 mlirContextAppendDialectRegistry, mlirContextAttachDiagnosticHandler, mlirContextCreate,
9 mlirContextDestroy, mlirContextDetachDiagnosticHandler, mlirContextEnableMultithreading,
10 mlirContextEqual, mlirContextGetAllowUnregisteredDialects, mlirContextGetNumLoadedDialects,
11 mlirContextGetNumRegisteredDialects, mlirContextGetOrLoadDialect,
12 mlirContextIsRegisteredOperation, mlirContextLoadAllAvailableDialects,
13 mlirContextSetAllowUnregisteredDialects, MlirContext, MlirDiagnostic, MlirLogicalResult,
14};
15use std::{ffi::c_void, marker::PhantomData, mem::transmute};
16
17#[derive(Debug)]
22pub struct Context {
23 raw: MlirContext,
24}
25
26impl Context {
27 pub fn new() -> Self {
29 Self {
30 raw: unsafe { mlirContextCreate() },
31 }
32 }
33
34 pub fn registered_dialect_count(&self) -> usize {
36 unsafe { mlirContextGetNumRegisteredDialects(self.raw) as usize }
37 }
38
39 pub fn loaded_dialect_count(&self) -> usize {
41 unsafe { mlirContextGetNumLoadedDialects(self.raw) as usize }
42 }
43
44 pub fn get_or_load_dialect(&self, name: &str) -> Dialect {
46 let name = StringRef::new(name);
47
48 unsafe { Dialect::from_raw(mlirContextGetOrLoadDialect(self.raw, name.to_raw())) }
49 }
50
51 pub fn append_dialect_registry(&self, registry: &DialectRegistry) {
53 unsafe { mlirContextAppendDialectRegistry(self.raw, registry.to_raw()) }
54 }
55
56 pub fn load_all_available_dialects(&self) {
58 unsafe { mlirContextLoadAllAvailableDialects(self.raw) }
59 }
60
61 pub fn enable_multi_threading(&self, enabled: bool) {
63 unsafe { mlirContextEnableMultithreading(self.raw, enabled) }
64 }
65
66 pub fn allow_unregistered_dialects(&self) -> bool {
68 unsafe { mlirContextGetAllowUnregisteredDialects(self.raw) }
69 }
70
71 pub fn set_allow_unregistered_dialects(&self, allowed: bool) {
73 unsafe { mlirContextSetAllowUnregisteredDialects(self.raw, allowed) }
74 }
75
76 pub fn is_registered_operation(&self, name: &str) -> bool {
78 let name = StringRef::new(name);
79
80 unsafe { mlirContextIsRegisteredOperation(self.raw, name.to_raw()) }
81 }
82
83 pub const fn to_raw(&self) -> MlirContext {
85 self.raw
86 }
87
88 pub fn attach_diagnostic_handler<F: FnMut(Diagnostic) -> bool>(
90 &self,
91 handler: F,
92 ) -> DiagnosticHandlerId {
93 unsafe extern "C" fn handle<F: FnMut(Diagnostic) -> bool>(
94 diagnostic: MlirDiagnostic,
95 user_data: *mut c_void,
96 ) -> MlirLogicalResult {
97 LogicalResult::from((*(user_data as *mut F))(Diagnostic::from_raw(diagnostic))).to_raw()
98 }
99
100 unsafe extern "C" fn destroy<F: FnMut(Diagnostic) -> bool>(user_data: *mut c_void) {
101 drop(Box::from_raw(user_data as *mut F));
102 }
103
104 unsafe {
105 DiagnosticHandlerId::from_raw(mlirContextAttachDiagnosticHandler(
106 self.to_raw(),
107 Some(handle::<F>),
108 Box::into_raw(Box::new(handler)) as *mut _,
109 Some(destroy::<F>),
110 ))
111 }
112 }
113
114 pub fn detach_diagnostic_handler(&self, id: DiagnosticHandlerId) {
116 unsafe { mlirContextDetachDiagnosticHandler(self.to_raw(), id.to_raw()) }
117 }
118
119 pub(crate) fn to_ref(&self) -> ContextRef {
120 unsafe { ContextRef::from_raw(self.to_raw()) }
121 }
122}
123
124impl Drop for Context {
125 fn drop(&mut self) {
126 unsafe { mlirContextDestroy(self.raw) };
127 }
128}
129
130impl Default for Context {
131 fn default() -> Self {
132 Self::new()
133 }
134}
135
136impl PartialEq for Context {
137 fn eq(&self, other: &Self) -> bool {
138 unsafe { mlirContextEqual(self.raw, other.raw) }
139 }
140}
141
142impl<'a> PartialEq<ContextRef<'a>> for Context {
143 fn eq(&self, &other: &ContextRef<'a>) -> bool {
144 self.to_ref() == other
145 }
146}
147
148impl Eq for Context {}
149
150#[derive(Clone, Copy, Debug)]
152pub struct ContextRef<'c> {
153 raw: MlirContext,
154 _reference: PhantomData<&'c Context>,
155}
156
157impl<'c> ContextRef<'c> {
158 pub unsafe fn from_raw(raw: MlirContext) -> Self {
164 Self {
165 raw,
166 _reference: Default::default(),
167 }
168 }
169
170 pub unsafe fn to_ref(&self) -> &'c Context {
180 transmute(self)
184 }
185}
186
187impl PartialEq for ContextRef<'_> {
188 fn eq(&self, other: &Self) -> bool {
189 unsafe { mlirContextEqual(self.raw, other.raw) }
190 }
191}
192
193impl PartialEq<Context> for ContextRef<'_> {
194 fn eq(&self, other: &Context) -> bool {
195 self == &other.to_ref()
196 }
197}
198
199impl Eq for ContextRef<'_> {}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn new() {
207 Context::new();
208 }
209
210 #[test]
211 fn registered_dialect_count() {
212 let context = Context::new();
213
214 assert_eq!(context.registered_dialect_count(), 1);
215 }
216
217 #[test]
218 fn loaded_dialect_count() {
219 let context = Context::new();
220
221 assert_eq!(context.loaded_dialect_count(), 1);
222 }
223
224 #[test]
225 fn append_dialect_registry() {
226 let context = Context::new();
227
228 context.append_dialect_registry(&DialectRegistry::new());
229 }
230
231 #[test]
232 fn is_registered_operation() {
233 let context = Context::new();
234
235 assert!(context.is_registered_operation("builtin.module"));
236 }
237
238 #[test]
239 fn is_not_registered_operation() {
240 let context = Context::new();
241
242 assert!(!context.is_registered_operation("func.func"));
243 }
244
245 #[test]
246 fn enable_multi_threading() {
247 let context = Context::new();
248
249 context.enable_multi_threading(true);
250 }
251
252 #[test]
253 fn disable_multi_threading() {
254 let context = Context::new();
255
256 context.enable_multi_threading(false);
257 }
258
259 #[test]
260 fn allow_unregistered_dialects() {
261 let context = Context::new();
262
263 assert!(!context.allow_unregistered_dialects());
264 }
265
266 #[test]
267 fn set_allow_unregistered_dialects() {
268 let context = Context::new();
269
270 context.set_allow_unregistered_dialects(true);
271
272 assert!(context.allow_unregistered_dialects());
273 }
274
275 #[test]
276 fn attach_and_detach_diagnostic_handler() {
277 let context = Context::new();
278
279 let id = context.attach_diagnostic_handler(|diagnostic| {
280 println!("{}", diagnostic);
281 true
282 });
283
284 context.detach_diagnostic_handler(id);
285 }
286
287 #[test]
288 fn compare_contexts() {
289 let one = Context::new();
290 let other = Context::new();
291
292 assert_eq!(&one, &one);
293 assert_ne!(&one, &other);
294 assert_ne!(&other, &one);
295 assert_eq!(&other, &other);
296 }
297
298 #[test]
299 fn compare_context_refs() {
300 let one = Context::new();
301 let other = Context::new();
302
303 let one_ref = one.to_ref();
304 let other_ref = other.to_ref();
305
306 assert_eq!(&one, &one_ref);
307 assert_eq!(&one_ref, &one);
308
309 assert_eq!(&other, &other_ref);
310 assert_eq!(&other_ref, &other);
311
312 assert_ne!(&one, &other_ref);
313 assert_ne!(&other_ref, &one);
314
315 assert_ne!(&other, &one_ref);
316 assert_ne!(&one_ref, &other);
317 }
318
319 #[test]
320 fn context_to_ref() {
321 let ctx = Context::new();
322 let ctx_ref = ctx.to_ref();
323 let ctx_ref_to_ref: &Context = unsafe { ctx_ref.to_ref() };
324
325 assert_eq!(&ctx_ref, ctx_ref_to_ref);
326 }
327}