From cdb0945cc6150f6a72995dbc54c99d4254602e86 Mon Sep 17 00:00:00 2001 From: TimLuq Date: Mon, 1 Jul 2024 20:57:07 +0200 Subject: [PATCH] add feature `nom_7` --- Cargo.toml | 17 ++- README.md | 5 + src/nom_7/bytedata.rs | 274 ++++++++++++++++++++++++++++++++++ src/nom_7/bytequeue.rs | 313 +++++++++++++++++++++++++++++++++++++++ src/nom_7/mod.rs | 10 ++ src/nom_7/stringdata.rs | 300 +++++++++++++++++++++++++++++++++++++ src/nom_7/stringqueue.rs | 310 ++++++++++++++++++++++++++++++++++++++ src/nom_7/tests.rs | 55 +++++++ 8 files changed, 1277 insertions(+), 7 deletions(-) create mode 100644 src/nom_7/bytedata.rs create mode 100644 src/nom_7/bytequeue.rs create mode 100644 src/nom_7/mod.rs create mode 100644 src/nom_7/stringdata.rs create mode 100644 src/nom_7/stringqueue.rs create mode 100644 src/nom_7/tests.rs diff --git a/Cargo.toml b/Cargo.toml index 0426be5..4031de0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bytedata" -version = "0.1.3" +version = "0.1.4" edition = "2021" rust-version = "1.70.0" description = "Representation of a byte slice that is either static, borrowed, or shared." @@ -16,20 +16,23 @@ http-body_04 = { package = "http-body", version = "0.4.5", optional = true } http-body_1 = { package = "http-body", version = "1", optional = true } http_02 = { package = "http", version = "0.2.4", optional = true } http_1 = { package = "http", version = "1", optional = true } +nom_7 = { package = "nom", version = "7", optional = true } serde_1 = { package = "serde", version = "1.0.0", optional = true, default-features = false } [features] default = ["macros", "chunk"] -macros = [] -chunk = [] + alloc = ["serde_1?/alloc"] +chunk = [] +macros = [] +nightly = [] +queue = [] +read_buf = ["std"] +std = ["alloc"] + bytes_1_safe = ["bytes_1"] http-body_04 = ["dep:http-body_04", "dep:http_02", "bytes_1"] http-body_1 = ["dep:http-body_1", "dep:http_1", "bytes_1"] -std = ["alloc"] -nightly = [] -read_buf = ["std"] -queue = [] [package.metadata.docs.rs] all-features = true diff --git a/README.md b/README.md index 70a54bb..d5f9868 100644 --- a/README.md +++ b/README.md @@ -56,3 +56,8 @@ The trait `http_body::Body` is then implemented for `ByteData` and `SharedBytes` Enables the `ByteQueue` type which is a queue of `ByteData` objects that can be pushed to and popped from. Unless the `alloc` feature is enabled, the queue will be limited to a maximum size of 8 elements. + +### nom_7 + +Enables integration with the `nom` crate (version `>=7, <8`). +This allows for `ByteData`, `StringData`, `ByteQueue`, and `StringQueue` data to be parsed using `nom` parsers. diff --git a/src/nom_7/bytedata.rs b/src/nom_7/bytedata.rs new file mode 100644 index 0000000..0e4228a --- /dev/null +++ b/src/nom_7/bytedata.rs @@ -0,0 +1,274 @@ +use nom_7 as nom; + +impl<'a> nom::AsBytes for crate::ByteData<'a> { + #[inline] + fn as_bytes(&self) -> &[u8] { + self.as_slice() + } +} + +impl<'a, 'b> nom::Compare> for crate::ByteData<'a> { + #[inline] + fn compare(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(&self.as_slice(), t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(&self.as_slice(), t.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::ByteData<'b>> for crate::ByteData<'a> { + #[inline] + fn compare(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(&self.as_slice(), t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(&self.as_slice(), t.as_slice()) + } +} + +impl<'a, 'b> nom::Compare<&'b [u8]> for crate::ByteData<'a> { + #[inline] + fn compare(&self, t: &'b [u8]) -> nom::CompareResult { + nom::Compare::<&'b [u8]>::compare(&self.as_slice(), t) + } + + #[inline] + fn compare_no_case(&self, t: &'b [u8]) -> nom::CompareResult { + nom::Compare::<&'b [u8]>::compare_no_case(&self.as_slice(), t) + } +} + +impl<'a, 'b> nom::Compare<&'b str> for crate::ByteData<'a> { + #[inline] + fn compare(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::<&'b str>::compare(&self.as_slice(), t) + } + + #[inline] + fn compare_no_case(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::<&'b str>::compare_no_case(&self.as_slice(), t) + } +} + +impl<'a, 'b> nom::FindSubstring> for crate::ByteData<'a> { + #[inline] + fn find_substring(&self, substr: crate::ByteData<'b>) -> Option { + nom::FindSubstring::find_substring(&self.as_slice(), substr.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::FindSubstring<&'c crate::ByteData<'b>> for crate::ByteData<'a> { + #[inline] + fn find_substring(&self, substr: &'c crate::ByteData<'b>) -> Option { + nom::FindSubstring::find_substring(&self.as_slice(), substr.as_slice()) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b [u8]> for crate::ByteData<'a> { + #[inline] + fn find_substring(&self, substr: &'b [u8]) -> Option { + nom::FindSubstring::find_substring(&self.as_slice(), substr) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b str> for crate::ByteData<'a> { + #[inline] + fn find_substring(&self, substr: &'b str) -> Option { + nom::FindSubstring::find_substring(&self.as_slice(), substr) + } +} + +impl<'a> nom::FindToken for crate::ByteData<'a> { + #[inline] + fn find_token(&self, token: u8) -> bool { + nom::FindToken::find_token(&self.as_slice(), token) + } +} + +impl<'a, 'b> nom::FindToken<&'b u8> for crate::ByteData<'a> { + #[inline] + fn find_token(&self, token: &'b u8) -> bool { + nom::FindToken::find_token(&self.as_slice(), token) + } +} + +impl<'a> nom::FindToken for crate::ByteData<'a> { + #[inline] + fn find_token(&self, token: char) -> bool { + nom::FindToken::find_token(&self.as_slice(), token) + } +} + +impl<'a, 'b> nom::FindToken<&'b char> for crate::ByteData<'a> { + #[inline] + fn find_token(&self, token: &'b char) -> bool { + nom::FindToken::find_token(&self.as_slice(), *token) + } +} + +#[cfg(feature = "alloc")] +impl<'a, 'b> nom::HexDisplay for crate::ByteData<'a> { + fn to_hex(&self, chunk_size: usize) -> alloc::string::String { + nom::HexDisplay::to_hex(self.as_slice(), chunk_size) + } + + fn to_hex_from(&self, chunk_size: usize, from: usize) -> alloc::string::String { + nom::HexDisplay::to_hex_from(self.as_slice(), chunk_size, from) + } +} + +impl<'a> nom::InputIter for crate::ByteData<'a> { + type Item = u8; + + type Iter = core::iter::Enumerate; + + type IterElem = Self; + + fn iter_indices(&self) -> Self::Iter { + Iterator::enumerate(self.clone()) + } + + fn iter_elements(&self) -> Self::IterElem { + self.clone() + } + + fn position

