feat: impl std error to error

* *BREAKING CHANGES*: refac errors and add main struct with inner enum kind
* Add Result type
This commit is contained in:
Dmitriy Pleshevskiy 2020-07-19 10:17:53 +03:00
parent dcfe82f6e7
commit 4a267f66b9
12 changed files with 91 additions and 76 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "sonic-channel"
version = "0.1.0-rc2"
version = "0.1.0-rc3"
authors = ["Dmitriy Pleshevskiy <dmitriy@ideascup.me>"]
description = "Rust client for sonic search backend"
categories = ["api-bindings"]

View file

@ -18,7 +18,7 @@ version = "0.1.0"
authors = ["Me <user@rust-lang.org>"]
[dependencies]
sonic-channel = { version = "0.1" }
sonic-channel = { version = "0.1.0-rc3" }
```
@ -29,7 +29,7 @@ sonic-channel = { version = "0.1" }
```rust
use sonic_channel::*;
fn main() -> Result<(), SonicError> {
fn main() -> result::Result<()> {
let mut channel = SonicChannel::connect("localhost:1491")?;
channel.start(ChannelMode::Search, "SecretPassword")?;
@ -45,7 +45,7 @@ fn main() -> Result<(), SonicError> {
```rust
use sonic_channel::*;
fn main() -> Result<(), SonicError> {
fn main() -> result::Result<()> {
let mut channel = SonicChannel::connect("localhost:1491")?;
channel.start(ChannelMode::Ingest, "SecretPassword")?;

View file

@ -1,5 +1,5 @@
use crate::commands::*;
use crate::errors::SonicError;
use crate::result::*;
use std::fmt;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::net::{TcpStream, ToSocketAddrs};
@ -26,9 +26,8 @@ macro_rules! init_commands {
pub fn $fn_name $(<$($lt)+>)? (
&self,
$($arg_name: $arg_type),*
) -> Result<
) -> crate::result::Result<
<$cmd_name as crate::commands::StreamCommand>::Response,
crate::errors::SonicError
> {
let command = $cmd_name { $($arg_name,)* ..Default::default() };
self.run_command(command)
@ -74,7 +73,7 @@ impl ChannelMode {
}
impl fmt::Display for ChannelMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
write!(f, "{}", self.to_str())
}
}
@ -88,8 +87,8 @@ pub struct SonicChannel {
}
impl SonicChannel {
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self, SonicError> {
let stream = TcpStream::connect(addr).map_err(|_| SonicError::ConnectToServer)?;
pub fn connect<A: ToSocketAddrs>(addr: A) -> Result<Self> {
let stream = TcpStream::connect(addr).map_err(|_| Error::new(ErrorKind::ConnectToServer))?;
let channel = SonicChannel {
stream,
@ -104,21 +103,21 @@ impl SonicChannel {
if message.starts_with("CONNECTED") {
Ok(channel)
} else {
Err(SonicError::ConnectToServer)
Err(Error::new(ErrorKind::ConnectToServer))
}
}
fn write<SC: StreamCommand>(&self, command: &SC) -> Result<(), SonicError> {
fn write<SC: StreamCommand>(&self, command: &SC) -> Result<()> {
let mut writer = BufWriter::with_capacity(self.max_buffer_size, &self.stream);
let message = command.message();
dbg!(&message);
writer
.write_all(message.as_bytes())
.map_err(|_| SonicError::WriteToStream)?;
.map_err(|_| Error::new(ErrorKind::WriteToStream))?;
Ok(())
}
fn read(&self, max_read_lines: usize) -> Result<String, SonicError> {
fn read(&self, max_read_lines: usize) -> Result<String> {
let mut reader = BufReader::with_capacity(self.max_buffer_size, &self.stream);
let mut message = String::new();
@ -126,23 +125,23 @@ impl SonicChannel {
while lines_read < max_read_lines {
reader
.read_line(&mut message)
.map_err(|_| SonicError::ReadStream)?;
.map_err(|_| Error::new(ErrorKind::ReadStream))?;
lines_read += 1;
}
Ok(message)
}
pub fn run_command<SC: StreamCommand>(&self, command: SC) -> Result<SC::Response, SonicError> {
pub fn run_command<SC: StreamCommand>(&self, command: SC) -> Result<SC::Response> {
self.write(&command)?;
let message = self.read(SC::READ_LINES_COUNT)?;
command.receive(message)
}
#[cfg(any(feature = "ingest", feature = "search", feature = "control"))]
pub fn start<S: ToString>(&mut self, mode: ChannelMode, password: S) -> Result<(), SonicError> {
pub fn start<S: ToString>(&mut self, mode: ChannelMode, password: S) -> Result<()> {
if self.mode.is_some() {
return Err(SonicError::RunCommand);
return Err(Error::new(ErrorKind::RunCommand));
}
let command = StartCommand {

View file

@ -1,6 +1,8 @@
mod quit;
mod start;
mod ping;
#[cfg(feature = "ingest")]
mod push;
#[cfg(feature = "search")]
@ -15,7 +17,7 @@ pub use push::PushCommand;
#[cfg(feature = "search")]
pub use query::QueryCommand;
use crate::errors::SonicError;
use crate::result::Result;
pub trait StreamCommand {
type Response;
@ -24,5 +26,5 @@ pub trait StreamCommand {
fn message(&self) -> String;
fn receive(&self, message: String) -> Result<Self::Response, SonicError>;
fn receive(&self, message: String) -> Result<Self::Response>;
}

View file

@ -1,5 +1,5 @@
use super::StreamCommand;
use crate::errors::SonicError;
use crate::result::*;
#[derive(Debug, Default)]
pub struct PingCommand;
@ -11,7 +11,7 @@ impl StreamCommand for PingCommand {
String::from("PING\r\n")
}
fn receive(&self, message: String) -> Result<<Self as StreamCommand>::Response, SonicError> {
fn receive(&self, message: String) -> Result<Self::Response> {
dbg!(&message);
Ok(message == "PONG\r\n")
}

View file

@ -1,5 +1,5 @@
use super::StreamCommand;
use crate::errors::SonicError;
use crate::result::Result;
#[derive(Debug, Default)]
pub struct PushCommand<'a> {
@ -25,7 +25,7 @@ impl StreamCommand for PushCommand<'_> {
message
}
fn receive(&self, message: String) -> Result<<Self as StreamCommand>::Response, SonicError> {
fn receive(&self, message: String) -> Result<Self::Response> {
dbg!(&message);
Ok(message == "OK\r\n")
}

View file

@ -1,5 +1,5 @@
use super::StreamCommand;
use crate::errors::SonicError;
use crate::result::*;
use regex::Regex;
const RE_QUERY_RECEIVED_MESSAGE: &str = r"(?x)
@ -36,7 +36,7 @@ impl StreamCommand for QueryCommand<'_> {
message
}
fn receive(&self, message: String) -> Result<Self::Response, SonicError> {
fn receive(&self, message: String) -> Result<Self::Response> {
lazy_static! {
static ref RE: Regex = Regex::new(RE_QUERY_RECEIVED_MESSAGE).unwrap();
}
@ -44,14 +44,14 @@ impl StreamCommand for QueryCommand<'_> {
dbg!(&message);
match RE.captures(&message) {
None => Err(SonicError::QueryResponseError(
None => Err(Error::new(ErrorKind::QueryResponseError(
"Sonic response are wrong. Please write issue to github.",
)),
))),
Some(caps) => {
if &caps["pending_query_id"] != &caps["event_query_id"] {
Err(SonicError::QueryResponseError(
Err(Error::new(ErrorKind::QueryResponseError(
"Pending id and event id don't match",
))
)))
} else if caps["objects"].is_empty() {
Ok(vec![])
} else {

View file

@ -1,5 +1,5 @@
use super::StreamCommand;
use crate::errors::SonicError;
use crate::result::Result;
#[derive(Debug, Default)]
pub struct QuitCommand;
@ -11,7 +11,7 @@ impl StreamCommand for QuitCommand {
String::from("QUIT\r\n")
}
fn receive(&self, message: String) -> Result<<Self as StreamCommand>::Response, SonicError> {
fn receive(&self, message: String) -> Result<Self::Response> {
dbg!(&message);
Ok(message.starts_with("ENDED "))
}

View file

@ -1,6 +1,6 @@
use super::StreamCommand;
use crate::channel::ChannelMode;
use crate::errors::SonicError;
use crate::result::*;
use regex::Regex;
const RE_START_RECEIVED_MESSAGE: &str = r"(?x)
@ -32,7 +32,7 @@ impl StreamCommand for StartCommand {
format!("START {} {}\r\n", self.mode, self.password)
}
fn receive(&self, message: String) -> Result<Self::Response, SonicError> {
fn receive(&self, message: String) -> Result<Self::Response> {
lazy_static! {
static ref RE: Regex = Regex::new(RE_START_RECEIVED_MESSAGE).unwrap();
}
@ -40,12 +40,11 @@ impl StreamCommand for StartCommand {
dbg!(&message);
match RE.captures(&message) {
None => Err(SonicError::SwitchMode),
None => Err(Error::new(ErrorKind::SwitchMode)),
Some(caps) => {
if self.mode.to_str() != &caps["mode"] {
return Err(SonicError::SwitchMode);
}
return Err(Error::new(ErrorKind::SwitchMode));
} else {
let protocol_version: usize =
caps["protocol"].parse().expect("Must be digit by regex");
let max_buffer_size: usize =
@ -59,4 +58,5 @@ impl StreamCommand for StartCommand {
}
}
}
}
}

View file

@ -1,27 +0,0 @@
use std::fmt;
#[derive(Debug)]
pub enum SonicError {
ConnectToServer,
WriteToStream,
ReadStream,
SwitchMode,
RunCommand,
QueryResponseError(&'static str),
}
impl fmt::Display for SonicError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let message = match self {
SonicError::ConnectToServer => String::from("Cannot connect to server"),
SonicError::WriteToStream => String::from("Cannot write data to stream"),
SonicError::ReadStream => String::from("Cannot read sonic response from stream"),
SonicError::SwitchMode => String::from("Cannot switch channel mode"),
SonicError::RunCommand => String::from("Cannot run command in current mode"),
SonicError::QueryResponseError(message) => format!("Error in query response: {}", message)
};
write!(f, "{}", message)
}
}

View file

@ -2,11 +2,10 @@
mod channel;
mod commands;
mod errors;
pub mod result;
pub use channel::*;
pub use commands::*;
pub use errors::*;
#[macro_use]
extern crate lazy_static;

42
src/result.rs Normal file
View file

@ -0,0 +1,42 @@
use std::error::Error as StdError;
use std::fmt;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
}
impl StdError for Error {}
impl Error {
pub fn new(kind: ErrorKind) -> Self {
Error { kind }
}
}
#[derive(Debug)]
pub enum ErrorKind {
ConnectToServer,
WriteToStream,
ReadStream,
SwitchMode,
RunCommand,
QueryResponseError(&'static str),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
match self.kind {
ErrorKind::ConnectToServer => write!(f, "Cannot connect to server"),
ErrorKind::WriteToStream => write!(f, "Cannot write data to stream"),
ErrorKind::ReadStream => write!(f, "Cannot read sonic response from stream"),
ErrorKind::SwitchMode => write!(f, "Cannot switch channel mode"),
ErrorKind::RunCommand => write!(f, "Cannot run command in current mode"),
ErrorKind::QueryResponseError(message) => {
write!(f, "Error in query response: {}", message)
}
}
}
}