Question on how to access to stdin, stdout (and stderr) since 0.32
YtvwlD opened this issue · 4 comments
Hi, I'm trying to display a menu. With older versions of uefi-rs, I'd have a function
pub fn choose<'a>(config: &'a Config, systab: &mut SystemTable<Boot>) -> &'a Entrythat accesses systab.stdin() and systab.stdout(). Since that is now deprecated, how would I change this?
The migration document doesn't mention stdin or stdout.
I've thought of this:
pub fn choose<'a>(config: &'a Config, stdin: &mut Input, stdout: &mut Output) -> &'a Entrybut I can't call it with:
let entry_to_boot = with_stdin(|stdin| with_stdout(
|stdout| menu::choose(&config, stdin, stdout)
));as this produces the following error:
error[E0596]: cannot borrow `*stdin` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:117:40
|
31 | fn efi_main(image: Handle, mut systab: SystemTable<Boot>) -> Status {
| -------- ------ change this to return `FnMut` instead of `Fn`
...
117 | |stdout| menu::choose(&config, stdin, stdout)
| -------- in this closure ^^^^^ cannot borrow as mutable
Do I have to put the calls to with_stdin and with_stdout inside the function?
Good question, thanks for pointing that out. I don't have capacity to look into this in the next days, but perhaps @nicholasbishop can work on it?
Good question indeed, the API here is not making what you want to do as easy as it should be.
I think the simplest way forward for now is to manually stash pointers. Here's an example that compiles:
#![no_std]
#![no_main]
use uefi::proto::console::text::{Output, Input};
use uefi::{Status, entry, system};
use core::ptr;
pub fn choose(_stdin: &mut Input, _stdout: &mut Output) {
unimplemented!();
}
#[entry]
fn main() -> Status {
let stdin: *mut Input = system::with_stdin(|stdin| ptr::from_mut(stdin));
let stdout: *mut Output = system::with_stdout(|stdout| ptr::from_mut(stdout));
// Safety: in the UEFI spec, section
// EFI_BOOT_SERVICES.UninstallProtocolInterface(), it says that
// console I/O protocols can never be removed. So these pointers are
// always valid, and within this block there is no shared mutable
// reference to stdin or stdout, so Rust's aliasing guarantees are
// maintained.
{
let stdin = unsafe { &mut *stdin };
let stdout = unsafe { &mut *stdout };
choose(stdin, stdout);
}
Status::SUCCESS
}This is not ideal though, we should think about this API some more.
Can f be FnMut? Would that work?
(This also applies to with_config_table.)
How now system::with_std(|stdin, stdout|)?