Heading 2 Reader API class mt-12 Markdown The [Document API](#document-api) requires `Reader` implementations to iterate through lines in a document. A reader is any type that implements the `Reader` trait, which provides an async method to read the next line from a source. Terrace provides built-in readers for common use cases, but you can implement the trait for your own custom sources. Heading 3 Reader Trait class mb-4 mt-12 Markdown The Reader trait defines the interface for reading lines from a document source. Implement this trait to create custom readers for different input sources. CodeBlock rust // Trait Definition #[async_trait::async_trait] pub trait Reader { /// Read the next line from the source. /// Returns None if there are no more lines. async fn read_line(&mut self) -> io::Result>; } Heading 3 StringReader class mb-4 mt-12 Markdown | Parameter | Type | Description | -------------- | --------------------- | ----------------------------------------------------------------------- | source | impl Into | The source content as a string or vector of strings. | **@returns** | [StringReader](#string-reader) | A reader that iterates over the lines in the source. A reader that reads from a string or vector of strings. This is the most common reader for parsing Terrace documents from memory. CodeBlock rust // Struct Definition pub struct StringReader { // Implementation details... } // Constructor pub fn new(source: impl Into) -> Self // Import Path use terrace::readers::StringReader; // Usage // From a string let reader = StringReader::new("line1\nline2\nline3"); // From a vector of strings let reader = StringReader::new(vec!["line1", "line2", "line3"]); // From a string slice let reader = StringReader::new("line1\nline2\nline3"); Heading 3 AsyncReader class mb-4 mt-12 Markdown | Parameter | Type | Description | -------------- | --------------------- | ----------------------------------------------------------------------- | reader | R | Any async reader that implements AsyncRead. | **@returns** | [AsyncReader](#async-reader) | A reader that reads lines from an async source. A reader that reads from any async source that implements the `AsyncRead` trait. This is useful for reading from files, network streams, or other async sources. CodeBlock rust // Struct Definition pub struct AsyncReader { // Implementation details... } // Constructor pub fn new(reader: R) -> Self // Import Path use terrace::readers::AsyncReader; use tokio::fs::File; // Usage let file = File::open("document.tce").await?; let reader = AsyncReader::new(file); // Can also be used with other async sources use tokio::io::BufReader; let buffered = BufReader::new(file); let reader = AsyncReader::new(buffered); Heading 3 Custom Reader Implementation class mb-4 mt-12 Markdown You can implement the Reader trait for your own custom sources. This allows you to read from databases, APIs, or any other source of line-based data. CodeBlock rust // Custom Reader Example use async_trait::async_trait; use std::io; use terrace::readers::Reader; struct DatabaseReader { connection: DatabaseConnection, query: String, current_row: usize, } #[async_trait] impl Reader for DatabaseReader { async fn read_line(&mut self) -> io::Result> { // Fetch next row from database match self.connection.fetch_row(&self.query, self.current_row).await { Ok(Some(row)) => { self.current_row += 1; Ok(Some(format!("{} {}", row.key, row.value))) } Ok(None) => Ok(None), Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), } } } // Usage let db_reader = DatabaseReader { connection: connect_to_db().await?, query: "SELECT key, value FROM config".to_string(), current_row: 0, }; let mut doc = TerraceDocument::with_reader(db_reader); while let Some(node) = doc.next().await { println!("{}: {}", node.head(), node.tail()); } Heading 3 Reader Trait Implementation Details class mb-4 mt-12 Markdown When implementing the Reader trait, follow these guidelines: - Return `Ok(Some(line))` for each line of content - Return `Ok(None)` when there are no more lines - Return `Err(error)` if an I/O error occurs - Lines should not include trailing newlines - The reader should be mutable to track state between calls CodeBlock rust // Complete Reader Implementation Example use async_trait::async_trait; use std::io; use terrace::readers::Reader; struct VecReader { lines: Vec, index: usize, } impl VecReader { fn new(lines: Vec) -> Self { Self { lines, index: 0 } } } #[async_trait] impl Reader for VecReader { async fn read_line(&mut self) -> io::Result> { if self.index >= self.lines.len() { return Ok(None); } let line = self.lines[self.index].clone(); self.index += 1; Ok(Some(line)) } } // Usage let lines = vec![ "config".to_string(), " database".to_string(), " host localhost".to_string(), ]; let reader = VecReader::new(lines); let mut doc = TerraceDocument::with_reader(reader);