1 //! # For `nom` users 2 //! 3 //! ## Migrating from `nom` 4 //! 5 //! For comparisons with `nom`, see 6 //! - [Why `winnow`][super::why] 7 //! - [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs/) 8 //! 9 //! What approach you take depends on the size and complexity of your parser. 10 //! For small, simple parsers, its likely easiest to directly port from `nom`. 11 //! When trying to look for the equivalent of a `nom` combinator, search in the docs for the name 12 //! of the `nom` combinator. It is expected that, where names diverge, a doc alias exists. 13 //! See also the [List of combinators][crate::combinator]. 14 //! 15 //! ### Complex migrations 16 //! 17 //! For larger parsers, it is likely best to take smaller steps 18 //! - Easier to debug when something goes wrong 19 //! - Deprecation messages will help assist through the process 20 //! 21 //! The workflow goes something like: 22 //! 1. Run `cargo rm nom && cargo add winnow@0.3` 23 //! 1. Ensure everything compiles and tests pass, ignoring deprecation messages (see [migration 24 //! notes](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md#nom-migration-guide)) 25 //! 1. Commit 26 //! 1. Switch any `impl FnMut(I) -> IResult<I, O, E>` to `impl Parser<I, O, E>` 27 //! 1. Resolve deprecation messages 28 //! 1. Commit 29 //! 1. Run `cargo add winnow@0.4` 30 //! 1. Ensure everything compiles and tests pass, ignoring deprecation messages (see [changelog](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md#040---2023-03-18) for more details) 31 //! 1. Commit 32 //! 1. Resolve deprecation messages 33 //! 1. Commit 34 //! 1. Run `cargo add winnow@0.5` 35 //! 1. Ensure everything compiles and tests pass, ignoring deprecation messages (see [migration 36 //! notes](https://github.com/winnow-rs/winnow/blob/main/CHANGELOG.md#050---2023-07-13)) 37 //! 1. Commit 38 //! 1. Resolve deprecation messages 39 //! 1. Commit 40 //! 41 //! ### Examples 42 //! 43 //! For example migrations, see 44 //! - [git-config-env](https://github.com/gitext-rs/git-config-env/pull/11) (nom to winnow 0.3) 45 //! - [git-conventional](https://github.com/crate-ci/git-conventional/pull/37) (nom to winnow 0.3, 46 //! adds explicit tracing for easier debugging) 47 //! - [typos](https://github.com/crate-ci/typos/pull/664) (nom to winnow 0.3) 48 //! - [cargo-smart-release](https://github.com/Byron/gitoxide/pull/948) (gradual migration from nom 49 //! to winnow 0.5) 50 //! - [gix-config](https://github.com/Byron/gitoxide/pull/951) (gradual migration from nom 51 //! to winnow 0.5) 52 //! - [gix-protocol](https://github.com/Byron/gitoxide/pull/1009) (gradual migration from nom 53 //! to winnow 0.5) 54 //! - [gitoxide](https://github.com/Byron/gitoxide/pull/956) (gradual migration from nom 55 //! to winnow 0.5) 56 //! 57 //! ## Differences 58 //! 59 //! These are key differences to help Nom users adapt to writing parsers with Winnow. 60 //! 61 //! ### Renamed APIs 62 //! 63 //! Names have changed for consistency or clarity. 64 //! 65 //! To find a parser you are looking for, 66 //! - Search the docs for the `nom` parser 67 //! - See the [List of combinators][crate::combinator] 68 //! 69 //! ### GATs 70 //! 71 //! `nom` v8 back-propagates how you will use a parser to parser functions using a language feature 72 //! called GATs. 73 //! Winnow has made the conscious choice not to use this feature, finding alternative ways of 74 //! getting most of the benefits. 75 //! 76 //! Benefits of GATs: 77 //! - Performance as the compiler is able to instantiate copies of a parser that are 78 //! better tailored to how it will be used, like discarding unused allocations for output or 79 //! errors. 80 //! 81 //! Benefits of not using GATs: 82 //! - Predictable performance: 83 //! With GATs, seemingly innocuous changes like choosing to hand write a parser using idiomatic function parsers 84 //! (`fn(&mut I) -> Result<O>`) can cause surprising slow downs because these functions sever the back-propagation from GATs. 85 //! The causes of these slowdowns could be hard to identify by inspection or profiling. 86 //! - No "eek out X% perf improvement" pressure to contort a parser 87 //! that is more easily written imperatively 88 //! to be written declaratively 89 //! so it can preserve the back-propagation from GATs. 90 //! - Built-in parsers serve are can serve as examples to users of idiomatic function parsers 91 //! (`fn(&mut I) -> Result<O>`). 92 //! With GATs, built-in parsers tend to be complex implementations of traits. 93 //! - Faster build times and smaller binary size as parsers only need to be generated for one mode, 94 //! not upto 8 95 //! 96 //! #### Partial/streaming parsers 97 //! 98 //! `nom` v8 back-propagates whether `Parser::parse_complete` was used to select `complete` 99 //! parsers. 100 //! Previously, users had ensure consistently using a parser from the `streaming` or `complete` module. 101 //! 102 //! Instead, you tag the input type (`I`) by wrapping it in [`Partial<I>`] and parsers will adjust 103 //! their behavior accordingly. 104 //! See [partial] special topic. 105 //! 106 //! #### Eliding Output 107 //! 108 //! `nom` v8 back-propagates whether an Output will be used and skips its creation. 109 //! For example, `value(Null, many0(_))` will avoid creating and pushing to a `Vec`. 110 //! Previously, users had to select `count_many0` over `many0` to avoid creating a `Vec`. 111 //! 112 //! Instead, `repeat` returns an `impl Accumulate<T>` which could be a `Vec`, a `usize` for `count` 113 //! variants, or `()` to do no extra work. 114 //! 115 //! #### Eliding Backtracked Errors 116 //! 117 //! Under the hood, [`alt`] is an `if-not-error-else` ladder, see [`_tutorial::chapter_3`]. 118 //! nom v8 back-propagates whether the error will be discarded and avoids any expensive work done 119 //! for rich error messages. 120 //! 121 //! Instead, [`ContextError`] and other changes have made it so errors have very little overhead. 122 //! [`dispatch!`] can also be used in some situations to avoid `alt`s overhead. 123 //! 124 //! ### Parsers return [`Stream::Slice`], rather than [`Stream`] 125 //! 126 //! In `nom`, parsers like [`take_while`] parse a [`Stream`] and return a [`Stream`]. 127 //! When wrapping the input, like with [`Stateful`], 128 //! you have to unwrap the input to integrate it in your application, 129 //! and it requires [`Stream`] to be `Clone` 130 //! (which requires `RefCell` for mutable external state and can be expensive). 131 //! 132 //! Instead, [`Stream::Slice`] was added to track the intended type for parsers to return. 133 //! If you want to then parse the slice, you then need to take it and turn it back into a 134 //! [`Stream`]. 135 //! 136 //! ### `&mut I` 137 //! 138 //! `winnow` switched from pure-function parser (`Fn(I) -> (I, O)` to `Fn(&mut I) -> O`). 139 //! On error, `i` is left pointing at where the error happened. 140 //! 141 //! Benefits of `Fn(&mut I) -> O`: 142 //! - Cleaner code: Removes need to pass `i` everywhere and makes changes to `i` more explicit 143 //! - Correctness: No forgetting to chain `i` through a parser 144 //! - Flexibility: `I` does not need to be `Copy` or even `Clone`. For example, [`Stateful`] can use `&mut S` instead of `RefCell<S>`. 145 //! - Performance: `Result::Ok` is smaller without `i`, reducing the risk that the output will be 146 //! returned on the stack, rather than the much faster CPU registers. 147 //! `Result::Err` can also be smaller because the error type does not need to carry `i` to point 148 //! to the error. 149 //! See also [#72](https://github.com/winnow-rs/winnow/issues/72). 150 //! 151 //! Benefits of `Fn(I) -> (I, O)`: 152 //! - Pure functions can be easier to reason about 153 //! - Less boilerplate in some situations (see below) 154 //! - Less syntactic noise in some situations (see below) 155 //! 156 //! When returning a slice from the input, you have to add a lifetime: 157 //! ```rust 158 //! # use winnow::prelude::*; 159 //! fn foo<'i>(i: &mut &'i str) -> ModalResult<&'i str> { 160 //! # Ok("") 161 //! // ... 162 //! } 163 //! ``` 164 //! 165 //! When writing a closure, you need to annotate the type 166 //! ```rust 167 //! # use winnow::prelude::*; 168 //! # use winnow::combinator::alt; 169 //! # use winnow::error::ContextError; 170 //! # let mut input = ""; 171 //! # fn foo<'i>() -> impl ModalParser<&'i str, &'i str, ContextError> { 172 //! alt(( 173 //! |i: &mut _| { 174 //! # Ok("") 175 //! // ... 176 //! }, 177 //! |i: &mut _| { 178 //! # Ok("") 179 //! // ... 180 //! }, 181 //! )) 182 //! # } 183 //! ``` 184 //! *(at least the full type isn't needed)* 185 //! 186 //! To save and restore from intermediate states, [`Stream::checkpoint`] and [`Stream::reset`] can help: 187 //! ```rust 188 //! use winnow::stream::Stream as _; 189 //! # let mut i = ""; 190 //! # let i = &mut i; 191 //! 192 //! let start = i.checkpoint(); 193 //! // ... 194 //! i.reset(&start); 195 //! ``` 196 //! 197 //! When the Output of a parser is a slice, you have to add a lifetime: 198 //! ```rust 199 //! # use winnow::prelude::*; 200 //! fn foo<'i>(i: &mut &'i str) -> PResult<&'i str> { 201 //! // ... 202 //! # winnow::token::rest.parse_next(i) 203 //! } 204 //! ``` 205 //! 206 //! When writing a closure, you need to annotate the type: 207 //! ```rust 208 //! # use winnow::prelude::*; 209 //! # use winnow::combinator::trace; 210 //! fn foo(i: &mut &str) -> PResult<usize> { 211 //! trace("foo", |i: &mut _| { 212 //! // ... 213 //! # Ok(0) 214 //! }).parse_next(i) 215 //! } 216 //! ``` 217 218 #![allow(unused_imports)] 219 use crate::_topic::partial; 220 use crate::_tutorial; 221 use crate::combinator::alt; 222 use crate::combinator::dispatch; 223 use crate::error::ContextError; 224 use crate::error::ErrMode; 225 use crate::error::ModalResult; 226 use crate::stream::Accumulate; 227 use crate::stream::Partial; 228 use crate::stream::Stateful; 229 use crate::stream::Stream; 230 use crate::token::take_while; 231