<commit_before>use std::str;
use std::time::{Duration,Instant};
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,LineWriter,Write,ErrorKind};

use super::{Subscriber,MetricData,StoredMetricData};

const VERSION: &str = env!("CARGO_PKG_VERSION");

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub struct NetworkDrain {
  queue:              VecDeque<MetricLine>,
  pub prefix:         String,
  pub remote:         LineWriter<MetricSocket>,
  is_writable:        bool,
  data:               BTreeMap<String, StoredMetricData>,
  /// (app_id, key) -> metric
  app_data:           BTreeMap<(String, String), StoredMetricData>,
  /// (app_id, backend_id, key) -> metric
  backend_data:       BTreeMap<(String, String, String), StoredMetricData>,
  pub use_tagged_metrics: bool,
  pub origin:         String,
  created:            Instant,
}

impl NetworkDrain {
  pub fn new(prefix: String, socket: UdpSocket, addr: SocketAddr) -> Self {
    NetworkDrain {
      queue:  VecDeque::new(),
      prefix,
      remote: LineWriter::with_capacity(2048, MetricSocket {
        addr, socket
      }),
      is_writable: true,
      data: BTreeMap::new(),
      app_data: BTreeMap::new(),
      backend_data: BTreeMap::new(),
      use_tagged_metrics: false,
      origin: String::from("x"),
      created: Instant::now(),
    }
  }

  pub fn writable(&mut self) {
    self.is_writable = true;
  }

  pub fn send_data(&mut self) {
    let now  = Instant::now();
    let secs = Duration::new(2, 0);
    let mut send_count = 0;

    if self.is_writable {

    for (ref key, ref mut stored_metric) in self.data.iter_mut().filter(|&(_, ref value)| value.updated && now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|g\n", self.prefix, key, self.origin, VERSION, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|g\n", self.prefix, self.origin, key, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|c\n", self.prefix, key, self.origin, VERSION, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|c\n", self.prefix, self.origin, key, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
          stored_metric.updated = false;

          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing global metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.app_data.iter_mut().filter(|&(_, ref value)| value.updated && now.duration_since(value.last_sent) > secs) {
      //info!("will write {:?} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|g\n",
              self.prefix, key.1, self.origin, VERSION, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|c\n",
              self.prefix, key.1, self.origin, VERSION, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
          stored_metric.updated = false;

          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing app metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.backend_data.iter_mut().filter(|&(_, ref value)| value.updated && now.duration_since(value.last_sent) > secs) {
      //info!("will write {:?} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|g\n",
              self.prefix, key.2, self.origin, VERSION, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|c\n",
              self.prefix, key.2, self.origin, VERSION, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
          stored_metric.updated = false;

          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) =self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing backend metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }
    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }

    if self.is_writable {
    for metric in self.queue.drain(..) {
       let res = match (metric.app_id, metric.backend_id) {
        (Some(app_id), Some(backend_id)) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, app_id, backend_id, metric.duration))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|ms\n", self.prefix, self.origin, app_id, backend_id,
              metric.label, metric.duration))
          }
        },
        (Some(app_id), None) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, app_id, metric.duration))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|ms\n", self.prefix, self.origin, app_id,
              metric.label, metric.duration))
          }
        },
        (None, None) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, metric.duration))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|ms\n", self.prefix, self.origin,
              metric.label, metric.duration))
          }
        },
        _ => { Ok(()) }
      };

      match res {
        Ok(()) => {
          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing timing metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }

    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }
    }
  }
}

impl Subscriber for NetworkDrain {
  fn receive_metric(&mut self, key: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if metric.is_time() {
      if let MetricData::Time(millis) = metric {
        self.queue.push_back(MetricLine {
          label: key,
          app_id: app_id.map(|s| s.to_string()),
          backend_id: backend_id.map(|s| s.to_string()),
          duration: millis,
        });
      }
    } else if let Some(id) = app_id {
      if let Some(bid) = backend_id {
        let k = (String::from(id), String::from(bid), String::from(key));
        if !self.backend_data.contains_key(&k) {
          self.backend_data.insert(
            k,
            StoredMetricData::new(self.created, metric)
            );
        } else {
          self.backend_data.get_mut(&k).map(|stored_metric| {
            stored_metric.update(key, metric);
          });
        }
      } else {
        let k = (String::from(id), String::from(key));
        if !self.app_data.contains_key(&k) {
          self.app_data.insert(
            k,
            StoredMetricData::new(self.created, metric)
            );
        } else {
          self.app_data.get_mut(&k).map(|stored_metric| {
            stored_metric.update(key, metric);
          });
        }
      }
    } else if !self.data.contains_key(key) {
      self.data.insert(
        String::from(key),
        StoredMetricData::new(self.created, metric)
        );
    } else {
      self.data.get_mut(key).map(|stored_metric| {
        stored_metric.update(key, metric);
      });
    }
  }
}

<commit_msg>clear network metrics too<commit_after>use std::str;
use std::time::{Duration,Instant};
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,LineWriter,Write,ErrorKind};
use std::collections::HashMap;

use super::{Subscriber,MetricData,StoredMetricData};

const VERSION: &str = env!("CARGO_PKG_VERSION");

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub struct NetworkDrain {
  queue:              VecDeque<MetricLine>,
  pub prefix:         String,
  pub remote:         LineWriter<MetricSocket>,
  is_writable:        bool,
  data:               BTreeMap<String, StoredMetricData>,
  /// (app_id, key) -> metric
  app_data:           HashMap<(String, String), StoredMetricData>,
  /// (app_id, backend_id, key) -> metric
  backend_data:       HashMap<(String, String, String), StoredMetricData>,
  pub use_tagged_metrics: bool,
  pub origin:         String,
  created:            Instant,
}

impl NetworkDrain {
  pub fn new(prefix: String, socket: UdpSocket, addr: SocketAddr) -> Self {
    NetworkDrain {
      queue:  VecDeque::new(),
      prefix,
      remote: LineWriter::with_capacity(2048, MetricSocket {
        addr, socket
      }),
      is_writable: true,
      data: BTreeMap::new(),
      app_data: HashMap::new(),
      backend_data: HashMap::new(),
      use_tagged_metrics: false,
      origin: String::from("x"),
      created: Instant::now(),
    }
  }

  pub fn writable(&mut self) {
    self.is_writable = true;
  }

