4
4
use std:: any:: Any ;
5
5
use std:: cell:: { Ref , RefCell } ;
6
6
use std:: rc:: Rc ;
7
+ use std:: sync:: { Arc , Mutex } ;
7
8
8
9
/// Environments associate names (i.e. variables/parameters) with values.
9
10
///
10
11
/// Environments are defined as a trait rather than a simple HashMap so that we can directly reuse
11
12
/// the various structs generated by Frame rather than constructing a bunch of parallel data
12
13
/// structures each time we query the state of the machine.
13
- ///
14
+ ///
14
15
/// It is common for a particular environment to be absent because there are no variables of the
15
16
/// kind held by that environment. We represent absent environments by an empty environment rather
16
17
/// than using an `Option` type because it simplifies the interface and because the distinction
17
- /// between `None` and `Some(empty )` is not significant.
18
+ /// between `None` and `Some(Empty )` is not significant.
18
19
pub trait Environment {
19
20
/// Is this the empty environment?
20
21
fn is_empty ( & self ) -> bool {
21
22
false
22
23
}
23
24
/// Get the value associated with a name.
24
- fn lookup ( & self , name : & str ) -> Option < & dyn Any > ;
25
+ fn lookup ( & self , name : & str ) -> Option < Box < dyn Any > > ;
25
26
}
26
27
27
28
/// The trivial empty enviorment. This can be used in place of an environment when that environment
28
29
/// is absent.
29
30
#[ derive( Clone , Debug , Eq , Hash , PartialEq , PartialOrd , Ord ) ]
30
- pub struct Empty { }
31
+ pub struct Empty ;
31
32
32
33
impl Empty {
33
- /// Create a new empty environment.
34
- pub fn new ( ) -> Empty {
35
- Empty { }
36
- }
37
-
38
- /// Create a new reference-counted pointer to an empty environment.
39
- pub fn new_rc ( ) -> Rc < Empty > {
40
- Rc :: new ( Empty :: new ( ) )
34
+ /// Get an `Arc` reference to the empty environment.
35
+ pub fn arc ( ) -> Arc < Empty > {
36
+ Arc :: new ( Empty )
41
37
}
42
- }
43
-
44
- impl Default for Empty {
45
- fn default ( ) -> Self {
46
- Empty :: new ( )
38
+ /// Get an `Rc` reference to the empty environment.
39
+ pub fn rc ( ) -> Rc < Empty > {
40
+ Rc :: new ( Empty )
47
41
}
48
42
}
49
43
50
44
impl Environment for Empty {
51
45
fn is_empty ( & self ) -> bool {
52
46
true
53
47
}
54
- fn lookup ( & self , _name : & str ) -> Option < & dyn Any > {
48
+ fn lookup ( & self , _name : & str ) -> Option < Box < dyn Any > > {
55
49
None
56
50
}
57
51
}
@@ -60,7 +54,7 @@ impl<'a, T: Environment> Environment for Ref<'a, T> {
60
54
fn is_empty ( & self ) -> bool {
61
55
( * * self ) . is_empty ( )
62
56
}
63
- fn lookup ( & self , name : & str ) -> Option < & dyn Any > {
57
+ fn lookup ( & self , name : & str ) -> Option < Box < dyn Any > > {
64
58
( * * self ) . lookup ( name)
65
59
}
66
60
}
@@ -69,15 +63,46 @@ impl<T: Environment> Environment for RefCell<T> {
69
63
fn is_empty ( & self ) -> bool {
70
64
self . borrow ( ) . is_empty ( )
71
65
}
72
- fn lookup ( & self , name : & str ) -> Option < & dyn Any > {
66
+ fn lookup ( & self , name : & str ) -> Option < Box < dyn Any > > {
73
67
unsafe { ( * self . as_ptr ( ) ) . lookup ( name) }
74
68
}
75
69
}
76
70
71
+ impl < T : Environment + Clone > Environment for Mutex < T > {
72
+ fn is_empty ( & self ) -> bool {
73
+ self . lock ( ) . unwrap ( ) . is_empty ( )
74
+ }
75
+ fn lookup ( & self , name : & str ) -> Option < Box < dyn Any > > {
76
+ // TODO: This could be super slow since it needs to clone the whole Args/Vars type...
77
+ // Probably need to re-think the whole Environment trait to get an efficient implementation
78
+ // for the `sync` case... :-(
79
+ self . lock ( ) . unwrap ( ) . clone ( ) . lookup ( name)
80
+ }
81
+ }
82
+
83
+ /// Definitions specific to the synchronized/thread-safe interface.
84
+ pub mod sync {
85
+ pub use super :: * ;
86
+ use std:: sync:: Arc ;
87
+
88
+ /// A reference-counted pointer to an environment.
89
+ pub type EnvironmentPtr = Arc < dyn super :: Environment > ;
90
+ }
91
+
92
+ /// Definitions specific to the unsynchronized interface.
93
+ pub mod unsync {
94
+ pub use super :: * ;
95
+ use std:: rc:: Rc ;
96
+
97
+ /// A reference-counted pointer to an environment.
98
+ pub type EnvironmentPtr = Rc < dyn super :: Environment > ;
99
+ }
100
+
77
101
#[ allow( clippy:: approx_constant) ]
78
102
#[ cfg( test) ]
79
103
mod tests {
80
104
use super :: * ;
105
+ use std:: any:: Any ;
81
106
82
107
struct TestArgs {
83
108
x : i32 ,
@@ -86,28 +111,26 @@ mod tests {
86
111
}
87
112
88
113
impl Environment for TestArgs {
89
- fn lookup ( & self , name : & str ) -> Option < & dyn Any > {
114
+ fn lookup ( & self , name : & str ) -> Option < Box < dyn Any > > {
90
115
match name {
91
- "x" => Some ( & self . x ) ,
92
- "y" => Some ( & self . y ) ,
93
- "z" => Some ( & self . z ) ,
116
+ "x" => Some ( Box :: new ( self . x ) ) ,
117
+ "y" => Some ( Box :: new ( self . y ) ) ,
118
+ "z" => Some ( Box :: new ( self . z ) ) ,
94
119
_ => None ,
95
120
}
96
121
}
97
122
}
98
123
99
124
#[ test]
100
125
fn empty_environment_is_empty ( ) {
101
- let empty = Empty :: new ( ) ;
102
- assert ! ( empty. is_empty( ) ) ;
126
+ assert ! ( Empty . is_empty( ) ) ;
103
127
}
104
128
105
129
#[ test]
106
130
fn empty_environment_returns_none ( ) {
107
- let empty = Empty :: new ( ) ;
108
- assert ! ( empty. lookup( "x" ) . is_none( ) ) ;
109
- assert ! ( empty. lookup( "y" ) . is_none( ) ) ;
110
- assert ! ( empty. lookup( "z" ) . is_none( ) ) ;
131
+ assert ! ( Empty . lookup( "x" ) . is_none( ) ) ;
132
+ assert ! ( Empty . lookup( "y" ) . is_none( ) ) ;
133
+ assert ! ( Empty . lookup( "z" ) . is_none( ) ) ;
111
134
}
112
135
113
136
#[ test]
@@ -130,19 +153,22 @@ mod tests {
130
153
131
154
let opt_x = args. lookup ( "x" ) ;
132
155
assert ! ( opt_x. is_some( ) ) ;
133
- let opt_i32 = opt_x. unwrap ( ) . downcast_ref :: < i32 > ( ) ;
156
+ let x = opt_x. unwrap ( ) ;
157
+ let opt_i32 = x. downcast_ref :: < i32 > ( ) ;
134
158
assert ! ( opt_i32. is_some( ) ) ;
135
159
assert_eq ! ( * opt_i32. unwrap( ) , 42 ) ;
136
160
137
161
let opt_y = args. lookup ( "y" ) ;
138
162
assert ! ( opt_y. is_some( ) ) ;
139
- let opt_bool = opt_y. unwrap ( ) . downcast_ref :: < bool > ( ) ;
163
+ let y = opt_y. unwrap ( ) ;
164
+ let opt_bool = y. downcast_ref :: < bool > ( ) ;
140
165
assert ! ( opt_bool. is_some( ) ) ;
141
166
assert ! ( !* opt_bool. unwrap( ) ) ;
142
167
143
- let opt_y = args. lookup ( "z" ) ;
144
- assert ! ( opt_y. is_some( ) ) ;
145
- let opt_bool = opt_y. unwrap ( ) . downcast_ref :: < Option < f32 > > ( ) ;
168
+ let opt_z = args. lookup ( "z" ) ;
169
+ assert ! ( opt_z. is_some( ) ) ;
170
+ let z = opt_z. unwrap ( ) ;
171
+ let opt_bool = z. downcast_ref :: < Option < f32 > > ( ) ;
146
172
assert ! ( opt_bool. is_some( ) ) ;
147
173
assert_eq ! ( * opt_bool. unwrap( ) , Some ( 3.14 ) ) ;
148
174
}
@@ -164,8 +190,9 @@ mod tests {
164
190
165
191
let opt_z = args. lookup ( "z" ) ;
166
192
assert ! ( opt_z. is_some( ) ) ;
167
- assert ! ( opt_y. unwrap( ) . downcast_ref:: <f32 >( ) . is_none( ) ) ;
168
- assert ! ( opt_y. unwrap( ) . downcast_ref:: <Option <i32 >>( ) . is_none( ) ) ;
193
+ let z = opt_z. unwrap ( ) ;
194
+ assert ! ( z. downcast_ref:: <f32 >( ) . is_none( ) ) ;
195
+ assert ! ( z. downcast_ref:: <Option <i32 >>( ) . is_none( ) ) ;
169
196
}
170
197
171
198
#[ test]
0 commit comments