Skip to main content

melior/ir/
region.rs

1use super::{Block, BlockRef};
2use mlir_sys::{
3    mlirRegionAppendOwnedBlock, mlirRegionCreate, mlirRegionDestroy, mlirRegionEqual,
4    mlirRegionGetFirstBlock, mlirRegionInsertOwnedBlockAfter, mlirRegionInsertOwnedBlockBefore,
5    MlirRegion,
6};
7use std::{
8    marker::PhantomData,
9    mem::{forget, transmute},
10    ops::Deref,
11};
12
13/// A region.
14#[derive(Debug)]
15pub struct Region<'c> {
16    raw: MlirRegion,
17    _block: PhantomData<Block<'c>>,
18}
19
20impl<'c> Region<'c> {
21    /// Creates a region.
22    pub fn new() -> Self {
23        Self {
24            raw: unsafe { mlirRegionCreate() },
25            _block: Default::default(),
26        }
27    }
28
29    /// Returns the first block in a region.
30    pub fn first_block(&self) -> Option<BlockRef<'c, '_>> {
31        unsafe {
32            let block = mlirRegionGetFirstBlock(self.raw);
33
34            if block.ptr.is_null() {
35                None
36            } else {
37                Some(BlockRef::from_raw(block))
38            }
39        }
40    }
41
42    /// Inserts a block after another block.
43    pub fn insert_block_after(&self, one: BlockRef<'c, '_>, other: Block<'c>) -> BlockRef<'c, '_> {
44        unsafe {
45            let r#ref = BlockRef::from_raw(other.to_raw());
46
47            mlirRegionInsertOwnedBlockAfter(self.raw, one.to_raw(), other.into_raw());
48
49            r#ref
50        }
51    }
52
53    /// Inserts a block before another block.
54    pub fn insert_block_before(&self, one: BlockRef<'c, '_>, other: Block<'c>) -> BlockRef<'c, '_> {
55        unsafe {
56            let r#ref = BlockRef::from_raw(other.to_raw());
57
58            mlirRegionInsertOwnedBlockBefore(self.raw, one.to_raw(), other.into_raw());
59
60            r#ref
61        }
62    }
63
64    /// Appends a block.
65    pub fn append_block(&self, block: Block<'c>) -> BlockRef<'c, '_> {
66        unsafe {
67            let r#ref = BlockRef::from_raw(block.to_raw());
68
69            mlirRegionAppendOwnedBlock(self.raw, block.into_raw());
70
71            r#ref
72        }
73    }
74
75    /// Converts a region into a raw object.
76    pub const fn into_raw(self) -> mlir_sys::MlirRegion {
77        let region = self.raw;
78
79        forget(self);
80
81        region
82    }
83}
84
85impl Default for Region<'_> {
86    fn default() -> Self {
87        Self::new()
88    }
89}
90
91impl Drop for Region<'_> {
92    fn drop(&mut self) {
93        unsafe { mlirRegionDestroy(self.raw) }
94    }
95}
96
97impl PartialEq for Region<'_> {
98    fn eq(&self, other: &Self) -> bool {
99        unsafe { mlirRegionEqual(self.raw, other.raw) }
100    }
101}
102
103impl Eq for Region<'_> {}
104
105/// A reference to a region.
106#[derive(Clone, Copy, Debug)]
107pub struct RegionRef<'c, 'a> {
108    raw: MlirRegion,
109    _region: PhantomData<&'a Region<'c>>,
110}
111
112impl RegionRef<'_, '_> {
113    /// Creates a region from a raw object.
114    ///
115    /// # Safety
116    ///
117    /// A raw object must be valid.
118    pub unsafe fn from_raw(raw: MlirRegion) -> Self {
119        Self {
120            raw,
121            _region: Default::default(),
122        }
123    }
124
125    /// Creates an optional region from a raw object.
126    ///
127    /// # Safety
128    ///
129    /// A raw object must be valid.
130    pub unsafe fn from_option_raw(raw: MlirRegion) -> Option<Self> {
131        if raw.ptr.is_null() {
132            None
133        } else {
134            Some(Self::from_raw(raw))
135        }
136    }
137}
138
139impl<'c> Deref for RegionRef<'c, '_> {
140    type Target = Region<'c>;
141
142    fn deref(&self) -> &Self::Target {
143        unsafe { transmute(self) }
144    }
145}
146
147impl PartialEq for RegionRef<'_, '_> {
148    fn eq(&self, other: &Self) -> bool {
149        unsafe { mlirRegionEqual(self.raw, other.raw) }
150    }
151}
152
153impl Eq for RegionRef<'_, '_> {}
154
155#[cfg(test)]
156mod tests {
157    use super::*;
158
159    #[test]
160    fn new() {
161        Region::new();
162    }
163
164    #[test]
165    fn first_block() {
166        assert!(Region::new().first_block().is_none());
167    }
168
169    #[test]
170    fn append_block() {
171        let region = Region::new();
172        let block = Block::new(&[]);
173
174        region.append_block(block);
175
176        assert!(region.first_block().is_some());
177    }
178
179    #[test]
180    fn insert_block_after() {
181        let region = Region::new();
182
183        let block = region.append_block(Block::new(&[]));
184        region.insert_block_after(block, Block::new(&[]));
185
186        assert_eq!(region.first_block(), Some(block));
187    }
188
189    #[test]
190    fn insert_block_before() {
191        let region = Region::new();
192
193        let block = region.append_block(Block::new(&[]));
194        let block = region.insert_block_before(block, Block::new(&[]));
195
196        assert_eq!(region.first_block(), Some(block));
197    }
198
199    #[test]
200    fn equal() {
201        let region = Region::new();
202
203        assert_eq!(region, region);
204    }
205
206    #[test]
207    fn not_equal() {
208        assert_ne!(Region::new(), Region::new());
209    }
210}