  pub fn send_data(&mut self) {
    let now  = Instant::now();
    let secs = Duration::new(2, 0);
    let mut send_count = 0;

    // remove metrics that were not touched in the last 10mn
    self.app_data.retain(|ref key, ref value| value.updated || now.duration_since(value.last_sent) < Duration::new(600, 00));
    self.backend_data.retain(|ref key, ref value| value.updated || now.duration_since(value.last_sent) < Duration::new(600, 00));

    if self.is_writable {

    for (ref key, ref mut stored_metric) in self.data.iter_mut().filter(|&(_, ref value)| value.updated && now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|g\n", self.prefix, key, self.origin, VERSION, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|g\n", self.prefix, self.origin, key, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|c\n", self.prefix, key, self.origin, VERSION, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|c\n", self.prefix, self.origin, key, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
          stored_metric.updated = false;

          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing global metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.app_data.iter_mut().filter(|&(_, ref value)| value.updated && now.duration_since(value.last_sent) > secs) {
      //info!("will write {:?} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|g\n",
              self.prefix, key.1, self.origin, VERSION, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|c\n",
              self.prefix, key.1, self.origin, VERSION, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
          stored_metric.updated = false;

          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing app metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.backend_data.iter_mut().filter(|&(_, ref value)| value.updated && now.duration_since(value.last_sent) > secs) {
      //info!("will write {:?} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|g\n",
              self.prefix, key.2, self.origin, VERSION, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|c\n",
              self.prefix, key.2, self.origin, VERSION, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
          stored_metric.updated = false;

          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) =self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing backend metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }
    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }

    if self.is_writable {
    for metric in self.queue.drain(..) {
       let res = match (metric.app_id, metric.backend_id) {
        (Some(app_id), Some(backend_id)) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, app_id, backend_id, metric.duration))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|ms\n", self.prefix, self.origin, app_id, backend_id,
              metric.label, metric.duration))
          }
        },
        (Some(app_id), None) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, app_id, metric.duration))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|ms\n", self.prefix, self.origin, app_id,
              metric.label, metric.duration))
          }
        },
        (None, None) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, metric.duration))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|ms\n", self.prefix, self.origin,
              metric.label, metric.duration))
          }
        },
        _ => { Ok(()) }
      };

      match res {
        Ok(()) => {
          send_count += 1;
          if send_count >= 10 {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
            send_count = 0;
          }
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            if let Err(e) = self.remote.flush() {
              error!("error flushing metrics socket: {:?}", e);
            }
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing timing metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }

    if let Err(e) = self.remote.flush() {
      error!("error flushing metrics socket: {:?}", e);
    }
    }
  }
}

impl Subscriber for NetworkDrain {
  fn receive_metric(&mut self, key: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if metric.is_time() {
      if let MetricData::Time(millis) = metric {
        self.queue.push_back(MetricLine {
          label: key,
          app_id: app_id.map(|s| s.to_string()),
          backend_id: backend_id.map(|s| s.to_string()),
          duration: millis,
        });
      }
    } else if let Some(id) = app_id {
      if let Some(bid) = backend_id {
        let k = (String::from(id), String::from(bid), String::from(key));
        if !self.backend_data.contains_key(&k) {
          self.backend_data.insert(
            k,
            StoredMetricData::new(self.created, metric)
            );
        } else {
          self.backend_data.get_mut(&k).map(|stored_metric| {
            stored_metric.update(key, metric);
          });
        }
      } else {
        let k = (String::from(id), String::from(key));
        if !self.app_data.contains_key(&k) {
          self.app_data.insert(
            k,
            StoredMetricData::new(self.created, metric)
            );
        } else {
          self.app_data.get_mut(&k).map(|stored_metric| {
            stored_metric.update(key, metric);
          });
        }
      }
    } else if !self.data.contains_key(key) {
      self.data.insert(
        String::from(key),
        StoredMetricData::new(self.created, metric)
        );
    } else {
      self.data.get_mut(key).map(|stored_metric| {
        stored_metric.update(key, metric);
      });
    }
  }
}

<|endoftext|>


<commit_before>//! An asynchronous `Mutex`-like type.
//!
//! This module provides [`Mutex`], a type that acts similarly to an asynchronous `Mutex`, with one
//! major difference: the [`MutexGuard`] returned by `lock` is not tied to the lifetime of the
//! `Mutex`. This enables you to acquire a lock, and then pass that guard into a future, and then
//! release it at some later point in time.
//!
//! This allows you to do something along the lines of:
//!
//! ```rust,no_run
//! use tokio::sync::Mutex;
//! use std::sync::Arc;
//!
//! #[tokio::main]
//! async fn main() {
//!     let data1 = Arc::new(Mutex::new(0));
//!     let data2 = Arc::clone(&data1);
//!
//!     tokio::spawn(async move {
//!         let mut lock = data2.lock().await;
//!         *lock += 1;
//!     });
//!
//!     let mut lock = data1.lock().await;
//!     *lock += 1;
//! }
//! ```
//!
//! [`Mutex`]: struct.Mutex.html
//! [`MutexGuard`]: struct.MutexGuard.html

use crate::future::poll_fn;
use crate::sync::semaphore;

use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Deref, DerefMut};

/// An asynchronous mutual exclusion primitive useful for protecting shared data
///
/// Each mutex has a type parameter (`T`) which represents the data that it is protecting. The data
/// can only be accessed through the RAII guards returned from `lock`, which
/// guarantees that the data is only ever accessed when the mutex is locked.
#[derive(Debug)]
pub struct Mutex<T> {
    c: UnsafeCell<T>,
    s: semaphore::Semaphore,
}

/// A handle to a held `Mutex`.
///
/// As long as you have this guard, you have exclusive access to the underlying `T`. The guard
/// internally keeps a reference-couned pointer to the original `Mutex`, so even if the lock goes
/// away, the guard remains valid.
///
/// The lock is automatically released whenever the guard is dropped, at which point `lock`
/// will succeed yet again.
#[derive(Debug)]
pub struct MutexGuard<'a, T> {
    lock: &'a Mutex<T>,
    permit: semaphore::Permit,
}

// As long as T: Send, it's fine to send and share Mutex<T> between threads.
// If T was not Send, sending and sharing a Mutex<T> would be bad, since you can access T through
// Mutex<T>.
unsafe impl<T> Send for Mutex<T> where T: Send {}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
unsafe impl<'a, T> Sync for MutexGuard<'a, T> where T: Send + Sync {}

#[test]
#[cfg(not(loom))]
fn bounds() {
    fn check<T: Send>() {}
    check::<MutexGuard<'_, u32>>();
}

impl<T> Mutex<T> {
    /// Creates a new lock in an unlocked state ready for use.
    pub fn new(t: T) -> Self {
        Self {
            c: UnsafeCell::new(t),
            s: semaphore::Semaphore::new(1),
        }
    }

