### Haskell Iteratee Basic Structure Source: https://github.com/rust-bakery/nom/blob/main/assets/links.txt Provides a foundational example of Haskell's Iteratee, a library for processing streams of data. It demonstrates the core components and their interaction for handling potentially infinite data streams. ```haskell data Iteratee state elem output = Continue (Input elem -> Iteratee state elem output) | Yield output state (Iteratee state elem output) | Done output state | Error String (Iteratee state elem output) ``` -------------------------------- ### Rust: Example of using context combinator with VerboseError Source: https://github.com/rust-bakery/nom/blob/main/doc/error_management.md Demonstrates how the `nom::error::context` combinator can be used to add descriptive labels to parser errors, improving the debugging experience. This example shows context being applied to a string parsing operation. ```rust context( "string", preceded(char('"'), cut(terminated(parse_str, char('"')))), )(i) ``` -------------------------------- ### Scala Play Framework Iteratee Example Source: https://github.com/rust-bakery/nom/blob/main/assets/links.txt Demonstrates a basic usage of Iteratees within the Play Framework in Scala. This snippet shows how to consume data from an Enumerator using an Iteratee. ```scala import play.api.libs.iteratee._ val enumerator = Enumerator("Hello".getBytes, " ".getBytes, "World".getBytes) val iteratee = Iteratee.consume[Array[Byte]]().map(bytes => new String(bytes)) val result = enumerator(iteratee) result.run(new Array[Byte](0)) map { bytes => println(new String(bytes)) } ``` -------------------------------- ### Rust Monad Example Source: https://github.com/rust-bakery/nom/blob/main/assets/links.txt Illustrates the concept of monads in Rust, drawing parallels with their use in Haskell. Monads provide a way to structure computations, particularly for handling side effects and sequential operations. ```rust struct MyMonad(Option); impl MyMonad { fn bind(self, f: F) -> MyMonad where F: FnOnce(T) -> MyMonad, { match self.0 { Some(value) => f(value), None => MyMonad(None), } } } fn main() { let m1 = MyMonad(Some(5)); let m2 = m1.bind(|x| MyMonad(Some(x * 2))); println!("{:?}", m2.0); } ``` -------------------------------- ### Rust: Example usage of `pair` combinator with `alpha0` and `digit0` Source: https://github.com/rust-bakery/nom/blob/main/doc/upgrading_to_nom_5.md This Rust code demonstrates how to use the `pair` combinator to combine two parsers, `alpha0` (which parses zero or more alphabetic characters) and `digit0` (which parses zero or more digits). The `parser` function takes a string slice and returns an `IResult` containing a tuple of the parsed alphabetic and digit strings. The example shows calling this parser with the input 'abc123;' and the expected output. ```rust fn parser(i: &str) -> IResult<&str, (&str, &str)> { pair(alpha0, digit0)(i) } // will return `Ok((";", ("abc", "123")))` parser("abc123;"); ``` -------------------------------- ### JSON Parser Error Example Source: https://github.com/rust-bakery/nom/blob/main/doc/error_management.md An example demonstrating the output of a JSON parser using nom's default error type. It showcases a Failure error with the input slice and the Char ErrorKind at the point of failure. ```rust let data = " { \"a\" : 42, \"b\": [ \"x\", \"y\", 12 ] , \"c\": { 1\"hello\" : \"world\" } } "; // will print: // Err( // Failure( // Error { // input: "1\"hello\" : \"world\"\n }\n } ", // code: Char, // }, // ), // ) println!( "{:#?}\n", json::>(data) ); ``` -------------------------------- ### Rust: Parse Floating-Point Numbers with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Parses various floating-point number formats, including those starting with '.', those with scientific notation (e/E), and those ending with '.'. It leverages the `decimal` parser and handles optional signs and fractional parts. This parser requires the `nom` crate. ```rust use nom::{ IResult, Parser, branch::alt, multi::{many0, many1}, combinator::{opt, recognize}, sequence::{preceded, terminated}, character::complete::{char, one_of}, }; fn float(input: &str) -> IResult<&str, &str> { alt(( // Case one: .42 recognize( ( char('.'), decimal, opt(( one_of("eE"), opt(one_of("+-")), decimal )) ) ) , // Case two: 42e42 and 42.42e42 recognize( ( decimal, opt(preceded( char('.'), decimal, )), one_of("eE"), opt(one_of("+-")), decimal ) ) , // Case three: 42. and 42.42 recognize( ( decimal, char('.'), opt(decimal) ) ) )).parse(input) } fn decimal(input: &str) -> IResult<&str, &str> { recognize( many1( terminated(one_of("0123456789"), many0(char('_'))) ) ).parse(input) } ``` -------------------------------- ### Rust Hexadecimal Color Parser Example using nom Source: https://github.com/rust-bakery/nom/blob/main/README.md This Rust code snippet demonstrates how to parse a hexadecimal color string (e.g., '#2F14DF') into a Color struct using the 'nom' parser combinator library. It defines helper functions for hex conversion and parsing, and includes a test case for validation. Dependencies include 'nom'. ```rust use nom::{ bytes::complete::{tag, take_while_m_n}, combinator::map_res, sequence::Tuple, IResult, Parser, }; #[derive(Debug, PartialEq)] pub struct Color { pub red: u8, pub green: u8, pub blue: u8, } fn from_hex(input: &str) -> Result { u8::from_str_radix(input, 16) } fn is_hex_digit(c: char) -> bool { c.is_digit(16) } fn hex_primary(input: &str) -> IResult<&str, u8> { map_res( take_while_m_n(2, 2, is_hex_digit), from_hex ).parse(input) } fn hex_color(input: &str) -> IResult<&str, Color> { let (input, _) = tag("#")(input)?; let (input, (red, green, blue)) = (hex_primary, hex_primary, hex_primary).parse(input)?; Ok((input, Color { red, green, blue })) } fn main() { println!("{:?}", hex_color("#2F14DF")) } #[test] fn parse_color() { assert_eq!( hex_color("#2F14DF"), Ok(( "", Color { red: 47, green: 20, blue: 223, } )) ); } ``` -------------------------------- ### Rust: Parse Rust-Style Identifiers Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md This Rust function `identifier` parses Rust-style identifiers. These identifiers must start with an alphabetic character or underscore and can be followed by zero or more alphanumeric characters or underscores. It uses `recognize` to return the matched string slice. ```rust use nom::{ IResult, Parser, branch::alt, multi::many0_count, combinator::recognize, sequence::pair, character::complete::{alpha1, alphanumeric1}, bytes::complete::tag, }; pub fn identifier(input: &str) -> IResult<&str, &str> { recognize( pair( alt((alpha1, tag("_"))), many0_count(alt((alphanumeric1, tag("_")))) ) ).parse(input) } ``` -------------------------------- ### Rust: Parse C++/EOL-Style Comments Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md This Rust function `peol_comment` parses C++/EOL-style comments, starting with '%' and continuing until a newline character. It uses `value` to discard the parsed comment content and returns `()`. The parser does not consume the newline character itself. ```rust use nom::{ IResult, Parser, error::ParseError, combinator::value, sequence::pair, bytes::complete::is_not, character::complete::char, }; pub fn peol_comment<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (), E> { value( (), // Output is thrown away. pair(char('%'), is_not("\n\r")) ).parse(i) } ``` -------------------------------- ### Testing Parsers with Include Bytes in Rust Source: https://github.com/rust-bakery/nom/blob/main/doc/making_a_new_parser_from_scratch.md Shows how to use Rust's `include_bytes!` macro to embed a file directly into the code as a byte slice for parser testing. This is useful for testing parsers on binary file headers or other raw data. ```rust #[test] fn header_test() { let data = include_bytes!("../assets/axolotl-piano.gif"); println!("bytes:\n stroken{}", &data[0..100].to_hex(8)); let res = header(data); // ... } ``` -------------------------------- ### Building an HTTP Request Line Parser in Rust with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/making_a_new_parser_from_scratch.md Demonstrates composing basic nom parsers like take_while1 and tag to build a more complex HTTP request line parser. It uses combinators like preceded and parser tuples to assemble the final Request struct. ```rust // first implement the basic parsers let method = take_while1(is_alpha); let space = take_while1(|c| c == ' '); let url = take_while1(|c| c!= ' '); let is_version = |c| c >= b'0' && c <= b'9' || c == b'.'; let http = tag("HTTP/"); let version = take_while1(is_version); let line_ending = tag("\r\n"); // combine http and version to extract the version string // preceded will return the result of the second parser // if both succeed let http_version = preceded(http, version); // combine all previous parsers in one function fn request_line(i: &[u8]) -> IResult<&[u8], Request> { // Tuples of parsers are a parser themselves, // parsing with each of them sequentially and returning a tuple of their results. // Unlike most other parsers, parser tuples are not `FnMut`, they must be wrapped // in the `parse` function to be able to be used in the same way as the others. let (input, (method, _, url, _, version, _)) = (method, space, url, space, http_version, line_ending).parse(i)?; Ok((input, Request { method, url, version })) } ``` -------------------------------- ### Generate Rust Documentation Source: https://github.com/rust-bakery/nom/blob/main/CONTRIBUTING.md Generates documentation for the Rust project using `cargo doc`. This command builds the documentation for your crate and its dependencies. For previewing changes, it suggests using `cargo external-doc` which might offer additional features for documentation generation or preview. ```shell cargo doc ``` -------------------------------- ### Binary Format Parsing Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Combinators for parsing binary data structures. ```APIDOC ## `length_data` / `length_value` ### Description Parsers that read a length prefix and then parse a corresponding amount of data. ### Method `length_data`: Reads a length using the first parser, then returns a subslice of that length. `length_value`: Reads a length using the first parser, then applies a second parser to a subslice of that length. ### Endpoint N/A (Function calls) ### Parameters N/A (Function arguments) ### Request Example ```rust // Example for length_data let (input, data_slice) = length_data(length_parser).parse(input)?; ``` ### Response N/A (Return values from parsed input) ``` -------------------------------- ### Debugging Parsers with dbg_dmp in Rust Source: https://github.com/rust-bakery/nom/blob/main/doc/making_a_new_parser_from_scratch.md Presents the `dbg_dmp` utility from nom for debugging parsers. It wraps a parser and prints a hexdump of the input if the wrapped parser encounters an error, aiding in identifying parsing failures. ```rust use nom::{IResult, error::dbg_dmp, bytes::complete::tag}; fn f(i: &[u8]) -> IResult<&[u8], &[u8]> { dbg_dmp(tag("abcd"), "tag")(i) } let a = &b"efghijkl"[..]; // Will print the following message: // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) ' // 00000000 65 66 67 68 69 6a 6b 6c efghijkl f(a); ``` -------------------------------- ### Rust Macros for File Format Parsing Source: https://github.com/rust-bakery/nom/blob/main/assets/links.txt Demonstrates the use of Rust's macro system for parsing various file formats. This approach allows for flexible and powerful parsing logic to be defined at compile time. ```rust macro_rules! parse_int { ($input:expr, $type:ident) => { { // ... parsing logic here ... ($type::from_str($input).unwrap()) } }; } ``` -------------------------------- ### Rust: Basic Length-Value Parser with nom Source: https://github.com/rust-bakery/nom/blob/main/doc/making_a_new_parser_from_scratch.md Demonstrates a simple parser function in Rust using the nom library to parse a 16-bit unsigned integer length followed by a byte slice of that length. This function is designed for parsing binary data formats. ```rust use nom::IResult; use nom::number::complete::be_u16; use nom::bytes::complete::take; pub fn length_value(input: &[u8]) -> IResult<&[u8],&[u8]> { let (input, length) = be_u16(input)?; take(length)(input) } ``` -------------------------------- ### Testing Parsers with String Literals in Rust Source: https://github.com/rust-bakery/nom/blob/main/doc/making_a_new_parser_from_scratch.md Illustrates testing parsers that handle textual data by using string literals directly within Rust's assert_eq! macro. This method is effective for validating parsers against various string inputs and expected outputs. ```rust #[test] fn factor_test() { assert_eq!(factor("3"), Ok(("", 3))); assert_eq!(factor(" 12"), Ok(("", 12))); assert_eq!(factor("537 "), Ok(("", 537))); assert_eq!(factor(" 24 "), Ok(("", 24))); } ``` -------------------------------- ### Format Rust Code with Rustfmt (Stable) Source: https://github.com/rust-bakery/nom/blob/main/CONTRIBUTING.md Ensures consistent Rust code style by running the stable version of rustfmt. This command formats your Rust project according to the standard Rust coding style, promoting readability and maintainability. It's recommended to use the stable toolchain to avoid minor differences that might appear in nightly versions. ```shell cargo +stable fmt ``` -------------------------------- ### Bit Stream Parsing Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Combinators for parsing data at the bit level. ```APIDOC ## `bits` / `bytes` ### Description Tools for switching between byte and bit stream parsing contexts. ### Method `bits`: Transforms the input to a bit stream, allowing bit-specific parsers. `bytes`: Transforms a bit stream input back into a byte slice for an underlying parser. ### Endpoint N/A (Function calls) ### Parameters N/A (Function arguments) ### Request Example ```rust // Example for bits let (input, bit_output) = bits(bit_parser).parse(input)?; ``` ### Response N/A (Return values from parsed input) ``` -------------------------------- ### Text Parsing Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Combinators specifically designed for parsing text data. ```APIDOC ## `escaped` / `escaped_transform` ### Description Parsers for handling escaped characters within byte strings. ### Method `escaped`: Matches a byte string containing escaped characters. `escaped_transform`: Matches a byte string with escaped characters and transforms it into a new string with escapes resolved. ### Endpoint N/A (Function calls) ### Parameters N/A (Function arguments) ### Request Example ```rust // Example for escaped_transform let (input, transformed_string) = escaped_transform(escaped_char, transform_function).parse(input)?; ``` ### Response N/A (Return values from parsed input) ``` ```APIDOC ## `precedence` ### Description Parses expressions considering operator precedence. ### Method `precedence`: Parses an expression by handling operators based on their defined precedence levels. ### Endpoint N/A (Function call) ### Parameters N/A (Function arguments) ### Request Example ```rust // Example for precedence let (input, expression_value) = precedence(grammar_rules).parse(input)?; ``` ### Response N/A (Return values from parsed input) ``` -------------------------------- ### Error Management and Debugging Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Utilities for managing and debugging parsing errors. ```APIDOC ## `dbg_dmp` ### Description Prints debugging information and the input upon parser failure. ### Method `dbg_dmp`: A combinator that prints a message and the input if the nested parser fails. ### Endpoint N/A (Function call) ### Parameters N/A (Function arguments) ### Request Example ```rust // Example for dbg_dmp let (input, output) = dbg_dmp("Parser failed here:")(parser).parse(input)?; ``` ### Response N/A (Return values from parsed input) ``` -------------------------------- ### Rust Lexer Implementation (rustlex) Source: https://github.com/rust-bakery/nom/blob/main/assets/links.txt Showcases an implementation of a lexer using the rustlex library. Lexers are essential components in parsing, responsible for breaking down input streams into tokens. ```rust use rustlex::Lexer; fn main() { let mut lexer = Lexer::new(r"[a-z]+"); let input = "hello world"; let tokens = lexer.tokenize(input); println!("{:?}", tokens); } ``` -------------------------------- ### Rust: Implement `take` combinator using closures Source: https://github.com/rust-bakery/nom/blob/main/doc/upgrading_to_nom_5.md This function implements a simplified `take` combinator in Rust. It returns a closure that attempts to take a specified number of bytes from the input slice. Dependencies include `nom`'s `IResult`, `Err`, and `ErrorKind`. It takes a `usize` count and a byte slice `&[u8]` as input, returning a result containing the remaining slice and the taken slice, or an error if the input is too short. ```rust pub fn take(count: usize) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> where { move |i: &[u8]| { if i.len() < count { Err(Err::Error((i, ErrorKind::Eof))) } else { Ok(i.split_at(count)) } } } ``` -------------------------------- ### Nom Sequence Combinator - Tuple Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Shows how to use the `tuple` combinator to chain multiple parsers together and collect their results into a tuple. This is useful for parsing structured data with a fixed sequence of elements. ```rust use nom::bytes::complete::tag; use nom::bytes::streaming::take; use nom::sequence::tuple; // Example for tuple let tuple_parser = tuple((tag("ab"), tag("XY"), take(1u8))); let input = "abXYZ!"; let result = tuple_parser(input); // result is Ok(("!", ("ab", "XY", "Z"))) ``` -------------------------------- ### Nom Sequence Combinators - Delimited, Preceded, Terminated Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Demonstrates the usage of `delimited`, `preceded`, and `terminated` sequence combinators in Nom. These combinators allow for parsing elements with specific boundaries or ordering. ```rust use nom::bytes::complete::tag; use nom::character::complete::char; use nom::sequence::{delimited, preceded, terminated}; use nom::combinator::map_res; // Example for delimited let delimited_parser = delimited(char('('), tag("ab"), char(')')); let input1 = "(ab)cd"; let result1 = delimited_parser(input1); // result1 is Ok(("cd", "ab")) // Example for preceded let preceded_parser = preceded(tag("ab"), tag("XY")); let input2 = "abXYZ"; let result2 = preceded_parser(input2); // result2 is Ok(("Z", "XY")) // Example for terminated let terminated_parser = terminated(tag("ab"), tag("XY")); let input3 = "abXYZ"; let result3 = terminated_parser(input3); // result3 is Ok(("Z", "ab")) ``` -------------------------------- ### Nom Byte Sequence Parser: take() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `take()` parser in Rust's 'nom' crate consumes and returns a specific number of bytes or characters from the input. It returns the taken slice and the remaining input. Useful for fixed-size fields. ```rust use nom::bytes::complete::take; let input = "hello"; let result = take(4usize)(input); // result is Ok(("o", "hell")) ``` -------------------------------- ### Rust: Parse Decimal String Slice with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Parses a decimal number string, handling optional underscores within the digits. This parser does not require a prefix. It uses `recognize` to capture the matched digits. This parser requires the `nom` crate. ```rust use nom::{ IResult, Parser, multi::{many0, many1}, combinator::recognize, sequence::terminated, character::complete::{char, one_of}, }; fn decimal(input: &str) -> IResult<&str, &str> { recognize( many1( terminated(one_of("0123456789"), many0(char('_'))) ) ).parse(input) } ``` -------------------------------- ### Rust: Parse with Leading/Trailing Whitespace Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md This Rust function `ws` is a combinator that consumes leading and trailing whitespace around another parser. It utilizes `delimited` with `multispace0` to achieve this. It returns the output of the inner parser and discards the whitespace. Custom whitespace parsers can be substituted for `multispace0`. ```rust use nom::{ IResult, Parser, error::ParseError, sequence::delimited, character::complete::multispace0, }; /// A combinator that takes a parser `inner` and produces a parser that also consumes both leading and /// trailing whitespace, returning the output of `inner`. pub fn ws<'a, O, E: ParseError<&'a str>, F>( inner: F, ) -> impl Parser<&'a str, Output = O, Error = E> where F: Parser<&'a str, Output = O, Error = E>, { delimited(multispace0, inner, multispace0) } ``` -------------------------------- ### Rust: Implement `pair` combinator for combining parsers Source: https://github.com/rust-bakery/nom/blob/main/doc/upgrading_to_nom_5.md This Rust function implements a `pair` combinator, which takes two other parser functions (`first` and `second`) and returns a new parser. The new parser applies `first` to the input, then applies `second` to the remaining input, returning a tuple of their results. It requires the `nom` crate for `IResult`. The input type `I` and output types `O1`, `O2` are generic, as is the error type `E`. ```rust pub fn pair(first: F, second: G) -> impl Fn(I) -> IResult where F: Fn(I) -> IResult, G: Fn(I) -> IResult, { move |input: I| { let (input, o1) = first(input)?; second(input).map(|(i, o2)| (i, (o1, o2))) } } ``` -------------------------------- ### Rust: Add nom as a dependency Source: https://github.com/rust-bakery/nom/blob/main/README.md This snippet shows how to add the nom crate to your Cargo.toml file to include it as a dependency in your Rust project. It specifies version 8 and includes default features. ```toml [dependencies] nom = "8" ``` -------------------------------- ### Rust: Parse Binary String Slice with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Parses a binary string, returning the slice of digits without the '0b' or '0B' prefix. It handles optional underscores within the digits. This parser requires the `nom` crate. ```rust use nom::{ IResult, Parser, branch::alt, multi::{many0, many1}, combinator::recognize, sequence::{preceded, terminated}, character::complete::{char, one_of}, bytes::complete::tag, }; fn binary(input: &str) -> IResult<&str, &str> { preceded( alt((tag("0b"), tag("0B"))), recognize( many1( terminated(one_of("01"), many0(char('_'))) ) ) ).parse(input) } ``` -------------------------------- ### Nom 4 Error Types Source: https://github.com/rust-bakery/nom/blob/main/doc/upgrading_to_nom_5.md Illustrates the error type structure in nom version 4, which included `Context` and handled verbose errors. ```rust type IResult = Result<(I, O), Err>; pub enum Err { Incomplete(Needed), Error(Context), Failure(Context), } pub enum Context { Code(I, ErrorKind), // this variant only present if `verbose-errors` is active List(Vec<(I, ErrorKind)>), } ``` -------------------------------- ### Nom Multi Combinators - Count and Many0 Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Explains the `count` and `many0` combinators for applying a parser multiple times. `count` applies a parser a specific number of times, while `many0` applies it zero or more times, collecting results in a Vec. ```rust use nom::bytes::streaming::take; use nom::multi::{count, many0}; // Example for count let count_parser = count(take(2usize), 3); let input1 = "abcdefgh"; let result1 = count_parser(input1); // result1 is Ok(("gh", vec!["ab", "cd", "ef"])) // Example for many0 let many0_parser = many0(tag("ab")); let input2 = "abababc"; let result2 = many0_parser(input2); // result2 is Ok(("c", vec!["ab", "ab", "ab"])) ``` -------------------------------- ### Rust: Configure nom features for no_std Source: https://github.com/rust-bakery/nom/blob/main/README.md This configuration demonstrates how to disable default features for the nom crate and explicitly enable the 'alloc' feature. This is useful for 'no_std' builds where memory allocators might not be available, allowing for combinators that don't require allocation. ```toml [dependencies.nom] version = "8" default-features = false features = ["alloc"] ``` -------------------------------- ### Nom Branch Combinator: alt() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `alt()` combinator in Rust's 'nom' crate tries a list of parsers and returns the result of the first one that succeeds. It's used for handling choices in a grammar. The input is returned to its original state if all parsers fail. ```rust use nom::branch::alt; use nom::bytes::complete::tag; let input = "cdef"; let parser = alt((tag("ab"), tag("cd"))); let result = parser(input); // result is Ok(("ef", "cd")) ``` -------------------------------- ### Rust Nom ASCII Character Tests Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md These functions test individual bytes for specific ASCII character types. They are typically used with combinators like `take_while` to parse sequences of characters. No external dependencies are needed beyond the `nom` crate. ```rust use nom::character::is_alphabetic; let input = b"Hello"; let (rest, _) = nom::bytes::complete::take_while(is_alphabetic)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_alphanumeric; let input = b"World123"; let (rest, _) = nom::bytes::complete::take_while(is_alphanumeric)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_digit; let input = b"12345"; let (rest, _) = nom::bytes::complete::take_while(is_digit)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_hex_digit; let input = b"A1B2c3d4"; let (rest, _) = nom::bytes::complete::take_while(is_hex_digit)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_oct_digit; let input = b"01234567"; let (rest, _) = nom::bytes::complete::take_while(is_oct_digit)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_bin_digit; let input = b"01011010"; let (rest, _) = nom::bytes::complete::take_while(is_bin_digit)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_space; let input = b" \t"; let (rest, _) = nom::bytes::complete::take_while(is_space)(input).unwrap(); assert_eq!(rest, b""); ``` ```rust use nom::character::is_newline; let input = b"\n"; let (rest, _) = nom::bytes::complete::take_while(is_newline)(input).unwrap(); assert_eq!(rest, b""); ``` -------------------------------- ### Nom Byte Sequence Parser: take_until() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `take_until()` parser in Rust's 'nom' crate returns the longest sequence of bytes until a specific tag is found. It returns the matched sequence and the remaining input. `take_until1` requires at least one character before the tag. ```rust use nom::bytes::complete::take_until; let input = "Hello world"; let result = take_until("world")(input); // result is Ok(("world", "Hello ")) ``` -------------------------------- ### Rust: Parse Hexadecimal String to i64 with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Parses a hexadecimal string (with '0x' or '0X' prefix and optional underscores) and converts it into an i64 integer. It uses `map_res` to handle the conversion and error mapping. This parser requires the `nom` crate and `std::str::FromStr` for conversion. ```rust use nom::{ IResult, Parser, branch::alt, multi::{many0, many1}, combinator::{map_res, recognize}, sequence::{preceded, terminated}, character::complete::{char, one_of}, bytes::complete::tag, }; fn hexadecimal_value(input: &str) -> IResult<&str, i64> { map_res( preceded( alt((tag("0x"), tag("0X"))), recognize( many1( terminated(one_of("0123456789abcdefABCDEF"), many0(char('_'))) ) ) ), |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 16) ).parse(input) } ``` -------------------------------- ### Nom Multi Combinator - Many_till Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Demonstrates the `many_till` combinator, which applies a parser repeatedly until another parser succeeds. It returns a tuple containing the results of the first parser (as a Vec) and the result of the second parser. ```rust use nom::bytes::streaming::tag; use nom::multi::many_till; // Example for many_till let many_till_parser = many_till(tag("ab"), tag("ef")); let input = "ababefg"; let result = many_till_parser(input); // result is Ok(("g", (vec!["ab", "ab"], "ef"))) ``` -------------------------------- ### Nom Multi Combinator - Length_count Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md Describes the `length_count` combinator, which first parses a length (a number) and then applies another parser that many times, collecting the results. This is useful for parsing length-prefixed data structures. ```rust use nom::bytes::streaming::tag; use nom::multi::length_count; use nom::number::streaming::be_u32; // Assuming 'number' is a parser that returns a u32 length // For demonstration, let's use be_u32, though the example implies a custom number parser let number_parser = be_u32; let length_count_parser = length_count(number_parser, tag("ab")); // Note: The example input '2ababab' suggests a parser for the number '2' itself. // A direct translation of the example usage might require a specific number parser. // Here's a conceptual example if 'number' was a parser for a single digit u8: use nom::character::streaming::digit1; use nom::combinator::map_res; let parse_digit = map_res(digit1, |s: &str| s.parse::()); let length_count_parser_digit = length_count(parse_digit, tag("ab")); let input = "2ababab"; let result = length_count_parser_digit(input); // result is Ok(("bab", vec!["ab", "ab"])) ``` -------------------------------- ### Nom Branch Combinator: permutation() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `permutation()` combinator in Rust's 'nom' crate succeeds when all its child parsers succeed, regardless of their order in the input. It returns a tuple of the results and the remaining input. This is useful for parsing fields that can appear in any order. ```rust use nom::branch::permutation; use nom::bytes::complete::tag; let input = "cd12abc"; let parser = permutation((tag("ab"), tag("cd"), tag("12"))); let result = parser(input); // result is Ok(("c", ("ab", "cd", "12"))) ``` -------------------------------- ### Rust: Printing VerboseError directly (unformatted) Source: https://github.com/rust-bakery/nom/blob/main/doc/error_management.md Illustrates the raw output of a VerboseError when printed directly. This format can be verbose and difficult to interpret, highlighting the need for functions like `convert_error` to present the information more clearly. ```rust // parsed verbose: Err( // Failure( // VerboseError { // errors: [ // ( // "1\"hello\" : \"world\" }\n } ", // Char( // '}', // ), // ), // ( // "{ 1\"hello\" : \"world\" }\n } ", // Context( // "map", // ), // ), // ( // "{ \"a\" : 42, \"b\": [ \"x\", \"y\", 12 ] , \"c\": { 1\"hello\" : \"world\" }\n } ", // Context( // "map", // ), // ), // ], // }, // ), // ) println!("parsed verbose: {:#?}", json::>(data)); ``` -------------------------------- ### Rust: Implement FromStr for Custom String Parsing with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Demonstrates how to implement the `FromStr` trait in Rust for a custom struct ('Name') by using a `nom` parser (`parse_name`). The `parse_name` function extracts a name from a "Hello, name!" string. The `FromStr` implementation handles the conversion from the parsed string slice to an owned `String` and manages potential errors. This requires the `nom` crate and `std::str::FromStr` trait. ```rust use nom::{ IResult, Parser, Finish, error::Error, bytes::complete::{tag, take_while}, }; use std::str::FromStr; // will recognize the name in "Hello, name!" fn parse_name(input: &str) -> IResult<&str, &str> { let (i, _) = tag("Hello, ").parse(input)?; let (i, name) = take_while(|c:char| c.is_alphabetic())(i)?; let (i, _) = tag("!")(i)?; Ok((i, name)) } // with FromStr, the result cannot be a reference to the input, it must be owned #[derive(Debug)] pub struct Name(pub String); impl FromStr for Name { // the error must be owned as well type Err = Error; fn from_str(s: &str) -> Result { match parse_name(s).finish() { Ok((_remaining, name)) => Ok(Name(name.to_string())), Err(Error { input, code }) => Err(Error { input: input.to_string(), code, }) } } } fn main() { // parsed: Ok(Name("nom")) println!("parsed: {:?}", "Hello, nom!".parse::()); // parsed: Err(Error { input: "123!", code: Tag }) println!("parsed: {:?}", "Hello, 123!".parse::()); } ``` -------------------------------- ### Nom Byte Sequence Parser: take_while() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `take_while()` parser in Rust's 'nom' crate returns the longest sequence of bytes for which a provided predicate function returns true. It returns the matched sequence and the remaining input. `take_while1` requires at least one match, and `take_while_m_n` specifies a range. ```rust use nom::bytes::complete::take_while; use nom::character::is_alphabetic; let input = "abc123"; let result = take_while(is_alphabetic)(input); // result is Ok(("123", "abc")) ``` -------------------------------- ### Nom Byte Sequence Parser: tag_no_case() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `tag_no_case()` parser in Rust's 'nom' crate performs a case-insensitive comparison to recognize a specific sequence of characters or bytes. It returns the matched sequence and the remaining input. Note: Unicode case-insensitive comparison can be complex. ```rust use nom::bytes::complete::tag_no_case; let input = "HeLLo World"; let result = tag_no_case("hello")(input); // result is Ok((" World", "HeLLo")) ``` -------------------------------- ### Use dbg_dmp for Debugging Parsers in Rust Source: https://github.com/rust-bakery/nom/blob/main/doc/error_management.md Shows the usage of the `dbg_dmp` function from the nom library to debug individual parsers. It wraps a parser (`tag("abcd")`) and prints a hexdump of the input if an error occurs, along with other debugging information. ```rust fn f(i: &[u8]) -> IResult<&[u8], &[u8]> { dbg_dmp(tag("abcd"), "tag")(i) } let a = &b"efghijkl"[..]; f(a); ``` -------------------------------- ### Rust: Parse Octal String Slice with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Parses an octal string, returning the slice of digits without the '0o' or '0O' prefix. It handles optional underscores within the digits. This parser requires the `nom` crate. ```rust use nom::{ IResult, Parser, branch::alt, multi::{many0, many1}, combinator::recognize, sequence::{preceded, terminated}, character::complete::{char, one_of}, bytes::complete::tag, }; fn octal(input: &str) -> IResult<&str, &str> { preceded( alt((tag("0o"), tag("0O"))), recognize( many1( terminated(one_of("01234567"), many0(char('_'))) ) ) ).parse(input) } ``` -------------------------------- ### Nom Byte Sequence Parser: take_till() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `take_till()` parser in Rust's 'nom' crate returns the longest sequence of bytes until a provided predicate function returns true. It returns the matched sequence and the remaining input. `take_till1` requires at least one match. It's the inverse of `take_while`. ```rust use nom::bytes::complete::take_till; use nom::character::is_alphabetic; let input = "123abc"; let result = take_till(is_alphabetic)(input); // result is Ok(("abc", "123")) ``` -------------------------------- ### Rust: Parse Hexadecimal String Slice with Nom Source: https://github.com/rust-bakery/nom/blob/main/doc/nom_recipes.md Parses a hexadecimal string, returning the slice of digits without the '0x' or '0X' prefix. It handles optional underscores within the digits. This parser requires the `nom` crate. ```rust use nom::{ IResult, Parser, branch::alt, multi::{many0, many1}, combinator::recognize, sequence::{preceded, terminated}, character::complete::{char, one_of}, bytes::complete::tag, }; fn hexadecimal(input: &str) -> IResult<&str, &str> { // <'a, E: ParseError<&'a str>> preceded( alt((tag("0x"), tag("0X"))), recognize( many1( terminated(one_of("0123456789abcdefABCDEF"), many0(char('_'))) ) ) ).parse(input) } ``` -------------------------------- ### Nom Byte Sequence Parser: tag() Source: https://github.com/rust-bakery/nom/blob/main/doc/choosing_a_combinator.md The `tag()` parser in Rust's 'nom' crate recognizes a specific sequence of characters or bytes. It returns the matched tag and the remaining input upon success. This is fundamental for parsing structured data. ```rust use nom::bytes::complete::tag; let input = "hello world"; let result = tag("hello")(input); // result is Ok((" world", "hello")) ```