1
1
use std:: collections:: HashMap ;
2
2
3
- pub type CellID = usize ;
4
- pub type CallbackID = usize ;
5
-
6
- #[ derive( Debug , PartialEq ) ]
7
- pub enum SetValueError {
8
- NonexistentCell ,
9
- ComputeCell ,
3
+ /// `InputCellID` is a unique identifier for an input cell.
4
+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
5
+ pub struct InputCellID ( usize ) ;
6
+ /// `ComputeCellID` is a unique identifier for a compute cell.
7
+ /// Values of type `InputCellID` and `ComputeCellID` should not be mutually assignable,
8
+ /// demonstrated by the following tests:
9
+ ///
10
+ /// ```compile_fail
11
+ /// let mut r = react::Reactor::new();
12
+ /// let input: react::ComputeCellID = r.create_input(111);
13
+ /// ```
14
+ ///
15
+ /// ```compile_fail
16
+ /// let mut r = react::Reactor::new();
17
+ /// let input = r.create_input(111);
18
+ /// let compute: react::InputCellID = r.create_compute(&[react::CellID::Input(input)], |_| 222).unwrap();
19
+ /// ```
20
+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
21
+ pub struct ComputeCellID ( usize ) ;
22
+ #[ derive( Clone , Copy , Debug , Eq , Hash , PartialEq ) ]
23
+ pub struct CallbackID ( usize ) ;
24
+
25
+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
26
+ pub enum CellID {
27
+ Input ( InputCellID ) ,
28
+ Compute ( ComputeCellID ) ,
10
29
}
11
30
12
31
#[ derive( Debug , PartialEq ) ]
@@ -15,80 +34,97 @@ pub enum RemoveCallbackError {
15
34
NonexistentCallback ,
16
35
}
17
36
18
- struct Cell < ' a , T : Copy > {
37
+ struct Cell < T : Copy > {
19
38
value : T ,
20
39
last_value : T ,
21
- dependents : Vec < CellID > ,
22
- cell_type : CellType < ' a , T > ,
23
- callbacks_issued : usize ,
24
- callbacks : HashMap < CallbackID , Box < FnMut ( T ) -> ( ) + ' a > > ,
40
+ dependents : Vec < ComputeCellID > ,
25
41
}
26
42
27
- enum CellType < ' a , T : Copy > {
28
- Input ,
29
- Compute ( Vec < CellID > , Box < Fn ( & [ T ] ) -> T + ' a > ) ,
43
+ struct ComputeCell < ' a , T : Copy > {
44
+ cell : Cell < T > ,
45
+
46
+ dependencies : Vec < CellID > ,
47
+ f : Box < Fn ( & [ T ] ) -> T + ' a > ,
48
+ callbacks_issued : usize ,
49
+ callbacks : HashMap < CallbackID , Box < FnMut ( T ) -> ( ) + ' a > > ,
30
50
}
31
51
32
- impl < ' a , T : Copy > Cell < ' a , T > {
33
- fn new ( initial : T , cell_type : CellType < ' a , T > ) -> Self {
52
+ impl < T : Copy > Cell < T > {
53
+ fn new ( initial : T ) -> Self {
34
54
Cell {
35
55
value : initial,
36
56
last_value : initial,
37
57
dependents : Vec :: new ( ) ,
38
- cell_type : cell_type,
58
+ }
59
+ }
60
+ }
61
+
62
+ impl < ' a , T : Copy > ComputeCell < ' a , T > {
63
+ fn new < F : Fn ( & [ T ] ) -> T + ' a > ( initial : T , dependencies : Vec < CellID > , f : F ) -> Self {
64
+ ComputeCell {
65
+ cell : Cell :: new ( initial) ,
66
+
67
+ dependencies,
68
+ f : Box :: new ( f) ,
39
69
callbacks_issued : 0 ,
40
70
callbacks : HashMap :: new ( ) ,
41
71
}
42
72
}
43
73
}
44
74
45
75
pub struct Reactor < ' a , T : Copy > {
46
- cells : Vec < Cell < ' a , T > > ,
76
+ inputs : Vec < Cell < T > > ,
77
+ computes : Vec < ComputeCell < ' a , T > > ,
47
78
}
48
79
49
80
impl < ' a , T : Copy + PartialEq > Reactor < ' a , T > {
50
81
pub fn new ( ) -> Self {
51
82
Reactor {
52
- cells : Vec :: new ( ) ,
83
+ inputs : Vec :: new ( ) ,
84
+ computes : Vec :: new ( ) ,
53
85
}
54
86
}
55
87
56
- pub fn create_input ( & mut self , initial : T ) -> CellID {
57
- self . cells . push ( Cell :: new ( initial, CellType :: Input ) ) ;
58
- self . cells . len ( ) - 1
88
+ pub fn create_input ( & mut self , initial : T ) -> InputCellID {
89
+ self . inputs . push ( Cell :: new ( initial) ) ;
90
+ InputCellID ( self . inputs . len ( ) - 1 )
59
91
}
60
92
61
- pub fn create_compute < F : Fn ( & [ T ] ) -> T + ' a > ( & mut self , dependencies : & [ CellID ] , compute_func : F ) -> Result < CellID , CellID > {
93
+ pub fn create_compute < F : Fn ( & [ T ] ) -> T + ' a > ( & mut self , dependencies : & [ CellID ] , compute_func : F ) -> Result < ComputeCellID , CellID > {
62
94
// Check all dependencies' validity before modifying any of them,
63
95
// so that we don't perform an incorrect partial write.
64
- if let Some ( & invalid) = dependencies. iter ( ) . find ( |& dep| * dep >= self . cells . len ( ) ) {
65
- return Err ( invalid) ;
96
+ for & dep in dependencies {
97
+ match dep {
98
+ CellID :: Input ( InputCellID ( id) ) => if id >= self . inputs . len ( ) { return Err ( dep) } ,
99
+ CellID :: Compute ( ComputeCellID ( id) ) => if id >= self . computes . len ( ) { return Err ( dep) } ,
100
+ }
66
101
}
67
- let new_id = self . cells . len ( ) ;
68
- for & id in dependencies {
69
- self . cells . get_mut ( id) . unwrap ( ) . dependents . push ( new_id) ;
102
+ let new_id = ComputeCellID ( self . computes . len ( ) ) ;
103
+ for & dep in dependencies {
104
+ match dep {
105
+ CellID :: Input ( InputCellID ( id) ) => self . inputs [ id] . dependents . push ( new_id) ,
106
+ CellID :: Compute ( ComputeCellID ( id) ) => self . computes [ id] . cell . dependents . push ( new_id) ,
107
+ }
70
108
}
71
109
let inputs: Vec < _ > = dependencies. iter ( ) . map ( |& id| self . value ( id) . unwrap ( ) ) . collect ( ) ;
72
110
let initial = compute_func ( & inputs) ;
73
- self . cells . push ( Cell :: new ( initial, CellType :: Compute ( dependencies. iter ( ) . cloned ( ) . collect ( ) , Box :: new ( compute_func) ) ) ) ;
111
+ self . computes . push ( ComputeCell :: new ( initial, dependencies. to_vec ( ) , compute_func) ) ;
74
112
Ok ( new_id)
75
113
}
76
114
77
115
pub fn value ( & self , id : CellID ) -> Option < T > {
78
- self . cells . get ( id) . map ( |c| c. value )
116
+ match id {
117
+ CellID :: Input ( InputCellID ( id) ) => self . inputs . get ( id) . map ( |c| c. value ) ,
118
+ CellID :: Compute ( ComputeCellID ( id) ) => self . computes . get ( id) . map ( |c| c. cell . value ) ,
119
+ }
79
120
}
80
121
81
- pub fn set_value ( & mut self , id : CellID , new_value : T ) -> Result < ( ) , SetValueError > {
82
- match self . cells . get_mut ( id) {
83
- Some ( c) => match c. cell_type {
84
- CellType :: Input => {
85
- c. value = new_value;
86
- Ok ( c. dependents . clone ( ) )
87
- } ,
88
- CellType :: Compute ( _, _) => Err ( SetValueError :: ComputeCell ) ,
89
- } ,
90
- None => Err ( SetValueError :: NonexistentCell ) ,
91
- } . map ( |deps| {
122
+ pub fn set_value ( & mut self , id : InputCellID , new_value : T ) -> bool {
123
+ let InputCellID ( id) = id;
124
+ self . inputs . get_mut ( id) . map ( |c| {
125
+ c. value = new_value;
126
+ c. dependents . clone ( )
127
+ } ) . map ( |deps| {
92
128
for & d in deps. iter ( ) {
93
129
self . update_dependent ( d) ;
94
130
}
@@ -97,19 +133,22 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
97
133
for d in deps {
98
134
self . fire_callbacks ( d) ;
99
135
}
100
- } )
136
+ } ) . is_some ( )
101
137
}
102
138
103
- pub fn add_callback < F : FnMut ( T ) -> ( ) + ' a > ( & mut self , id : CellID , callback : F ) -> Option < CallbackID > {
104
- self . cells . get_mut ( id) . map ( |c| {
139
+ pub fn add_callback < F : FnMut ( T ) -> ( ) + ' a > ( & mut self , id : ComputeCellID , callback : F ) -> Option < CallbackID > {
140
+ let ComputeCellID ( id) = id;
141
+ self . computes . get_mut ( id) . map ( |c| {
105
142
c. callbacks_issued += 1 ;
106
- c. callbacks . insert ( c. callbacks_issued , Box :: new ( callback) ) ;
107
- c. callbacks_issued
143
+ let cbid = CallbackID ( c. callbacks_issued ) ;
144
+ c. callbacks . insert ( cbid, Box :: new ( callback) ) ;
145
+ cbid
108
146
} )
109
147
}
110
148
111
- pub fn remove_callback ( & mut self , cell : CellID , callback : CallbackID ) -> Result < ( ) , RemoveCallbackError > {
112
- match self . cells . get_mut ( cell) {
149
+ pub fn remove_callback ( & mut self , cell : ComputeCellID , callback : CallbackID ) -> Result < ( ) , RemoveCallbackError > {
150
+ let ComputeCellID ( cell) = cell;
151
+ match self . computes . get_mut ( cell) {
113
152
Some ( c) => match c. callbacks . remove ( & callback) {
114
153
Some ( _) => Ok ( ( ) ) ,
115
154
None => Err ( RemoveCallbackError :: NonexistentCallback ) ,
@@ -118,29 +157,28 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
118
157
}
119
158
}
120
159
121
- fn update_dependent ( & mut self , id : CellID ) {
160
+ fn update_dependent ( & mut self , id : ComputeCellID ) {
161
+ let ComputeCellID ( id) = id;
162
+
122
163
let ( new_value, dependents) = {
123
164
// This block limits the scope of the self.cells borrow.
124
165
// This is necessary becaue we borrow it mutably below.
125
- let ( dependencies, f, dependents) = match self . cells . get ( id) {
126
- Some ( c) => match c. cell_type {
127
- CellType :: Input => panic ! ( "Input cell can't be a dependent" ) ,
128
- CellType :: Compute ( ref dependencies, ref f) => ( dependencies, f, c. dependents . clone ( ) ) ,
129
- } ,
166
+ let ( dependencies, f, dependents) = match self . computes . get ( id) {
167
+ Some ( c) => ( & c. dependencies , & c. f , c. cell . dependents . clone ( ) ) ,
130
168
None => panic ! ( "Cell to update disappeared while querying" ) ,
131
169
} ;
132
170
let inputs: Vec < _ > = dependencies. iter ( ) . map ( |& id| self . value ( id) . unwrap ( ) ) . collect ( ) ;
133
171
( f ( & inputs) , dependents)
134
172
} ;
135
173
136
- match self . cells . get_mut ( id) {
174
+ match self . computes . get_mut ( id) {
137
175
Some ( c) => {
138
- if c. value == new_value {
176
+ if c. cell . value == new_value {
139
177
// No change here, we don't need to update our dependents.
140
178
// (It wouldn't hurt to, but it would be unnecessary work)
141
179
return ;
142
180
}
143
- c. value = new_value;
181
+ c. cell . value = new_value;
144
182
} ,
145
183
None => panic ! ( "Cell to update disappeared while updating" ) ,
146
184
}
@@ -150,19 +188,20 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
150
188
}
151
189
}
152
190
153
- fn fire_callbacks ( & mut self , id : CellID ) {
154
- let dependents = match self . cells . get_mut ( id) {
191
+ fn fire_callbacks ( & mut self , id : ComputeCellID ) {
192
+ let ComputeCellID ( id) = id;
193
+ let dependents = match self . computes . get_mut ( id) {
155
194
Some ( c) => {
156
- if c. value == c. last_value {
195
+ if c. cell . value == c. cell . last_value {
157
196
// Value hasn't changed since last callback fire.
158
197
// We thus shouldn't fire the callbacks.
159
198
return
160
199
}
161
200
for cb in c. callbacks . values_mut ( ) {
162
- cb ( c. value ) ;
201
+ cb ( c. cell . value ) ;
163
202
}
164
- c. last_value = c. value ;
165
- c. dependents . clone ( )
203
+ c. cell . last_value = c. cell . value ;
204
+ c. cell . dependents . clone ( )
166
205
} ,
167
206
None => panic ! ( "Callback cell disappeared" ) ,
168
207
} ;
0 commit comments