diff options
-rw-r--r-- | vndbapi-msg/src/msg.rs | 57 | ||||
-rw-r--r-- | vndbapi-msg/src/parser.rs | 26 |
2 files changed, 63 insertions, 20 deletions
diff --git a/vndbapi-msg/src/msg.rs b/vndbapi-msg/src/msg.rs index ead8ac0..55bf257 100644 --- a/vndbapi-msg/src/msg.rs +++ b/vndbapi-msg/src/msg.rs @@ -1,9 +1,54 @@ -use std::fmt; +use std::{fmt,error}; use serde_json::Value; use parser::{parse_filter,parse_arg,parse_message}; +#[derive(Debug)] +pub enum Error { + FilterToken, + FilterOp, + FilterStart, + Json(::serde_json::Error), + InvalidArg, + UnexpectedEof, + MsgName +} + +impl Error { + fn as_str(&self) -> &'static str { + use Error::*; + match self { + FilterToken => "Invalid token in filter expression", + FilterOp => "Invalid comparison operator in filter expression", + FilterStart => "Filter expression not surrounded by parenthesis", + Json(_) => "Invalid JSON value", + InvalidArg => "Invalid argument", + UnexpectedEof => "Unexpected end of message", + MsgName => "Invalid message name" + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match self { + Error::Json(e) => Some(e), + _ => None + } + } +} + + +pub type Result<T> = ::std::result::Result<T, Error>; + + #[derive(Debug,Clone)] pub enum Arg { BareString(String), @@ -95,27 +140,27 @@ impl fmt::Display for Message { impl Filter { - pub fn parse(s: &str) -> Result<(Filter, &str), &'static str> { + pub fn parse(s: &str) -> Result<(Filter, &str)> { parse_filter(s) } } impl Arg { - pub fn parse(s: &str) -> Result<(Arg, &str), &'static str> { + pub fn parse(s: &str) -> Result<(Arg, &str)> { parse_arg(s) } } impl Message { - pub fn parse(s: &str) -> Result<Message, &'static str> { + pub fn parse(s: &str) -> Result<Message> { parse_message(s) } - pub fn new(name: &str) -> Result<Message, &'static str> { + pub fn new(name: &str) -> Result<Message> { if name.contains(|c| !(c >= 'a' && c <= 'z')) { - return Err("Invalid message name") + return Err(Error::MsgName) } Ok(Message{name: name.to_string(), args: Vec::new()}) } diff --git a/vndbapi-msg/src/parser.rs b/vndbapi-msg/src/parser.rs index c5d384e..0a28472 100644 --- a/vndbapi-msg/src/parser.rs +++ b/vndbapi-msg/src/parser.rs @@ -1,8 +1,6 @@ use serde_json::Value; -use msg::{Filter,Op,Arg,Message}; - -type Result<T> = ::std::result::Result<T, &'static str>; +use msg::*; @@ -20,7 +18,7 @@ fn parse_json(s: &str) -> Result<(Value, &str)> { } else { s }; let mut stream = ::serde_json::Deserializer::from_str(json).into_iter::<Value>(); - let val = stream.next().ok_or("Expected JSON value")?.map_err(|_| "Invalid JSON value")?; + let val = stream.next().ok_or(Error::UnexpectedEof)?.map_err(Error::Json)?; Ok((val, &s[stream.byte_offset()..])) } @@ -62,12 +60,12 @@ impl<'a> FilterParser<'a> { fn token_expr(&mut self) -> Result<Filter> { let name: String = self.buf.chars().take_while(|&c| is_filtername(c)).collect(); if name.len() == 0 { - return Err("Invalid token"); + return Err(Error::FilterToken); } self.con(name.len()); self.conws(); - let op = parse_op(self.buf).ok_or("Expected comparison operator")?; + let op = parse_op(self.buf).ok_or(Error::FilterOp)?; self.con(op.as_str().len()); self.conws(); @@ -92,13 +90,13 @@ impl<'a> FilterParser<'a> { self.conws(); let ret = match (self.hasexpr, self.buf.chars().next()) { - (_, None) => Err("Unexpected end of input"), + (_, None) => Err(Error::UnexpectedEof), (false,Some('(')) => { self.con(1); Ok(Token::Open) }, (true, Some(')')) => { self.con(1); Ok(Token::Close) }, - (true, Some('a')) => if self.buf.starts_with("and") { self.con(3); Ok(Token::And) } else { Err("Invalid token") }, - (true, Some('o')) => if self.buf.starts_with("or") { self.con(2); Ok(Token::Or ) } else { Err("Invalid token") }, + (true, Some('a')) => if self.buf.starts_with("and") { self.con(3); Ok(Token::And) } else { Err(Error::FilterToken) }, + (true, Some('o')) => if self.buf.starts_with("or") { self.con(2); Ok(Token::Or ) } else { Err(Error::FilterToken) }, (false,_) => Ok(Token::Expr), - _ => Err("Invalid token"), + _ => Err(Error::FilterToken), }; self.hasexpr = match ret { Ok(Token::Close) | Ok(Token::Expr) => true, _ => false }; @@ -111,7 +109,7 @@ impl<'a> FilterParser<'a> { let mut ops = vec![Token::Open]; // Only And, Or and Open if self.token()? != Token::Open { - return Err("Filter must start with an open parentheses"); + return Err(Error::FilterStart); } while ops.len() > 0 { @@ -180,7 +178,7 @@ pub fn parse_arg(s: &str) -> Result<(Arg, &str)> { // parse_json in sequence; but that results in less than ideal error messages on badly // formatted input. match s.chars().next() { - None => return Err("Empty argument"), + None => return Err(Error::UnexpectedEof), Some('(') => { return parse_filter(s).map(|(v,r)| (Arg::Filter(v), r)); @@ -202,7 +200,7 @@ pub fn parse_arg(s: &str) -> Result<(Arg, &str)> { if !v.contains(|c| !is_barestr(c)) { return Ok((Arg::BareString(v.to_string()), rem)); } else { - return Err("Invalid argument") + return Err(Error::InvalidArg) } } }, @@ -214,7 +212,7 @@ pub fn parse_message(s: &str) -> Result<Message> { let mut buf = trim_ws(s); let mut splt = buf.splitn(2, is_ws); - let name = splt.next().ok_or("Empty message")?; + let name = splt.next().ok_or(Error::UnexpectedEof)?; let mut msg = Message::new(name)?; buf = trim_ws(splt.next().unwrap_or("")); |