From 0eeff9148e327183e532752f46421a75506dd7a6 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Fri, 29 Jul 2022 18:22:59 +0200 Subject: Refactor to improve states * Remove custom kind wrappers, use plain bytes instead * Remove `Into`s, use the explicit expected types instead * Refactor to use `slice.as_str` in most places * Remove unneeded unique check before adding a definition * Use a shared CDATA prefix in constants * Inline byte checks into matches * Pass bytes back from parser instead of whole parse state * Refactor to work more often on bytes * Rename custom `size` to `len` --- src/construct/partial_title.rs | 93 ++++++++---------------------------------- 1 file changed, 17 insertions(+), 76 deletions(-) (limited to 'src/construct/partial_title.rs') diff --git a/src/construct/partial_title.rs b/src/construct/partial_title.rs index 80861af..9cf2f14 100644 --- a/src/construct/partial_title.rs +++ b/src/construct/partial_title.rs @@ -48,70 +48,13 @@ pub struct Options { pub string: Token, } -/// Type of title. -#[derive(Debug, PartialEq)] -enum Kind { - /// In a parenthesized (`(` and `)`) title. - /// - /// ## Example - /// - /// ```markdown - /// (a) - /// ``` - Paren, - /// In a double quoted (`"`) title. - /// - /// ## Example - /// - /// ```markdown - /// "a" - /// ``` - Double, - /// In a single quoted (`'`) title. - /// - /// ## Example - /// - /// ```markdown - /// 'a' - /// ``` - Single, -} - -impl Kind { - /// Turn the kind into a byte ([u8]). - /// - /// > 👉 **Note**: a closing paren is used for `Kind::Paren`. - fn as_byte(&self) -> u8 { - match self { - Kind::Paren => b')', - Kind::Double => b'"', - Kind::Single => b'\'', - } - } - /// Turn a byte ([u8]) into a kind. - /// - /// > 👉 **Note**: an opening paren must be used for `Kind::Paren`. - /// - /// ## Panics - /// - /// Panics if `byte` is not `(`, `"`, or `'`. - fn from_byte(byte: u8) -> Kind { - match byte { - b'(' => Kind::Paren, - b'"' => Kind::Double, - b'\'' => Kind::Single, - _ => unreachable!("invalid byte"), - } - } -} - /// State needed to parse titles. #[derive(Debug)] struct Info { /// Whether we’ve seen data. connect: bool, - /// Kind of title. - kind: Kind, + /// Closing marker. + marker: u8, /// Configuration. options: Options, } @@ -124,10 +67,11 @@ struct Info { /// ``` pub fn start(tokenizer: &mut Tokenizer, options: Options) -> State { match tokenizer.current { - Some(byte) if matches!(byte, b'"' | b'\'' | b'(') => { + Some(b'"' | b'\'' | b'(') => { + let marker = tokenizer.current.unwrap(); let info = Info { connect: false, - kind: Kind::from_byte(byte), + marker: if marker == b'(' { b')' } else { marker }, options, }; tokenizer.enter(info.options.title.clone()); @@ -150,7 +94,7 @@ pub fn start(tokenizer: &mut Tokenizer, options: Options) -> State { /// ``` fn begin(tokenizer: &mut Tokenizer, info: Info) -> State { match tokenizer.current { - Some(byte) if byte == info.kind.as_byte() => { + Some(b'"' | b'\'' | b')') if tokenizer.current.unwrap() == info.marker => { tokenizer.enter(info.options.marker.clone()); tokenizer.consume(); tokenizer.exit(info.options.marker.clone()); @@ -172,10 +116,6 @@ fn begin(tokenizer: &mut Tokenizer, info: Info) -> State { /// ``` fn at_break(tokenizer: &mut Tokenizer, mut info: Info) -> State { match tokenizer.current { - Some(byte) if byte == info.kind.as_byte() => { - tokenizer.exit(info.options.string.clone()); - begin(tokenizer, info) - } None => State::Nok, Some(b'\n') => tokenizer.go( space_or_tab_eol_with_options(EolOptions { @@ -187,7 +127,11 @@ fn at_break(tokenizer: &mut Tokenizer, mut info: Info) -> State { at_break(t, info) }, )(tokenizer), - _ => { + Some(b'"' | b'\'' | b')') if tokenizer.current.unwrap() == info.marker => { + tokenizer.exit(info.options.string.clone()); + begin(tokenizer, info) + } + Some(_) => { tokenizer.enter_with_content(Token::Data, Some(ContentType::String)); if info.connect { @@ -210,21 +154,18 @@ fn at_break(tokenizer: &mut Tokenizer, mut info: Info) -> State { /// ``` fn title(tokenizer: &mut Tokenizer, info: Info) -> State { match tokenizer.current { - Some(byte) if byte == info.kind.as_byte() => { + None | Some(b'\n') => { tokenizer.exit(Token::Data); at_break(tokenizer, info) } - None | Some(b'\n') => { + Some(b'"' | b'\'' | b')') if tokenizer.current.unwrap() == info.marker => { tokenizer.exit(Token::Data); at_break(tokenizer, info) } - Some(b'\\') => { + Some(byte) => { + let func = if matches!(byte, b'\\') { escape } else { title }; tokenizer.consume(); - State::Fn(Box::new(|t| escape(t, info))) - } - _ => { - tokenizer.consume(); - State::Fn(Box::new(|t| title(t, info))) + State::Fn(Box::new(move |t| func(t, info))) } } } @@ -237,7 +178,7 @@ fn title(tokenizer: &mut Tokenizer, info: Info) -> State { /// ``` fn escape(tokenizer: &mut Tokenizer, info: Info) -> State { match tokenizer.current { - Some(byte) if byte == info.kind.as_byte() => { + Some(b'"' | b'\'' | b')') => { tokenizer.consume(); State::Fn(Box::new(|t| title(t, info))) } -- cgit