orgize/src/objects/link.rs

67 lines
1.7 KiB
Rust

use jetscii::Substring;
use memchr::memchr;
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct Link<'a> {
pub path: &'a str,
pub desc: Option<&'a str>,
}
impl<'a> Link<'a> {
#[inline]
pub(crate) fn parse(text: &str) -> Option<(Link<'_>, usize)> {
debug_assert!(text.starts_with("[["));
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
}
}
}
#[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);
}