    /// A future that resolves on acquiring the lock and returns the `MutexGuard`.
    pub async fn lock(&self) -> MutexGuard<'_, T> {
        let mut guard = MutexGuard {
            lock: self,
            permit: semaphore::Permit::new(),
        };
        poll_fn(|cx| guard.permit.poll_acquire(cx, &self.s))
            .await
            .unwrap_or_else(|_| {
                // The semaphore was closed. but, we never explicitly close it, and we have a
                // handle to it through the Arc, which means that this can never happen.
                unreachable!()
            });
        guard
    }
}

impl<'a, T> Drop for MutexGuard<'a, T> {
    fn drop(&mut self) {
        self.permit.release(&self.lock.s);
    }
}

impl<T> From<T> for Mutex<T> {
    fn from(s: T) -> Self {
        Self::new(s)
    }
}

impl<T> Default for Mutex<T>
where
    T: Default,
{
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<'a, T> Deref for MutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &*self.lock.c.get() }
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &mut *self.lock.c.get() }
    }
}

impl<'a, T: fmt::Display> fmt::Display for MutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}
<commit_msg>sync::Mutex: Add note about the absence of poisoning (#1933)<commit_after>//! An asynchronous `Mutex`-like type.
//!
//! This module provides [`Mutex`], a type that acts similarly to an asynchronous `Mutex`, with one
//! major difference: the [`MutexGuard`] returned by `lock` is not tied to the lifetime of the
//! `Mutex`. This enables you to acquire a lock, and then pass that guard into a future, and then
//! release it at some later point in time.
//!
//! This allows you to do something along the lines of:
//!
//! ```rust,no_run
//! use tokio::sync::Mutex;
//! use std::sync::Arc;
//!
//! #[tokio::main]
//! async fn main() {
//!     let data1 = Arc::new(Mutex::new(0));
//!     let data2 = Arc::clone(&data1);
//!
//!     tokio::spawn(async move {
//!         let mut lock = data2.lock().await;
//!         *lock += 1;
//!     });
//!
//!     let mut lock = data1.lock().await;
//!     *lock += 1;
//! }
//! ```
//!
//! Note that in contrast to `std::sync::Mutex`, this implementation does not
//! poison the mutex when a thread holding the `MutexGuard` panics. In such a
//! case, the mutex will be unlocked. If the panic is caught, this might leave
//! the data protected by the mutes in an inconsistent state.
//!
//! [`Mutex`]: struct.Mutex.html
//! [`MutexGuard`]: struct.MutexGuard.html

use crate::future::poll_fn;
use crate::sync::semaphore;

use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Deref, DerefMut};

/// An asynchronous mutual exclusion primitive useful for protecting shared data
///
/// Each mutex has a type parameter (`T`) which represents the data that it is protecting. The data
/// can only be accessed through the RAII guards returned from `lock`, which
/// guarantees that the data is only ever accessed when the mutex is locked.
#[derive(Debug)]
pub struct Mutex<T> {
    c: UnsafeCell<T>,
    s: semaphore::Semaphore,
}

/// A handle to a held `Mutex`.
///
/// As long as you have this guard, you have exclusive access to the underlying `T`. The guard
/// internally keeps a reference-couned pointer to the original `Mutex`, so even if the lock goes
/// away, the guard remains valid.
///
/// The lock is automatically released whenever the guard is dropped, at which point `lock`
/// will succeed yet again.
#[derive(Debug)]
pub struct MutexGuard<'a, T> {
    lock: &'a Mutex<T>,
    permit: semaphore::Permit,
}

// As long as T: Send, it's fine to send and share Mutex<T> between threads.
// If T was not Send, sending and sharing a Mutex<T> would be bad, since you can access T through
// Mutex<T>.
unsafe impl<T> Send for Mutex<T> where T: Send {}
unsafe impl<T> Sync for Mutex<T> where T: Send {}
unsafe impl<'a, T> Sync for MutexGuard<'a, T> where T: Send + Sync {}

#[test]
#[cfg(not(loom))]
fn bounds() {
    fn check<T: Send>() {}
    check::<MutexGuard<'_, u32>>();
}

impl<T> Mutex<T> {
    /// Creates a new lock in an unlocked state ready for use.
    pub fn new(t: T) -> Self {
        Self {
            c: UnsafeCell::new(t),
            s: semaphore::Semaphore::new(1),
        }
    }

    /// A future that resolves on acquiring the lock and returns the `MutexGuard`.
    pub async fn lock(&self) -> MutexGuard<'_, T> {
        let mut guard = MutexGuard {
            lock: self,
            permit: semaphore::Permit::new(),
        };
        poll_fn(|cx| guard.permit.poll_acquire(cx, &self.s))
            .await
            .unwrap_or_else(|_| {
                // The semaphore was closed. but, we never explicitly close it, and we have a
                // handle to it through the Arc, which means that this can never happen.
                unreachable!()
            });
        guard
    }
}

impl<'a, T> Drop for MutexGuard<'a, T> {
    fn drop(&mut self) {
        self.permit.release(&self.lock.s);
    }
}

impl<T> From<T> for Mutex<T> {
    fn from(s: T) -> Self {
        Self::new(s)
    }
}

impl<T> Default for Mutex<T>
where
    T: Default,
{
    fn default() -> Self {
        Self::new(T::default())
    }
}

impl<'a, T> Deref for MutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &*self.lock.c.get() }
    }
}

impl<'a, T> DerefMut for MutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        assert!(self.permit.is_acquired());
        unsafe { &mut *self.lock.c.get() }
    }
}

impl<'a, T: fmt::Display> fmt::Display for MutexGuard<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}
<|endoftext|>


<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u16,OpcodeExecInfo>,
}

impl CpuExecutor {
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u16, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
    }
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState,mut mem:&Memory) {
    }
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        self.execute(cpu_state,mem);
    }
}
<commit_msg>the fetch part of 'fetch_and_decode' is implemented<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use memory::Memory;
use std::collections::HashMap;

pub struct CpuExecutor {
    op_table: HashMap<u16,OpcodeExecInfo>,
}

impl CpuExecutor {
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        // Construct the HashMap and copy it over to CpuExecutor's constructor.
        let mut op_table_temp: HashMap<u16, OpcodeExecInfo> = HashMap::new();
        for oc in opcodes {
            if op_table_temp.contains_key(&oc.opcode) {
                println!("Encountered duplicate opcode: {:#x}", oc.opcode);
                println!("Replacing previous opcode, which was {{ opcode: {:#x}, len: {}, cycles: {}, page_cycles: {} }}", oc.opcode, oc.len, oc.cycles, oc.page_cycles);
            }
            op_table_temp.insert(oc.opcode, oc);
        }

