-
-
Notifications
You must be signed in to change notification settings - Fork 169
Enhancement/efi shell interface #1679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Enhancement/efi shell interface #1679
Conversation
uefi/src/proto/shell/mod.rs
Outdated
/// * `Some(Vec<env_names>)` - Vector of environment variable names | ||
/// * `None` - Environment variable doesn't exist | ||
#[must_use] | ||
pub fn get_env<'a>(&'a self, name: Option<&CStr16>) -> Option<EnvOutput<'a>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd much rather have the high-level API to not replicate the low-level interface here. Instead, we can use the low-level interface to create an API similar to:
std::env::var
- Returns an Option (Or Result>), depending on your impl
std::env::vars
- Returns a Vec in our case
Then we also don't need the EnvOutput
type effectively acting as a Either
type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed get_env()
to return an Option<Vec<&CStr16>>
. In the case where name
is specified, the function will return a Vec
of length 1 where the resulting &CStr16
contains the value of that environment variable. Otherwise in the name=None
case, the Vec
would contain the names of all environment variables. That way, the caller can just deal with the one type.
Is this more so along the lines of what you are thinking?
Also, I've chosen to wrap the return value in Option
since the specification returns a NULL
pointer in the case that name
does not point to a valid environment variable, so I don't believe there are any errors we'd expect to return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this! As a general rule of thumb: High-level wrappers should be close to the API of std
and not replicate "ugly" or unusual details of the low-level API. See my suggestions for get_var
uefi/src/proto/shell/mod.rs
Outdated
/// TODO | ||
#[repr(C)] | ||
#[derive(Debug, Clone, Copy)] | ||
pub struct ListEntry { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having now lifetime here makes it easy to introduce bugs. Also, this is code that we can't test using miri unfortunately.
Some general guidance:
|
Thanks for the feedback! I will start with making the PR to update |
This commit implements wrappers for the following EFI Shell Protocol functions: set_env(), get_env(), set_cur_dir(), and get_cur_dir().
This commit includes tests for the following EFI Shell Protocol functions: get_env(), set_env(), get_cur_dir(), and set_cur_dir().
Hi all. Now that #1680 is merged, I was wondering if it would be alright to use this PR to work on the 4 ergonomic wrappers I've implemented ( If it is okay to continue to use this PR, then I plan to rebase this branch onto the current main, squash the commits, and then continue from there. |
That sounds good, start with doing that in this PR. Once the changes are in this PR it's possible I might ask for it to be split up into more than one PR for review, but we can start with the assumption that one PR is OK. |
b9a3be8
to
0f30078
Compare
I've rebased this branch onto the current main and updated it to disclude the |
uefi/src/proto/shell/mod.rs
Outdated
/// * `Some(Vec<env_names>)` - Vector of environment variable names | ||
/// * `None` - Environment variable doesn't exist | ||
#[must_use] | ||
pub fn get_env<'a>(&'a self, name: Option<&CStr16>) -> Option<Vec<&'a CStr16>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please don't export this unintuitive/unrusty UEFI API in this high-level wrapper. Instead, please aim to stay close to std
. This means:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Philipp, thanks again for the resources. However, it is not clear to me what you are asking. Are you asking for get_env()
to have a similar return type to the var()
and vars()
functions? Or are you asking for get_env()
to be split up into two separate functions- one dedicated to returning the value of an environment variable and the other dedicated to returning the current environment variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the confusion!
Or are you asking for get_env() to be split up into two separate functions- one dedicated to returning the value of an environment variable and the other dedicated to returning the current environment variables?
This.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries! I can see how having separate dedicated functions is more intuitive. In the spirit of mirroring std
, I have updated the protocol with these two new functions using the same naming convention as var
and vars
where:
get_env()
- retrieves the value of an environment variable
get_envs()
- retrieves the names of all environment variables
The UEFI get_env() implementation is used for getting individual environment variable values and also environment variable names. This is not intuitive so this commit splits the function into two dedicated ones: one for accessing values and the other for accessing names.
This PR will implement the wrappers for EFI Shell Protocol functions to address #448 . This PR does branch off of the changes made in #596 so big thanks to @timrobertsdev for laying the groundwork!
Currently, I've implemented wrappers and wrote tests for
GetEnv()
,SetEnv()
,GetCurDir()
andSetCurDir()
. My plan is to first write tests for and finish implementingExecute()
,CloseFile()
,CreateFile()
,FindFiles()
,FindFilesInDir()
, andGetFileSize()
since they have already been started. Then I can implement the rest in either this PR or subsequent follow up PRs (whichever is preferable).I do have some questions about my
get_env()
implementation. UEFI'sGetEnv()
returns the value of a variable if its name is specified. However if its name is not specified, it returns all known variable names in a*const Char16
where the names are delimited by aNULL
and the end of the list is terminated by a doubleNULL
.My initial approach was to parse the
*const Char16
into aVec
in this case. I wrapped the return value in an Enum that can be unpacked into a single&CStr16
or into a vector of&CStr16
s depending on which is expected. Is this approach okay? I was concerned that if I simply returned a&CStr16
in the "name list" case that the true size of the string wouldn't be visible since the names are separated byNULL
. Also, is it okay for me to usealloc::vec::Vec
? I saw that a lot of other protocols don't use anyVec
at all so I'm not clear on if there are some restrictions for doing so.Checklist