Skip to content

Commit 265367a

Browse files
committed
Big improvement to the documentation of this crate
1 parent da55102 commit 265367a

File tree

2 files changed

+122
-3
lines changed

2 files changed

+122
-3
lines changed

Cargo.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,5 @@ proc-macro2 = "1.0"
4343
syn = { version = "2.0", features = ["extra-traits", "full", "visit", "visit-mut"] }
4444
itertools = "0.14.0"
4545
phf = { version = "0.11.2", features = ["macros"] }
46-
47-
[dev-dependencies]
4846
nom-parse-trait = "0.2.0"
49-
nom = "7.1"
47+
nom = "7.1.3"

src/lib.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,46 @@
1+
//! # nom-parse-trait
2+
//!
3+
//! This macro generates a `ParseFrom` implementation for a struct or enum using the provided
4+
//! nom expression(s). The expression should return a tuple for the parsed fields.
5+
//!
6+
//! There are 2 separate macros available, [`parse_from()`] and [`parse_match()`].
7+
//! The first one is really generic and can be useful in many cases, since you have the full
8+
//! flexibility of nom functions and combinators. The second one is a very simple one that
9+
//! matches a string verbatim. This is useful when you have a very simple format that you want
10+
//! to parse.
11+
//!
12+
//! # nom functions
13+
//!
14+
//! The expression in the `parse_from` attribute will be translated to be using valid nom functions.
15+
//! The main function here is to automatically put the namespace before the function name, so you
16+
//! don't need a ton of use statements in your code. But there are also a couple of special cases:
17+
//!
18+
//! - `{}` or `()` will be replaced with a [`nom_parse_trait::ParseFrom::parse`] call for the
19+
//! corresponding field. This is useful when you are using types that have implemented the
20+
//! `ParseFrom` trait already.
21+
//! - Strings, bytes strings and characters will be translated to match the input verbatim using
22+
//! the [`nom::bytes::complete::tag`] function.
23+
//!
24+
//! # Input types that are supported
25+
//!
26+
//! The generated `ParseFrom` implementation is made to be very generic, where it supports any
27+
//! input and error type from nom. This is done with a where clause with many traits that the input
28+
//! should have implemented. All of these are true for the standard `&str` and `&[u8]` types.
29+
//!
30+
//! If you run into a situation where the trait limitations on the input type does not match your
31+
//! use case, please open an issue on the GitHub repository.
32+
//!
33+
//! # Known limitations
34+
//!
35+
//! - When your try to use a custom parser combinator, the nom function parser will try to change
36+
//! all parameters to be nom parsers. This is useful in many cases, but when you need to pass in
37+
//! a normal string for example, it won't work. In these cases, you can define a separate function
38+
//! to wrap the call. I'm not sure how to fix that right now, but I'm open to suggestions.
39+
//!
40+
//! - Since the generated input type is very generic, all functions that you want to use in the
41+
//! nom expression should also be very generic. In the future I might add a way to specify if you
42+
//! want to generate a specific input type, but for now it's not possible.
43+
144
extern crate proc_macro;
245
mod fields;
346
mod nom_packages;
@@ -16,6 +59,63 @@ use syn::{
1659
LitStr, TypeParam, WhereClause, WherePredicate,
1760
};
1861

62+
/// This macro generates a [`nom_parse_trait::ParseFrom`] implementation for a struct or enum using
63+
/// the provided nom expression(s). The expression should return a tuple for the parsed fields.
64+
///
65+
/// # Examples
66+
///
67+
/// ## Basic struct with fields
68+
///
69+
/// This first example shows how to parse a simple struct with two fields, using the `separated_pair`
70+
/// combinator. Here we also show some of the special parsing that goes on behind the scenes, where
71+
/// the special {} syntax means that it infers the type parser it needs to use in that place. Also,
72+
/// we accept normal strings as matching input, which will be translated to `tag` function calls.
73+
///
74+
/// ```rust
75+
/// use nom_parse_macros::parse_from;
76+
///
77+
/// #[parse_from(separated_pair({}, tuple(space0, ",", space0), {}))]
78+
/// struct NumberPair {
79+
/// x: u32,
80+
/// y: u32,
81+
/// }
82+
/// ```
83+
///
84+
/// ## Basic enum with variants
85+
///
86+
/// This example shows how we can define a format for each variant in an enum. The first variant
87+
/// actually uses the default `ParseFrom` implementation for parsing the u32. The `Numbers` variant
88+
/// uses a custom format, which is a delimited list of u32 values.
89+
///
90+
/// ```rust
91+
/// use nom_parse_macros::parse_from;
92+
///
93+
/// #[parse_from]
94+
/// enum MultipleTypes {
95+
/// Number(u32),
96+
/// #[format(delimited('(', separated_list0(",", {}), ')'))]
97+
/// Numbers(Vec<u32>),
98+
/// }
99+
/// ```
100+
///
101+
/// ## Derived fields
102+
///
103+
/// Sometimes it's useful to have a field that is not actually parsed, but derived from the other
104+
/// fields. This can be done with the `#[derived]` attribute. In this example, we derive the sum of
105+
/// the two fields `x` and `y`.
106+
///
107+
/// ```rust
108+
/// use nom_parse_macros::parse_from;
109+
///
110+
/// #[parse_from(separated_pair({}, tuple(space0, ",", space0), {}))]
111+
/// struct NumberPair {
112+
/// x: u32,
113+
/// y: u32,
114+
/// #[derived(x + y)]
115+
/// sum: u32,
116+
/// }
117+
/// ```
118+
19119
#[proc_macro_attribute]
20120
pub fn parse_from(attrs: TokenStream, object: TokenStream) -> TokenStream {
21121
match parse_macro_input!(object as Item) {
@@ -135,6 +235,27 @@ fn generate_enum_parser(mut object: ItemEnum) -> TokenStream {
135235
)
136236
}
137237

238+
/// The `parse_match` macro can be used to match strings verbatim. This is useful when you have
239+
/// a very simple format that you want to parse. The {} gets replaced with a parser for the
240+
/// corresponding field. The rest of the characters are matched verbatim.
241+
///
242+
/// # Example
243+
///
244+
/// This example shows how to parse a three-dimensional vector from a string with a fixed format.
245+
/// As you can see, this macro is limited in its use, but is very straightforward to use in cases
246+
/// where it works.
247+
///
248+
/// ```rust
249+
/// use nom_parse_macros::parse_match;
250+
///
251+
/// #[parse_match("({},{},{})")]
252+
/// struct Vector3 {
253+
/// x: u32,
254+
/// y: u32,
255+
/// z: u32,
256+
/// }
257+
/// ```
258+
///
138259
#[proc_macro_attribute]
139260
pub fn parse_match(attrs: TokenStream, object: TokenStream) -> TokenStream {
140261
let literal = parse_macro_input! { attrs as LitStr };

0 commit comments

Comments
 (0)