        CpuExecutor {
            op_table: op_table_temp,
        }
    }

    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.pc=cpu_state.pc+1;
    }
    pub fn execute(self: &CpuExecutor, mut cpu_state: &CpuState,mut mem:&Memory) {
    }
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) {
        self.fetch_and_decode(cpu_state,mem);
        self.execute(cpu_state,mem);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(unused_unsafe)];
#[deny(unsafe_block)];

unsafe fn allowed() {}

#[allow(unsafe_block)] fn also_allowed() { unsafe {} }

fn main() {
    unsafe {} //~ ERROR: usage of an `unsafe` block
}
<commit_msg>test: test that the `unsafe_block` lint picks up `unsafe` blocks in macros.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[allow(unused_unsafe)];
#[deny(unsafe_block)];
#[feature(macro_rules)];

unsafe fn allowed() {}

#[allow(unsafe_block)] fn also_allowed() { unsafe {} }

macro_rules! unsafe_in_macro {
    () => {
        unsafe {} //~ ERROR: usage of an `unsafe` block
    }
}

fn main() {
    unsafe {} //~ ERROR: usage of an `unsafe` block

    unsafe_in_macro!()
}
<|endoftext|>


<commit_before>//! This module is UNSTABLE, the reason is - recently added.

use std::convert::From;
use std::io::{self, Read, BufRead};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::ValueRef;

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to fill the internal reader buffer.
    ///
    /// RMP tries to obtain the buffer at the beginning of read operation using `read_buf` function.
    ///
    /// According to the Rust documentation, `fill_buf` function will return an I/O error if the
    /// underlying reader was read, but returned an error.
    InvalidBufferFill(io::Error),
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),

    // length overflow (read length >= usize -> cannot be sliced).

    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str(buf: &[u8], len: usize) -> Result<&str, Error> {
    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

// NOTE: Consumes nothing from the given `BufRead` either on success or fail.
pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let mut buf = try!(rd.fill_buf().map_err(|err| Error::InvalidBufferFill(err)));

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `buf`, not from the `rd`.
    let marker = try!(read_marker(&mut buf));

    let val = match marker {
        Marker::FixedString(len) => {
            // Impossible to panic, since u8 always fits in usize.
            let len = len as usize;
            let res = try!(read_str(buf, len));
            ValueRef::String(res)
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));

            // Impossible to panic, since u8 always fits in usize.
            let len = len as usize;
            let res = try!(read_str(buf, len));
            ValueRef::String(res)
        }
        Marker::Str16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));

            // TODO: This can overflow on 8-bit systems.
            let len = len as usize;
            let res = try!(read_str(buf, len));
            ValueRef::String(res)
        }
        Marker::Str32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));

            // TODO: This can overflow on 8- and 16-bit systems.
            let len = len as usize;
            let res = try!(read_str(buf, len));
            ValueRef::String(res)
        }
        _ => unimplemented!(),
    };

    Ok(val)
}

// TODO: Concepts: less code; more tests; fast refactoring after each test; no more than 5 min for
// each red-yellow-green.
<commit_msg>ValueRef: functional decomposition.<commit_after>//! This module is UNSTABLE, the reason is - recently added.

use std::convert::From;
use std::io::{self, Read, BufRead};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::ValueRef;

trait USizeCast {
    fn from(v: Self) -> Option<usize> where Self: Sized;
}

impl USizeCast for u8 {
    fn from(v: u8) -> Option<usize> {
        // Impossible to panic, since u8 always fits in usize.
        Some(v as usize)
    }
}

impl USizeCast for u16 {
    fn from(v: u16) -> Option<usize> {
        // TODO: This can overflow on 8-bit systems.
        Some(v as usize)
    }
}

impl USizeCast for u32 {
    fn from(v: u32) -> Option<usize> {
        // TODO: This can overflow on 8- and 16-bit systems.
        Some(v as usize)
    }
}

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to fill the internal reader buffer.
    ///
    /// RMP tries to obtain the buffer at the beginning of read operation using `read_buf` function.
    ///
    /// According to the Rust documentation, `fill_buf` function will return an I/O error if the
    /// underlying reader was read, but returned an error.
    InvalidBufferFill(io::Error),
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),

    /// Failed to cast the length read to machine size.
    InvalidLengthSize,

    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str(buf: &[u8], len: usize) -> Result<&str, Error> {
    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

#[inline]
fn read_str_value<U>(buf: &[u8], len: U) -> Result<ValueRef, Error>
    where U: USizeCast
{
    let len = try!(U::from(len).ok_or(Error::InvalidLengthSize));
    let res = try!(read_str(buf, len));

    Ok(ValueRef::String(res))
}

// NOTE: Consumes nothing from the given `BufRead` either on success or fail.
pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let mut buf = try!(rd.fill_buf().map_err(|err| Error::InvalidBufferFill(err)));

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `buf`, not from the `rd`.
    let marker = try!(read_marker(&mut buf));

    let val = match marker {
        Marker::FixedString(len) => {
            try!(read_str_value(buf, len))
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(buf, len))
        }
        Marker::Str16 => {
            let len: u16 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(buf, len))
        }
        Marker::Str32 => {
            let len: u32 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));
            try!(read_str_value(buf, len))
        }
        _ => unimplemented!(),
    };

    Ok(val)
}

// TODO: Concepts: less code; more tests; fast refactoring after each test; no more than 5 min for
// each red-yellow-green.
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::fmt;
use term;
use time::precise_time_s;

/// Keep track of this many past download amounts
const DOWNLOAD_TRACK_COUNT: usize = 5;

/// Tracks download progress and displays information about it to a terminal.
pub struct DownloadTracker {
    /// Content-Length of the to-be downloaded object.
    content_len: Option<u64>,
    /// Total data downloaded in bytes.
    total_downloaded: usize,
    /// Data downloaded this second.
    downloaded_this_sec: usize,
    /// Keeps track of amount of data downloaded every last few secs.
    /// Used for averaging the download speed.
    downloaded_last_few_secs: VecDeque<usize>,
    /// Time stamp of the last second
    last_sec: Option<f64>,
    /// How many seconds have elapsed since the download started
    seconds_elapsed: u32,
    /// The terminal we write the information to.
    term: Box<term::StdoutTerminal>,
}

