Repository: Geal/nom
Pull request #1526 (2022-05-12 17:36:39)

Implement `nom::sequence::Tuple` for `()` (Unit)
Right now, `()` (Unit) does not implement the [`nom::sequence::Tuple` trait](https://docs.rs/nom/7.1.1/nom/sequence/trait.Tuple.html) required to use the [`tuple` combinator](https://docs.rs/nom/7.1.1/nom/sequence/fn.tuple.html). This makes it difficult to use in macros.

## Example

I'm currently mass-producing parsers using a macro for a fictional instruction set assembler. Each instruction may take a variable number of arguments so I am using this macro component to parse all arguments:

```rust
		tuple(($(
			preceded(space1, $parser)),*
		))
```

This works fine for any number of arguments `>=1` and `<=21`, but notably does not work for a number `==0`. Here's why: 

```
the trait bound `(): nom::sequence::Tuple<_, _, _>` is not satisfied
```

Looks like `()` does not implement `Tuple`, even though it could concievably implement a tuple of zero elements.

This pull request implements `Tuple` for `()` such that it will always succeed and it is always a no-op. It also adds a test case that verifies that `tuple(())` never fails and always returns the input unchanged.

I am unsure if the `ParseError<I>` bound is needed on the impl, but I figured it's better to be safe than sorry and stay consistent with the existing tuple impls. I would also appreciate assistance with removing the ugly turbofishes from the test.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/49075505/badge)](https://coveralls.io/builds/49075505)

Coverage increased (+0.004%) to 79.568% when pulling **476f5032f0fcf0b18b2f21599a8e8190f588e7fd on LoganDark:unit-tuple** into **294ffb3d9e0ade2c3b7ddfff52484b6d643dcce1 on Geal:main**.


Patch:
diff --git a/README.md b/README.md
index d429164..f2c1b05 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,25 @@ error prone plumbing.
 
 *nom will happily take a byte out of your files :)*
 
+<!-- toc -->
+
+- [Example](#example)
+- [Documentation](#documentation)
+- [Why use nom?](#why-use-nom)
+    - [Binary format parsers](#binary-format-parsers)
+    - [Text format parsers](#text-format-parsers)
+    - [Programming language parsers](#programming-language-parsers)
+    - [Streaming formats](#streaming-formats)
+- [Parser combinators](#parser-combinators)
+- [Technical features](#technical-features)
+- [Rust version requirements](#rust-version-requirements-msrv)
+- [Installation](#installation)
+- [Related projects](#related-projects)
+- [Parsers written with nom](#parsers-written-with-nom)
+- [Contributors](#contributors)
+
+<!-- tocstop -->
+
 ## Example
 
 [Hexadecimal color](https://developer.mozilla.org/en-US/docs/Web/CSS/color) parser:
@@ -296,7 +315,8 @@ Here is a (non exhaustive) list of known projects using nom:
 [Telcordia/Bellcore SR-4731 SOR OTDR files](https://github.com/JamesHarrison/otdrs),
 [MySQL binary log](https://github.com/PrivateRookie/boxercrab),
 [URI](https://github.com/Skasselbard/nom-uri),
-[Furigana](https://github.com/sachaarbonel/furigana.rs)
+[Furigana](https://github.com/sachaarbonel/furigana.rs),
+[Wordle Result](https://github.com/Fyko/wordle-stats/tree/main/parser)
 
 Want to create a new parser using `nom`? A list of not yet implemented formats is available [here](https://github.com/Geal/nom/issues/14).
 
diff --git a/src/sequence/mod.rs b/src/sequence/mod.rs
index e09d413..735ab45 100644
--- a/src/sequence/mod.rs
+++ b/src/sequence/mod.rs
@@ -252,6 +252,15 @@ macro_rules! tuple_trait_inner(
 tuple_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L,
   FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);
 
+// Special case: implement `Tuple` for `()`, the unit type.
+// This can come up in macros which accept a variable number of arguments.
+// Literally, `()` is an empty tuple, so it should simply parse nothing.
+impl<I, E: ParseError<I>> Tuple<I, (), E> for () {
+  fn parse(&mut self, input: I) -> IResult<I, (), E> {
+    Ok((input, ()))
+  }
+}
+
 ///Applies a tuple of parsers one by one and returns their results as a tuple.
 ///There is a maximum of 21 parsers
 /// ```rust


Test patch:
diff --git a/src/sequence/tests.rs b/src/sequence/tests.rs
index 201579b..ea66260 100644
--- a/src/sequence/tests.rs
+++ b/src/sequence/tests.rs
@@ -1,6 +1,6 @@
 use super::*;
 use crate::bytes::streaming::{tag, take};
-use crate::error::ErrorKind;
+use crate::error::{ErrorKind, Error};
 use crate::internal::{Err, IResult, Needed};
 use crate::number::streaming::be_u16;
 
@@ -272,3 +272,10 @@ fn tuple_test() {
     Err(Err::Error(error_position!(&b"jk"[..], ErrorKind::Tag)))
   );
 }
+
+#[test]
+fn unit_type() {
+  assert_eq!(tuple::<&'static str, (), Error<&'static str>, ()>(())("abxsbsh"), Ok(("abxsbsh", ())));
+  assert_eq!(tuple::<&'static str, (), Error<&'static str>, ()>(())("sdfjakdsas"), Ok(("sdfjakdsas", ())));
+  assert_eq!(tuple::<&'static str, (), Error<&'static str>, ()>(())(""), Ok(("", ())));
+}