diff --git a/core/src/lib.rs b/core/src/lib.rs index 142fe23..f3bfd10 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,2 +1,2 @@ mod text_buffer; -pub use text_buffer::TextBuffer; +pub use text_buffer::{TextBuffer, TextBufferReader}; diff --git a/core/src/text_buffer/mod.rs b/core/src/text_buffer/mod.rs index 7e7c764..937b9fc 100644 --- a/core/src/text_buffer/mod.rs +++ b/core/src/text_buffer/mod.rs @@ -4,6 +4,9 @@ mod rope; use rope::Rope; pub use rope::{CharIterator, CharWithPointIterator}; +mod reader; +pub use reader::TextBufferReader; + pub struct TextBuffer { contents: Rc, } diff --git a/core/src/text_buffer/reader.rs b/core/src/text_buffer/reader.rs new file mode 100644 index 0000000..8f3e43c --- /dev/null +++ b/core/src/text_buffer/reader.rs @@ -0,0 +1,91 @@ +use std::rc::Rc; + +use super::{ + TextBuffer, + rope::{NodeIterator, Rope}, +}; + +pub struct TextBufferReader { + node_iterator: NodeIterator, + current_node: Option>, + cursor: usize, +} + +impl TextBufferReader { + pub fn new(text_buffer: &TextBuffer) -> Self { + let mut node_iterator = Rc::clone(&text_buffer.contents).iter_nodes(); + let current_node = node_iterator.next(); + Self { + node_iterator, + current_node, + cursor: 0, + } + } +} + +impl std::io::Read for TextBufferReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let mut bytes_written = 0; + while let Some(rope) = self.current_node.clone() { + if let Rope::Leaf { text } = rope.as_ref() { + let bytes = text.as_bytes(); + let length = bytes + .len() + .min(buf.len() - bytes_written) + .min(bytes.len() - self.cursor); + buf[bytes_written..bytes_written + length] + .copy_from_slice(&bytes[self.cursor..self.cursor + length]); + bytes_written += length; + self.cursor += length; + if self.cursor == bytes.len() { + self.current_node = self.node_iterator.next(); + self.cursor = 0; + } + } else { + // Should always be leaf node + panic!(); + } + if bytes_written == buf.len() { + break; + } + } + Ok(bytes_written) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::text_buffer::Point; + use std::io::Read; + + #[test] + fn test_read_string() { + let text_fragments = [ + "Sed ut perspiciatis unde omnis iste natus error sit voluptatem ", + "accusantium doloremque laudantium, totam rem aperiam, eaque ", + "ipsa quae ab illo inventore veritatis et quasi architecto beatae ", + "vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia ", + "voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur ", + "magni dolores eos qui ratione voluptatem sequi nesciunt. Neque ", + "porro quisquam est, qui dolorem ipsum quia dolor sit amet, ", + "consectetur, adipisci velit, sed quia non numquam eius modi tempora ", + "incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut ", + "enim ad minima veniam, quis nostrum exercitationem ullam ", + "corporis suscipit laboriosam, nisi ut aliquid ex ea commodi ", + "consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate ", + "velit esse quam nihil molestiae consequatur, vel illum qui dolorem ", + "eum fugiat quo voluptas nulla pariatur?", + ]; + let mut text_buffer = TextBuffer::new(); + for fragment in text_fragments { + text_buffer.insert_text(fragment, Point::End); + } + let mut target = TextBufferReader::new(&text_buffer); + let mut bytes_buffer = Vec::new(); + target.read_to_end(&mut bytes_buffer).unwrap(); + let target_string = String::from_utf8(bytes_buffer).unwrap(); + let expected_string: String = text_fragments.iter().flat_map(|s| s.chars()).collect(); + assert_eq!(target_string, expected_string); + } +} diff --git a/core/src/text_buffer/rope/mod.rs b/core/src/text_buffer/rope/mod.rs index fe21c71..8ecef0f 100644 --- a/core/src/text_buffer/rope/mod.rs +++ b/core/src/text_buffer/rope/mod.rs @@ -252,7 +252,7 @@ impl Rope { } /// Returns an iterater over the leaf nodes - fn iter_nodes(self: Rc) -> NodeIterator { + pub fn iter_nodes(self: Rc) -> NodeIterator { NodeIterator::new(self) } } @@ -269,7 +269,7 @@ fn merge(leaf_nodes: &[Rc]) -> Rc { } } -struct NodeIterator { +pub struct NodeIterator { stack: Vec>, }