impl DownloadTracker {
    /// Creates a new DownloadTracker.
    pub fn new() -> Self {
        DownloadTracker {
            content_len: None,
            total_downloaded: 0,
            downloaded_this_sec: 0,
            downloaded_last_few_secs: VecDeque::with_capacity(DOWNLOAD_TRACK_COUNT),
            seconds_elapsed: 0,
            last_sec: None,
            term: term::stdout().expect("Failed to open terminal"),
        }
    }
    /// Notifies self that Content-Length information has been received.
    pub fn content_length_received(&mut self, content_len: u64) {
        self.content_len = Some(content_len);
    }
    /// Notifies self that data of size `len` has been received.
    pub fn data_received(&mut self, len: usize) {
        self.total_downloaded += len;
        self.downloaded_this_sec += len;

        match self.last_sec {
            None => self.last_sec = Some(precise_time_s()),
            Some(start) => {
                let elapsed = precise_time_s() - start;
                if elapsed >= 1.0 {
                    self.seconds_elapsed += 1;

                    self.display();
                    self.last_sec = Some(precise_time_s());
                    if self.downloaded_last_few_secs.len() == DOWNLOAD_TRACK_COUNT {
                        self.downloaded_last_few_secs.pop_back();
                    }
                    self.downloaded_last_few_secs.push_front(self.downloaded_this_sec);
                    self.downloaded_this_sec = 0;
                }
            }
        }
    }
    /// Notifies self that the download has finished.
    pub fn download_finished(&mut self) {
        let _ = writeln!(&mut self.term, "");
        self.last_sec = None;
    }
    /// Display the tracked download information to the terminal.
    fn display(&mut self) {
        let total_h = HumanReadable(self.total_downloaded as f64);

        match self.content_len {
            Some(content_len) => {
                use std::borrow::Cow;

                let percent = (self.total_downloaded as f64 / content_len as f64) * 100.;
                let content_len_h = HumanReadable(content_len as f64);
                let remaining = content_len - self.total_downloaded as u64;
                let sum = self.downloaded_last_few_secs
                              .iter()
                              .fold(0usize, |a, &v| a + v);
                let len = self.downloaded_last_few_secs.len();
                let speed = if len > 0 {
                    (sum / len) as u64
                } else {
                    0
                };
                let eta = if speed > 0 {
                    Cow::Owned(format!("{}s", remaining / speed))
                } else {
                    Cow::Borrowed("Unknown")
                };
                let _ = write!(&mut self.term,
                               "{} / {} ({:.2}%) ~{}/s ETA: {}",
                               total_h,
                               content_len_h,
                               percent,
                               HumanReadable(speed as f64),
                               eta);
            }
            None => {
                let _ = write!(&mut self.term, "{}", total_h);
            }
        }
        // delete_line() doesn't seem to clear the line properly.
        // Instead, let's just print some whitespace to clear it.
        let _ = write!(&mut self.term, "                ");
        let _ = self.term.flush();
        let _ = self.term.carriage_return();
    }
}

/// Human readable representation of data size in bytes
struct HumanReadable<T>(T);

impl<T: Into<f64> + Clone> fmt::Display for HumanReadable<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const KIB: f64 = 1024.0;
        const MIB: f64 = 1048576.0;
        let size: f64 = self.0.clone().into();

        if size >= MIB {
            write!(f, "{:.2} MiB", size / MIB)
        } else if size >= KIB {
            write!(f, "{:.2} KiB", size / KIB)
        } else {
            write!(f, "{} B", size)
        }
    }
}
<commit_msg>Present download speed info even if we don't have Content-Length info<commit_after>use std::collections::VecDeque;
use std::fmt;
use term;
use time::precise_time_s;

/// Keep track of this many past download amounts
const DOWNLOAD_TRACK_COUNT: usize = 5;

/// Tracks download progress and displays information about it to a terminal.
pub struct DownloadTracker {
    /// Content-Length of the to-be downloaded object.
    content_len: Option<u64>,
    /// Total data downloaded in bytes.
    total_downloaded: usize,
    /// Data downloaded this second.
    downloaded_this_sec: usize,
    /// Keeps track of amount of data downloaded every last few secs.
    /// Used for averaging the download speed.
    downloaded_last_few_secs: VecDeque<usize>,
    /// Time stamp of the last second
    last_sec: Option<f64>,
    /// How many seconds have elapsed since the download started
    seconds_elapsed: u32,
    /// The terminal we write the information to.
    term: Box<term::StdoutTerminal>,
}

impl DownloadTracker {
    /// Creates a new DownloadTracker.
    pub fn new() -> Self {
        DownloadTracker {
            content_len: None,
            total_downloaded: 0,
            downloaded_this_sec: 0,
            downloaded_last_few_secs: VecDeque::with_capacity(DOWNLOAD_TRACK_COUNT),
            seconds_elapsed: 0,
            last_sec: None,
            term: term::stdout().expect("Failed to open terminal"),
        }
    }
    /// Notifies self that Content-Length information has been received.
    pub fn content_length_received(&mut self, content_len: u64) {
        self.content_len = Some(content_len);
    }
    /// Notifies self that data of size `len` has been received.
    pub fn data_received(&mut self, len: usize) {
        self.total_downloaded += len;
        self.downloaded_this_sec += len;

        match self.last_sec {
            None => self.last_sec = Some(precise_time_s()),
            Some(start) => {
                let elapsed = precise_time_s() - start;
                if elapsed >= 1.0 {
                    self.seconds_elapsed += 1;

                    self.display();
                    self.last_sec = Some(precise_time_s());
                    if self.downloaded_last_few_secs.len() == DOWNLOAD_TRACK_COUNT {
                        self.downloaded_last_few_secs.pop_back();
                    }
                    self.downloaded_last_few_secs.push_front(self.downloaded_this_sec);
                    self.downloaded_this_sec = 0;
                }
            }
        }
    }
    /// Notifies self that the download has finished.
    pub fn download_finished(&mut self) {
        let _ = writeln!(&mut self.term, "");
        self.last_sec = None;
    }
    /// Display the tracked download information to the terminal.
    fn display(&mut self) {
        let total_h = HumanReadable(self.total_downloaded as f64);
        let sum = self.downloaded_last_few_secs
                      .iter()
                      .fold(0usize, |a, &v| a + v);
        let len = self.downloaded_last_few_secs.len();
        let speed = if len > 0 {
            (sum / len) as u64
        } else {
            0
        };
        let speed_h = HumanReadable(speed as f64);

        match self.content_len {
            Some(content_len) => {
                use std::borrow::Cow;

                let percent = (self.total_downloaded as f64 / content_len as f64) * 100.;
                let content_len_h = HumanReadable(content_len as f64);
                let remaining = content_len - self.total_downloaded as u64;
                let eta = if speed > 0 {
                    Cow::Owned(format!("{}s", remaining / speed))
                } else {
                    Cow::Borrowed("Unknown")
                };
                let _ = write!(&mut self.term,
                               "{} / {} ({:.2}%) ~{}/s ETA: {}",
                               total_h,
                               content_len_h,
                               percent,
                               speed_h,
                               eta);
            }
            None => {
                let _ = write!(&mut self.term, "Total: {} Speed: {}/s", total_h, speed_h);
            }
        }
        // delete_line() doesn't seem to clear the line properly.
        // Instead, let's just print some whitespace to clear it.
        let _ = write!(&mut self.term, "                ");
        let _ = self.term.flush();
        let _ = self.term.carriage_return();
    }
}

