Add vpv example

This commit is contained in:
Alexandre Bury 2018-04-10 11:46:02 -07:00
parent 063589b0cd
commit b1e9afe0ff
4 changed files with 152 additions and 1 deletions

View File

@ -62,6 +62,7 @@ version = "1.5.0"
[dev-dependencies] [dev-dependencies]
rand = "0.4" rand = "0.4"
pretty-bytes = "0.2.2"
[features] [features]
blt-backend = ["bear-lib-terminal"] blt-backend = ["bear-lib-terminal"]

139
examples/vpv.rs Normal file
View File

@ -0,0 +1,139 @@
extern crate cursive;
extern crate pretty_bytes;
use std::io;
use cursive::Cursive;
use cursive::traits::{Boxable, With};
use cursive::utils;
use cursive::views::{Canvas, Dialog, LinearLayout, ProgressBar};
use pretty_bytes::converter::convert;
use std::thread;
use std::time;
// This example is a visual version of the `pv` tool.
fn main() {
let mut siv = Cursive::default();
// We'll use this channel to signal the end of the transfer
let cb_sink = siv.cb_sink().clone();
// Use a counter to track progress
let counter = utils::Counter::new(0);
let counter_copy = counter.clone();
let start = time::Instant::now();
// If an argument is given, it is the file we'll read from.
// Else, read from stdin.
let (source, len) = match std::env::args().nth(1) {
Some(source) => {
let meta = std::fs::metadata(&source).unwrap();
// If possible, read the file size to have a progress bar.
let len = meta.len();
(
Some(source),
if len > 0 { Some(len) } else { None },
)
}
None => (None, None),
};
// Start the copy in a separate thread
thread::spawn(move || {
// Copy to stdout - lock it for better performance.
let stdout = io::stdout();
let mut stdout = stdout.lock();
match source {
None => {
// Copy from stdin - lock it for better performance.
let stdin = io::stdin();
let stdin = stdin.lock();
let mut reader =
utils::ProgressReader::new(counter_copy, stdin);
// And copy!
io::copy(&mut reader, &mut stdout).unwrap();
}
Some(source) => {
// Copy from stdin - lock it for better performance.
let input = std::fs::File::open(source).unwrap();
let mut reader =
utils::ProgressReader::new(counter_copy, input);
// And copy!
io::copy(&mut reader, &mut stdout).unwrap();
}
}
// When we're done, shut down the application
cb_sink
.send(Box::new(|s: &mut Cursive| s.quit()))
.unwrap();
});
// Add a single view: progress status
siv.add_layer(
Dialog::new().title("Copying...").content(
LinearLayout::vertical()
.child(
Canvas::new(counter.clone())
.with_draw(move |c, printer| {
let ticks = c.get() as f64;
let now = time::Instant::now();
let duration = now - start;
let seconds = duration.as_secs() as f64
+ duration.subsec_nanos() as f64 * 1e-9;
let speed = ticks / seconds;
// Print ETA if we have a file size
// Otherwise prints elapsed time.
if let Some(len) = len {
let remaining = (len as f64 - ticks) / speed;
printer.print(
(0, 0),
&format!(
"ETA: {:.1} seconds",
remaining
),
);
} else {
printer.print(
(0, 0),
&format!(
"Elapsed: {:.1} seconds",
seconds
),
);
}
printer.print(
(0, 1),
&format!("Copied: {}", convert(ticks)),
);
printer.print(
(0, 2),
&format!("Speed: {}/s", convert(speed)),
);
})
.fixed_size((25, 3)),
)
.with(|l| {
// If we have a file length, add a progress bar
if let Some(len) = len {
l.add_child(
ProgressBar::new()
.max(len as usize)
.with_value(counter.clone()),
);
}
}),
),
);
siv.set_fps(10);
siv.run();
}

View File

@ -32,7 +32,7 @@ impl<R: Read> ProgressReader<R> {
impl<R: Read> Read for ProgressReader<R> { impl<R: Read> Read for ProgressReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let result = try!(self.reader.read(buf)); let result = self.reader.read(buf)?;
self.counter.tick(result); self.counter.tick(result);
Ok(result) Ok(result)
} }

View File

@ -14,6 +14,17 @@ pub trait With: Sized {
f(&mut self)?; f(&mut self)?;
Ok(self) Ok(self)
} }
/// Calls the given closure if `condition == true`.
fn with_if<F>(mut self, condition: bool, f: F) -> Self
where
F: FnOnce(&mut Self),
{
if condition {
f(&mut self);
}
self
}
} }
impl<T: Sized> With for T {} impl<T: Sized> With for T {}