Skip to main content

winnow/_topic/
why.rs

1//! # Why `winnow`?
2//!
3//! To answer this question, it will be useful to contrast this with other approaches to parsing.
4//!
5//! <div class="warning">
6//!
7//! **Note:** This will focus on principles and priorities. For a deeper and wider
8//! comparison with other Rust parser libraries, see
9//! [parse-rosetta-rs](https://github.com/rosetta-rs/parse-rosetta-rs).
10//!
11//! </div>
12//!
13//! ## Hand-written parsers
14//!
15//! Typically, a hand-written parser gives you the flexibility to get
16//! - Fast parse performance
17//! - Fast compile-time
18//! - Small binary sizes
19//! - High quality error message
20//! - Fewer dependencies to audit
21//!
22//! However, this comes at the cost of doing it all yourself, including
23//! - Optimizing for each of the above characteristics you care about
24//! - Ensuring the safety of any `unsafe` code (buffer overflows being a common bug with parsers)
25//! - Being aware of, familiar with, and correctly implement the relevant algorithms.
26//!   matklad, who has written two rust compile frontends, commented
27//!   ["I’ve implemented a production-grade Pratt parser once, but I no longer immediately understand that code :-)"](https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html)
28//!
29//! This approach works well if:
30//! - Your format is small and is unlikely to change
31//! - Your format is large but you have people who can focus solely on parsing, like with large
32//!   programming languages
33//!
34//! ## `winnow`
35//!
36//! Unlike traditional programming language parsers that use
37//! [lex](https://en.wikipedia.org/wiki/Lex_(software)) or
38//! [yacc](https://en.wikipedia.org/wiki/Yacc), you can think of `winnow` as a general version of
39//! the helpers you would create along the way to writing a hand-written parser.
40//!
41//! `winnow` includes support for:
42//! - Zero-copy parsing
43//! - [Parse traces][trace] for easier debugging
44//! - [Streaming parsing][Partial] for network communication or large file
45//! - [Stateful] parsers
46//!
47//! For binary formats, `winnow` includes:
48//! - [A hexadecimal view][crate::Bytes] in [trace]
49//! - [TLV](https://en.wikipedia.org/wiki/Type-length-value) (e.g. [`length_take`])
50//! - Some common parsers to help get started, like numbers
51//!
52//! For text formats, `winnow` includes:
53//! - [Tracking of spans][crate::LocatingSlice]
54//! - [A textual view when parsing as bytes][crate::BStr] in [trace]
55//! - Ability to evaluate directly, parse to an AST, or lex and parse the format
56//!
57//! This works well for:
58//! - Prototyping for what will be a hand-written parser
59//! - When you want to minimize the work to evolve your format
60//! - When you don't have contributors focused solely on parsing and your grammar is large enough
61//!   to be unwieldy to hand write.
62//!
63//! ## `nom`
64//!
65//! `winnow` is a fork of the venerable [`nom`](https://crates.io/crates/nom). The difference
66//! between them is largely in priorities.  `nom` prioritizes:
67//! - Lower churn for existing users while `winnow` is trying to find ways to make things better
68//!   for the parsers yet to be written.
69//! - Having a small core, relying on external crates like
70//!   [`nom-locate`](https://crates.io/crates/nom_locate) and
71//!   [`nom-supreme`](https://crates.io/crates/nom-supreme), encouraging flexibility among users
72//!   and to not block users on new features being merged while `winnow` aims to include all the
73//!   fundamentals for parsing to ensure the experience is cohesive and high quality.
74//!
75//! For more details, see the [design differences][super::nom#api-differences].
76//!
77//! See also our [nom migration guide][super::nom#migrating-from-nom].
78//!
79//! ## `chumsky`
80//!
81//! [`chumsky`](https://crates.io/crates/chumsky) is an up and coming parser-combinator library
82//! that includes advanced features like error recovery.
83//!
84//! Probably the biggest diverging philosophy is `chumsky`s stance:
85//!
86//! > "If you need to implement either `Parser` or `Strategy` by hand, that's a problem that needs fixing".
87//!
88//! This is under "batteries included" but it also ties into the feeling that `chumsky` acts more like
89//! a framework. Instead of composing together helpers, you are expected to do everything through
90//! their system to the point that it is non-trivial to implement their `Parser` trait and are
91//! encouraged to use the
92//! [`custom`](https://docs.rs/chumsky/0.9.0/chumsky/primitive/fn.custom.html) helper. This
93//! requires re-framing everything to fit within their model and makes the code harder to understand
94//! and debug as you are working with abstract operations that will eventually be applied
95//! rather than directly with the parsers.
96//!
97//! In contrast, `winnow` is an introspectable toolbox that can easily be customized at any level.
98//! Probably the biggest thing that `winnow` loses out on is optimizations from ["parse modes" via
99//! GATs](https://github.com/zesterer/chumsky/pull/82) which allows downstream parsers to tell
100//! upstream parsers when information will be discarded, allowing bypassing expensive operations,
101//! like allocations. This requires a lot more complex interaction with parsers that isn't as
102//! trivial to do with bare functions which would lose out on any of that side-band information.
103//! Instead, we work around this with things like the [`Accumulate`] trait.
104
105#![allow(unused_imports)]
106use crate::binary::length_take;
107use crate::combinator::trace;
108use crate::stream::Accumulate;
109use crate::stream::Partial;
110use crate::stream::Stateful;