diff options
author | Yorhel <git@yorhel.nl> | 2017-03-04 11:12:31 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2017-03-04 11:12:31 +0100 |
commit | 634d0ea29755da9047014f94a04e445646e49bfc (patch) | |
tree | 33dd16e08feaf4f56b5948509aa9cfd27366e35b | |
parent | bea3ab5e55acf1da0862c668b73ff4121dd17f39 (diff) |
Some old outstanding changes
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | src/conn.rs | 2 | ||||
-rw-r--r-- | src/msg.rs | 24 | ||||
-rw-r--r-- | src/parser.rs | 84 |
4 files changed, 68 insertions, 46 deletions
@@ -1,7 +1,7 @@ [package] -name = "vndb" +name = "vndbapi" version = "0.1.0" -authors = ["Yorhel <git@yorhel.nl>"] +authors = ["Yorhel <projects@yorhel.nl>"] [dependencies] rustls = "0.5.3" diff --git a/src/conn.rs b/src/conn.rs index 84ebc42..a642a59 100644 --- a/src/conn.rs +++ b/src/conn.rs @@ -87,6 +87,8 @@ impl Connection { Ok(m) } + // WARNING: This method should not be called when there are still outstanding commands. + // (Might as well get rid of this convenient method to prevent that scenario?) pub fn cmd(&mut self, cmd: &Message) -> Result<Message, Box<Error>> { self.send(cmd); self.recv() @@ -1,7 +1,7 @@ use std::fmt; use serde_json::Value; -use parser::{parse_filter,parse_message}; +use parser::{parse_filter,parse_arg,parse_message}; #[derive(Debug,Clone)] @@ -101,12 +101,30 @@ impl Filter { } +impl Arg { + pub fn parse(s: &str) -> Result<(Arg, &str), &'static str> { + parse_arg(s) + } +} + + impl Message { pub fn parse(s: &str) -> Result<Message, &'static str> { parse_message(s) } - pub fn new(name: String, args: Vec<Arg>) -> Message { - Message{name: name, args: args} + pub fn new(name: &str) -> Result<Message, &'static str> { + if name.contains(|c| !(c >= 'a' && c <= 'z')) { + return Err("Invalid message name") + } + Ok(Message{name: name.to_string(), args: Vec::new()}) } + + pub fn push_arg(mut self, arg: Arg) -> Message { self.args.push(arg); self } + pub fn push_bare (self, arg: &str ) -> Message { self.push_arg(Arg::BareString(arg.to_string())) } + pub fn push_json (self, arg: Value ) -> Message { self.push_arg(Arg::Json(arg)) } + pub fn push_filter(self, arg: Filter) -> Message { self.push_arg(Arg::Filter(arg)) } + + pub fn name(&self) -> &str { &self.name } + pub fn args(&self) -> &[Arg] { &self.args } } diff --git a/src/parser.rs b/src/parser.rs index 03b288b..0644e45 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -22,7 +22,6 @@ fn parse_json(s: &str) -> Result<(Value, &str)> { fn is_ws(c: char) -> bool { c == ' ' || c == '\t' || c == '\r' || c == '\n' } fn is_filtername(c: char) -> bool { (c >= 'a' && c <= 'z') || c == '_' } -fn is_msgname(c: char) -> bool { c >= 'a' && c <= 'z' } fn is_barestr(c: char) -> bool { (c >= 'a' && c <= 'z') || c == '_' || c == ',' } fn trim_ws(s: &str) -> &str { s.trim_left_matches(is_ws) } @@ -169,55 +168,58 @@ pub fn parse_filter(s: &str) -> Result<(Filter, &str)> { } +pub fn parse_arg(s: &str) -> Result<(Arg, &str)> { + let s = trim_ws(s); + + // This match on the first character can be replaced by simply trying parse_filter and + // 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"), + + Some('(') => { + return parse_filter(s).map(|(v,r)| (Arg::Filter(v), r)); + }, + + Some('[') | Some('{') | Some('"') => { + return parse_json(s).map(|(v,r)| (Arg::Json(v), r)); + }, + + Some(_) => { + if let Ok((v,r)) = parse_json(s) { + return Ok((Arg::Json(v), r)); + + } else { + let mut splt = s.splitn(2, is_ws); + let v = splt.next().unwrap(); + let rem = splt.next().unwrap_or(""); + + if !v.contains(|c| !is_barestr(c)) { + return Ok((Arg::BareString(v.to_string()), rem)); + } else { + return Err("Invalid argument") + } + } + }, + } +} + + pub fn parse_message(s: &str) -> Result<Message> { let mut buf = trim_ws(s); - let mut args = Vec::new(); let mut splt = buf.splitn(2, is_ws); let name = splt.next().ok_or("Empty message")?; - if name.contains(|c| !is_msgname(c)) { - return Err("Invalid message name") - } + let mut msg = Message::new(name)?; buf = trim_ws(splt.next().unwrap_or("")); - while let Some(c) = buf.chars().next() { - // This match on the first character can be replaced by simply trying parse_filter and - // parse_json in sequence; but that results in less than ideal error messages on badly - // formatted input. - match c { - '(' => { - let v = parse_filter(buf)?; - args.push(Arg::Filter(v.0)); - buf = v.1; - }, - '[' | '{' | '"' => { - let v = parse_json(buf)?; - args.push(Arg::Json(v.0)); - buf = v.1; - }, - _ => { - if let Ok(v) = parse_json(buf) { - args.push(Arg::Json(v.0)); - buf = v.1; - - } else { - let mut splt = buf.splitn(2, is_ws); - let v = splt.next().unwrap(); - - if !v.contains(|c| !is_barestr(c)) { - args.push(Arg::BareString(v.to_string())); - } else { - return Err("Invalid argument") - } - - buf = splt.next().unwrap_or(""); - } - }, - } - buf = trim_ws(buf); + while buf.len() > 0 { + let v = parse_arg(buf)?; + msg = msg.push_arg(v.0); + buf = trim_ws(v.1); } - Ok(Message::new(name.to_string(), args)) + Ok(msg) } |