hydroperfox_smodel/
lib.rs

1use std::{cell::RefCell, rc::{Rc, Weak}};
2use std::fmt::Debug;
3
4pub mod util;
5
6pub use hydroperfox_smodel_proc::smodel;
7
8pub struct Arena<T> {
9    data: RefCell<Vec<Rc<T>>>,
10}
11
12impl<T> Arena<T> {
13    pub fn new() -> Self {
14        Self {
15            data: RefCell::new(vec![]),
16        }
17    }
18
19    pub fn allocate(&self, value: T) -> Weak<T> {
20        let obj = Rc::new(value);
21        self.data.borrow_mut().push(obj.clone());
22        Rc::downgrade(&obj)
23    }
24
25    /// Frees dead objects from the arena. Note that a call to `clean()`
26    /// may be expensive; therefore it is recommended to call it after a long
27    /// processing has been done with the arena.
28    pub fn clean(&self) {
29        let mut data = self.data.borrow_mut();
30        let mut i = data.len();
31        while i != 0 {
32            i -= 1;
33            let obj = data.get(i).unwrap();
34            if Rc::weak_count(obj) == 0 && Rc::strong_count(obj) == 1 {
35                data.remove(i);
36            }
37        }
38    }
39}
40
41#[derive(Debug)]
42pub enum SModelError {
43    Contravariant,
44}
45
46#[cfg(test)]
47mod test {
48    #[test]
49    fn test() {
50        use crate::smodel;
51
52        smodel! {
53            mod smodel = crate;
54
55            type Arena = Arena;
56        
57            /// My unified data type.
58            struct Thingy {
59                pub fn Thingy() {
60                    super();
61                }
62        
63                /// Empty, Foo, FooBar or FooQux
64                pub fn name(&self) -> String {
65                    "".into()
66                }
67
68                pub fn base_example(&self) -> String {
69                    "from base".into()
70                }
71
72                pub fn x(&self) -> f64 {
73                    0.0
74                }
75            }
76        
77            struct Foo: Thingy {
78                pub fn Foo() {
79                    super();
80                }
81
82                #[inheritdoc]
83                pub override fn name(&self) -> String {
84                    "Foo".into()
85                }
86            }
87        
88            struct FooBar: Foo {
89                pub fn FooBar() {
90                    super();
91                }
92
93                #[inheritdoc]
94                pub override fn name(&self) -> String {
95                    "FooBar".into()
96                }
97
98                pub override fn base_example(&self) -> String {
99                    format!("from bar; {}", super.base_example())
100                }
101            }
102            
103            struct FooBarBar: FooBar {
104                let m_x: f64 = 0.0;
105                let ref m_y: String = "".into();
106
107                pub fn FooBarBar(x: f64, y: &str) {
108                    super();
109                    self.set_m_x(x);
110                    self.set_m_y(y.into());
111                }
112
113                #[inheritdoc]
114                pub override fn name(&self) -> String {
115                    "FooBarBar".into()
116                }
117
118                pub override fn x(&self) -> f64 {
119                    self.m_x()
120                }
121
122                pub override fn base_example(&self) -> String {
123                    format!("from {}; {}", self.m_y(), super.base_example())
124                }
125            }
126        
127            struct FooQux: Foo {
128                pub fn FooQux() {
129                    super();
130                }
131
132                #[inheritdoc]
133                pub override fn name(&self) -> String {
134                    "FooQux".into()
135                }
136            }
137        }
138
139        let arena = Arena::new();
140
141        let symbol = Foo::new(&arena);
142        let base_symbol: Thingy = symbol.into();
143        assert_eq!("Foo", base_symbol.name());
144        assert_eq!(true, base_symbol.is::<Foo>());
145        assert_eq!(false, base_symbol.is::<FooBar>());
146        assert_eq!(false, base_symbol.is::<FooQux>());
147        assert_eq!("from base", base_symbol.base_example());
148        assert_eq!(0.0, base_symbol.x());
149
150        let symbol = FooBar::new(&arena);
151        let base_symbol: Thingy = symbol.into();
152        assert_eq!("FooBar", base_symbol.name());
153        assert_eq!(true, base_symbol.is::<Foo>());
154        assert_eq!(true, base_symbol.is::<FooBar>());
155        assert_eq!(false, base_symbol.is::<FooBarBar>());
156        assert_eq!(false, base_symbol.is::<FooQux>());
157        assert_eq!("from bar; from base", base_symbol.base_example());
158        assert_eq!(0.0, base_symbol.x());
159
160        let symbol = FooBarBar::new(&arena, 10.0, "bar bar");
161        let base_symbol: Thingy = symbol.into();
162        assert_eq!("FooBarBar", base_symbol.name());
163        assert_eq!(true, base_symbol.is::<Foo>());
164        assert_eq!(true, base_symbol.is::<FooBar>());
165        assert_eq!(true, base_symbol.is::<FooBarBar>());
166        assert_eq!(false, base_symbol.is::<FooQux>());
167        assert_eq!("from bar bar; from bar; from base", base_symbol.base_example());
168        assert_eq!(10.0, base_symbol.x());
169
170        let symbol = FooQux::new(&arena);
171        let base_symbol: Thingy = symbol.into();
172        assert_eq!("FooQux", base_symbol.name());
173        assert_eq!(true, base_symbol.is::<Foo>());
174        assert_eq!(false, base_symbol.is::<FooBar>());
175        assert_eq!(true, base_symbol.is::<FooQux>());
176        assert_eq!(0.0, base_symbol.x());
177    }
178}