/// Human readable representation of data size in bytes
struct HumanReadable<T>(T);

impl<T: Into<f64> + Clone> fmt::Display for HumanReadable<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        const KIB: f64 = 1024.0;
        const MIB: f64 = 1048576.0;
        let size: f64 = self.0.clone().into();

        if size >= MIB {
            write!(f, "{:.2} MiB", size / MIB)
        } else if size >= KIB {
            write!(f, "{:.2} KiB", size / KIB)
        } else {
            write!(f, "{} B", size)
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;
use libimagerror::into::IntoError;

use error::LinkErrorKind as LEK;
use error::MapErrInto;
use result::Result;

use toml::Value;
use itertools::Itertools;

pub type Link = StoreId;

pub trait InternalLinker {

    /// Get the internal links from the implementor object
    fn get_internal_links(&self) -> Result<Vec<Link>>;

    /// Set the internal links for the implementor object
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>>;

    /// Add an internal link to the implementor object
    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>;

    /// Remove an internal link from the implementor object
    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>;

}

impl InternalLinker for Entry {

    fn get_internal_links(&self) -> Result<Vec<Link>> {
        process_rw_result(self.get_header().read("imag.links"))
    }

    /// Set the links in a header and return the old links, if any.
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>> {
        let self_location = self.get_location().clone();
        let mut new_links = vec![];

        for link in links {
            if let Err(e) = add_foreign_link(link, self_location.clone()) {
                return Err(e);
            }
            let link = link.get_location().clone();
            new_links.push(link);
        }

        let new_links = try!(links_into_values(new_links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    elem.map_err_into(LEK::InternalConversionError)
                                        .map(|e| {
                                            v.push(e);
                                            v
                                        })
                                })
                            }));
        process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
    }

    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let new_link = link.get_location().clone();

        add_foreign_link(link, self.get_location().clone())
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|mut links| {
                        links.push(new_link);
                        rewrite_links(self.get_header_mut(), links)
                    })
            })
    }

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let own_loc   = link.get_location().clone();
        let other_loc = link.get_location().clone();

        link.get_internal_links()
            .and_then(|links| {
                let links = links.into_iter().filter(|l| l.clone() != own_loc).collect();
                rewrite_links(self.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        let links = links.into_iter().filter(|l| l.clone() != other_loc).collect();
                        rewrite_links(link.get_header_mut(), links)
                    })
            })
    }

}

fn links_into_values(links: Vec<StoreId>) -> Vec<Result<Value>> {
    links
        .into_iter()
        .unique()
        .map(|s| s.without_base().to_str().map_err_into(LEK::InternalConversionError))
        .map(|elem| elem.map(Value::String))
        .sorted_by(|a, b| {
            match (a, b) {
                (&Ok(Value::String(ref a)), &Ok(Value::String(ref b))) => Ord::cmp(a, b),
                (&Err(_), _) | (_, &Err(_)) => Ordering::Equal,
                _ => unreachable!()
            }
        })
}

fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
    let links = try!(links_into_values(links)
                     .into_iter()
                     .fold(Ok(vec![]), |acc, elem| {
                        acc.and_then(move |mut v| {
                            elem.map_err_into(LEK::InternalConversionError)
                                .map(|e| {
                                    v.push(e);
                                    v
                                })
                        })
                     }));

    let process = header.set("imag.links", Value::Array(links));
    process_rw_result(process).map(|_| ())
}

/// When Linking A -> B, the specification wants us to link back B -> A.
/// This is a helper function which does this.
fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
    target.get_internal_links()
        .and_then(|mut links| {
            links.push(from);
            let links = try!(links_into_values(links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    elem.map_err_into(LEK::InternalConversionError)
                                        .map(|e| {
                                            v.push(e);
                                            v
                                        })
                                })
                             }));
            process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
                .map(|_| ())
        })
}

fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
    use std::path::PathBuf;

    let links = match links {
        Err(e) => {
            debug!("RW action on store failed. Generating LinkError");
            return Err(LEK::EntryHeaderReadError.into_error_with_cause(Box::new(e)))
        },
        Ok(None) => {
            debug!("We got no value from the header!");
            return Ok(vec![])
        },
        Ok(Some(Value::Array(l))) => l,
        Ok(Some(_)) => {
            debug!("We expected an Array for the links, but there was a non-Array!");
            return Err(LEK::ExistingLinkTypeWrong.into());
        }
    };

    if !links.iter().all(|l| is_match!(*l, Value::String(_))) {
        debug!("At least one of the Values which were expected in the Array of links is a non-String!");
        debug!("Generating LinkError");
        return Err(LEK::ExistingLinkTypeWrong.into());
    }

    let links : Vec<Link> = try!(links.into_iter()
        .map(|link| {
            match link {
                Value::String(s) => StoreId::new_baseless(PathBuf::from(s))
                    .map_err_into(LEK::StoreIdError),
                _ => unreachable!(),
            }
        })
        .collect());

    debug!("Ok, the RW action was successful, returning link vector now!");
    Ok(links)
}

<commit_msg>Bugfix: unique()ing the list of links<commit_after>use std::cmp::Ordering;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;
use libimagerror::into::IntoError;

use error::LinkErrorKind as LEK;
use error::MapErrInto;
use result::Result;

use toml::Value;
use itertools::Itertools;

pub type Link = StoreId;

pub trait InternalLinker {

    /// Get the internal links from the implementor object
    fn get_internal_links(&self) -> Result<Vec<Link>>;

    /// Set the internal links for the implementor object
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>>;

    /// Add an internal link to the implementor object
    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>;

    /// Remove an internal link from the implementor object
    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>;

}

impl InternalLinker for Entry {

    fn get_internal_links(&self) -> Result<Vec<Link>> {
        process_rw_result(self.get_header().read("imag.links"))
    }

