1use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
5use std::ops::Deref;
6use std::cmp::{PartialOrd, Ordering};
7use std::sync::{Arc, Weak};
8use std::convert::Infallible;
9use std::hash::{Hash, Hasher};
10use crate::value::{
11 ValId, ValueEnum, ValueData, ValueDesc, Value,
12 error::RegionAlreadyFused
13};
14
15#[derive(Debug, Clone)]
17pub struct Region(Arc<RegionData>);
18
19impl Region {
20 pub fn new() -> Region { Region::new_in(WeakRegion::default()) }
22 pub fn new_in(parent: WeakRegion) -> Region {
24 let depth = parent.upgrade().map(|parent| parent.depth).unwrap_or(0) + 1;
25 let result = Region(Arc::new(RegionData {
26 parent,
27 depth,
28 params: RwLock::new(Parameters::new()),
29 _private: ()
30 }));
31 let weak = result.downgrade();
32 result.params.write().this = weak;
33 result
34 }
35 #[inline] pub fn downgrade(&self) -> WeakRegion { WeakRegion(Arc::downgrade(&self.0)) }
37}
38
39impl PartialEq for Region {
40 fn eq(&self, other: &Region) -> bool { Arc::ptr_eq(&self.0, &other.0) }
41}
42
43impl Eq for Region {}
44
45impl Hash for Region {
46 #[inline] fn hash<H: Hasher>(&self, hasher: &mut H) {
47 Arc::as_ptr(&self.0).hash(hasher)
48 }
49}
50
51impl PartialOrd for Region {
52 fn partial_cmp(&self, other: &Region) -> Option<Ordering> {
53 if self == other { return Some(Ordering::Equal) }
54 let ordering = self.depth.cmp(&other.depth);
55 let (deeper, shallower) = match ordering {
56 Ordering::Equal => { return None },
57 Ordering::Greater => (self, other),
58 Ordering::Less => (other, self)
59 };
60 let mut parent = deeper.parent.upgrade()?;
61 while parent.depth > shallower.depth {
62 parent = parent.parent.upgrade()?;
63 }
64 if &parent == shallower {
65 Some(ordering.reverse())
66 } else {
67 None
68 }
69 }
70}
71
72impl PartialEq<WeakRegion> for Region {
73 fn eq(&self, other: &WeakRegion) -> bool {
74 if let Some(other) = other.upgrade() { other.eq(self) } else { false }
75 }
76}
77
78impl PartialOrd<WeakRegion> for Region {
79 fn partial_cmp(&self, other: &WeakRegion) -> Option<Ordering> {
80 if other.is_null() { Some(Ordering::Less) }
81 else { self.partial_cmp(&other.upgrade()?) }
82 }
83}
84
85impl PartialEq<Region> for WeakRegion {
86 fn eq(&self, other: &Region) -> bool { other.eq(self) }
87}
88
89impl PartialOrd<Region> for WeakRegion {
90 fn partial_cmp(&self, other: &Region) -> Option<Ordering> {
91 other.partial_cmp(self).map(Ordering::reverse)
92 }
93}
94
95impl Deref for Region {
96 type Target = RegionData;
97 #[inline] fn deref(&self) -> &RegionData { self.0.deref() }
98}
99
100#[derive(Debug, Clone, Default)]
102pub struct WeakRegion(pub Weak<RegionData>);
103
104impl WeakRegion {
105 #[inline] pub fn upgrade(&self) -> Option<Region> { self.0.upgrade().map(Region) }
107 #[inline] pub fn is_null(&self) -> bool { self == &WeakRegion::default() }
109 #[inline] pub fn outer<'a>(&'a self, other: &'a WeakRegion) -> Option<&'a WeakRegion> {
111 self.partial_cmp(other).map(|ord| match ord { Ordering::Greater => self, _ => other })
112 }
113 #[inline] pub fn inner<'a>(&'a self, other: &'a WeakRegion) -> Option<&'a WeakRegion> {
115 self.partial_cmp(other).map(|ord| match ord { Ordering::Less => self, _ => other })
116 }
117 #[inline] pub fn innermost<'a, I>(&'a self, mut regions: I)
120 -> Result<&'a WeakRegion, (&'a WeakRegion, &'a WeakRegion)>
121 where I: Iterator<Item=&'a WeakRegion> {
122 let mut res = self;
123 while let Some(region) = regions.next() {
124 match res.partial_cmp(region) {
125 None => return Err((res, region)),
126 Some(Ordering::Less) => res = region,
127 _ => {}
128 }
129 }
130 Ok(res)
131 }
132}
133
134impl PartialEq for WeakRegion {
135 fn eq(&self, other: &WeakRegion) -> bool { Weak::ptr_eq(&self.0, &other.0) }
136}
137
138impl Eq for WeakRegion {}
139
140impl Hash for WeakRegion {
141 #[inline] fn hash<H: Hasher>(&self, hasher: &mut H) {
142 self.0.as_ptr().hash(hasher)
143 }
144}
145
146impl PartialOrd for WeakRegion {
147 fn partial_cmp(&self, other: &WeakRegion) -> Option<Ordering> {
148 if self == other {
149 Some(Ordering::Equal)
150 } else if self.is_null() {
151 Some(Ordering::Greater)
152 } else if other.is_null() {
153 Some(Ordering::Less)
154 } else {
155 let left = self.upgrade()?;
156 let right = other.upgrade()?;
157 let ordering = left.partial_cmp(&right);
158 debug_assert_ne!(ordering, Some(Ordering::Equal));
159 ordering
160 }
161 }
162}
163
164#[derive(Debug)]
166pub struct RegionData {
167 pub parent: WeakRegion,
169 pub depth: usize,
171 pub params: RwLock<Parameters>,
173 _private: ()
175}
176
177impl RegionData {
178 pub fn params(&self) -> RwLockReadGuard<Parameters> { self.params.read() }
180 pub fn params_mut(&self) -> RwLockWriteGuard<Parameters> { self.params.write() }
182 pub fn add_param(&self, desc: ParameterDesc) -> (usize, ValId) {
184 let mut params = self.params_mut();
185 let ix = params.add_param(desc).expect("Unfused region");
186 let param = params.arr()[ix].clone();
187 (ix, param)
188 }
189 pub fn add_with_ty(&self, ty: ValId) -> (usize, ValId) {
191 let mut params = self.params_mut();
192 let ix = params.add_with_ty(ty).expect("Unfused region");
193 let param = params.arr()[ix].clone();
194 (ix, param)
195 }
196 pub fn this(&self) -> WeakRegion { self.params().this() }
198}
199
200#[derive(Debug)]
202pub struct Parameters {
203 arr: Vec<ValId>,
205 this: WeakRegion,
207 fused: bool
209}
210
211impl Parameters {
212 fn new() -> Parameters {
214 Parameters { arr: Vec::new(), this: WeakRegion::default(), fused: false }
215 }
216 pub fn add_param(&mut self, desc: ParameterDesc) -> Result<usize, RegionAlreadyFused> {
218 if self.fused { return Err(RegionAlreadyFused) } let ix = self.arr.len();
220 let param = Parameter {
221 ty: desc.ty,
222 region: self.this.clone(),
223 ix
224 };
225 let node = ValId::from(param);
226 self.arr.push(node);
227 Ok(ix)
228 }
229 pub fn add_with_ty(&mut self, ty: ValId) -> Result<usize, RegionAlreadyFused> {
231 self.add_param(ParameterDesc { ty })
232 }
233 pub fn arr(&self) -> &[ValId] { &self.arr }
235 pub fn this(&self) -> WeakRegion { self.this.clone() }
237 pub fn fused(&self) -> bool { self.fused }
239 pub fn fuse(&mut self) { self.fused = true }
241}
242
243#[derive(Debug, Clone, PartialEq)]
245pub struct ParameterDesc {
246 pub ty: ValId
248}
249
250#[derive(Debug, Clone, Hash)]
252pub struct Parameter {
253 pub ty: ValId,
255 region: WeakRegion,
257 ix: usize
259}
260
261impl From<Parameter> for ValueEnum {
262 fn from(param: Parameter) -> ValueEnum { ValueEnum::Parameter(param) }
263}
264impl From<Parameter> for ValueData {
265 fn from(param: Parameter) -> ValueData {
266 let region = param.region.clone();
267 ValueData::with_region(ValueEnum::Parameter(param), region)
268 }
269}
270impl From<Parameter> for ValId {
271 fn from(param: Parameter) -> ValId {
272 ValId::try_new(ValueData::from(param)).expect("Impossible")
273 }
274}
275
276impl ValueDesc for Parameter {
277 type Err = Infallible;
278}
279
280impl Value for Parameter {}
281
282impl Parameter {
283 pub fn ix(&self) -> usize { self.ix }
285 pub fn region(&self) -> &WeakRegion { &self.region }
287}
288
289impl PartialEq for Parameter {
290 fn eq(&self, other: &Parameter) -> bool {
291 self.region == other.region && self.ix == other.ix
292 }
293}
294
295impl Eq for Parameter {}
296
297#[cfg(test)]
298pub mod tests {
299 use super::*;
300 use crate::value::primitive::{Unit, logical::{Unary, Bool}};
301 use crate::value::expr::SexprArgs;
302 use smallvec::smallvec;
303 use std::convert::TryInto;
304
305 #[test]
306 fn nested_region_construction() {
307 let region = Region::new();
308 let nested_region = Region::new_in(region.downgrade());
309 let other_region = Region::new();
310 let null = WeakRegion::default();
311 assert_eq!(nested_region.parent, region.downgrade());
312 assert_eq!(nested_region.this(), nested_region.downgrade());
313 assert_eq!(region.this(), region.downgrade());
314 assert_eq!(region.parent, WeakRegion::default());
315 assert_eq!(region.depth, 1);
316 assert_eq!(other_region.parent, WeakRegion::default());
317 assert_eq!(other_region.depth, 1);
318 assert_eq!(nested_region.depth, 2);
319 assert_eq!(region, region);
320 assert_eq!(nested_region, nested_region);
321 assert_eq!(other_region, other_region);
322 assert_ne!(region, other_region);
323 assert_ne!(region, nested_region);
324 assert_ne!(other_region, nested_region);
325 assert_eq!(region.partial_cmp(&nested_region), Some(Ordering::Greater));
326 assert_eq!(region.partial_cmp(&null), Some(Ordering::Less));
327 assert_eq!(region.partial_cmp(&other_region), None);
328 assert_eq!(nested_region.partial_cmp(®ion), Some(Ordering::Less));
329 assert_eq!(nested_region.partial_cmp(&other_region), None);
330 }
331
332 #[test]
333 fn parameters_are_added_to_region() {
334 let region = Region::new();
335 let unit_ty = ValId::from(Unit);
336 let bool_ty = ValId::from(Bool);
337 let mut params = region.params_mut();
338 assert_eq!(params.arr().len(), 0);
339 let tys = [unit_ty.clone(), bool_ty.clone(), unit_ty.clone()];
340 for (i, ty) in tys.iter().enumerate() {
341 assert_eq!(i, params.add_with_ty(ty.clone()).expect("Unfused region"))
342 }
343 assert_eq!(params.arr().len(), tys.len());
344 let weak = region.downgrade();
345 for (i, a) in params.arr().iter().enumerate() {
346 let data = a.data();
347 match &data.value {
348 ValueEnum::Parameter(p) => {
349 assert_eq!(p.ix, i);
350 assert_eq!(p.region, weak);
351 assert_eq!(p.ty, tys[i])
352 },
353 v => panic!("Bad parameter value {} @ params[{}]", v, i)
354 }
355 }
356
357 let not_args = SexprArgs(
358 smallvec![params.arr()[1].clone(), Unary::Not.into()]
359 );
360 let not: ValId = not_args.try_into().expect("This is a valid expression");
361 {
362 let not = not.data();
363 assert_eq!(
364 not.region, weak,
365 "Wrong region for (not #parameter): is null = {}",
366 not.region == WeakRegion::default()
367 );
368 }
369 }
370}