#![doc(html_root_url = "https://docs.rs/nyx/1.0.0")]
#![deny(
bad_style,
bare_trait_objects,
missing_docs,
unused_import_braces,
unused_qualifications,
unsafe_code,
unstable_features
)]
use std::fmt::{self, Debug, Display, Formatter};
use std::io::{self, Read, Write};
use std::iter::FusedIterator;
use std::mem;
use std::sync::mpsc::Sender;
use std::time::{Duration, Instant};
macro_rules! common_methods {
() => {
#[inline]
pub fn interval(&self) -> Duration { self.bytes.interval }
#[inline]
pub fn set_interval(&mut self, interval: Duration) { self.bytes.interval = interval; }
#[inline]
pub fn get_ref(&self) -> &T { &self.inner }
#[inline]
pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
#[inline]
pub fn into_inner(self) -> T { self.inner }
};
}
#[inline]
pub fn stdout<T>(inner: T) -> Stdout<T> {
Stdout {
inner,
bytes: Bytes::new(),
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct Stdout<T> {
inner: T,
bytes: Bytes,
}
impl<T> Stdout<T> {
common_methods!();
#[inline]
fn update(&mut self, bytes: usize) {
self.bytes.update(bytes, |bps| println!("{}", bps));
}
}
impl<T: Iterator> Iterator for Stdout<T> {
type Item = T::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.next();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: DoubleEndedIterator> DoubleEndedIterator for Stdout<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let item = self.inner.next_back();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: ExactSizeIterator> ExactSizeIterator for Stdout<T> {}
impl<T: FusedIterator> FusedIterator for Stdout<T> {}
impl<T: Read> Read for Stdout<T> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.inner.read(buf)?;
self.update(bytes);
Ok(bytes)
}
}
impl<T: Write> Write for Stdout<T> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let bytes = self.inner.write(buf)?;
self.update(bytes);
Ok(bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
#[inline]
pub fn stderr<T>(inner: T) -> Stderr<T> {
Stderr {
inner,
bytes: Bytes::new(),
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct Stderr<T> {
inner: T,
bytes: Bytes,
}
impl<T> Stderr<T> {
common_methods!();
#[inline]
fn update(&mut self, bytes: usize) {
self.bytes.update(bytes, |bps| eprintln!("{}", bps));
}
}
impl<T: Iterator> Iterator for Stderr<T> {
type Item = T::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.next();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: DoubleEndedIterator> DoubleEndedIterator for Stderr<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let item = self.inner.next_back();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: ExactSizeIterator> ExactSizeIterator for Stderr<T> {}
impl<T: FusedIterator> FusedIterator for Stderr<T> {}
impl<T: Read> Read for Stderr<T> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.inner.read(buf)?;
self.update(bytes);
Ok(bytes)
}
}
impl<T: Write> Write for Stderr<T> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let bytes = self.inner.write(buf)?;
self.update(bytes);
Ok(bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
#[inline]
pub fn send<T>(inner: T, sender: Sender<Bps>) -> Send<T> {
Send {
inner,
sender,
bytes: Bytes::new(),
}
}
#[derive(Clone, Debug)]
pub struct Send<T> {
inner: T,
sender: Sender<Bps>,
bytes: Bytes,
}
impl<T> Send<T> {
common_methods!();
#[inline]
fn update(&mut self, bytes: usize) {
let sender = &self.sender;
self.bytes.update(bytes, move |bps| {
sender.send(bps).expect("failed sending bps");
});
}
}
impl<T: Iterator> Iterator for Send<T> {
type Item = T::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.next();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: DoubleEndedIterator> DoubleEndedIterator for Send<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let item = self.inner.next_back();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: ExactSizeIterator> ExactSizeIterator for Send<T> {}
impl<T: FusedIterator> FusedIterator for Send<T> {}
impl<T: Read> Read for Send<T> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.inner.read(buf)?;
self.update(bytes);
Ok(bytes)
}
}
impl<T: Write> Write for Send<T> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let bytes = self.inner.write(buf)?;
self.update(bytes);
Ok(bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
#[inline]
pub fn slot<T, F: FnMut(Bps)>(inner: T, f: F) -> Slot<T, F> {
Slot {
inner,
f,
bytes: Bytes::new(),
}
}
#[derive(Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct Slot<T, F> {
inner: T,
f: F,
bytes: Bytes,
}
impl<T, F: FnMut(Bps)> Slot<T, F> {
common_methods!();
#[inline]
fn update(&mut self, bytes: usize) {
self.bytes.update(bytes, &mut self.f);
}
}
impl<T: Debug, F> Debug for Slot<T, F> {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("Slot")
.field("inner", &self.inner)
.field("bytes", &self.bytes)
.finish()
}
}
impl<T: Iterator, F: FnMut(Bps)> Iterator for Slot<T, F> {
type Item = T::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let item = self.inner.next();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: DoubleEndedIterator, F: FnMut(Bps)> DoubleEndedIterator for Slot<T, F> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let item = self.inner.next_back();
self.update(mem::size_of_val(&item));
item
}
}
impl<T: ExactSizeIterator, F: FnMut(Bps)> ExactSizeIterator for Slot<T, F> {}
impl<T: FusedIterator, F: FnMut(Bps)> FusedIterator for Slot<T, F> {}
impl<T: Read, F: FnMut(Bps)> Read for Slot<T, F> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.inner.read(buf)?;
self.update(bytes);
Ok(bytes)
}
}
impl<T: Write, F: FnMut(Bps)> Write for Slot<T, F> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let bytes = self.inner.write(buf)?;
self.update(bytes);
Ok(bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.inner.flush()
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
struct Bytes {
total: u64,
instant: Instant,
interval: Duration,
}
impl Bytes {
#[inline]
fn new() -> Bytes {
Bytes {
total: 0,
instant: Instant::now(),
interval: Duration::from_secs(1),
}
}
#[inline]
fn update(&mut self, bytes: usize, mut f: impl FnMut(Bps)) {
self.total += bytes as u64;
let elapsed = self.instant.elapsed();
if elapsed >= self.interval {
f(Bps(self.total as f64 / elapsed.as_secs_f64()));
self.total = 0;
self.instant = Instant::now();
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialOrd, PartialEq)]
pub struct Bps(pub f64);
impl Bps {
#[inline]
pub fn to_kb(self) -> f64 {
self.0 / 1000.0
}
#[inline]
pub fn to_mb(self) -> f64 {
self.0 / 1_000_000.0
}
#[inline]
pub fn to_gb(self) -> f64 {
self.0 / 1_000_000_000.0
}
#[inline]
pub fn to_tb(self) -> f64 {
self.0 / 1_000_000_000_000.0
}
#[inline]
pub fn to_kib(self) -> f64 {
self.0 / 1024.0
}
#[inline]
pub fn to_mib(self) -> f64 {
self.0 / 1_048_576.0
}
#[inline]
pub fn to_gib(self) -> f64 {
self.0 / 1_073_741_824.0
}
#[inline]
pub fn to_tib(self) -> f64 {
self.0 / 1_099_511_627_776.0
}
}
impl Display for Bps {
#[inline]
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self.0 as u64 {
0..=1023 => write!(f, "{:.1} B/s", self.0),
1024..=1_048_575 => write!(f, "{:.1} KiB/s", self.to_kib()),
1_048_576..=1_073_741_823 => write!(f, "{:.1} MiB/s", self.to_mib()),
1_073_741_824..=1_099_511_627_775 => write!(f, "{:.1} GiB/s", self.to_gib()),
_ => write!(f, "{:.1} TiB/s", self.to_tib()),
}
}
}