1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
use jetscii::Substring; use memchr::memchr; #[cfg_attr(test, derive(PartialEq))] #[derive(Debug)] pub struct Snippet<'a> { pub name: &'a str, pub value: &'a str, } impl<'a> Snippet<'a> { pub fn parse(src: &'a str) -> Option<(Snippet<'a>, usize)> { debug_assert!(src.starts_with("@@")); let name = memchr(b':', src.as_bytes()).filter(|&i| { i != 2 && src.as_bytes()[2..i] .iter() .all(|&c| c.is_ascii_alphanumeric() || c == b'-') })?; let end = Substring::new("@@") .find(&src[name + 1..]) .map(|i| i + name + 1)?; Some(( Snippet { name: &src[2..name], value: &src[name + 1..end], }, end + 2, )) } } #[test] fn parse() { assert_eq!( Snippet::parse("@@html:<b>@@").unwrap(), ( Snippet { name: "html", value: "<b>" }, "@@html:<b>@@".len() ) ); assert_eq!( Snippet::parse("@@latex:any arbitrary LaTeX code@@").unwrap(), ( Snippet { name: "latex", value: "any arbitrary LaTeX code" }, "@@latex:any arbitrary LaTeX code@@".len() ) ); assert_eq!( Snippet::parse("@@html:@@").unwrap(), ( Snippet { name: "html", value: "" }, "@@html:@@".len() ) ); assert!(Snippet::parse("@@html:<b>@").is_none()); assert!(Snippet::parse("@@html<b>@@").is_none()); assert!(Snippet::parse("@@:<b>@@").is_none()); }