summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vndbapi-msg/src/msg.rs57
-rw-r--r--vndbapi-msg/src/parser.rs26
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(""));