(&self, predicate: P) -> Option + where + P: Fn(Self::Item) -> bool, + { + nom::InputIter::position(&self.as_slice(), predicate) + } + + fn slice_index(&self, count: usize) -> Result { + nom::InputIter::slice_index(&self.as_slice(), count) + } +} + +impl<'a> nom::InputLength for crate::ByteData<'a> { + fn input_len(&self) -> usize { + self.len() + } +} + +impl<'a> nom::InputTake for crate::ByteData<'a> { + fn take(&self, count: usize) -> Self { + self.sliced(..count) + } + + fn take_split(&self, count: usize) -> (Self, Self) { + (self.sliced(count..), self.sliced(..count)) + } +} + +impl<'a> nom::InputTakeAtPosition for crate::ByteData<'a> { + type Item = u8; + + fn split_at_position>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self.as_slice(); + let mut i = 0; + for b in a { + if predicate(*b) { + return Ok((self.sliced(i..), self.sliced(..i))); + } + i += 1; + } + Err(nom::Err::Incomplete(nom::Needed::new(1))) + } + + fn split_at_position1>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self.as_slice(); + let mut i = 0; + for b in a { + if predicate(*b) { + if i == 0 { + return Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))); + } + return Ok((self.sliced(i..), self.sliced(..i))); + } + i += 1; + } + Err(nom::Err::Incomplete(nom::Needed::new(1))) + } + + fn split_at_position_complete>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self.as_slice(); + let mut i = 0; + for b in a { + if predicate(*b) { + return Ok((self.sliced(i..), self.sliced(..i))); + } + i += 1; + } + Ok((Self::empty(), self.clone())) + } + + fn split_at_position1_complete>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self.as_slice(); + let mut i = 0; + for b in a { + if predicate(*b) { + if i == 0 { + return Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))); + } + return Ok((self.sliced(i..), self.sliced(..i))); + } + i += 1; + } + Ok((Self::empty(), self.clone())) + } +} + +impl<'a> nom::Slice> for crate::ByteData<'a> { + fn slice(&self, range: core::ops::Range) -> Self { + self.sliced(range) + } +} + +impl<'a> nom::Slice> for crate::ByteData<'a> { + fn slice(&self, range: core::ops::RangeTo) -> Self { + self.sliced(range) + } +} + +impl<'a> nom::Slice> for crate::ByteData<'a> { + fn slice(&self, range: core::ops::RangeFrom) -> Self { + self.sliced(range) + } +} + +impl<'a> nom::Slice for crate::ByteData<'a> { + fn slice(&self, range: core::ops::RangeFull) -> Self { + self.sliced(range) + } +} diff --git a/src/nom_7/bytequeue.rs b/src/nom_7/bytequeue.rs new file mode 100644 index 0000000..3f57c79 --- /dev/null +++ b/src/nom_7/bytequeue.rs @@ -0,0 +1,313 @@ +use nom_7 as nom; + +impl<'a, 'b> nom::Compare> for crate::ByteQueue<'a> { + #[inline] + fn compare(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(self, t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::ByteData<'b>> for crate::ByteQueue<'a> { + #[inline] + fn compare(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(self, t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_slice()) + } +} + +impl<'a, 'b> nom::Compare> for crate::ByteQueue<'a> { + #[inline] + fn compare(&self, t: crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare(self, t.as_str()) + } + + #[inline] + fn compare_no_case(&self, t: crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_str()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::StringData<'b>> for crate::ByteQueue<'a> { + #[inline] + fn compare(&self, t: &'c crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare(self, t.as_str()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_str()) + } +} + +impl<'a, 'b> nom::Compare<&'b [u8]> for crate::ByteQueue<'a> { + #[inline] + fn compare(&self, t: &'b [u8]) -> nom::CompareResult { + let mut rest = t; + for s in self.chunks() { + let (a, rest2) = rest.split_at(s.len().min(rest.len())); + rest = rest2; + match nom::Compare::compare(&s.as_slice(), a) { + nom::CompareResult::Ok => continue, + nom::CompareResult::Error => return nom::CompareResult::Error, + nom::CompareResult::Incomplete => return nom::CompareResult::Incomplete, + } + } + if rest.is_empty() { + nom::CompareResult::Ok + } else { + nom::CompareResult::Incomplete + } + } + + #[inline] + fn compare_no_case(&self, t: &'b [u8]) -> nom::CompareResult { + let mut rest = t; + for s in self.chunks() { + let (a, rest2) = rest.split_at(s.len().min(rest.len())); + rest = rest2; + match nom::Compare::compare_no_case(&s.as_slice(), a) { + nom::CompareResult::Ok => continue, + nom::CompareResult::Error => return nom::CompareResult::Error, + nom::CompareResult::Incomplete => return nom::CompareResult::Incomplete, + } + } + if rest.is_empty() { + nom::CompareResult::Ok + } else { + nom::CompareResult::Incomplete + } + } +} + +impl<'a, 'b> nom::Compare<&'b str> for crate::ByteQueue<'a> { + #[inline] + fn compare(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::compare(self, t.as_bytes()) + } + + #[inline] + fn compare_no_case(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_bytes()) + } +} + +impl<'a, 'b> nom::FindSubstring> for crate::ByteQueue<'a> { + #[inline] + fn find_substring(&self, substr: crate::ByteData<'b>) -> Option { + self.find_slice(substr.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::FindSubstring<&'c crate::ByteData<'b>> for crate::ByteQueue<'a> { + #[inline] + fn find_substring(&self, substr: &'c crate::ByteData<'b>) -> Option { + self.find_slice(substr.as_slice()) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b [u8]> for crate::ByteQueue<'a> { + #[inline] + fn find_substring(&self, substr: &'b [u8]) -> Option { + self.find_slice(substr) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b str> for crate::ByteQueue<'a> { + #[inline] + fn find_substring(&self, substr: &'b str) -> Option { + self.find_slice(substr.as_bytes()) + } +} + +impl<'a> nom::FindToken for crate::ByteQueue<'a> { + #[inline] + fn find_token(&self, token: u8) -> bool { + self.bytes().any(|b| b == token) + } +} + +impl<'a, 'b> nom::FindToken<&'b u8> for crate::ByteQueue<'a> { + #[inline] + fn find_token(&self, token: &'b u8) -> bool { + let token = *token; + self.bytes().any(|b| b == token) + } +} + +impl<'a> nom::FindToken for crate::ByteQueue<'a> { + #[inline] + fn find_token(&self, token: char) -> bool { + let mut utf8 = [0; 4]; + let utf8 = token.encode_utf8(&mut utf8); + self.find_slice(utf8.as_bytes()).is_some() + } +} + +impl<'a, 'b> nom::FindToken<&'b char> for crate::ByteQueue<'a> { + #[inline] + fn find_token(&self, token: &'b char) -> bool { + nom::FindToken::find_token(self, *token) + } +} + +#[cfg(feature = "alloc")] +impl<'a, 'b> nom::HexDisplay for crate::ByteQueue<'a> { + fn to_hex(&self, chunk_size: usize) -> alloc::string::String { + self.to_hex_from(chunk_size, 0) + } + + fn to_hex_from(&self, chunk_size: usize, from: usize) -> alloc::string::String { + use core::fmt::Write; + let l = self.len() - from; + let mut s = alloc::string::String::with_capacity((l << 1) + 1 + (l / chunk_size)); + for (i, chunk) in self.bytes().skip(from).enumerate() { + if i % chunk_size == 0 { + s.push('\n'); + } + write!(s, "{:02x}", chunk).unwrap(); + } + s + } +} + +impl<'a> nom::InputIter for crate::ByteQueue<'a> { + type Item = u8; + + type Iter = core::iter::Enumerate>; + + type IterElem = crate::queue::OwnedByteIter<'a>; + + fn iter_indices(&self) -> Self::Iter { + Iterator::enumerate(self.clone().into_bytes()) + } + + fn iter_elements(&self) -> Self::IterElem { + self.clone().into_bytes() + } + + fn position

(&self, predicate: P) -> Option + where + P: Fn(Self::Item) -> bool, + { + self.find_byte(predicate) + } + + fn slice_index(&self, count: usize) -> Result { + if self.len() >= count { + Ok(count) + } else { + Err(nom::Needed::new(count - self.len())) + } + } +} + +impl<'a> nom::InputLength for crate::ByteQueue<'a> { + fn input_len(&self) -> usize { + self.len() + } +} + +impl<'a> nom::InputTake for crate::ByteQueue<'a> { + fn take(&self, count: usize) -> Self { + self.slice(..count) + } + + fn take_split(&self, count: usize) -> (Self, Self) { + (self.slice(count..), self.slice(..count)) + } +} + +impl<'a> nom::InputTakeAtPosition for crate::ByteQueue<'a> { + type Item = u8; + + fn split_at_position>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + if let Some(a) = self.find_byte(predicate) { + Ok((self.slice(a..), self.slice(..a))) + } else { + Err(nom::Err::Incomplete(nom::Needed::new(1))) + } + } + + fn split_at_position1>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + match self.find_byte(predicate) { + None => Err(nom::Err::Incomplete(nom::Needed::new(1))), + Some(0) => Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))), + Some(a) => Ok((self.slice(a..), self.slice(..a))), + } + } + + fn split_at_position_complete>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + if let Some(a) = self.find_byte(predicate) { + Ok((self.slice(a..), self.slice(..a))) + } else { + Ok((Self::new(), self.clone())) + } + } + + fn split_at_position1_complete>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + match self.find_byte(predicate) { + None => Ok((Self::new(), self.clone())), + Some(0) => Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))), + Some(a) => Ok((self.slice(a..), self.slice(..a))), + } + } +} + +impl<'a> nom::Slice> for crate::ByteQueue<'a> { + fn slice(&self, range: core::ops::Range) -> Self { + self.slice(range) + } +} + +impl<'a> nom::Slice> for crate::ByteQueue<'a> { + fn slice(&self, range: core::ops::RangeTo) -> Self { + self.slice(range) + } +} + +impl<'a> nom::Slice> for crate::ByteQueue<'a> { + fn slice(&self, range: core::ops::RangeFrom) -> Self { + self.slice(range) + } +} + +impl<'a> nom::Slice for crate::ByteQueue<'a> { + fn slice(&self, range: core::ops::RangeFull) -> Self { + self.slice(range) + } +} diff --git a/src/nom_7/mod.rs b/src/nom_7/mod.rs new file mode 100644 index 0000000..99a944b --- /dev/null +++ b/src/nom_7/mod.rs @@ -0,0 +1,10 @@ +mod bytedata; +mod stringdata; + +#[cfg(feature = "queue")] +mod bytequeue; +#[cfg(feature = "queue")] +mod stringqueue; + +#[cfg(test)] +mod tests; diff --git a/src/nom_7/stringdata.rs b/src/nom_7/stringdata.rs new file mode 100644 index 0000000..127d85e --- /dev/null +++ b/src/nom_7/stringdata.rs @@ -0,0 +1,300 @@ +use nom_7 as nom; + +impl<'a> nom::AsBytes for crate::StringData<'a> { + #[inline] + fn as_bytes(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a, 'b> nom::Compare> for crate::StringData<'a> { + #[inline] + fn compare(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(&self.as_bytes(), t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(&self.as_bytes(), t.as_slice()) + } +} + +impl<'a, 'b> nom::Compare> for crate::StringData<'a> { + #[inline] + fn compare(&self, t: crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare(&self.as_str(), t.as_str()) + } + + #[inline] + fn compare_no_case(&self, t: crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(&self.as_str(), t.as_str()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::ByteData<'b>> for crate::StringData<'a> { + #[inline] + fn compare(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(&self.as_bytes(), t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(&self.as_bytes(), t.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::StringData<'b>> for crate::StringData<'a> { + #[inline] + fn compare(&self, t: &'c crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare(&self.as_str(), t.as_str()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(&self.as_str(), t.as_str()) + } +} + +impl<'a, 'b> nom::Compare<&'b [u8]> for crate::StringData<'a> { + #[inline] + fn compare(&self, t: &'b [u8]) -> nom::CompareResult { + nom::Compare::<&'b [u8]>::compare(&self.as_bytes(), t) + } + + #[inline] + fn compare_no_case(&self, t: &'b [u8]) -> nom::CompareResult { + nom::Compare::<&'b [u8]>::compare_no_case(&self.as_bytes(), t) + } +} + +impl<'a, 'b> nom::Compare<&'b str> for crate::StringData<'a> { + #[inline] + fn compare(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::<&'b str>::compare(&self.as_str(), t) + } + + #[inline] + fn compare_no_case(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::<&'b str>::compare_no_case(&self.as_str(), t) + } +} + +impl<'a, 'b> nom::FindSubstring> for crate::StringData<'a> { + #[inline] + fn find_substring(&self, substr: crate::ByteData<'b>) -> Option { + nom::FindSubstring::find_substring(&self.as_bytes(), substr.as_slice()) + } +} + +impl<'a, 'b> nom::FindSubstring> for crate::StringData<'a> { + #[inline] + fn find_substring(&self, substr: crate::StringData<'b>) -> Option { + nom::FindSubstring::find_substring(&self.as_str(), substr.as_str()) + } +} + +impl<'a, 'b: 'c, 'c> nom::FindSubstring<&'c crate::ByteData<'b>> for crate::StringData<'a> { + #[inline] + fn find_substring(&self, substr: &'c crate::ByteData<'b>) -> Option { + nom::FindSubstring::find_substring(&self.as_bytes(), substr.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::FindSubstring<&'c crate::StringData<'b>> for crate::StringData<'a> { + #[inline] + fn find_substring(&self, substr: &'c crate::StringData<'b>) -> Option { + nom::FindSubstring::find_substring(&self.as_str(), substr.as_str()) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b [u8]> for crate::StringData<'a> { + #[inline] + fn find_substring(&self, substr: &'b [u8]) -> Option { + nom::FindSubstring::find_substring(&self.as_bytes(), substr) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b str> for crate::StringData<'a> { + #[inline] + fn find_substring(&self, substr: &'b str) -> Option { + nom::FindSubstring::find_substring(&self.as_str(), substr) + } +} + +impl<'a> nom::FindToken for crate::StringData<'a> { + #[inline] + fn find_token(&self, token: u8) -> bool { + nom::FindToken::find_token(&self.as_bytes(), token) + } +} + +impl<'a, 'b> nom::FindToken<&'b u8> for crate::StringData<'a> { + #[inline] + fn find_token(&self, token: &'b u8) -> bool { + nom::FindToken::find_token(&self.as_bytes(), token) + } +} + +impl<'a> nom::FindToken for crate::StringData<'a> { + #[inline] + fn find_token(&self, token: char) -> bool { + nom::FindToken::find_token(&self.as_str(), token) + } +} + +impl<'a, 'b> nom::FindToken<&'b char> for crate::StringData<'a> { + #[inline] + fn find_token(&self, token: &'b char) -> bool { + nom::FindToken::find_token(&self.as_str(), *token) + } +} + +#[cfg(feature = "alloc")] +impl<'a, 'b> nom::HexDisplay for crate::StringData<'a> { + fn to_hex(&self, chunk_size: usize) -> alloc::string::String { + nom::HexDisplay::to_hex(self.as_str(), chunk_size) + } + + fn to_hex_from(&self, chunk_size: usize, from: usize) -> alloc::string::String { + nom::HexDisplay::to_hex_from(self.as_str(), chunk_size, from) + } +} + +impl<'a> nom::InputIter for crate::StringData<'a> { + type Item = char; + + type Iter = core::iter::Enumerate; + + type IterElem = Self; + + fn iter_indices(&self) -> Self::Iter { + Iterator::enumerate(self.clone()) + } + + fn iter_elements(&self) -> Self::IterElem { + self.clone() + } + + fn position