    /// Set the links in a header and return the old links, if any.
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>> {
        let self_location = self.get_location().clone();
        let mut new_links = vec![];

        for link in links {
            if let Err(e) = add_foreign_link(link, self_location.clone()) {
                return Err(e);
            }
            let link = link.get_location().clone();
            new_links.push(link);
        }

        let new_links = try!(links_into_values(new_links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    elem.map_err_into(LEK::InternalConversionError)
                                        .map(|e| {
                                            v.push(e);
                                            v
                                        })
                                })
                            }));
        process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
    }

    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let new_link = link.get_location().clone();

        add_foreign_link(link, self.get_location().clone())
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|mut links| {
                        links.push(new_link);
                        rewrite_links(self.get_header_mut(), links)
                    })
            })
    }

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let own_loc   = link.get_location().clone();
        let other_loc = link.get_location().clone();

        link.get_internal_links()
            .and_then(|links| {
                let links = links.into_iter().filter(|l| l.clone() != own_loc).collect();
                rewrite_links(self.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        let links = links.into_iter().filter(|l| l.clone() != other_loc).collect();
                        rewrite_links(link.get_header_mut(), links)
                    })
            })
    }

}

fn links_into_values(links: Vec<StoreId>) -> Vec<Result<Value>> {
    links
        .into_iter()
        .map(|s| s.without_base().to_str().map_err_into(LEK::InternalConversionError))
        .unique_by(|entry| {
            match entry {
                &Ok(ref e) => Some(e.clone()),
                &Err(_) => None,
            }
        })
        .map(|elem| elem.map(Value::String))
        .sorted_by(|a, b| {
            match (a, b) {
                (&Ok(Value::String(ref a)), &Ok(Value::String(ref b))) => Ord::cmp(a, b),
                (&Err(_), _) | (_, &Err(_)) => Ordering::Equal,
                _ => unreachable!()
            }
        })
}

fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
    let links = try!(links_into_values(links)
                     .into_iter()
                     .fold(Ok(vec![]), |acc, elem| {
                        acc.and_then(move |mut v| {
                            elem.map_err_into(LEK::InternalConversionError)
                                .map(|e| {
                                    v.push(e);
                                    v
                                })
                        })
                     }));

    let process = header.set("imag.links", Value::Array(links));
    process_rw_result(process).map(|_| ())
}

/// When Linking A -> B, the specification wants us to link back B -> A.
/// This is a helper function which does this.
fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
    target.get_internal_links()
        .and_then(|mut links| {
            links.push(from);
            let links = try!(links_into_values(links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    elem.map_err_into(LEK::InternalConversionError)
                                        .map(|e| {
                                            v.push(e);
                                            v
                                        })
                                })
                             }));
            process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
                .map(|_| ())
        })
}

fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
    use std::path::PathBuf;

    let links = match links {
        Err(e) => {
            debug!("RW action on store failed. Generating LinkError");
            return Err(LEK::EntryHeaderReadError.into_error_with_cause(Box::new(e)))
        },
        Ok(None) => {
            debug!("We got no value from the header!");
            return Ok(vec![])
        },
        Ok(Some(Value::Array(l))) => l,
        Ok(Some(_)) => {
            debug!("We expected an Array for the links, but there was a non-Array!");
            return Err(LEK::ExistingLinkTypeWrong.into());
        }
    };

    if !links.iter().all(|l| is_match!(*l, Value::String(_))) {
        debug!("At least one of the Values which were expected in the Array of links is a non-String!");
        debug!("Generating LinkError");
        return Err(LEK::ExistingLinkTypeWrong.into());
    }

    let links : Vec<Link> = try!(links.into_iter()
        .map(|link| {
            match link {
                Value::String(s) => StoreId::new_baseless(PathBuf::from(s))
                    .map_err_into(LEK::StoreIdError),
                _ => unreachable!(),
            }
        })
        .collect());

    debug!("Ok, the RW action was successful, returning link vector now!");
    Ok(links)
}

<|endoftext|>


<commit_before>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
            // to optimize it into a branchless form (see also #75545):
            //
            // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
            //    in both branches, i.e. the `else` must have its `- 1`
            //    subtraction after the common one, not interleaved with it
            //    (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
            //
            // 2. the `Duration::new` call (or any other additional complexity)
            //    is outside of the `if`-`else`, not duplicated in both branches
            //
            // Ideally this code could be rearranged such that it more
            // directly expresses the lower-cost behavior we want from it.
            let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
                ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
            } else {
                (
                    (self.t.tv_sec - other.t.tv_sec - 1) as u64,
                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
                )
            };

            Ok(Duration::new(secs, nsec))
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::sync::atomic::{AtomicBool, AtomicU64, Ordering};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::Timespec;
    use super::NSEC_PER_SEC;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
            return SystemTime::from(s);
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos =
            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        static INITIALIZED: AtomicBool = AtomicBool::new(false);
        static INFO_BITS: AtomicU64 = AtomicU64::new(0);

        // If a previous thread has filled in this global INITIALIZED, use that.
        if INITIALIZED.load(Ordering::Acquire) {
            // The Acquire/Release pair used for INITIALIZED ensures that this
            // load can see the corresponding `INFO_BITS` store, despite them
            // both being Relaxed.
            return info_from_bits(INFO_BITS.load(Ordering::Relaxed));
        }

        // ... otherwise learn for ourselves ...
        extern "C" {
            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
        }

        let mut info = info_from_bits(0);
        unsafe {
            mach_timebase_info(&mut info);
        }

        // Note: This is racy, but the race is against other threads trying to
        // write the same value.
        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);

        // The `Release` here "publishes" the store of `INFO_BITS` to other
        // threads (which do a `INITIALIZED.load(Acquire)`) despite it being
        // read/written w/ `Relaxed`.
        INITIALIZED.store(true, Ordering::Release);
        info
    }

    #[inline]
    fn info_to_bits(info: mach_timebase_info) -> u64 {
        ((info.denom as u64) << 32) | (info.numer as u64)
    }

    #[inline]
    fn info_from_bits(bits: u64) -> mach_timebase_info {
        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant { t: Timespec::zero() }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
                || cfg!(target_os = "fuchsia")
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    #[cfg(not(target_os = "dragonfly"))]
    pub type clock_t = libc::c_int;
    #[cfg(target_os = "dragonfly")]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
        t
    }
}
<commit_msg>Fiddle with the comments<commit_after>use crate::cmp::Ordering;
use crate::time::Duration;

use core::hash::{Hash, Hasher};

pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;

const NSEC_PER_SEC: u64 = 1_000_000_000;

#[derive(Copy, Clone)]
struct Timespec {
    t: libc::timespec,
}

