#![warn(missing_docs)]
#[macro_use] extern crate log;
use std::any::Any;
use std::fmt;
use std::marker::PhantomData;
pub trait Warn<W> {
fn warn(&mut self, warning: W);
}
impl<W> Warn<W> for Vec<W> {
fn warn(&mut self, warning: W) {
self.push(warning);
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct Ignore;
impl<W> Warn<W> for Ignore {
fn warn(&mut self, warning: W) {
let _ = warning;
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct Panic;
impl<W: Any+fmt::Debug+Send> Warn<W> for Panic {
fn warn(&mut self, warning: W) {
panic!("{:?}", warning);
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct Log;
impl<W: fmt::Debug> Warn<W> for Log {
fn warn(&mut self, warning: W) {
warn!("{:?}", warning);
}
}
pub struct RevMap<'a, WF, WT, W: Warn<WT> + 'a, F: FnMut(WF) -> WT> {
warn: &'a mut W,
fn_: F,
phantom: PhantomData<fn(WF) -> WT>,
}
pub fn rev_map<WF, WT, W, F>(warn: &mut W, fn_: F) -> RevMap<WF, WT, W, F>
where W: Warn<WT>,
F: FnMut(WF) -> WT,
{
RevMap {
warn: warn,
fn_: fn_,
phantom: PhantomData,
}
}
impl<'a, WF, WT, W: Warn<WT>, F: FnMut(WF) -> WT> Warn<WF> for RevMap<'a, WF, WT, W, F> {
fn warn(&mut self, warning: WF) {
self.warn.warn((self.fn_)(warning));
}
}
pub struct Closure<W, F: FnMut(W)> {
fn_: F,
phantom: PhantomData<fn(W)>,
}
pub fn closure<W, F: FnMut(W)>(fn_: &mut F) -> &mut Closure<W, F> {
unsafe {
&mut *(fn_ as *mut _ as *mut _)
}
}
impl<W, F: FnMut(W)> Warn<W> for Closure<W, F> {
fn warn(&mut self, warning: W) {
(self.fn_)(warning)
}
}
pub struct Wrap<WT, W: Warn<WT>> {
warn: W,
phantom: PhantomData<WT>,
}
pub fn wrap<WT, W: Warn<WT>>(warn: &mut W) -> &mut Wrap<WT, W> {
unsafe {
&mut *(warn as *mut _ as *mut _)
}
}
impl<WT, WF: Into<WT>, W: Warn<WT>> Warn<WF> for Wrap<WT, W> {
fn warn(&mut self, warning: WF) {
self.warn.warn(warning.into());
}
}
#[cfg(test)]
mod test {
use super::Ignore;
use super::Log;
use super::Panic;
use super::Warn;
const WARNING: &'static str = "unique_string";
const WARNING2: &'static str = "unique_no2";
#[test]
#[should_panic(expected="unique_string")]
fn panic() {
Panic.warn(WARNING);
}
#[test]
#[should_panic(expected="unique_no2")]
fn rev_map() {
super::rev_map(&mut Panic, |_| WARNING2).warn(WARNING);
}
#[test]
#[should_panic(expected="unique_no2")]
fn closure_panic() {
super::closure(&mut |_| panic!(WARNING2)).warn(WARNING);
}
#[test]
fn closure_nopanic() {
super::closure(&mut |()| panic!(WARNING2));
}
#[test]
fn ignore() {
Ignore.warn(WARNING);
}
#[test]
fn vec() {
let mut vec = vec![];
vec.warn(WARNING);
assert_eq!(vec, [WARNING]);
}
#[test]
fn log() {
Log.warn(WARNING);
}
}