Repository: Marwes/combine (language: rust)

Issue:
Type-Length-Value combinator
I'm new to combine and currently working on a binary parser. I looked at nom before, and what I cannot seem to find is a combinator for type-length-value, something like length_data in nom.

Is there any convenience helper for TLV in combine?


Discussion / hints:

Fix patch:
diff --git a/src/parser/range.rs b/src/parser/range.rs
index be768ea3..9f0768e2 100644
--- a/src/parser/range.rs
+++ b/src/parser/range.rs
@@ -11,13 +11,19 @@ use crate::{
         ParseResult::{self, *},
         ResultExt, StreamError, Tracked,
     },
-    lib::marker::PhantomData,
+    lib::{convert::TryFrom, marker::PhantomData},
     parser::ParseMode,
 };
 
+#[cfg(feature = "std")]
+use crate::lib::error::Error as StdError;
+
+#[cfg(not(feature = "std"))]
+use crate::lib::fmt;
+
 use crate::stream::{
     uncons_range, uncons_while, uncons_while1, wrap_stream_error, Range as StreamRange,
-    RangeStream, StreamOnce,
+    RangeStream, StreamErrorFor, StreamOnce,
 };
 
 use crate::Parser;
@@ -626,6 +632,76 @@ where
     }
 }
 
+#[cfg(feature = "std")]
+parser! {
+/// Takes a parser which parses a `length` then extracts a range of that length and returns it.
+/// Commonly used in binary formats
+///
+/// ```
+/// # use combine::parser::{byte::num::be_u16, range::length_prefix};
+/// # use combine::*;
+/// # fn main() {
+/// let mut input = Vec::new();
+/// input.extend_from_slice(&3u16.to_be_bytes());
+/// input.extend_from_slice(b"1234");
+///
+/// let mut parser = length_prefix(be_u16());
+/// let result = parser.parse(&input[..]);
+/// assert_eq!(result, Ok((&b"123"[..], &b"4"[..])));
+/// # }
+/// ```
+pub fn length_prefix[Input, P](len: P)(Input) -> Input::Range
+where [
+    Input: RangeStream,
+    P: Parser<Input>,
+    usize: TryFrom<P::Output>,
+    <usize as TryFrom<P::Output>>::Error: StdError + Send + Sync + 'static,
+]
+{
+    len
+        .and_then(|u| {
+            usize::try_from(u)
+                .map_err(StreamErrorFor::<Input>::other)
+        })
+        .then_partial(|&mut len| take(len))
+}
+}
+
+#[cfg(not(feature = "std"))]
+parser! {
+/// Takes a parser which parses a `length` then extracts a range of that length and returns it.
+/// Commonly used in binary formats
+///
+/// ```
+/// # use combine::parser::{byte::num::be_u16, range::length_prefix};
+/// # use combine::*;
+/// # fn main() {
+/// let mut input = Vec::new();
+/// input.extend_from_slice(&3u16.to_be_bytes());
+/// input.extend_from_slice(b"1234");
+///
+/// let mut parser = length_prefix(be_u16());
+/// let result = parser.parse(&input[..]);
+/// assert_eq!(result, Ok((&b"123"[..], &b"4"[..])));
+/// # }
+/// ```
+pub fn length_prefix[Input, P](len: P)(Input) -> Input::Range
+where [
+    Input: RangeStream,
+    P: Parser<Input>,
+    usize: TryFrom<P::Output>,
+    <usize as TryFrom<P::Output>>::Error: fmt::Display + Send + Sync + 'static,
+]
+{
+    len
+        .and_then(|u| {
+            usize::try_from(u)
+                .map_err(StreamErrorFor::<Input>::message_format)
+        })
+        .then_partial(|&mut len| take(len))
+}
+}
+
 #[cfg(test)]
 mod tests {
 
diff --git a/travis.sh b/travis.sh
index 682a2513..0b998353 100755
--- a/travis.sh
+++ b/travis.sh
@@ -1,12 +1,12 @@
 #!/bin/bash -x
 set -ex
 
-cargo build
-cargo test --all-features
-cargo test --all-features --examples
+cargo "$@" build
+cargo "$@" test --all-features
+cargo "$@" test --all-features --examples
 
-cargo test --bench json --bench http -- --test
-cargo check --bench mp4 --features mp4
+cargo "$@" test --bench json --bench http -- --test
+cargo "$@" check --bench mp4 --features mp4
 
-cargo build --no-default-features
-cargo test --no-default-features --examples
+cargo "$@" build --no-default-features
+cargo "$@" test --no-default-features --examples


Test patch: