@@ -15,30 +15,45 @@ use uefi_raw::protocol::shell::ShellProtocol;
1515#[ unsafe_protocol( ShellProtocol :: GUID ) ]
1616pub struct Shell ( ShellProtocol ) ;
1717
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+
1824/// Iterator over the names of environmental variables obtained from the Shell protocol.
1925#[ derive( Debug ) ]
20- pub struct Vars < ' a > {
26+ pub struct Vars < ' a , T : ShellVar > {
2127 /// Char16 containing names of environment variables
22- inner : * const Char16 ,
28+ names : * const Char16 ,
29+ /// Reference to Shell Protocol
30+ protocol : * const T ,
2331 /// Placeholder to attach a lifetime to `Vars`
2432 placeholder : PhantomData < & ' a CStr16 > ,
2533}
2634
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 > ) ;
2937 // We iterate a list of NUL terminated CStr16s.
3038 // The list is terminated with a double NUL.
3139 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 ) } ;
3341 if s. is_empty ( ) {
3442 None
3543 } 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 ) } ) )
3846 }
3947 }
4048}
4149
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+
4257impl Shell {
4358 /// Returns the current directory on the specified device.
4459 ///
@@ -106,10 +121,11 @@ impl Shell {
106121
107122 /// Gets an iterator over the names of all environment variables
108123 #[ must_use]
109- pub fn vars ( & self ) -> Vars < ' _ > {
124+ pub fn vars ( & self ) -> Vars < ' _ , Self > {
110125 let env_ptr = unsafe { ( self . 0 . get_env ) ( ptr:: null ( ) ) } ;
111126 Vars {
112- inner : env_ptr. cast :: < Char16 > ( ) ,
127+ names : env_ptr. cast :: < Char16 > ( ) ,
128+ protocol : self ,
113129 placeholder : PhantomData ,
114130 }
115131 }
@@ -136,9 +152,33 @@ impl Shell {
136152#[ cfg( test) ]
137153mod tests {
138154 use super :: * ;
155+ use alloc:: collections:: BTreeMap ;
139156 use alloc:: vec:: Vec ;
140157 use uefi:: cstr16;
141158
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+
142182 /// Testing Vars struct
143183 #[ test]
144184 fn test_vars ( ) {
@@ -147,9 +187,11 @@ mod tests {
147187 vars_mock. push ( 0 ) ;
148188 vars_mock. push ( 0 ) ;
149189 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 ( ) ) ,
151192 placeholder : PhantomData ,
152193 } ;
194+
153195 assert ! ( vars. next( ) . is_none( ) ) ;
154196
155197 // One environment variable in Vars
@@ -160,10 +202,14 @@ mod tests {
160202 vars_mock. push ( 0 ) ;
161203 vars_mock. push ( 0 ) ;
162204 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" ) ] ) ) ,
164207 placeholder : PhantomData ,
165208 } ;
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+ ) ;
167213
168214 // Multiple environment variables in Vars
169215 let mut vars_mock = Vec :: < u16 > :: new ( ) ;
@@ -184,12 +230,20 @@ mod tests {
184230 vars_mock. push ( 0 ) ;
185231
186232 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+ ) ,
188238 placeholder : PhantomData ,
189239 } ;
190240 assert_eq ! (
191241 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+ ] )
193247 ) ;
194248 }
195249}
0 commit comments