From 0816ab4dcb7807a3aebcc17448bca9fb1cae9d7f Mon Sep 17 00:00:00 2001 From: Noah Hellman Date: Sun, 15 Jan 2023 16:12:05 +0100 Subject: [PATCH] mv inline span structs to span module --- src/lib.rs | 197 ++------------------------------------------------- src/span.rs | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 203 insertions(+), 193 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index daf7a34..331c75e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ mod lex; mod span; mod tree; +use span::DiscontinuousString; use span::Span; pub use attr::Attributes; @@ -254,201 +255,11 @@ impl<'s> Container<'s> { } } -#[derive(Clone)] -struct InlineChars<'s, I> { - src: &'s str, - inlines: I, - next: std::str::Chars<'s>, -} - -// Implement inlines.flat_map(|sp| sp.of(self.src).chars()) -impl<'s, I: Iterator> InlineChars<'s, I> { - fn new(src: &'s str, inlines: I) -> Self { - Self { - src, - inlines, - next: "".chars(), - } - } -} - -impl<'s, I: Iterator> Iterator for InlineChars<'s, I> { - type Item = char; - - fn next(&mut self) -> Option { - (&mut self.inlines) - .flat_map(|sp| sp.of(self.src).chars()) - .next() - } -} - -trait DiscontinuousString<'s> { - type Chars: Iterator; - - fn src(&self, span: Span) -> CowStr<'s>; - - fn chars(&self) -> Self::Chars; -} - -impl<'s> DiscontinuousString<'s> for &'s str { - type Chars = std::str::Chars<'s>; - - fn src(&self, span: Span) -> CowStr<'s> { - span.of(self).into() - } - - fn chars(&self) -> Self::Chars { - str::chars(self) - } -} - -impl<'s> DiscontinuousString<'s> for InlineSpans<'s> { - type Chars = InlineCharsIter<'s>; - - fn src(&self, span: Span) -> CowStr<'s> { - Self::borrow_or_copy(self.src, self.spans.iter().copied(), span) - } - - fn chars(&self) -> Self::Chars { - // SAFETY: do not call set_spans while chars is in use - unsafe { std::mem::transmute(InlineChars::new(self.src, self.spans.iter().copied())) } - } -} - -impl<'s, 'i> DiscontinuousString<'s> for InlineSpansSlice<'s, 'i> { - type Chars = InlineChars<'s, InlineSpansSliceIter<'i>>; - - /// Borrow if continuous, copy if discontiunous. - fn src(&self, span: Span) -> CowStr<'s> { - InlineSpans::borrow_or_copy(self.src, self.spans(), span) - } - - fn chars(&self) -> Self::Chars { - InlineChars::new(self.src, self.spans()) - } -} - -#[derive(Default, Debug)] -struct InlineSpans<'s> { - src: &'s str, - spans: Vec, -} - -impl<'s> InlineSpans<'s> { - fn new(src: &'s str) -> Self { - Self { - src, - spans: Vec::new(), - } - } - - fn set_spans(&mut self, spans: impl Iterator) { - self.spans.clear(); - self.spans.extend(spans); - } - - fn slice<'i>(&'i self, span: Span) -> InlineSpansSlice<'s, 'i> { - let mut first = 0; - let mut last = 0; - let mut first_skip = 0; - let mut last_len = 0; - - let mut a = 0; - for (i, sp) in self.spans.iter().enumerate() { - let b = a + sp.len(); - if span.start() < b { - if a <= span.start() { - first = i; - first_skip = span.start() - a; - if span.end() <= b { - // continuous - last = i; - last_len = span.len(); - break; - } - } else { - last = i; - last_len = sp.len().min(span.end() - a); - break; - }; - } - a = b; - } - - assert_ne!(last_len, 0); - - InlineSpansSlice { - src: self.src, - first_skip, - last_len, - spans: &self.spans[first..=last], - } - } - - /// Borrow if continuous, copy if discontiunous. - fn borrow_or_copy>(src: &str, spans: I, span: Span) -> CowStr { - let mut a = 0; - let mut s = String::new(); - for sp in spans { - let b = a + sp.len(); - if span.start() < b { - let r = if a <= span.start() { - if span.end() <= b { - // continuous - return CowStr::Borrowed(&sp.of(src)[span.start() - a..span.end() - a]); - } - (span.start() - a)..sp.len() - } else { - 0..sp.len().min(span.end() - a) - }; - s.push_str(&sp.of(src)[r]); - } - a = b; - } - assert_eq!(span.len(), s.len()); - CowStr::Owned(s) - } -} - -struct InlineSpansSlice<'s, 'i> { - src: &'s str, - first_skip: usize, - last_len: usize, - spans: &'i [Span], -} - -type InlineSpansSliceIter<'i> = std::iter::Chain< - std::iter::Chain, std::iter::Copied>>, - std::iter::Once, ->; - -impl<'s, 'i> InlineSpansSlice<'s, 'i> { - fn spans(&self) -> InlineSpansSliceIter<'i> { - let (span_start, r_middle, span_end) = if self.spans.len() == 1 { - ( - Span::by_len(self.spans[0].start() + self.first_skip, self.last_len), - 0..0, - Span::by_len(self.spans[self.spans.len() - 1].start(), 0), - ) - } else { - ( - Span::new(self.spans[0].start() + self.first_skip, self.spans[0].end()), - 1..self.spans.len().saturating_sub(2), - Span::by_len(self.spans[self.spans.len() - 1].start(), self.last_len), - ) - }; - std::iter::once(span_start) - .chain(self.spans[r_middle].iter().copied()) - .chain(std::iter::once(span_end)) - } -} -type InlineCharsIter<'s> = InlineChars<'s, std::iter::Copied>>; - pub struct Parser<'s> { src: &'s str, tree: block::Tree, - inlines: InlineSpans<'s>, - inline_parser: Option>>, + inlines: span::InlineSpans<'s>, + inline_parser: Option>>, inline_start: usize, } @@ -458,7 +269,7 @@ impl<'s> Parser<'s> { Self { src, tree: block::parse(src), - inlines: InlineSpans::new(src), + inlines: span::InlineSpans::new(src), inline_parser: None, inline_start: 0, } diff --git a/src/span.rs b/src/span.rs index 6d2f49a..66097f6 100644 --- a/src/span.rs +++ b/src/span.rs @@ -1,3 +1,5 @@ +use crate::CowStr; + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] pub struct Span { start: u32, @@ -84,6 +86,203 @@ impl Span { } } +pub trait DiscontinuousString<'s> { + type Chars: Iterator; + + fn src(&self, span: Span) -> CowStr<'s>; + + fn chars(&self) -> Self::Chars; +} + +impl<'s> DiscontinuousString<'s> for &'s str { + type Chars = std::str::Chars<'s>; + + fn src(&self, span: Span) -> CowStr<'s> { + span.of(self).into() + } + + fn chars(&self) -> Self::Chars { + str::chars(self) + } +} + +/// Multiple discontinuous [`std::str::Chars`] objects concatenated. +#[derive(Clone)] +pub struct InlineChars<'s, I> { + src: &'s str, + inlines: I, + next: std::str::Chars<'s>, +} + +// Implement inlines.flat_map(|sp| sp.of(self.src).chars()) +impl<'s, I: Iterator> InlineChars<'s, I> { + fn new(src: &'s str, inlines: I) -> Self { + Self { + src, + inlines, + next: "".chars(), + } + } +} + +impl<'s, I: Iterator> Iterator for InlineChars<'s, I> { + type Item = char; + + fn next(&mut self) -> Option { + if self.next.as_str().is_empty() { + self.next = self + .inlines + .next() + .map_or_else(|| "".chars(), |sp| sp.of(self.src).chars()); + } + self.next.next() + } +} + +pub type InlineCharsIter<'s> = InlineChars<'s, std::iter::Copied>>; + +#[derive(Default, Debug)] +pub struct InlineSpans<'s> { + src: &'s str, + spans: Vec, +} + +impl<'s> InlineSpans<'s> { + pub fn new(src: &'s str) -> Self { + Self { + src, + spans: Vec::new(), + } + } + + pub fn set_spans(&mut self, spans: impl Iterator) { + self.spans.clear(); + self.spans.extend(spans); + } + + pub fn slice<'i>(&'i self, span: Span) -> InlineSpansSlice<'s, 'i> { + let mut first = 0; + let mut last = 0; + let mut first_skip = 0; + let mut last_len = 0; + + let mut a = 0; + for (i, sp) in self.spans.iter().enumerate() { + let b = a + sp.len(); + if span.start() < b { + if a <= span.start() { + first = i; + first_skip = span.start() - a; + if span.end() <= b { + // continuous + last = i; + last_len = span.len(); + break; + } + } else { + last = i; + last_len = sp.len().min(span.end() - a); + break; + }; + } + a = b; + } + + assert_ne!(last_len, 0); + + InlineSpansSlice { + src: self.src, + first_skip, + last_len, + spans: &self.spans[first..=last], + } + } + + /// Borrow if continuous, copy if discontiunous. + fn borrow_or_copy>(src: &str, spans: I, span: Span) -> CowStr { + let mut a = 0; + let mut s = String::new(); + for sp in spans { + let b = a + sp.len(); + if span.start() < b { + let r = if a <= span.start() { + if span.end() <= b { + // continuous + return CowStr::Borrowed(&sp.of(src)[span.start() - a..span.end() - a]); + } + (span.start() - a)..sp.len() + } else { + 0..sp.len().min(span.end() - a) + }; + s.push_str(&sp.of(src)[r]); + } + a = b; + } + assert_eq!(span.len(), s.len()); + CowStr::Owned(s) + } +} + +impl<'s> DiscontinuousString<'s> for InlineSpans<'s> { + type Chars = InlineCharsIter<'s>; + + fn src(&self, span: Span) -> CowStr<'s> { + Self::borrow_or_copy(self.src, self.spans.iter().copied(), span) + } + + fn chars(&self) -> Self::Chars { + // SAFETY: do not call set_spans while chars is in use + unsafe { std::mem::transmute(InlineChars::new(self.src, self.spans.iter().copied())) } + } +} + +/// A read-only slice of an [`InlineSpans`] object. +pub struct InlineSpansSlice<'s, 'i> { + src: &'s str, + first_skip: usize, + last_len: usize, + spans: &'i [Span], +} + +impl<'s, 'i> InlineSpansSlice<'s, 'i> { + fn spans(&self) -> InlineSpansSliceIter<'i> { + let (span_start, r_middle, span_end) = if self.spans.len() == 1 { + ( + Span::by_len(self.spans[0].start() + self.first_skip, self.last_len), + 0..0, + Span::by_len(self.spans[self.spans.len() - 1].start(), 0), + ) + } else { + ( + Span::new(self.spans[0].start() + self.first_skip, self.spans[0].end()), + 1..self.spans.len().saturating_sub(2), + Span::by_len(self.spans[self.spans.len() - 1].start(), self.last_len), + ) + }; + std::iter::once(span_start) + .chain(self.spans[r_middle].iter().copied()) + .chain(std::iter::once(span_end)) + } +} + +impl<'s, 'i> DiscontinuousString<'s> for InlineSpansSlice<'s, 'i> { + type Chars = InlineChars<'s, InlineSpansSliceIter<'i>>; + + /// Borrow if continuous, copy if discontiunous. + fn src(&self, span: Span) -> CowStr<'s> { + InlineSpans::borrow_or_copy(self.src, self.spans(), span) + } + + fn chars(&self) -> Self::Chars { + InlineChars::new(self.src, self.spans()) + } +} + +type InlineSpansSliceIter<'i> = std::iter::Chain< + std::iter::Chain, std::iter::Copied>>, + std::iter::Once, +>; + #[cfg(test)] mod test { use super::Span;