diff options
author | Titus Wormer <tituswormer@gmail.com> | 2022-07-29 18:22:59 +0200 |
---|---|---|
committer | Titus Wormer <tituswormer@gmail.com> | 2022-07-29 18:22:59 +0200 |
commit | 0eeff9148e327183e532752f46421a75506dd7a6 (patch) | |
tree | 4f0aed04f90aa759ce96a2e87aa719e7fa95c450 /src/construct/partial_title.rs | |
parent | 148ede7f0f42f0ccb1620b13d91f35d0c7d04c2f (diff) | |
download | markdown-rs-0eeff9148e327183e532752f46421a75506dd7a6.tar.gz markdown-rs-0eeff9148e327183e532752f46421a75506dd7a6.tar.bz2 markdown-rs-0eeff9148e327183e532752f46421a75506dd7a6.zip |
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`
Diffstat (limited to '')
-rw-r--r-- | src/construct/partial_title.rs | 93 |
1 files changed, 17 insertions, 76 deletions
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))) } |