1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use crate::utils::CastableMeta;
use crate::{
    AllocId, Attr, ContextRef, ContextWRef, OpAssembly, OpValidator, Printable, RegionRef,
    RegionWRef, Type, Validate, Value,
};
use std::any::Any;
use std::{cell::RefCell, collections::HashMap, rc::Rc};

pub type OpRef = Rc<RefCell<dyn Op>>;

pub trait Op: Any + OpAssembly + Printable + Validate + OpValidator {
    fn get_operation_name(&self) -> &'static str;
    fn get_attrs(&self) -> &HashMap<String, Attr>;
    fn add_attrs(&mut self, attrs: &HashMap<String, Attr>);
    fn get_context(&self) -> ContextRef;
    fn get_parent_region(&self) -> Option<RegionRef>;
    fn set_parent_region(&mut self, region: RegionWRef);
    fn get_return_type(&self) -> Option<Type>;
    fn get_return_value(&self) -> Option<Value>;

    fn set_alloc_id(&mut self, id: AllocId);
    fn get_alloc_id(&self) -> AllocId;

    fn get_dialect_id(&self) -> u32;

    fn get_regions(&self) -> OpRegionIter;
    fn has_regions(&self) -> bool;

    #[doc(hidden)]
    fn has_trait(&self, type_id: std::any::TypeId) -> bool;
    #[doc(hidden)]
    fn get_meta(&self) -> &'static linkme::DistributedSlice<[fn() -> CastableMeta]>;
}

#[derive(Debug, Clone)]
pub struct OpImpl {
    pub context: ContextWRef,
    pub dialect_id: u32,
    pub operation_id: u32,
    pub alloc_id: AllocId,
    pub parent_region: Option<RegionWRef>,
    pub attrs: HashMap<String, Attr>,
}

pub struct OpRegionIter {
    regions: Vec<RegionRef>,
    index_front: isize,
    index_back: isize,
}

impl OpRegionIter {
    pub fn new(src: &[RegionRef]) -> Self {
        let mut regions = vec![];
        regions.extend_from_slice(src);

        OpRegionIter {
            regions,
            index_front: 0,
            index_back: src.len() as isize - 1,
        }
    }
}

impl Iterator for OpRegionIter {
    type Item = RegionRef;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index_front > self.index_back {
            return None;
        }
        let item = self.regions.get(self.index_front as usize).cloned();
        self.index_front += 1;
        item
    }
}

impl DoubleEndedIterator for OpRegionIter {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.index_front > self.index_back || self.index_back < 0 {
            return None;
        }
        let item = self.regions.get(self.index_back as usize).cloned();
        self.index_front -= 1;
        item
    }
}