diff --git a/src/combinators.rs b/src/combinators.rs index 9d4a16e..9f9798d 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -648,24 +648,25 @@ macro_rules! text_token { #[macro_export] macro_rules! until { ($i:expr, $term:ident!( $( $args:tt )* ) ) => {{ - use $crate::{Result, Offsetable}; - let mut acc = Vec::new(); + use $crate::{Result, Offsetable, Span, SpanRange}; + let start_offset = $i.get_offset(); let mut _i = $i.clone(); let pfn = || { loop { match $term!(_i.clone(), $($args)*) { - Result::Complete(_, _) => return Result::Complete(_i, acc), + Result::Complete(_, _) => { + let range = SpanRange::Range(start_offset.._i.get_offset()); + return Result::Complete(_i, $i.span(range)); + }, Result::Abort(e) => return Result::Abort(e), Result::Incomplete(offset) => return Result::Incomplete(offset), Result::Fail(_) => { // noop } } - let item = match _i.next() { - Some(it) => it, - None => return Result::Incomplete(_i.get_offset()), - }; - acc.push(item); + if let None = _i.next() { + return Result::Incomplete(_i.get_offset()); + } } }; pfn() @@ -674,24 +675,4 @@ macro_rules! until { ($i:expr, $term:ident) => { consume_until!($i, run!($term)) }; -} - -/// Maps a Result of type Vec<&u8> to a Result of type String. -pub fn must_string<'a, I, E>(matched: Result>, msg: E) -> Result -where - I: InputIter, - E: Into, -{ - match matched { - Result::Complete(i, mut o) => { - let new_string = String::from_utf8(o.drain(0..).map(|b| *b).collect()); - match new_string { - Ok(s) => Result::Complete(i, s), - Err(_) => Result::Abort(Error::new(msg, &i)), - } - }, - Result::Incomplete(offset) => Result::Incomplete(offset), - Result::Abort(e) => Result::Abort(e), - Result::Fail(e) => Result::Fail(e), - } } \ No newline at end of file diff --git a/src/iter.rs b/src/iter.rs index 1d4ab79..ff7c98d 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; use std::iter::Iterator; -use super::{InputIter, Offsetable}; +use super::{InputIter, Offsetable, Span, SpanRange}; /// Implements `InputIter` for any slice of T. #[derive(Debug)] @@ -21,10 +21,6 @@ impl<'a, T: Debug + 'a> SliceIter<'a, T> { } } -fn str_iter<'a>(input: &'a str) -> SliceIter<'a, u8> { - SliceIter::new(input.as_bytes()) -} - impl<'a, T: Debug + 'a> Iterator for SliceIter<'a, T> { type Item = &'a T; @@ -56,10 +52,20 @@ impl<'a, T: Debug + 'a> Clone for SliceIter<'a, T> { impl<'a, T: Debug + 'a> InputIter for SliceIter<'a, T> {} +impl<'a, T: Debug + 'a> Span<&'a [T]> for SliceIter<'a, T> { + fn span(&self, idx: SpanRange) -> &'a [T] { + match idx { + SpanRange::Range(r) => self.source.index(r), + SpanRange::RangeTo(r) => self.source.index(r), + SpanRange::RangeFrom(r) => self.source.index(r), + SpanRange::RangeFull(r) => self.source.index(r), + } + } +} impl<'a> From<&'a str> for SliceIter<'a, u8> { fn from(source: &'a str) -> Self { - str_iter(source) + SliceIter::new(source.as_bytes()) } } @@ -73,4 +79,71 @@ impl <'a, T: Debug> From<&'a Vec> for SliceIter<'a, T> { fn from(source: &'a Vec) -> Self { SliceIter::new(source.as_slice()) } +} + +/// Implements `InputIter` for any slice of T. +#[derive(Debug)] +pub struct StrIter<'a> { + source: &'a str, + offset: usize, +} + +impl<'a> StrIter<'a> { + /// new constructs a StrIter from a Slice of T. + pub fn new(source: &'a str) -> Self { + StrIter { + source: source, + offset: 0, + } + } +} + +impl<'a> Iterator for StrIter<'a> { + type Item = &'a u8; + + fn next(&mut self) -> Option { + match self.source.as_bytes().get(self.offset) { + Some(item) => { + self.offset += 1; + Some(item) + } + None => None, + } + } +} + +impl<'a> Offsetable for StrIter<'a> { + fn get_offset(&self) -> usize { + self.offset + } +} + +impl<'a> Clone for StrIter<'a> { + fn clone(&self) -> Self { + StrIter { + source: self.source, + offset: self.offset, + } + } +} + +impl<'a> InputIter for StrIter<'a> {} + +impl<'a> From<&'a str> for StrIter<'a> { + fn from(source: &'a str) -> Self { + Self::new(source) + } +} + +use std::ops::Index; + +impl<'a> Span<&'a str> for StrIter<'a> { + fn span(&self, idx: SpanRange) -> &'a str { + match idx { + SpanRange::Range(r) => self.source.index(r), + SpanRange::RangeTo(r) => self.source.index(r), + SpanRange::RangeFrom(r) => self.source.index(r), + SpanRange::RangeFull(r) => self.source.index(r), + } + } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 4ba1c23..b672953 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,18 @@ impl Offsetable for usize { } } +pub enum SpanRange { + Range(std::ops::Range), + RangeTo(std::ops::RangeTo), + RangeFrom(std::ops::RangeFrom), + RangeFull(std::ops::RangeFull), +} + +// An input that can provide a span of a range of the input. +pub trait Span { + fn span(&self, idx: SpanRange) -> O; +} + /// A Cloneable Iterator that can report an offset as a count of processed Items. pub trait InputIter: Iterator + Clone + Offsetable {} diff --git a/src/test.rs b/src/test.rs index 7203fd2..324afa5 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1,8 +1,7 @@ use std::fmt::{Debug, Display}; use super::{InputIter, Offsetable, Result}; -use iter::SliceIter; -use combinators::must_string; +use iter::{StrIter, SliceIter}; #[test] fn test_slice_iter() { @@ -354,13 +353,13 @@ fn test_repeat_abort() { #[test] fn test_until() { let input_str = "foo; "; - let iter = SliceIter::new(input_str.as_bytes()); - let result = must_string(until!(iter, text_token!("; ")), "AAAHHH!".to_string()); + let iter = StrIter::new(input_str); + let result = until!(iter, text_token!("; ")); assert!(result.is_complete()); if let Result::Complete(i, o) = result { assert_eq!(i.get_offset(), 3); assert_eq!(o.len(), 3); - assert_eq!(&o, "foo"); + assert_eq!(o, "foo"); } }