1
- use std:: fmt;
1
+ //! Interface with Screeps' `Memory` global variable
2
+ //!
3
+ //! Screeps' memory lives in the javascript `Memory` global variable and is
4
+ //! encoded as a javascript object. This object's reference is tracked within
5
+ //! rust as a `MemoryReference`. The [`root`] function gives access to a
6
+ //! reference to the `Memory` global object.
7
+ //!
8
+ //! # Typing
9
+ //! Contrary to accessing the memory in javascript, rust's strong type system,
10
+ //! requires that read values be assigned a type. To facilitate this, the
11
+ //! `MemoryReference` provides methods to read a part of the memory as a
12
+ //! certain type. If the value read cannot be transformed to the requested
13
+ //! type, the method return `None`.
14
+ //!
15
+ //! # Accessing the memory
16
+ //! Memory can be accessed in two ways:
17
+ //! - via _keys_
18
+ //! - via _paths_ (methods prefixed with `path_`)
19
+ //!
20
+ //! In both cases, if the value requested is `undefined`, `null`, or even just
21
+ //! of the wrong type, the method returns `None`.
22
+ //!
23
+ //! ## Accessing memory with a _key_
24
+ //! Since a `MemoryReference` represents a javascript object, its children can
25
+ //! be accessed using the `object["key"]` javascript syntax using type methods.
26
+ //! ```no_run
27
+ //! let mem = screeps::memory::root();
28
+ //! let cpu_used_last_tick = mem.int("cpu_used_last_tick").unwrap();
29
+ //! ```
30
+ //!
31
+ //! ## Accessing memory with a _path_
32
+ //! A quality of life improvement upon the key access is through full path. In
33
+ //! javascript, it is possible to query a value with a full path:
34
+ //! ```javascript
35
+ //! var creep_time = Memory.creeps.John.time;
36
+ //! ```
37
+ //!
38
+ //! To emulate this behavior in rust, you can write such a path to a string and
39
+ //! it will fetch the javascript object using
40
+ //! [lodash](https://lodash.com/docs/4.17.10#get) and convert the result
41
+ //! depending on the method used. For example,
42
+ //! ```no_run
43
+ //! let mem = screeps::memory::root();
44
+ //! let creep_time = mem.path_num("creeps.John.time").unwrap();
45
+ //! ```
46
+ //!
47
+ //! # Other methods that provide `MemoryReference`s
48
+ //! In addition to accessing the memory from the root, it is possible to
49
+ //! access the memory via creeps, spawns, rooms and flags. Accessing the memory
50
+ //! from those objects will also result in a `MemoryReference` which instead
51
+ //! points at the root of this object's memory.
52
+ //!
2
53
54
+ use std:: fmt;
3
55
use stdweb:: unstable:: { TryFrom , TryInto } ;
4
56
use stdweb:: { Array , JsSerialize , Reference , Value } ;
5
57
58
+ use ConversionError ;
59
+
6
60
#[ derive( Clone , Debug ) ]
7
61
pub struct UnexpectedTypeError ;
8
62
@@ -13,7 +67,8 @@ impl fmt::Display for UnexpectedTypeError {
13
67
}
14
68
}
15
69
16
- /// TODO: do we even need this over just a raw 'Reference'?
70
+ // TODO: do we even need this over just a raw 'Reference'?
71
+ /// A [`Reference`] to a screeps memory object
17
72
pub struct MemoryReference ( Reference ) ;
18
73
19
74
impl AsRef < Reference > for MemoryReference {
@@ -42,46 +97,60 @@ impl MemoryReference {
42
97
MemoryReference ( reference)
43
98
}
44
99
45
- pub fn bool ( & self , path : & str ) -> bool {
46
- js_unwrap ! ( Boolean ( @{ self . as_ref( ) } [ @{ path } ] ) )
100
+ pub fn bool ( & self , key : & str ) -> bool {
101
+ js_unwrap ! ( Boolean ( @{ self . as_ref( ) } [ @{ key } ] ) )
47
102
}
48
103
49
- pub fn num ( & self , path : & str ) -> Option < f64 > {
104
+ pub fn path_bool ( & self , path : & str ) -> bool {
105
+ js_unwrap ! ( Boolean ( _. get( @{ self . as_ref( ) } , @{ path} ) ) )
106
+ }
107
+
108
+ pub fn f64 ( & self , key : & str ) -> Result < Option < f64 > , ConversionError > {
50
109
( js ! {
51
- return ( @{ self . as_ref( ) } ) [ @{ path } ] ;
110
+ return ( @{ self . as_ref( ) } ) [ @{ key } ] ;
52
111
} ) . try_into ( )
53
- . map ( Some )
54
- . unwrap_or_default ( )
55
112
}
56
113
57
- pub fn int ( & self , path : & str ) -> Option < i32 > {
114
+ pub fn path_f64 ( & self , path : & str ) -> Result < Option < f64 > , ConversionError > {
58
115
( js ! {
59
- return ( @{ self . as_ref( ) } ) [ @{ path} ] ;
116
+ return _ . get ( @{ self . as_ref( ) } , @{ path} ) ;
60
117
} ) . try_into ( )
61
- . map ( Some )
62
- . unwrap_or_default ( )
63
118
}
64
119
65
- pub fn string ( & self , path : & str ) -> Option < String > {
120
+ pub fn i32 ( & self , key : & str ) -> Result < Option < i32 > , ConversionError > {
66
121
( js ! {
67
- return ( @{ self . as_ref( ) } ) [ @{ path } ] ;
122
+ return ( @{ self . as_ref( ) } ) [ @{ key } ] ;
68
123
} ) . try_into ( )
69
- . map ( Some )
70
- . unwrap_or_default ( )
71
124
}
72
125
73
- pub fn dict ( & self , path : & str ) -> Option < MemoryReference > {
126
+ pub fn path_i32 ( & self , path : & str ) -> Result < Option < i32 > , ConversionError > {
74
127
( js ! {
75
- var v = ( @{ self . as_ref( ) } ) [ @{ path} ] ;
76
- if ( _. isArray( v) ) {
77
- return null;
78
- } else {
79
- return v || null;
80
- }
128
+ return _. get( @{ self . as_ref( ) } , @{ path} ) ;
129
+ } ) . try_into ( )
130
+ }
131
+
132
+ pub fn string ( & self , key : & str ) -> Result < Option < String > , ConversionError > {
133
+ ( js ! {
134
+ return ( @{ self . as_ref( ) } ) [ @{ key} ] ;
135
+ } ) . try_into ( )
136
+ }
137
+
138
+ pub fn path_string ( & self , path : & str ) -> Result < Option < String > , ConversionError > {
139
+ ( js ! {
140
+ return _. get( @{ self . as_ref( ) } , @{ path} ) ;
141
+ } ) . try_into ( )
142
+ }
143
+
144
+ pub fn dict ( & self , key : & str ) -> Result < Option < MemoryReference > , ConversionError > {
145
+ ( js ! {
146
+ return ( @{ self . as_ref( ) } ) [ @{ key} ] ;
147
+ } ) . try_into ( )
148
+ }
149
+
150
+ pub fn path_dict ( & self , path : & str ) -> Result < Option < MemoryReference > , ConversionError > {
151
+ ( js ! {
152
+ return _. get( @{ self . as_ref( ) } , @{ path} ) ;
81
153
} ) . try_into ( )
82
- . map ( Some )
83
- . unwrap_or_default ( )
84
- . map ( MemoryReference )
85
154
}
86
155
87
156
/// Get a dictionary value or create it if it does not exist.
@@ -110,48 +179,57 @@ impl MemoryReference {
110
179
js_unwrap ! ( Object . keys( @{ self . as_ref( ) } ) )
111
180
}
112
181
113
- pub fn del ( & self , path : & str ) {
182
+ pub fn del ( & self , key : & str ) {
183
+ js ! {
184
+ ( @{ self . as_ref( ) } ) [ @{ key} ] = undefined;
185
+ }
186
+ }
187
+
188
+ pub fn path_del ( & self , path : & str ) {
114
189
js ! {
115
- ( @{ self . as_ref( ) } ) [ @{ path} ] = undefined;
190
+ _ . set ( @{ self . as_ref( ) } , @{ path} , undefined) ;
116
191
}
117
192
}
118
193
119
- pub fn set < T > ( & self , path : & str , value : T )
194
+ pub fn set < T > ( & self , key : & str , value : T )
120
195
where
121
196
T : JsSerialize ,
122
197
{
123
198
js ! {
124
- ( @{ self . as_ref( ) } ) [ @{ path } ] = @{ value} ;
199
+ ( @{ self . as_ref( ) } ) [ @{ key } ] = @{ value} ;
125
200
}
126
201
}
127
202
128
- pub fn arr < T > ( & self , path : & str ) -> Option < Vec < T > >
203
+ pub fn path_set < T > ( & self , path : & str , value : T )
129
204
where
130
- T : TryFrom < Value , Error = < Reference as TryFrom < Value > > :: Error > ,
205
+ T : JsSerialize ,
131
206
{
132
- let x: Reference = ( js ! {
133
- var v = ( @{ self . as_ref( ) } ) [ @{ path} ] ;
134
- if ( !_. isArray( v) ) {
135
- return null;
136
- } else {
137
- return v || null;
138
- }
139
- } ) . try_into ( )
140
- . ok ( ) ?;
207
+ js ! {
208
+ _. set( @{ self . as_ref( ) } , @{ path} , @{ value} ) ;
209
+ }
210
+ }
141
211
142
- // Memory arrays don't have the regular Array as their prototype - they
143
- // have the 'outside' type.
144
- let as_arr: Array = unsafe {
145
- use stdweb:: ReferenceType ;
146
- Array :: from_reference_unchecked ( x)
147
- } ;
212
+ pub fn arr < T > ( & self , key : & str ) -> Result < Option < Vec < T > > , ConversionError >
213
+ where
214
+ T : TryFrom < Value , Error = ConversionError > ,
215
+ {
216
+ ( js ! {
217
+ return ( @{ self . as_ref( ) } ) [ @{ key} ] ;
218
+ } ) . try_into ( )
219
+ }
148
220
149
- as_arr. try_into ( ) . ok ( )
221
+ pub fn path_arr < T > ( & self , path : & str ) -> Result < Option < Vec < T > > , ConversionError >
222
+ where
223
+ T : TryFrom < Value , Error = ConversionError > ,
224
+ {
225
+ ( js ! {
226
+ return _. get( @{ self . as_ref( ) } , @{ path} ) ;
227
+ } ) . try_into ( )
150
228
}
151
229
}
152
230
153
231
impl TryFrom < Value > for MemoryReference {
154
- type Error = < Reference as TryFrom < Value > > :: Error ;
232
+ type Error = ConversionError ;
155
233
156
234
fn try_from ( v : Value ) -> Result < Self , Self :: Error > {
157
235
let r: Reference = v. try_into ( ) ?; // fail early.
@@ -168,6 +246,7 @@ impl TryFrom<Value> for MemoryReference {
168
246
}
169
247
}
170
248
249
+ /// Get a reference to the `Memory` global object
171
250
pub fn root ( ) -> MemoryReference {
172
251
js_unwrap ! ( Memory )
173
252
}
0 commit comments