#![warn(missing_docs)]
extern crate rand;
use std::fmt;
#[macro_use]
mod macros;
pub mod error;
pub trait Trackable {
type Event: From<Location>;
fn track<F>(&mut self, f: F)
where
F: FnOnce() -> Self::Event,
{
self.history_mut().map(|h| h.add(f()));
}
fn assign_tracking_number(&mut self);
fn tracking_number(&self) -> Option<TrackingNumber>;
fn in_tracking(&self) -> bool {
self.history().is_some()
}
fn enable_tracking(self) -> Self
where
Self: Sized;
fn disable_tracking(self) -> Self
where
Self: Sized;
fn history(&self) -> Option<&History<Self::Event>>;
fn history_mut(&mut self) -> Option<&mut History<Self::Event>>;
}
impl<T: Trackable> Trackable for Option<T> {
type Event = T::Event;
fn assign_tracking_number(&mut self) {
self.as_mut().map(|t| t.assign_tracking_number());
}
fn tracking_number(&self) -> Option<TrackingNumber> {
self.as_ref().and_then(|t| t.tracking_number())
}
fn enable_tracking(self) -> Self
where
Self: Sized,
{
self.map(|t| t.enable_tracking())
}
fn disable_tracking(self) -> Self
where
Self: Sized,
{
self.map(|t| t.disable_tracking())
}
fn history(&self) -> Option<&History<Self::Event>> {
self.as_ref().and_then(|t| t.history())
}
fn history_mut(&mut self) -> Option<&mut History<Self::Event>> {
self.as_mut().and_then(|t| t.history_mut())
}
}
impl<T, E: Trackable> Trackable for Result<T, E> {
type Event = E::Event;
fn assign_tracking_number(&mut self) {
self.as_mut().err().map(|t| t.assign_tracking_number());
}
fn tracking_number(&self) -> Option<TrackingNumber> {
self.as_ref().err().and_then(|t| t.tracking_number())
}
fn enable_tracking(self) -> Self
where
Self: Sized,
{
self.map_err(|t| t.enable_tracking())
}
fn disable_tracking(self) -> Self
where
Self: Sized,
{
self.map_err(|t| t.disable_tracking())
}
fn history(&self) -> Option<&History<Self::Event>> {
self.as_ref().err().and_then(|t| t.history())
}
fn history_mut(&mut self) -> Option<&mut History<Self::Event>> {
self.as_mut().err().and_then(|t| t.history_mut())
}
}
#[derive(Debug, Clone)]
pub struct History<Event>(Vec<Event>);
impl<Event> History<Event> {
pub fn new() -> Self {
History(Vec::new())
}
pub fn add(&mut self, event: Event) {
self.0.push(event);
}
pub fn events(&self) -> &[Event] {
&self.0[..]
}
}
impl<Event: fmt::Display> fmt::Display for History<Event> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "HISTORY:")?;
for (i, e) in self.events().iter().enumerate() {
writeln!(f, " [{}] {}", i, e)?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Location {
module_path: &'static str,
file: &'static str,
line: u32,
message: String,
}
impl Location {
pub fn new(module_path: &'static str, file: &'static str, line: u32, message: String) -> Self {
Location {
module_path: module_path,
file: file,
line: line,
message: message,
}
}
pub fn crate_name(&self) -> &'static str {
if let Some(end) = self.module_path.find(":") {
&self.module_path[..end]
} else {
self.module_path
}
}
pub fn module_path(&self) -> &'static str {
self.module_path
}
pub fn file(&self) -> &'static str {
self.file
}
pub fn line(&self) -> u32 {
self.line
}
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for Location {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "at {}:{}", self.file(), self.line())?;
if !self.message().is_empty() {
write!(f, " -- {}", self.message())?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct TrackingNumber(pub u64);
impl TrackingNumber {
pub fn generate() -> Self {
TrackingNumber(rand::random())
}
}
impl fmt::Display for TrackingNumber {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:08x}", self.0)
}
}