impl Timespec {
    const fn zero() -> Timespec {
        Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }
    }

    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
        if self >= other {
            // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
            // to optimize it into a branchless form (see also #75545):
            //
            // 1. `self.t.tv_sec - other.t.tv_sec` shows up as a common expression
            //    in both branches, i.e. the `else` must have its `- 1`
            //    subtraction after the common one, not interleaved with it
            //    (it used to be `self.t.tv_sec - 1 - other.t.tv_sec`)
            //
            // 2. the `Duration::new` call (or any other additional complexity)
            //    is outside of the `if`-`else`, not duplicated in both branches
            //
            // Ideally this code could be rearranged such that it more
            // directly expresses the lower-cost behavior we want from it.
            let (secs, nsec) = if self.t.tv_nsec >= other.t.tv_nsec {
                ((self.t.tv_sec - other.t.tv_sec) as u64, (self.t.tv_nsec - other.t.tv_nsec) as u32)
            } else {
                (
                    (self.t.tv_sec - other.t.tv_sec - 1) as u64,
                    self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32,
                )
            };

            Ok(Duration::new(secs, nsec))
        } else {
            match other.sub_timespec(self) {
                Ok(d) => Err(d),
                Err(d) => Ok(d),
            }
        }
    }

    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;

        // Nano calculations can't overflow because nanos are <1B which fit
        // in a u32.
        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
        if nsec >= NSEC_PER_SEC as u32 {
            nsec -= NSEC_PER_SEC as u32;
            secs = secs.checked_add(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }

    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
        let mut secs = other
            .as_secs()
            .try_into() // <- target type would be `libc::time_t`
            .ok()
            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;

        // Similar to above, nanos can't overflow.
        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
        if nsec < 0 {
            nsec += NSEC_PER_SEC as i32;
            secs = secs.checked_sub(1)?;
        }
        Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } })
    }
}

impl PartialEq for Timespec {
    fn eq(&self, other: &Timespec) -> bool {
        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
    }
}

impl Eq for Timespec {}

impl PartialOrd for Timespec {
    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Timespec {
    fn cmp(&self, other: &Timespec) -> Ordering {
        let me = (self.t.tv_sec, self.t.tv_nsec);
        let other = (other.t.tv_sec, other.t.tv_nsec);
        me.cmp(&other)
    }
}

impl Hash for Timespec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.t.tv_sec.hash(state);
        self.t.tv_nsec.hash(state);
    }
}

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod inner {
    use crate::fmt;
    use crate::sync::atomic::{AtomicBool, AtomicU64, Ordering};
    use crate::sys::cvt;
    use crate::sys_common::mul_div_u64;
    use crate::time::Duration;

    use super::Timespec;
    use super::NSEC_PER_SEC;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
    pub struct Instant {
        t: u64,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    #[repr(C)]
    #[derive(Copy, Clone)]
    struct mach_timebase_info {
        numer: u32,
        denom: u32,
    }
    type mach_timebase_info_t = *mut mach_timebase_info;
    type kern_return_t = libc::c_int;

    impl Instant {
        pub fn now() -> Instant {
            extern "C" {
                fn mach_absolute_time() -> u64;
            }
            Instant { t: unsafe { mach_absolute_time() } }
        }

        pub const fn zero() -> Instant {
            Instant { t: 0 }
        }

        pub fn actually_monotonic() -> bool {
            true
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            let diff = self.t.checked_sub(other.t)?;
            let info = info();
            let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
            Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            use crate::ptr;

            let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
            cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
            return SystemTime::from(s);
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timeval> for SystemTime {
        fn from(t: libc::timeval) -> SystemTime {
            SystemTime::from(libc::timespec {
                tv_sec: t.tv_sec,
                tv_nsec: (t.tv_usec * 1000) as libc::c_long,
            })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
        let nanos =
            dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
        let info = info();
        Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
    }

    fn info() -> mach_timebase_info {
        static INITIALIZED: AtomicBool = AtomicBool::new(false);
        static INFO_BITS: AtomicU64 = AtomicU64::new(0);

        // If a previous thread has initialized `INFO_BITS`, use that.
        if INITIALIZED.load(Ordering::Acquire) {
            // Note: `Relaxed` is correct here and below -- the `Acquire` /
            // `Release` pair used for `INITIALIZED` ensures this load can see
            // the corresponding store below.
            return info_from_bits(INFO_BITS.load(Ordering::Relaxed));
        }

        // ... otherwise learn for ourselves ...
        extern "C" {
            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
        }

        let mut info = info_from_bits(0);
        unsafe {
            mach_timebase_info(&mut info);
        }

        // This is racy, but the race should be against other threads trying to
        // write the same value.
        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);

        // The `Release` here "publishes" the store of `INFO_BITS` to other
        // threads (which do a `INITIALIZED.load(Acquire)`) despite it being
        // read/written w/ `Relaxed`.
        INITIALIZED.store(true, Ordering::Release);
        info
    }

    #[inline]
    fn info_to_bits(info: mach_timebase_info) -> u64 {
        ((info.denom as u64) << 32) | (info.numer as u64)
    }

    #[inline]
    fn info_from_bits(bits: u64) -> mach_timebase_info {
        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
    }
}

#[cfg(not(any(target_os = "macos", target_os = "ios")))]
mod inner {
    use crate::fmt;
    use crate::sys::cvt;
    use crate::time::Duration;

    use super::Timespec;

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct Instant {
        t: Timespec,
    }

    #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
    pub struct SystemTime {
        t: Timespec,
    }

    pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };

    impl Instant {
        pub fn now() -> Instant {
            Instant { t: now(libc::CLOCK_MONOTONIC) }
        }

        pub const fn zero() -> Instant {
            Instant { t: Timespec::zero() }
        }

        pub fn actually_monotonic() -> bool {
            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
                || cfg!(target_os = "fuchsia")
        }

        pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
            self.t.sub_timespec(&other.t).ok()
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
            Some(Instant { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl fmt::Debug for Instant {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("Instant")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    impl SystemTime {
        pub fn now() -> SystemTime {
            SystemTime { t: now(libc::CLOCK_REALTIME) }
        }

        pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
            self.t.sub_timespec(&other.t)
        }

        pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_add_duration(other)? })
        }

        pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
            Some(SystemTime { t: self.t.checked_sub_duration(other)? })
        }
    }

    impl From<libc::timespec> for SystemTime {
        fn from(t: libc::timespec) -> SystemTime {
            SystemTime { t: Timespec { t } }
        }
    }

    impl fmt::Debug for SystemTime {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.debug_struct("SystemTime")
                .field("tv_sec", &self.t.t.tv_sec)
                .field("tv_nsec", &self.t.t.tv_nsec)
                .finish()
        }
    }

    #[cfg(not(target_os = "dragonfly"))]
    pub type clock_t = libc::c_int;
    #[cfg(target_os = "dragonfly")]
    pub type clock_t = libc::c_ulong;

    fn now(clock: clock_t) -> Timespec {
        let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } };
        cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap();
        t
    }
}
<|endoftext|>