@@ -15,30 +15,45 @@ use uefi_raw::protocol::shell::ShellProtocol;
15
15
#[ unsafe_protocol( ShellProtocol :: GUID ) ]
16
16
pub struct Shell ( ShellProtocol ) ;
17
17
18
+ /// Trait for implementing the var function
19
+ pub trait ShellVar {
20
+ /// Gets the value of the specified environment variable
21
+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > ;
22
+ }
23
+
18
24
/// Iterator over the names of environmental variables obtained from the Shell protocol.
19
25
#[ derive( Debug ) ]
20
- pub struct Vars < ' a > {
26
+ pub struct Vars < ' a , T : ShellVar > {
21
27
/// Char16 containing names of environment variables
22
- inner : * const Char16 ,
28
+ names : * const Char16 ,
29
+ /// Reference to Shell Protocol
30
+ protocol : * const T ,
23
31
/// Placeholder to attach a lifetime to `Vars`
24
32
placeholder : PhantomData < & ' a CStr16 > ,
25
33
}
26
34
27
- impl < ' a > Iterator for Vars < ' a > {
28
- type Item = & ' a CStr16 ;
35
+ impl < ' a , T : ShellVar + ' a > Iterator for Vars < ' a , T > {
36
+ type Item = ( & ' a CStr16 , Option < & ' a CStr16 > ) ;
29
37
// We iterate a list of NUL terminated CStr16s.
30
38
// The list is terminated with a double NUL.
31
39
fn next ( & mut self ) -> Option < Self :: Item > {
32
- let s = unsafe { CStr16 :: from_ptr ( self . inner ) } ;
40
+ let s = unsafe { CStr16 :: from_ptr ( self . names ) } ;
33
41
if s. is_empty ( ) {
34
42
None
35
43
} else {
36
- self . inner = unsafe { self . inner . add ( s. num_chars ( ) + 1 ) } ;
37
- Some ( s )
44
+ self . names = unsafe { self . names . add ( s. num_chars ( ) + 1 ) } ;
45
+ Some ( ( s , unsafe { self . protocol . as_ref ( ) . unwrap ( ) . var ( s ) } ) )
38
46
}
39
47
}
40
48
}
41
49
50
+ impl ShellVar for Shell {
51
+ /// Gets the value of the specified environment variable
52
+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > {
53
+ self . var ( name)
54
+ }
55
+ }
56
+
42
57
impl Shell {
43
58
/// Returns the current directory on the specified device.
44
59
///
@@ -106,10 +121,11 @@ impl Shell {
106
121
107
122
/// Gets an iterator over the names of all environment variables
108
123
#[ must_use]
109
- pub fn vars ( & self ) -> Vars < ' _ > {
124
+ pub fn vars ( & self ) -> Vars < ' _ , Self > {
110
125
let env_ptr = unsafe { ( self . 0 . get_env ) ( ptr:: null ( ) ) } ;
111
126
Vars {
112
- inner : env_ptr. cast :: < Char16 > ( ) ,
127
+ names : env_ptr. cast :: < Char16 > ( ) ,
128
+ protocol : self ,
113
129
placeholder : PhantomData ,
114
130
}
115
131
}
@@ -136,9 +152,33 @@ impl Shell {
136
152
#[ cfg( test) ]
137
153
mod tests {
138
154
use super :: * ;
155
+ use alloc:: collections:: BTreeMap ;
139
156
use alloc:: vec:: Vec ;
140
157
use uefi:: cstr16;
141
158
159
+ struct ShellMock < ' a > {
160
+ inner : BTreeMap < & ' a CStr16 , & ' a CStr16 > ,
161
+ }
162
+
163
+ impl < ' a > ShellMock < ' a > {
164
+ fn new ( names : Vec < & ' a CStr16 > , values : Vec < & ' a CStr16 > ) -> ShellMock < ' a > {
165
+ let mut inner_map = BTreeMap :: new ( ) ;
166
+ for ( name, val) in names. iter ( ) . zip ( values. iter ( ) ) {
167
+ inner_map. insert ( * name, * val) ;
168
+ }
169
+ ShellMock { inner : inner_map }
170
+ }
171
+ }
172
+ impl < ' a > ShellVar for ShellMock < ' a > {
173
+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > {
174
+ if let Some ( val) = self . inner . get ( name) {
175
+ Some ( * val)
176
+ } else {
177
+ None
178
+ }
179
+ }
180
+ }
181
+
142
182
/// Testing Vars struct
143
183
#[ test]
144
184
fn test_vars ( ) {
@@ -147,9 +187,11 @@ mod tests {
147
187
vars_mock. push ( 0 ) ;
148
188
vars_mock. push ( 0 ) ;
149
189
let mut vars = Vars {
150
- inner : vars_mock. as_ptr ( ) . cast ( ) ,
190
+ names : vars_mock. as_ptr ( ) . cast ( ) ,
191
+ protocol : & ShellMock :: new ( Vec :: new ( ) , Vec :: new ( ) ) ,
151
192
placeholder : PhantomData ,
152
193
} ;
194
+
153
195
assert ! ( vars. next( ) . is_none( ) ) ;
154
196
155
197
// One environment variable in Vars
@@ -160,10 +202,14 @@ mod tests {
160
202
vars_mock. push ( 0 ) ;
161
203
vars_mock. push ( 0 ) ;
162
204
let vars = Vars {
163
- inner : vars_mock. as_ptr ( ) . cast ( ) ,
205
+ names : vars_mock. as_ptr ( ) . cast ( ) ,
206
+ protocol : & ShellMock :: new ( Vec :: from ( [ cstr16 ! ( "foo" ) ] ) , Vec :: from ( [ cstr16 ! ( "value" ) ] ) ) ,
164
207
placeholder : PhantomData ,
165
208
} ;
166
- assert_eq ! ( vars. collect:: <Vec <_>>( ) , Vec :: from( [ cstr16!( "foo" ) ] ) ) ;
209
+ assert_eq ! (
210
+ vars. collect:: <Vec <_>>( ) ,
211
+ Vec :: from( [ ( cstr16!( "foo" ) , Some ( cstr16!( "value" ) ) ) ] )
212
+ ) ;
167
213
168
214
// Multiple environment variables in Vars
169
215
let mut vars_mock = Vec :: < u16 > :: new ( ) ;
@@ -184,12 +230,20 @@ mod tests {
184
230
vars_mock. push ( 0 ) ;
185
231
186
232
let vars = Vars {
187
- inner : vars_mock. as_ptr ( ) . cast ( ) ,
233
+ names : vars_mock. as_ptr ( ) . cast ( ) ,
234
+ protocol : & ShellMock :: new (
235
+ Vec :: from ( [ cstr16 ! ( "foo1" ) , cstr16 ! ( "bar" ) , cstr16 ! ( "baz2" ) ] ) ,
236
+ Vec :: from ( [ cstr16 ! ( "value" ) , cstr16 ! ( "one" ) , cstr16 ! ( "two" ) ] ) ,
237
+ ) ,
188
238
placeholder : PhantomData ,
189
239
} ;
190
240
assert_eq ! (
191
241
vars. collect:: <Vec <_>>( ) ,
192
- Vec :: from( [ cstr16!( "foo1" ) , cstr16!( "bar" ) , cstr16!( "baz2" ) ] )
242
+ Vec :: from( [
243
+ ( cstr16!( "foo1" ) , Some ( cstr16!( "value" ) ) ) ,
244
+ ( cstr16!( "bar" ) , Some ( cstr16!( "one" ) ) ) ,
245
+ ( cstr16!( "baz2" ) , Some ( cstr16!( "two" ) ) )
246
+ ] )
193
247
) ;
194
248
}
195
249
}
0 commit comments