diff --git a/src/tdb2/ff4.rs b/src/tdb2/ff4.rs index 63e353e73..f51edc826 100644 --- a/src/tdb2/ff4.rs +++ b/src/tdb2/ff4.rs @@ -103,18 +103,15 @@ pub(super) fn parse_ff4(line: &str) -> Result { let name = subpig.get_until(b':')?; let name = str::from_utf8(name)?; subpig.skip(b':')?; - if let Some(value) = subpig.get_quoted(b'"') { - let value = json_decode(value)?; - let value = decode(value); - builder = builder.set(name, value); - } else { - bail!("bad line 3"); - } + let value = subpig.get_quoted(b'"')?; + let value = json_decode(value)?; + let value = decode(value); + builder = builder.set(name, value); subpig.skip(b' ').ok(); // ignore if not found.. } pig.skip(b']')?; if !pig.depleted() { - bail!("bad line 5"); + bail!("trailing characters on line"); } Ok(builder.finish()) } diff --git a/src/tdb2/pig.rs b/src/tdb2/pig.rs index 16319ccba..a8995a80e 100644 --- a/src/tdb2/pig.rs +++ b/src/tdb2/pig.rs @@ -1,5 +1,5 @@ //! A minimal implementation of the "Pig" parsing utility from the Taskwarrior -//! source. +//! source. This is just enough to parse FF4 lines. use errors::*; @@ -35,25 +35,12 @@ impl<'a> Pig<'a> { Ok(rv) } - // TODO: get_until_str - // TODO: get_until_one_of - // TODO: get_until_ws - - pub fn get_until_eos(&mut self) -> Option<&'a [u8]> { - if self.cursor >= self.input.len() { - return None; - } - let rv = &self.input[self.cursor..]; - self.cursor = self.input.len(); - return Some(rv); - } - - // TODO: get_n - - pub fn get_quoted(&mut self, c: u8) -> Option<&'a [u8]> { + pub fn get_quoted(&mut self, c: u8) -> Result<&'a [u8]> { let length = self.input.len(); if self.cursor >= length || self.input[self.cursor] != c { - return None; + return Err(Error::from( + "quoted string does not begin with quote character", + )); } let start = self.cursor + 1; @@ -64,11 +51,10 @@ impl<'a> Pig<'a> { i += 1 } if i == length { - // unclosed quote - return None; + return Err(Error::from("unclosed quote")); } if i == start { - return Some(&self.input[i..i]); + return Ok(&self.input[i..i]); } if self.input[i - 1] == b'\\' { @@ -88,24 +74,12 @@ impl<'a> Pig<'a> { // none of the above matched, so we are at the end self.cursor = i + 1; - return Some(&self.input[start..i]); + return Ok(&self.input[start..i]); } unreachable!(); } - // TODO: (missing funcs) - - pub fn skip_n(&mut self, n: usize) -> bool { - let length = self.input.len(); - if self.cursor < length && self.cursor + n <= length { - self.cursor += n; - return true; - } - - return false; - } - pub fn skip(&mut self, c: u8) -> Result<()> { if self.cursor < self.input.len() && self.input[self.cursor] == c { self.cursor += 1; @@ -117,23 +91,6 @@ impl<'a> Pig<'a> { )); } - // TODO: skip_all_one_of - // TODO: skip_ws - - pub fn next(&mut self) -> Option { - if self.cursor >= self.input.len() { - return None; - } - let rv = self.input[self.cursor]; - self.cursor += 1; - return Some(rv); - } - - // TODO: next_n - // TODO: cursor - // TODO: save - // TODO: restore - pub fn depleted(&self) -> bool { self.cursor >= self.input.len() } @@ -164,92 +121,60 @@ mod test { assert_eq!(pig.get_until(b'/').unwrap(), &s[..]); } - #[test] - fn test_get_until_eos() { - let s = b"abc:123"; - let mut pig = Pig::new(s); - assert_eq!(pig.get_until_eos(), Some(&s[..])); - } - #[test] fn test_get_quoted() { let s = b"'abcd'efg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), Some(&s[1..5])); - assert_eq!(pig.next(), Some(b'e')); + assert_eq!(pig.get_quoted(b'\'').unwrap(), &s[1..5]); + assert_eq!(pig.cursor, 6); } #[test] fn test_get_quoted_unopened() { let s = b"abcd'efg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), None); - assert_eq!(pig.next(), Some(b'a')); // nothing consumed + assert!(pig.get_quoted(b'\'').is_err()); + assert_eq!(pig.cursor, 0); // nothing consumed } #[test] fn test_get_quoted_unclosed() { let s = b"'abcdefg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), None); - assert_eq!(pig.next(), Some(b'\'')); // nothing consumed + assert!(pig.get_quoted(b'\'').is_err()); + assert_eq!(pig.cursor, 0); } #[test] fn test_get_quoted_escaped() { let s = b"'abc\\'de'fg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), Some(&s[1..8])); - assert_eq!(pig.next(), Some(b'f')); + assert_eq!(pig.get_quoted(b'\'').unwrap(), &s[1..8]); + assert_eq!(pig.cursor, 9); } #[test] fn test_get_quoted_double_escaped() { let s = b"'abc\\\\'de'fg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), Some(&s[1..6])); - assert_eq!(pig.next(), Some(b'd')); + assert_eq!(pig.get_quoted(b'\'').unwrap(), &s[1..6]); + assert_eq!(pig.cursor, 7); } #[test] fn test_get_quoted_triple_escaped() { let s = b"'abc\\\\\\'de'fg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), Some(&s[1..10])); - assert_eq!(pig.next(), Some(b'f')); + assert_eq!(pig.get_quoted(b'\'').unwrap(), &s[1..10]); + assert_eq!(pig.cursor, 11); } #[test] fn test_get_quoted_all_escapes() { let s = b"'\\\\\\'\\\\'fg"; let mut pig = Pig::new(s); - assert_eq!(pig.get_quoted(b'\''), Some(&s[1..7])); - assert_eq!(pig.next(), Some(b'f')); - } - - #[test] - fn test_skip_n() { - let s = b"abc:123"; - let mut pig = Pig::new(s); - assert!(pig.skip_n(3)); - assert_eq!(pig.get_until_eos(), Some(&s[3..])); - } - - #[test] - fn test_skip_n_too_long() { - let s = b"abc:123"; - let mut pig = Pig::new(s); - assert!(!pig.skip_n(33)); - // nothing is consumed - assert_eq!(pig.get_until_eos(), Some(&s[..])); - } - - #[test] - fn test_skip_n_exact_eos() { - let s = b"abc:123"; - let mut pig = Pig::new(s); - assert!(pig.skip_n(7)); - assert_eq!(pig.get_until_eos(), None); + assert_eq!(pig.get_quoted(b'\'').unwrap(), &s[1..7]); + assert_eq!(pig.cursor, 8); } #[test] @@ -257,7 +182,7 @@ mod test { let s = b"foo"; let mut pig = Pig::new(s); assert!(pig.skip(b'f').is_ok()); - assert_eq!(pig.get_until_eos(), Some(&s[1..])); + assert_eq!(pig.cursor, 1); } #[test] @@ -265,36 +190,14 @@ mod test { let s = b"foo"; let mut pig = Pig::new(s); assert!(pig.skip(b'x').is_err()); - assert_eq!(pig.get_until_eos(), Some(&s[..])); + assert_eq!(pig.cursor, 0); // nothing consumed } #[test] fn test_skip_eos() { - let s = b"foo"; + let s = b"f"; let mut pig = Pig::new(s); - assert!(pig.skip_n(3)); - assert!(pig.skip(b'x').is_err()); - } - - #[test] - fn test_next() { - let s = b"foo"; - let mut pig = Pig::new(s); - assert_eq!(pig.next(), Some(b'f')); - assert_eq!(pig.next(), Some(b'o')); - assert_eq!(pig.next(), Some(b'o')); - assert_eq!(pig.next(), None); - assert_eq!(pig.next(), None); - } - - #[test] - fn test_depleted() { - let s = b"xy"; - let mut pig = Pig::new(s); - assert!(!pig.depleted()); - assert_eq!(pig.next(), Some(b'x')); - assert!(!pig.depleted()); - assert_eq!(pig.next(), Some(b'y')); - assert!(pig.depleted()); + assert!(pig.skip(b'f').is_ok()); + assert!(pig.skip(b'f').is_err()); } }