Last active
June 7, 2017 07:42
-
-
Save andoriyu/2b64d1dae73da3795d198a1416e80d7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![doc(html_root_url = "https://andoriyu.github.io/blunder.rs/")] | |
| #[macro_use] extern crate enum_primitive; | |
| extern crate num; | |
| extern crate errno; | |
| use std::error::Error as StdError; | |
| use std::fmt; | |
| use std::ops::Deref; | |
| use std::convert::{From, Into}; | |
| mod bsd; | |
| pub use bsd::*; | |
| #[macro_export] | |
| macro_rules! fail { | |
| ($expr:expr) => ( | |
| return ::std::result::Result::Err(::std::convert::From::from($expr)); | |
| ) | |
| } | |
| /// Macro helper to propagate an error if there is one. See BsdError::from_errno() for inpsiration. | |
| #[macro_export] | |
| macro_rules! maybe_fail { | |
| ($expr:expr) => ({ | |
| if let Some(err) = $expr { | |
| fail!(err) | |
| } | |
| }) | |
| } | |
| /// Generic af struct for errror handling | |
| /// Designed to host anything that implements error::Error trait | |
| /// Yet can host whatever (like errno from libc) | |
| #[derive(Debug, PartialEq)] | |
| pub struct Blunder<T: StdError> { | |
| /// How to identify the error | |
| kind: T, | |
| detail: Option<String> | |
| } | |
| /// Because we want easy switch/case on kind... | |
| impl <T: StdError> Deref for Blunder<T> { | |
| type Target = T; | |
| fn deref<'a>(&'a self) -> &'a T { | |
| &self.kind | |
| } | |
| } | |
| impl <T: StdError> Blunder<T> { | |
| /// Optional reasoning behind such behavior. | |
| /// Think "Client doesn't understand XXX cipher" | |
| pub fn detail(&self) -> Option<String> { | |
| self.detail.clone() | |
| } | |
| } | |
| impl <T: StdError> StdError for Blunder<T> { | |
| fn description(&self) -> &str { | |
| self.kind.description() | |
| } | |
| fn cause(&self) -> Option<&StdError> { | |
| self.kind.cause() | |
| } | |
| } | |
| impl <T: StdError> fmt::Display for Blunder<T> { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f,"{}", self.description()) | |
| } | |
| } | |
| impl <E: StdError> From<E> for Blunder<E> { | |
| fn from(err: E) -> Blunder<E> { | |
| Blunder { kind: err, detail: None } | |
| } | |
| } | |
| impl<E> Into<std::io::Error> for Blunder<E> where E: Into<std::io::Error> + StdError { | |
| fn into(self) -> std::io::Error { | |
| self.kind.into() | |
| } | |
| } | |
| #[test] | |
| fn it_works() { | |
| #[derive(Debug, PartialEq)] | |
| enum Wat { | |
| One, | |
| }; | |
| impl fmt::Display for Wat { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f,"{}", "wat") | |
| } | |
| } | |
| impl StdError for Wat { | |
| fn description(&self) -> &str { | |
| "wat" | |
| } | |
| fn cause(&self) -> Option<&StdError> { | |
| None | |
| } | |
| } | |
| let error: Blunder<Wat> = Blunder { kind: Wat::One, detail: None }; | |
| assert_eq!(error.cause().is_some(), false); | |
| assert_eq!(error.description(), "wat"); | |
| assert_eq!(*error, Wat::One); | |
| // Test fail! macro | |
| fn goto_fail() -> Result<(), Blunder<Wat>> { | |
| fail!(Wat::One) | |
| }; | |
| let fail = Blunder { kind: Wat::One, detail: None }; | |
| if let Err(err) = goto_fail() { | |
| assert_eq!(err, fail); | |
| } else { | |
| panic!(); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Compiling angel_whisper v0.1.0 (file:///usr/home/andoriyu/Dev/Heaven/angel_whisper) | |
| error[E0277]: the trait bound `blunder::Blunder<llsd::errors::LlsdErrorKind>: std::convert::From<std::io::Error>` is not satisfied | |
| --> src/angel_system.rs:148:10 | |
| | | |
| 148 | impl Decoder for FrameCodec { | |
| | ^^^^^^^ the trait `std::convert::From<std::io::Error>` is not implemented for `blunder::Blunder<llsd::errors::LlsdErrorKind>` | |
| | | |
| = help: the following implementations were found: | |
| <blunder::Blunder<E> as std::convert::From<E>> | |
| = note: required by `tokio_io::codec::Decoder` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::result::Result; | |
| use std::error::Error; | |
| use std::fmt; | |
| use std::io; | |
| use std::convert::{Into, From}; | |
| use blunder::Blunder; | |
| pub type LlsdError = Blunder<LlsdErrorKind>; | |
| pub type LlsdResult<T> = Result<T,LlsdError>; | |
| #[derive(Debug, PartialEq)] | |
| pub enum LlsdErrorKind { | |
| HandshakeFailed, | |
| MessageTooBig, | |
| UnknownClient, | |
| BadFrame, | |
| SessionExpired, | |
| InvalidState | |
| } | |
| impl Error for LlsdErrorKind { | |
| fn cause(&self) -> Option<&Error> { | |
| None | |
| } | |
| fn description(&self) -> &str { | |
| match *self { | |
| _ => "Description not available" | |
| } | |
| } | |
| } | |
| impl fmt::Display for LlsdErrorKind { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| write!(f,"{}", self.description()) | |
| } | |
| } | |
| impl Into<io::Error> for LlsdErrorKind { | |
| fn into(self) -> io::Error { | |
| match self { | |
| LlsdErrorKind::BadFrame => io::Error::new(io::ErrorKind::InvalidData, self), | |
| _ => io::Error::new(io::ErrorKind::Other, self) | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #[cfg(feature = "system-on-tokio")] | |
| pub mod tokio { | |
| use llsd::errors::LlsdError; | |
| use frames::Frame; | |
| use tokio_io::codec::{Encoder, Decoder}; | |
| use bytes::BytesMut; | |
| use std::io; | |
| pub struct FrameCodec; | |
| impl Decoder for FrameCodec { | |
| type Item = Frame; | |
| type Error = LlsdError; | |
| fn decode(&mut self, buf: &mut BytesMut) -> LlsdResult<Option<Frame>> { | |
| match Frame::from_slice(&buf) { | |
| Ok(frame) => Ok(Some(frame)), | |
| Err(e) => fail!(e) | |
| } | |
| } | |
| } | |
| impl Encoder for FrameCodec { | |
| type Item = Frame; | |
| type Error = io::Error; | |
| fn encode(&mut self, msg: Frame, buf: &mut BytesMut) -> io::Result<()> { | |
| msg.pack_to_buf(buf); | |
| Ok(()) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment