From 3fb7cb82cda854839b3d97c2cd25ae8182aca387 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 1 Nov 2023 01:07:54 -0400 Subject: [PATCH] Implement get_contents for document. --- src/types/document.rs | 27 +++++++++++++---- src/types/remove_trailing.rs | 56 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 src/types/remove_trailing.rs diff --git a/src/types/document.rs b/src/types/document.rs index a6e8217..157e929 100644 --- a/src/types/document.rs +++ b/src/types/document.rs @@ -1,12 +1,12 @@ use std::path::PathBuf; +use super::remove_trailing::RemoveTrailing; use super::Element; use super::NodeProperty; use super::Object; use super::PostBlank; use super::StandardProperties; use super::Timestamp; -use crate::types::remove_trailing::RemoveTrailing; pub type PriorityCookie = u8; pub type HeadlineLevel = u16; @@ -64,10 +64,27 @@ impl<'s> StandardProperties<'s> for Document<'s> { fn get_contents<'b>(&'b self) -> Option<&'s str> { let post_blank = self.get_post_blank(); - let foo: RemoveTrailing<_, post_blank> = - RemoveTrailing::new(self.source.split_inclusive("\n")); - // self.source.split_inclusive("\n") - todo!() + let mut content_lines = self + .source + .split_inclusive('\n') + .remove_trailing(post_blank); + let first_line = content_lines.next(); + let last_line = content_lines.last().or(first_line); + match (first_line, last_line) { + (None, None) => None, + (None, Some(_)) | (Some(_), None) => unreachable!(), + (Some(first_line), Some(last_line)) => { + let first_line_offset = first_line.as_ptr() as usize; + let last_line_offset = last_line.as_ptr() as usize + last_line.len(); + let source_offset = self.source.as_ptr() as usize; + debug_assert!(super::lesser_element::is_slice_of(self.source, first_line)); + debug_assert!(super::lesser_element::is_slice_of(self.source, last_line)); + Some( + &self.source[(first_line_offset - source_offset) + ..(last_line_offset - first_line_offset)], + ) + } + } } fn get_post_blank(&self) -> PostBlank { diff --git a/src/types/remove_trailing.rs b/src/types/remove_trailing.rs new file mode 100644 index 0000000..822c64c --- /dev/null +++ b/src/types/remove_trailing.rs @@ -0,0 +1,56 @@ +pub(crate) trait RemoveTrailing: Iterator + Sized { + fn remove_trailing>(self, amount_to_remove: R) -> RemoveTrailingIter; +} + +impl RemoveTrailing for I +where + I: Iterator, +{ + fn remove_trailing>(self, amount_to_remove: R) -> RemoveTrailingIter { + RemoveTrailingIter { + inner: self, + buffer: Vec::new(), + next_to_pop: 0, + amount_to_remove: amount_to_remove.into(), + } + } +} + +pub(crate) struct RemoveTrailingIter { + inner: I, + buffer: Vec, + next_to_pop: usize, + amount_to_remove: usize, +} + +impl Iterator for RemoveTrailingIter { + type Item = I::Item; + + fn next(&mut self) -> Option { + if self.buffer.len() < self.amount_to_remove { + self.buffer.reserve_exact(self.amount_to_remove); + } + while self.buffer.len() < self.amount_to_remove { + if let Some(elem) = self.inner.next() { + self.buffer.push(elem); + } else { + // The inner was smaller than amount_to_remove, so never return anything. + return None; + } + } + + let new_value = self.inner.next(); + if self.amount_to_remove == 0 { + return new_value; + } + + if let Some(new_value) = new_value { + let ret = std::mem::replace(&mut self.buffer[self.next_to_pop], new_value); + self.next_to_pop = (self.next_to_pop + 1) % self.amount_to_remove; + Some(ret) + } else { + // We have exactly the amount in the buffer than we wanted to cut off, so stop returning values. + None + } + } +}