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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! # types
//!
//! Defines the various types and aliases used or exposed by the simple_redis library.
//!

extern crate redis;
use std::error;
use std::fmt;
use std::fmt::Display;

#[derive(Debug)]
/// Holds the error information
pub enum ErrorInfo {
    /// Root redis error
    RedisError(redis::RedisError),
    /// Description text of the error reason
    Description(&'static str),
    /// TimeoutError error
    TimeoutError(&'static str)
}

#[derive(Debug)]
/// Redis Error struct
pub struct RedisError {
    /// Holds the error information
    pub info: ErrorInfo
}

impl error::Error for RedisError {
    /// A short description of the error.
    fn description(&self) -> &str {
        match self.info {
            ErrorInfo::RedisError(ref cause) => cause.description(),
            ErrorInfo::Description(description) => description,
            ErrorInfo::TimeoutError(description) => description,
        }
    }

    /// The lower-level cause of this error, if any.
    fn cause(&self) -> Option<&error::Error> {
        match self.info {
            ErrorInfo::RedisError(ref cause) => Some(cause as &error::Error),
            _ => None,
        }
    }
}

impl Display for RedisError {
    /// Formats the value using the given formatter.
    fn fmt(
        &self,
        format: &mut fmt::Formatter,
    ) -> Result<(), fmt::Error> {
        match self.info {
            ErrorInfo::RedisError(ref cause) => cause.fmt(format),
            ErrorInfo::Description(description) => description.fmt(format),
            ErrorInfo::TimeoutError(description) => description.fmt(format),
        }
    }
}

/// Defines a redis command argument
pub trait RedisArg: Sized + ToString {}

macro_rules! as_redis_arg {
    ($t:ty) => (
        impl RedisArg for $t {}
    )
}

impl<'a> RedisArg for &'a str {}

as_redis_arg!(i8);
as_redis_arg!(i16);
as_redis_arg!(u16);
as_redis_arg!(i32);
as_redis_arg!(u32);
as_redis_arg!(i64);
as_redis_arg!(u64);
as_redis_arg!(f32);
as_redis_arg!(f64);
as_redis_arg!(isize);
as_redis_arg!(usize);
as_redis_arg!(bool);

/// PubSub message
pub type Message = redis::Msg;

/// Redis result which either holds a value or a Redis error
pub type RedisResult<T> = Result<T, RedisError>;

/// Holds empty result or error
pub type RedisEmptyResult = RedisResult<()>;

/// Holds pubsub message result or error
pub type RedisMessageResult = RedisResult<Message>;

/// Holds string result or error
pub type RedisStringResult = RedisResult<String>;

/// Holds bool result or error
pub type RedisBoolResult = RedisResult<bool>;


#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;
    use std::io::Write;

    #[test]
    fn redis_error_description() {
        let redis_error = RedisError { info: ErrorInfo::Description("test") };

        assert_eq!(redis_error.description(), "test");
        assert!(redis_error.cause().is_none());

        let mut writer = Vec::new();
        write!(&mut writer, "formatted {}", redis_error).unwrap();
        assert_eq!(writer, b"formatted test");
    }

    #[test]
    fn redis_error_timeout_error() {
        let redis_error = RedisError { info: ErrorInfo::TimeoutError("timeout") };

        assert_eq!(redis_error.description(), "timeout");
        assert!(redis_error.cause().is_none());

        let mut writer = Vec::new();
        write!(&mut writer, "formatted {}", redis_error).unwrap();
        assert_eq!(writer, b"formatted timeout");
    }
}