(&self, predicate: P) -> Option + where + P: Fn(Self::Item) -> bool, + { + nom::InputIter::position(&self.as_str(), predicate) + } + + fn slice_index(&self, count: usize) -> Result { + nom::InputIter::slice_index(&self.as_str(), count) + } +} + +impl<'a> nom::InputLength for crate::StringData<'a> { + fn input_len(&self) -> usize { + nom::InputLength::input_len(&self.as_str()) + } +} + +impl<'a> nom::InputTake for crate::StringData<'a> { + fn take(&self, count: usize) -> Self { + self.sliced(..count) + } + + fn take_split(&self, count: usize) -> (Self, Self) { + (self.sliced(count..), self.sliced(..count)) + } +} + +impl<'a> nom::InputTakeAtPosition for crate::StringData<'a> { + type Item = char; + + fn split_at_position>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + for (i, b) in self.as_str().char_indices() { + if predicate(b) { + return Ok((self.sliced(i..), self.sliced(..i))); + } + } + Err(nom::Err::Incomplete(nom::Needed::new(1))) + } + + fn split_at_position1>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + for (i, b) in self.as_str().char_indices() { + if predicate(b) { + if i == 0 { + return Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))); + } + return Ok((self.sliced(i..), self.sliced(..i))); + } + } + Err(nom::Err::Incomplete(nom::Needed::new(1))) + } + + fn split_at_position_complete>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + for (i, b) in self.as_str().char_indices() { + if predicate(b) { + return Ok((self.sliced(i..), self.sliced(..i))); + } + } + Ok((Self::empty(), self.clone())) + } + + fn split_at_position1_complete>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + for (i, b) in self.as_str().char_indices() { + if predicate(b) { + if i == 0 { + return Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))); + } + return Ok((self.sliced(i..), self.sliced(..i))); + } + } + Ok((Self::empty(), self.clone())) + } +} + +impl<'a> nom::Slice> for crate::StringData<'a> { + fn slice(&self, range: core::ops::Range) -> Self { + self.sliced(range) + } +} + +impl<'a> nom::Slice> for crate::StringData<'a> { + fn slice(&self, range: core::ops::RangeTo) -> Self { + self.sliced(range) + } +} + +impl<'a> nom::Slice> for crate::StringData<'a> { + fn slice(&self, range: core::ops::RangeFrom) -> Self { + self.sliced(range) + } +} + +impl<'a> nom::Slice for crate::StringData<'a> { + fn slice(&self, range: core::ops::RangeFull) -> Self { + self.sliced(range) + } +} diff --git a/src/nom_7/stringqueue.rs b/src/nom_7/stringqueue.rs new file mode 100644 index 0000000..9d6e0a6 --- /dev/null +++ b/src/nom_7/stringqueue.rs @@ -0,0 +1,310 @@ +use nom_7 as nom; + +impl<'a, 'b> nom::Compare> for crate::StringQueue<'a> { + #[inline] + fn compare(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(self.as_bytequeue(), t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self.as_bytequeue(), t.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::ByteData<'b>> for crate::StringQueue<'a> { + #[inline] + fn compare(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare(self.as_bytequeue(), t.as_slice()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::ByteData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self.as_bytequeue(), t.as_slice()) + } +} + +impl<'a, 'b> nom::Compare> for crate::StringQueue<'a> { + #[inline] + fn compare(&self, t: crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare(self, t.as_str()) + } + + #[inline] + fn compare_no_case(&self, t: crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_str()) + } +} + +impl<'a, 'b: 'c, 'c> nom::Compare<&'c crate::StringData<'b>> for crate::StringQueue<'a> { + #[inline] + fn compare(&self, t: &'c crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare(self, t.as_str()) + } + + #[inline] + fn compare_no_case(&self, t: &'c crate::StringData<'b>) -> nom::CompareResult { + nom::Compare::compare_no_case(self, t.as_str()) + } +} + +impl<'a, 'b> nom::Compare<&'b [u8]> for crate::StringQueue<'a> { + #[inline] + fn compare(&self, t: &'b [u8]) -> nom::CompareResult { + nom::Compare::compare(self.as_bytequeue(), t) + } + + #[inline] + fn compare_no_case(&self, t: &'b [u8]) -> nom::CompareResult { + nom::Compare::compare_no_case(self.as_bytequeue(), t) + } +} + +impl<'a, 'b> nom::Compare<&'b str> for crate::StringQueue<'a> { + #[inline] + fn compare(&self, t: &'b str) -> nom::CompareResult { + nom::Compare::compare(self, t.as_bytes()) + } + + #[inline] + fn compare_no_case(&self, t: &'b str) -> nom::CompareResult { + let pos = self + .chars() + .zip(t.chars()) + .position(|(a, b)| a.to_lowercase().ne(b.to_lowercase())); + + match pos { + Some(_) => nom::CompareResult::Error, + None => { + if self.len() >= t.len() { + nom::CompareResult::Ok + } else { + nom::CompareResult::Incomplete + } + } + } + } +} + +impl<'a, 'b> nom::FindSubstring> for crate::StringQueue<'a> { + #[inline] + fn find_substring(&self, substr: crate::ByteData<'b>) -> Option { + self.as_bytequeue().find_slice(substr.as_slice()) + } +} + +impl<'a, 'b: 'c, 'c> nom::FindSubstring<&'c crate::ByteData<'b>> for crate::StringQueue<'a> { + #[inline] + fn find_substring(&self, substr: &'c crate::ByteData<'b>) -> Option { + self.as_bytequeue().find_slice(substr.as_slice()) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b [u8]> for crate::StringQueue<'a> { + #[inline] + fn find_substring(&self, substr: &'b [u8]) -> Option { + self.as_bytequeue().find_slice(substr) + } +} + +impl<'a, 'b> nom::FindSubstring<&'b str> for crate::StringQueue<'a> { + #[inline] + fn find_substring(&self, substr: &'b str) -> Option { + self.as_bytequeue().find_slice(substr.as_bytes()) + } +} + +impl<'a> nom::FindToken for crate::StringQueue<'a> { + #[inline] + fn find_token(&self, token: u8) -> bool { + self.bytes().any(|b| b == token) + } +} + +impl<'a, 'b> nom::FindToken<&'b u8> for crate::StringQueue<'a> { + #[inline] + fn find_token(&self, token: &'b u8) -> bool { + let token = *token; + self.bytes().any(|b| b == token) + } +} + +impl<'a> nom::FindToken for crate::StringQueue<'a> { + #[inline] + fn find_token(&self, token: char) -> bool { + let mut utf8 = [0; 4]; + let utf8 = token.encode_utf8(&mut utf8); + self.as_bytequeue().find_slice(utf8.as_bytes()).is_some() + } +} + +impl<'a, 'b> nom::FindToken<&'b char> for crate::StringQueue<'a> { + #[inline] + fn find_token(&self, token: &'b char) -> bool { + nom::FindToken::find_token(self, *token) + } +} + +#[cfg(feature = "alloc")] +impl<'a, 'b> nom::HexDisplay for crate::StringQueue<'a> { + fn to_hex(&self, chunk_size: usize) -> alloc::string::String { + nom::HexDisplay::to_hex(self.as_bytequeue(), chunk_size) + } + + fn to_hex_from(&self, chunk_size: usize, from: usize) -> alloc::string::String { + nom::HexDisplay::to_hex_from(self.as_bytequeue(), chunk_size, from) + } +} + +impl<'a> nom::InputIter for crate::StringQueue<'a> { + type Item = char; + + type Iter = core::iter::Enumerate>; + + type IterElem = crate::queue::OwnedCharIter<'a>; + + fn iter_indices(&self) -> Self::Iter { + Iterator::enumerate(self.clone().into_chars()) + } + + fn iter_elements(&self) -> Self::IterElem { + self.clone().into_chars() + } + + fn position

(&self, predicate: P) -> Option + where + P: Fn(Self::Item) -> bool, + { + self.chars().position(predicate) + } + + fn slice_index(&self, count: usize) -> Result { + if self.len() >= count { + Ok(count) + } else { + Err(nom::Needed::new(count - self.len())) + } + } +} + +impl<'a> nom::InputLength for crate::StringQueue<'a> { + fn input_len(&self) -> usize { + self.len() + } +} + +impl<'a> nom::InputTake for crate::StringQueue<'a> { + fn take(&self, count: usize) -> Self { + self.slice(..count) + } + + fn take_split(&self, count: usize) -> (Self, Self) { + (self.slice(count..), self.slice(..count)) + } +} + +impl<'a> nom::InputTakeAtPosition for crate::StringQueue<'a> { + type Item = char; + + fn split_at_position>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self + .chars_indecies() + .map(|(i, c)| (i, c)) + .find(|(_, c)| predicate(*c)) + .map(|(i, _)| i); + if let Some(a) = a { + Ok((self.slice(a..), self.slice(..a))) + } else { + Err(nom::Err::Incomplete(nom::Needed::new(1))) + } + } + + fn split_at_position1>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self + .chars_indecies() + .map(|(i, c)| (i, c)) + .find(|(_, c)| predicate(*c)) + .map(|(i, _)| i); + match a { + None => Err(nom::Err::Incomplete(nom::Needed::new(1))), + Some(0) => Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))), + Some(a) => Ok((self.slice(a..), self.slice(..a))), + } + } + + fn split_at_position_complete>( + &self, + predicate: P, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self + .chars_indecies() + .map(|(i, c)| (i, c)) + .find(|(_, c)| predicate(*c)) + .map(|(i, _)| i); + if let Some(a) = a { + Ok((self.slice(a..), self.slice(..a))) + } else { + Ok((Self::new(), self.clone())) + } + } + + fn split_at_position1_complete>( + &self, + predicate: P, + e: nom::error::ErrorKind, + ) -> nom::IResult + where + P: Fn(Self::Item) -> bool, + { + let a = self + .chars_indecies() + .map(|(i, c)| (i, c)) + .find(|(_, c)| predicate(*c)) + .map(|(i, _)| i); + match a { + None => Ok((Self::new(), self.clone())), + Some(0) => Err(nom::Err::Failure(E::from_error_kind(self.clone(), e))), + Some(a) => Ok((self.slice(a..), self.slice(..a))), + } + } +} + +impl<'a> nom::Slice> for crate::StringQueue<'a> { + fn slice(&self, range: core::ops::Range) -> Self { + self.slice(range) + } +} + +impl<'a> nom::Slice> for crate::StringQueue<'a> { + fn slice(&self, range: core::ops::RangeTo) -> Self { + self.slice(range) + } +} + +impl<'a> nom::Slice> for crate::StringQueue<'a> { + fn slice(&self, range: core::ops::RangeFrom) -> Self { + self.slice(range) + } +} + +impl<'a> nom::Slice for crate::StringQueue<'a> { + fn slice(&self, range: core::ops::RangeFull) -> Self { + self.slice(range) + } +} diff --git a/src/nom_7/tests.rs b/src/nom_7/tests.rs new file mode 100644 index 0000000..aa751c5 --- /dev/null +++ b/src/nom_7/tests.rs @@ -0,0 +1,55 @@ +use nom_7 as nom; + +fn read_alpha1(s: T) -> nom::IResult +where + T: nom::InputTakeAtPosition, + ::Item: nom::AsChar, +{ + nom::character::streaming::alpha1(s) +} + +fn read_alpha1_final(s: T) -> nom::IResult +where + T: nom::InputTakeAtPosition, + ::Item: nom::AsChar, +{ + nom::character::complete::alpha1(s) +} + +fn read_ws1(s: T) -> nom::IResult +where + T: nom::InputTakeAtPosition, + ::Item: nom::AsChar + core::clone::Clone, +{ + nom::character::streaming::space1(s) +} + +#[test] +fn test_nom_string() { + let s = crate::StringData::from_static("hello world"); + let (s, res) = read_alpha1(s).unwrap(); + assert_eq!(res, "hello"); + let (s, res) = read_ws1(s).unwrap(); + assert_eq!(res, " "); + let (s, res) = read_alpha1_final(s).unwrap(); + assert_eq!(res, "world"); + assert_eq!(s, "") +} + +#[cfg(feature = "queue")] +#[test] +fn test_nom_string_queue() { + let s = crate::queue::StringQueue::from_iter([ + crate::StringData::from_static("hel"), + crate::StringData::from_static("lo"), + crate::StringData::from_static(" w"), + crate::StringData::from_static("orld"), + ]); + let (s, res) = read_alpha1(s).unwrap(); + assert_eq!(res, "hello"); + let (s, res) = read_ws1(s).unwrap(); + assert_eq!(res, " "); + let (s, res) = read_alpha1_final(s).unwrap(); + assert_eq!(res, "world"); + assert_eq!(s, "") +}