@@ -17,30 +17,45 @@ use crate::{CStr16, Char16, Result, StatusExt};
1717#[ unsafe_protocol( ShellProtocol :: GUID ) ]
1818pub struct Shell ( ShellProtocol ) ;
1919
20+ /// Trait for implementing the var function
21+ pub trait ShellVar {
22+ /// Gets the value of the specified environment variable
23+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > ;
24+ }
25+
2026/// Iterator over the names of environmental variables obtained from the Shell protocol.
2127#[ derive( Debug ) ]
22- pub struct Vars < ' a > {
28+ pub struct Vars < ' a , T : ShellVar > {
2329 /// Char16 containing names of environment variables
24- inner : * const Char16 ,
30+ names : * const Char16 ,
31+ /// Reference to Shell Protocol
32+ protocol : * const T ,
2533 /// Placeholder to attach a lifetime to `Vars`
2634 placeholder : PhantomData < & ' a CStr16 > ,
2735}
2836
29- impl < ' a > Iterator for Vars < ' a > {
30- type Item = & ' a CStr16 ;
37+ impl < ' a , T : ShellVar + ' a > Iterator for Vars < ' a , T > {
38+ type Item = ( & ' a CStr16 , Option < & ' a CStr16 > ) ;
3139 // We iterate a list of NUL terminated CStr16s.
3240 // The list is terminated with a double NUL.
3341 fn next ( & mut self ) -> Option < Self :: Item > {
34- let s = unsafe { CStr16 :: from_ptr ( self . inner ) } ;
42+ let s = unsafe { CStr16 :: from_ptr ( self . names ) } ;
3543 if s. is_empty ( ) {
3644 None
3745 } else {
38- self . inner = unsafe { self . inner . add ( s. num_chars ( ) + 1 ) } ;
39- Some ( s )
46+ self . names = unsafe { self . names . add ( s. num_chars ( ) + 1 ) } ;
47+ Some ( ( s , unsafe { self . protocol . as_ref ( ) . unwrap ( ) . var ( s ) } ) )
4048 }
4149 }
4250}
4351
52+ impl ShellVar for Shell {
53+ /// Gets the value of the specified environment variable
54+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > {
55+ self . var ( name)
56+ }
57+ }
58+
4459impl Shell {
4560 /// Gets the value of the specified environment variable
4661 ///
@@ -67,10 +82,11 @@ impl Shell {
6782
6883 /// Gets an iterator over the names of all environment variables
6984 #[ must_use]
70- pub fn vars ( & self ) -> Vars < ' _ > {
85+ pub fn vars ( & self ) -> Vars < ' _ , Self > {
7186 let env_ptr = unsafe { ( self . 0 . get_env ) ( ptr:: null ( ) ) } ;
7287 Vars {
73- inner : env_ptr. cast :: < Char16 > ( ) ,
88+ names : env_ptr. cast :: < Char16 > ( ) ,
89+ protocol : self ,
7490 placeholder : PhantomData ,
7591 }
7692 }
@@ -97,9 +113,33 @@ impl Shell {
97113#[ cfg( test) ]
98114mod tests {
99115 use super :: * ;
116+ use alloc:: collections:: BTreeMap ;
100117 use alloc:: vec:: Vec ;
101118 use uefi:: cstr16;
102119
120+ struct ShellMock < ' a > {
121+ inner : BTreeMap < & ' a CStr16 , & ' a CStr16 > ,
122+ }
123+
124+ impl < ' a > ShellMock < ' a > {
125+ fn new ( names : Vec < & ' a CStr16 > , values : Vec < & ' a CStr16 > ) -> ShellMock < ' a > {
126+ let mut inner_map = BTreeMap :: new ( ) ;
127+ for ( name, val) in names. iter ( ) . zip ( values. iter ( ) ) {
128+ inner_map. insert ( * name, * val) ;
129+ }
130+ ShellMock { inner : inner_map }
131+ }
132+ }
133+ impl < ' a > ShellVar for ShellMock < ' a > {
134+ fn var ( & self , name : & CStr16 ) -> Option < & CStr16 > {
135+ if let Some ( val) = self . inner . get ( name) {
136+ Some ( * val)
137+ } else {
138+ None
139+ }
140+ }
141+ }
142+
103143 /// Testing Vars struct
104144 #[ test]
105145 fn test_vars ( ) {
@@ -108,9 +148,11 @@ mod tests {
108148 vars_mock. push ( 0 ) ;
109149 vars_mock. push ( 0 ) ;
110150 let mut vars = Vars {
111- inner : vars_mock. as_ptr ( ) . cast ( ) ,
151+ names : vars_mock. as_ptr ( ) . cast ( ) ,
152+ protocol : & ShellMock :: new ( Vec :: new ( ) , Vec :: new ( ) ) ,
112153 placeholder : PhantomData ,
113154 } ;
155+
114156 assert ! ( vars. next( ) . is_none( ) ) ;
115157
116158 // One environment variable in Vars
@@ -121,10 +163,14 @@ mod tests {
121163 vars_mock. push ( 0 ) ;
122164 vars_mock. push ( 0 ) ;
123165 let vars = Vars {
124- inner : vars_mock. as_ptr ( ) . cast ( ) ,
166+ names : vars_mock. as_ptr ( ) . cast ( ) ,
167+ protocol : & ShellMock :: new ( Vec :: from ( [ cstr16 ! ( "foo" ) ] ) , Vec :: from ( [ cstr16 ! ( "value" ) ] ) ) ,
125168 placeholder : PhantomData ,
126169 } ;
127- assert_eq ! ( vars. collect:: <Vec <_>>( ) , Vec :: from( [ cstr16!( "foo" ) ] ) ) ;
170+ assert_eq ! (
171+ vars. collect:: <Vec <_>>( ) ,
172+ Vec :: from( [ ( cstr16!( "foo" ) , Some ( cstr16!( "value" ) ) ) ] )
173+ ) ;
128174
129175 // Multiple environment variables in Vars
130176 let mut vars_mock = Vec :: < u16 > :: new ( ) ;
@@ -145,12 +191,20 @@ mod tests {
145191 vars_mock. push ( 0 ) ;
146192
147193 let vars = Vars {
148- inner : vars_mock. as_ptr ( ) . cast ( ) ,
194+ names : vars_mock. as_ptr ( ) . cast ( ) ,
195+ protocol : & ShellMock :: new (
196+ Vec :: from ( [ cstr16 ! ( "foo1" ) , cstr16 ! ( "bar" ) , cstr16 ! ( "baz2" ) ] ) ,
197+ Vec :: from ( [ cstr16 ! ( "value" ) , cstr16 ! ( "one" ) , cstr16 ! ( "two" ) ] ) ,
198+ ) ,
149199 placeholder : PhantomData ,
150200 } ;
151201 assert_eq ! (
152202 vars. collect:: <Vec <_>>( ) ,
153- Vec :: from( [ cstr16!( "foo1" ) , cstr16!( "bar" ) , cstr16!( "baz2" ) ] )
203+ Vec :: from( [
204+ ( cstr16!( "foo1" ) , Some ( cstr16!( "value" ) ) ) ,
205+ ( cstr16!( "bar" ) , Some ( cstr16!( "one" ) ) ) ,
206+ ( cstr16!( "baz2" ) , Some ( cstr16!( "two" ) ) )
207+ ] )
154208 ) ;
155209 }
156210}
0 commit comments