1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
use std;
use std::fmt::{self, Debug, Display, Formatter};

#[derive(Debug)]
pub struct Error {
	/// Dumped using debug trait.
	pub got: String,
	pub kind: ErrorKind,
}


/// Common prefix: (so do not incude it in separate message)
///
/// {} must
///
///
///
#[derive(Debug)]
pub enum ErrorKind {
	MustEq { to: String },
	MustNotEq { to: String },
	MustBeOk,
	MustBeErr,
	MustBeSome,
	MustBeNone,
	MustHaveLength { len: usize },
	MustBeEmpty,
	MustBeInRange { range: String },
	MustNotBeInRange { range: String },
	MustBeLowercase,
	MustBeUppercase,
	MustBeAscii,
	MustBeEqAsciiIgnoreCase { to: String },
	MustBeLessThan { other: String },
	MustBeLessThanOrEqual { other: String },
	MustBeGreaterThan { other: String },
	MustBeGreaterThanOrEqual { other: String },
	MustBeNan,
	MustNotBeNan,

	Msg(String),
	Error(Box<std::error::Error>),
}

impl Display for ErrorKind {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		use self::ErrorKind::*;
		match self {
			&MustEq { ref to } => write!(f, "must be {}", to),
			&MustNotEq { ref to } => write!(f, "must not be {}", to),
			&MustBeOk => write!(f, "must be ok"),
			&MustBeErr => write!(f, "must be err"),
			&MustBeSome => write!(f, "must be some"),
			&MustBeNone => write!(f, "must be none"),
			&MustHaveLength { len } => write!(f, "must have length {}", len),
			&MustBeEmpty => write!(f, "must be empty"),
			&MustBeInRange { ref range } => write!(f, "must be in range {}", range),
			&MustNotBeInRange { ref range } => write!(f, "must not be in range {}", range),
			&MustBeLowercase => write!(f, "must be lowercase"),
			&MustBeUppercase => write!(f, "must be uppercase"),
			&MustBeAscii => write!(f, "must be ascii"),
			&MustBeEqAsciiIgnoreCase { ref to } => write!(f, "must eq ignore ascii case {}", to),
			&MustBeLessThan { ref other } => write!(f, "must be less than {}", other),
			&MustBeLessThanOrEqual { ref other } => {
				write!(f, "must be less than or equal {}", other)
			}
			&MustBeGreaterThan { ref other } => write!(f, "must be greater than {}", other),
			&MustBeGreaterThanOrEqual { ref other } => {
				write!(f, "must be greater than or equal to {}", other)
			}
			&MustBeNan => write!(f, "must be NAN"),
			&MustNotBeNan => write!(f, "must not be NAN"),

			&Msg(ref msg) => write!(f, "{}", msg),

			// TODO(kdy): cause chain
			&Error(ref err) => write!(f, "{}", err.description()),
		}
	}
}

/// shortcut for
/// format!("{:?}", t)
pub fn dump<T: Debug>(t: T) -> String {
	format!("{:?}", t)
}



/// Used from [ErrorKind.but_got][].
///
/// [ErrorKind.but_got]:enum.ErrorKind.html#method.but_got
pub trait FromError {
	fn from_err(err: ErrorKind, got: String) -> Self;
}

impl ErrorKind {
	pub fn but_got<T: Debug, R: FromError>(self, got: T) -> R {
		R::from_err(self, dump(got))
	}
}

impl<O: Debug> FromError for Result<O, Error> {
	fn from_err(err: ErrorKind, got: String) -> Self {
		Err(Error {
			got: got,
			kind: err,
		})
	}
}