meilies 0.2.0

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

use crate::resp::{RespValue, FromResp, RespStringConvertError};

pub const ALL_STREAMS: &str = "$all";

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StreamName(String);

impl StreamName {
    pub fn all() -> StreamName {
        StreamName(String::from(ALL_STREAMS))
    }

    pub fn new(name: String) -> Result<StreamName, StreamNameError> {
        if name.is_empty() {
            return Err(StreamNameError::EmptyName)
        }

        if name.contains(':') {
            return Err(StreamNameError::ContainColon)
        }

        Ok(StreamName(name))
    }

    pub fn into_inner(self) -> String {
        self.0
    }

    pub fn into_bytes(self) -> Vec<u8> {
        self.0.into_bytes()
    }

    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for StreamName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl AsRef<[u8]> for StreamName {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

#[derive(Debug)]
pub enum RespStreamNameConvertError {
    InvalidRespType,
    InvalidUtf8String(FromUtf8Error),
    InnerStreamNameConvertError(StreamNameError),
}

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

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

impl FromStr for StreamName {
    type Err = StreamNameError;

    fn from_str(s: &str) -> Result<StreamName, Self::Err> {
        StreamName::new(s.to_owned())
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StreamNameError {
    EmptyName,
    ContainColon,
}

impl fmt::Display for StreamNameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            StreamNameError::EmptyName => f.write_str("stream name is empty"),
            StreamNameError::ContainColon => f.write_str("stream name contains a colon (:)"),
        }
    }
}

impl PartialEq<&'_ str> for StreamName {
    fn eq(&self, other: &&'_ str) -> bool {
        self.0.eq(other)
    }
}