forked from FuelLabs/sway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
concurrent_slab.rs
113 lines (100 loc) · 2.73 KB
/
concurrent_slab.rs
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use std::{fmt, sync::RwLock};
use sway_types::{Named, Spanned};
use crate::{decl_engine::*, engine_threading::*, type_system::*};
#[derive(Debug)]
pub(crate) struct ConcurrentSlab<T> {
inner: RwLock<Vec<T>>,
}
impl<T> Clone for ConcurrentSlab<T>
where
T: Clone,
{
fn clone(&self) -> Self {
let inner = self.inner.read().unwrap();
Self {
inner: RwLock::new(inner.clone()),
}
}
}
impl<T> Default for ConcurrentSlab<T> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<T> ConcurrentSlab<T> {
pub fn with_slice<R>(&self, run: impl FnOnce(&[T]) -> R) -> R {
run(&self.inner.read().unwrap())
}
}
pub struct ListDisplay<I> {
pub list: I,
}
impl<I: IntoIterator + Clone> fmt::Display for ListDisplay<I>
where
I::Item: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let fmt_elems = self
.list
.clone()
.into_iter()
.enumerate()
.map(|(i, value)| format!("{i:<10}\t->\t{value}"))
.collect::<Vec<_>>();
write!(f, "{}", fmt_elems.join("\n"))
}
}
impl<T> ConcurrentSlab<T>
where
T: Clone,
{
pub fn insert(&self, value: T) -> usize {
let mut inner = self.inner.write().unwrap();
let ret = inner.len();
inner.push(value);
ret
}
pub fn get(&self, index: usize) -> T {
let inner = self.inner.read().unwrap();
inner[index].clone()
}
}
impl ConcurrentSlab<TypeInfo> {
pub fn replace(
&self,
index: TypeId,
prev_value: &TypeInfo,
new_value: TypeInfo,
engines: Engines<'_>,
) -> Option<TypeInfo> {
let index = index.index();
// The comparison below ends up calling functions in the slab, which
// can lead to deadlocks if we used a single read/write lock.
// So we split the operation: we do the read only operations with
// a single scoped read lock below, and only after the scope do
// we get a write lock for writing into the slab.
{
let inner = self.inner.read().unwrap();
let actual_prev_value = &inner[index];
if !actual_prev_value.eq(prev_value, engines) {
return Some(actual_prev_value.clone());
}
}
let mut inner = self.inner.write().unwrap();
inner[index] = new_value;
None
}
}
impl<T> ConcurrentSlab<T>
where
DeclEngine: DeclEngineIndex<T>,
T: Named + Spanned,
{
pub fn replace(&self, index: DeclId<T>, new_value: T) -> Option<T> {
let mut inner = self.inner.write().unwrap();
inner[index.inner()] = new_value;
None
}
}