refactor(parser): wrap some objects and elements with struct

This commit is contained in:
PoiScript 2019-04-24 17:42:21 +08:00
parent 69534576f1
commit 56e289fb48
22 changed files with 1055 additions and 875 deletions

View file

@ -1,43 +1,67 @@
use jetscii::Substring;
use memchr::memchr;
/// returns (link path, link description, offset)
#[inline]
pub fn parse(text: &str) -> Option<(&str, Option<&str>, usize)> {
debug_assert!(text.starts_with("[["));
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct Link<'a> {
pub path: &'a str,
pub desc: Option<&'a str>,
}
let (path, off) = memchr(b']', text.as_bytes())
.map(|i| (&text[2..i], i))
.filter(|(path, _)| {
path.as_bytes()
.iter()
.all(|&c| c != b'<' && c != b'>' && c != b'\n')
})?;
impl<'a> Link<'a> {
#[inline]
pub(crate) fn parse(text: &str) -> Option<(Link<'_>, usize)> {
debug_assert!(text.starts_with("[["));
if *text.as_bytes().get(off + 1)? == b']' {
Some((path, None, off + 2))
} else if text.as_bytes()[off + 1] == b'[' {
let (desc, off) = Substring::new("]]")
.find(&text[off + 1..])
.map(|i| (&text[off + 2..off + i + 1], off + i + 3))
.filter(|(desc, _)| desc.as_bytes().iter().all(|&c| c != b'[' && c != b']'))?;
Some((path, Some(desc), off))
} else {
None
let (path, off) = memchr(b']', text.as_bytes())
.map(|i| (&text["[[".len()..i], i))
.filter(|(path, _)| {
path.as_bytes()
.iter()
.all(|&c| c != b'<' && c != b'>' && c != b'\n')
})?;
if *text.as_bytes().get(off + 1)? == b']' {
Some((Link { path, desc: None }, off + 2))
} else if text.as_bytes()[off + 1] == b'[' {
let (desc, off) = Substring::new("]]")
.find(&text[off + 1..])
.map(|i| (&text[off + 2..off + 1 + i], off + 1 + i + "]]".len()))
.filter(|(desc, _)| desc.as_bytes().iter().all(|&c| c != b'[' && c != b']'))?;
Some((
Link {
path,
desc: Some(desc),
},
off,
))
} else {
None
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn parse() {
use super::parse;
assert_eq!(parse("[[#id]]"), Some(("#id", None, "[[#id]]".len())));
assert_eq!(
parse("[[#id][desc]]"),
Some(("#id", Some("desc"), "[[#id][desc]]".len()))
);
assert_eq!(parse("[[#id][desc]"), None);
}
#[test]
fn parse() {
assert_eq!(
Link::parse("[[#id]]"),
Some((
Link {
path: "#id",
desc: None
},
"[[#id]]".len()
))
);
assert_eq!(
Link::parse("[[#id][desc]]"),
Some((
Link {
path: "#id",
desc: Some("desc")
},
"[[#id][desc]]".len()
))
);
assert_eq!(Link::parse("[[#id][desc]"), None);
}