meilies 0.2.0

The RESP and MeiliES protocol types
Documentation
use std::fmt;
use std::num::ParseIntError;
use std::str::FromStr;
use std::string::FromUtf8Error;

use crate::resp::{RespValue, FromResp, RespStringConvertError};
use crate::stream::{StreamName, StreamNameError};

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum StartReadFrom {
    EventNumber(u64),
    End,
}

impl StartReadFrom {
    pub fn map<F: FnOnce(u64) -> u64>(self, f: F) -> StartReadFrom {
        match self {
            StartReadFrom::EventNumber(number) => StartReadFrom::EventNumber(f(number)),
            StartReadFrom::End => StartReadFrom::End,
        }
    }
}

impl Into<Option<u64>> for StartReadFrom {
    fn into(self) -> Option<u64> {
        match self {
            StartReadFrom::EventNumber(number) => Some(number),
            StartReadFrom::End => None,
        }
    }
}

impl From<Option<u64>> for StartReadFrom {
    fn from(option: Option<u64>) -> StartReadFrom {
        match option {
            Some(number) => StartReadFrom::EventNumber(number),
            None => StartReadFrom::End,
        }
    }
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Stream {
    pub name: StreamName,
    pub from: StartReadFrom,
}

impl Stream {
    pub fn all(from: StartReadFrom) -> Stream {
        Stream::new(StreamName::all(), from)
    }

    pub fn new(name: StreamName, from: StartReadFrom) -> Stream {
        Stream { name, from }
    }
}

impl fmt::Debug for Stream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Stream(\"{}\")", self)
    }
}

impl fmt::Display for Stream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.from {
            StartReadFrom::EventNumber(number) => write!(f, "{}:{}", self.name, number),
            StartReadFrom::End => write!(f, "{}", self.name),
        }
    }
}

impl Into<RespValue> for Stream {
    fn into(self) -> RespValue {
        let text = match self.from {
            StartReadFrom::EventNumber(number) => format!("{}:{}", self.name, number),
            StartReadFrom::End => format!("{}", self.name),
        };

        RespValue::BulkString(text.into_bytes())
    }
}

#[derive(Debug)]
pub enum RespStreamConvertError {
    InvalidRespType,
    InvalidUtf8String(FromUtf8Error),
    InnerStreamConvertError(ParseStreamError),
}

impl fmt::Display for RespStreamConvertError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use RespStreamConvertError::*;
        match self {
            InvalidRespType => write!(f, "invalid RESP type found, expected String"),
            InvalidUtf8String(e) => write!(f, "invalid UTF8 string; {}", e),
            InnerStreamConvertError(e) => write!(f, "inner Stream convert error: {}", e),
        }
    }
}

impl FromResp for Stream {
    type Error = RespStreamConvertError;
    fn from_resp(value: RespValue) -> Result<Self, Self::Error> {
        use RespStreamConvertError::*;
        match String::from_resp(value) {
            Ok(string) => Stream::from_str(&string).map_err(InnerStreamConvertError),
            Err(RespStringConvertError::InvalidRespType) => Err(InvalidRespType),
            Err(RespStringConvertError::InvalidUtf8String(error)) => Err(InvalidUtf8String(error)),
        }
    }
}

impl From<StreamName> for Stream {
    fn from(name: StreamName) -> Stream {
        Stream { name, from: StartReadFrom::End }
    }
}

impl FromStr for Stream {
    type Err = ParseStreamError;

    fn from_str(s: &str) -> Result<Stream, Self::Err> {
        use ParseStreamError::*;

        let mut split = s.split(':');
        match (split.next(), split.next(), split.next()) {
            (Some(name), None, None) => {
                let name = StreamName::from_str(name).map_err(StreamNameError)?;
                Ok(Stream::from(name))
            },
            (Some(name), Some(from), None) => {
                let name = StreamName::new(name.to_owned()).map_err(StreamNameError)?;
                let number = u64::from_str_radix(from, 10).map_err(StartFromError)?;
                Ok(Stream { name, from: StartReadFrom::EventNumber(number) })
            },
            (_, _, _) => Err(FormatError),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseStreamError {
    StreamNameError(StreamNameError),
    StartFromError(ParseIntError),
    FormatError,
}

impl fmt::Display for ParseStreamError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use ParseStreamError::*;

        match self {
            StreamNameError(e) => write!(f, "stream not properly formatted; {}", e),
            StartFromError(e) => write!(f, "stream \"start from\" not properly formatted; {}", e),
            FormatError => f.write_str("stream is not properly formatted"),
        }
    }
}