use Fd;
use io::{FileDesc, Permissions};
use env::{AsyncIoEnvironment, FileDescEnvironment};
use eval::RedirectAction;
use std::collections::HashMap;
use std::fmt;
use std::io::Result as IoResult;
pub trait RedirectEnvRestorer<E: ?Sized> {
fn reserve(&mut self, additional: usize);
fn apply_action(&mut self, action: RedirectAction<E::FileHandle>, env: &mut E) -> IoResult<()>
where E: AsyncIoEnvironment + FileDescEnvironment,
E::FileHandle: From<FileDesc>;
fn backup(&mut self, fd: Fd, env: &mut E);
fn restore(&mut self, env: &mut E);
}
impl<'a, T, E: ?Sized> RedirectEnvRestorer<E> for &'a mut T
where T: RedirectEnvRestorer<E>
{
fn reserve(&mut self, additional: usize) {
(**self).reserve(additional);
}
fn apply_action(&mut self, action: RedirectAction<E::FileHandle>, env: &mut E) -> IoResult<()>
where E: AsyncIoEnvironment + FileDescEnvironment,
E::FileHandle: From<FileDesc>
{
(**self).apply_action(action, env)
}
fn backup(&mut self, fd: Fd, env: &mut E) {
(**self).backup(fd, env)
}
fn restore(&mut self, env: &mut E) {
(**self).restore(env)
}
}
#[derive(Clone)]
pub struct RedirectRestorer<E: ?Sized>
where E: FileDescEnvironment,
{
overrides: HashMap<Fd, Option<(E::FileHandle, Permissions)>>,
}
impl<E: ?Sized> Eq for RedirectRestorer<E>
where E: FileDescEnvironment,
E::FileHandle: Eq,
{}
impl<E: ?Sized> PartialEq<Self> for RedirectRestorer<E>
where E: FileDescEnvironment,
E::FileHandle: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.overrides == other.overrides
}
}
impl<E: ?Sized> fmt::Debug for RedirectRestorer<E>
where E: FileDescEnvironment,
E::FileHandle: fmt::Debug,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("RedirectRestorer")
.field("overrides", &self.overrides)
.finish()
}
}
impl<E: ?Sized> Default for RedirectRestorer<E>
where E: FileDescEnvironment,
{
fn default() -> Self {
Self::new()
}
}
impl<E: ?Sized> RedirectRestorer<E>
where E: FileDescEnvironment,
{
pub fn new() -> Self {
RedirectRestorer {
overrides: HashMap::new(),
}
}
pub fn with_capacity(capacity: usize) -> Self {
RedirectRestorer {
overrides: HashMap::with_capacity(capacity),
}
}
#[deprecated(note = "use the `RedirectEnvRestorer` trait instead")]
pub fn reserve(&mut self, additional: usize) {
self.overrides.reserve(additional);
}
#[deprecated(note = "use the `RedirectEnvRestorer` trait instead")]
pub fn apply_action(&mut self, action: RedirectAction<E::FileHandle>, env: &mut E)
-> IoResult<()>
where E: AsyncIoEnvironment,
E::FileHandle: Clone + From<FileDesc>,
{
RedirectEnvRestorer::apply_action(self, action, env)
}
#[deprecated(note = "use the `RedirectEnvRestorer` trait instead")]
pub fn backup(&mut self, fd: Fd, env: &mut E)
where E::FileHandle: Clone,
{
RedirectEnvRestorer::backup(self, fd, env);
}
#[deprecated(note = "use the `RedirectEnvRestorer` trait instead")]
pub fn restore(mut self, env: &mut E) {
self._restore(env)
}
fn _restore(&mut self, env: &mut E) {
for (fd, backup) in self.overrides.drain() {
match backup {
Some((handle, perms)) => env.set_file_desc(fd, handle, perms),
None => env.close_file_desc(fd),
}
}
}
}
impl<E: ?Sized> RedirectEnvRestorer<E> for RedirectRestorer<E>
where E: FileDescEnvironment,
E::FileHandle: Clone
{
fn reserve(&mut self, additional: usize) {
self.overrides.reserve(additional);
}
fn apply_action(&mut self, action: RedirectAction<E::FileHandle>, env: &mut E) -> IoResult<()>
where E: AsyncIoEnvironment + FileDescEnvironment,
E::FileHandle: From<FileDesc>
{
match action {
RedirectAction::Close(fd) |
RedirectAction::Open(fd, _, _) |
RedirectAction::HereDoc(fd, _) => self.backup(fd, env),
}
action.apply(env)
}
fn backup(&mut self, fd: Fd, env: &mut E) {
self.overrides.entry(fd).or_insert_with(|| {
env.file_desc(fd).map(|(handle, perms)| (handle.clone(), perms))
});
}
fn restore(&mut self, env: &mut E) {
self._restore(env)
}
}