use std::error::Error;
use std::marker::PhantomData;
pub trait ChainMap: Sized {
fn chain_map<F>(self, f: F) -> Self
where F: FnOnce(Self) -> Self {
f(self)
}
}
impl<T> ChainMap for T {}
#[must_use]
pub struct Defer<'a, F, E>(Option<F>, PhantomData<&'a F>)
where F: 'a + FnOnce() -> Result<(), E>,
E: Error;
impl<'a, F, E> Defer<'a, F, E>
where F: 'a + FnOnce() -> Result<(), E>,
E: Error
{
pub fn defer(f: F) -> Defer<'a, F, E> {
Defer(Some(f), PhantomData)
}
pub fn disarm(mut self) {
self.0 = None;
drop(self);
}
}
impl<'a, F, E> ::std::ops::Drop for Defer<'a, F, E>
where
F: 'a + FnOnce() -> Result<(), E>,
E: Error
{
fn drop(&mut self) {
if let Some(f) = self.0.take() {
if let Err(err) = f() {
error!("deferred function failed: {}", err);
}
}
}
}
#[cfg(feature="suppress-cargo-output")]
pub use self::suppress_child_output::{ChildToken, suppress_child_output};
#[cfg(feature="suppress-cargo-output")]
mod suppress_child_output {
use std::io;
use std::process::{self, Command};
use std::thread;
use std::time::Duration;
use chan;
use error::Result;
pub fn suppress_child_output(cmd: &mut Command, timeout: Duration) -> Result<ChildToken> {
cmd.stderr(process::Stdio::piped());
let mut child = try!(cmd.spawn());
let stderr = child.stderr.take().expect("no stderr pipe found");
let timeout_chan = chan::after(timeout);
let (done_sig, done_gate) = chan::sync(0);
let _ = thread::spawn(move || {
let show_stderr;
let mut recv_done = false;
chan_select! {
timeout_chan.recv() => {
show_stderr = true;
},
done_gate.recv() -> success => {
show_stderr = !success.unwrap_or(true);
recv_done = true;
},
}
if show_stderr {
let mut stderr = stderr;
io::copy(&mut stderr, &mut io::stderr())
.expect("could not copy child stderr");
}
if !recv_done {
done_gate.recv();
}
});
Ok(ChildToken {
child: child,
done_sig: Some(done_sig),
})
}
pub struct ChildToken {
child: process::Child,
done_sig: Option<chan::Sender<bool>>,
}
impl ChildToken {
pub fn status(&mut self) -> io::Result<process::ExitStatus> {
let st = match self.child.wait() {
Ok(r) => r,
Err(e) => {
if let Some(done_sig) = self.done_sig.take() {
done_sig.send(false);
}
return Err(e.into());
}
};
if let Some(done_sig) = self.done_sig.take() {
done_sig.send(st.success());
}
Ok(st)
}
}
}
pub trait SubsliceOffset {
fn subslice_offset_stable(&self, inner: &Self) -> Option<usize>;
}
impl SubsliceOffset for str {
fn subslice_offset_stable(&self, inner: &str) -> Option<usize> {
let self_beg = self.as_ptr() as usize;
let inner = inner.as_ptr() as usize;
if inner < self_beg || inner > self_beg.wrapping_add(self.len()) {
None
} else {
Some(inner.wrapping_sub(self_beg))
}
}
}
use std::path::Path;
pub trait PathExt {
fn is_file_polyfill(&self) -> bool;
}
impl PathExt for Path {
fn is_file_polyfill(&self) -> bool {
::std::fs::metadata(self)
.map(|md| md.is_file())
.unwrap_or(false)
}
}