This commit is contained in:
Joshua Bemenderfer
2025-09-08 16:24:38 -04:00
parent 70200a4091
commit 9d9757e868
79 changed files with 11705 additions and 3554 deletions

View File

@@ -0,0 +1,79 @@
Heading 2 Core API
class mt-12
Markdown
**Note:** The Core API provides low-level parsing functionality optimized for performance
and memory efficiency. It uses direct mutation patterns similar to C for optimal performance.
For most projects you'll want to use the [Document API](#document-api) instead.
It provides an ergonomic wrapper around the Core API and lets you focus on parsing
your documents without worrying about low-level details.
Heading 3 LineData
class mb-4 mt-12
CodeBlock rust
// Struct Definition
/// Holds the parsed information from each line.
#[derive(Debug, Clone, PartialEq)]
pub struct LineData {
/// Which character is being used for indentation.
pub indent: char,
/// How many indent characters are present in the current line before the first non-indent character.
pub level: usize,
/// The number of characters before the start of the line's "head" section.
pub offset_head: usize,
/// The number of characters before the start of the line's "tail" section.
pub offset_tail: usize,
}
Heading 3 create_line_data()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| indent | char | The character used for indentation in the document. Only a single character is permitted.
| **@returns** | [LineData](#line-data) | A LineData instance with the specified indent character and all other values initialized to 0.
Initialize a LineData instance with default values to pass to [parse_line()](#parse-line).
CodeBlock rust
// Function Signature
pub fn create_line_data(indent: char) -> LineData
// Import Path
use terrace::parser::{create_line_data, LineData};
// Usage
let line_data = create_line_data(' ');
println!("{:?}", line_data);
// LineData { indent: ' ', level: 0, offset_head: 0, offset_tail: 0 }
// Use the same line_data object for all calls to parse_line in the same document.
Heading 3 parse_line()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| line | &str | A string slice containing a line to parse. Shouldn't end with a newline.
| line_data | &mut [LineData](#line-data) | A mutable reference to a LineData object to store information about the current line, from [create_line_data()](#create-line-data).<br/>**Mutated in-place!**
Core Terrace parser function, sets `level`, `offset_head`, and `offset_tail` in a [LineData](#line-data) object based on the passed line.
Note that this is a C-style function, `line_data` is treated as a mutable reference and mutated in-place for performance.
CodeBlock rust
// Function Signature
pub fn parse_line(line: &str, line_data: &mut LineData)
// Import Path
use terrace::parser::{create_line_data, parse_line};
// Usage
let mut line_data = create_line_data(' ');
parse_line("title Example Title", &mut line_data);
println!("{:?}", line_data);
// LineData { indent: ' ', level: 0, offset_head: 0, offset_tail: 5 }
// Parse indented line
parse_line(" subtitle Example Subtitle", &mut line_data);
println!("{:?}", line_data);
// LineData { indent: ' ', level: 2, offset_head: 2, offset_tail: 10 }

View File

@@ -0,0 +1,296 @@
Heading 2 Document API
class mt-12
Heading 3 TerraceDocument::new()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| reader | impl [Reader](#reader) | An object that implements the Reader trait for reading lines.
| indent | char | The character used for indentation in the document. Only a single character is permitted.
| **@returns** | [TerraceDocument](#terrace-document) | An async iterator for parsing a Terrace document line by line.
Creates a new TerraceDocument with the specified reader and indentation character.
This is the main entry point for parsing Terrace documents.
CodeBlock rust
// Function Signature
pub fn new<R: Reader + Send + Sync + 'static>(reader: R, indent: char) -> Self
// Import Path
use terrace::{TerraceDocument, StringReader};
// Usage
let reader = StringReader::new("config\n database\n host localhost");
let mut doc = TerraceDocument::new(reader, ' ');
Heading 3 TerraceDocument::with_reader()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| reader | impl [Reader](#reader) | An object that implements the Reader trait for reading lines.
| **@returns** | [TerraceDocument](#terrace-document) | An async iterator for parsing a Terrace document with default space indentation.
Creates a new TerraceDocument with the specified reader and default space (' ') indentation.
CodeBlock rust
// Function Signature
pub fn with_reader<R: Reader + Send + Sync + 'static>(reader: R) -> Self
// Import Path
use terrace::{TerraceDocument, StringReader};
// Usage
let reader = StringReader::new("config\n database\n host localhost");
let mut doc = TerraceDocument::with_reader(reader);
Heading 3 TerraceDocument
class mb-4 mt-12
Markdown
The main document iterator that provides async access to parsed Terrace nodes.
Use this for ergonomic document parsing with automatic memory management and async iteration.
CodeBlock rust
// Struct Definition
pub struct TerraceDocument {
// Implementation details...
}
Heading 3 TerraceDocument::next()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | Option<[TerraceNode](#terrace-node)> | The next parsed node in the document, or None if the document has ended.
Advances to the next line in the document and returns a parsed TerraceNode.
This method is async and should be called in an async context.
CodeBlock rust
// Function Signature
pub async fn next(&mut self) -> Option<TerraceNode>
// Import Path
use terrace::{TerraceDocument, StringReader};
// Usage
let reader = StringReader::new("line1\n line2\nline3");
let mut doc = TerraceDocument::with_reader(reader);
while let Some(node) = doc.next().await {
println!("Level: {}, Content: '{}'", node.level(), node.content());
}
Heading 3 TerraceNode
class mb-4 mt-12
Markdown
Represents a single parsed line/node in a Terrace document.
Provides convenient access to different parts of the parsed line.
CodeBlock rust
// Struct Definition
#[derive(Debug, Clone)]
pub struct TerraceNode {
// Implementation details...
}
Heading 3 TerraceNode::head()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | &str | The head portion of the node (text before the first space).
Returns the first word or identifier of the line.
CodeBlock rust
// Function Signature
pub fn head(&self) -> &str
// Usage
let reader = StringReader::new("config database localhost");
let mut doc = TerraceDocument::with_reader(reader);
if let Some(node) = doc.next().await {
assert_eq!(node.head(), "config");
}
Heading 3 TerraceNode::tail()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | &str | The tail portion of the node (text after the first space).
Returns everything after the first space character in the line.
CodeBlock rust
// Function Signature
pub fn tail(&self) -> &str
// Usage
let reader = StringReader::new("config database localhost");
let mut doc = TerraceDocument::with_reader(reader);
if let Some(node) = doc.next().await {
assert_eq!(node.tail(), "database localhost");
}
Heading 3 TerraceNode::content()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | &str | The full content of the node after indentation.
Returns the complete text content of the line, excluding the indentation characters.
CodeBlock rust
// Function Signature
pub fn content(&self) -> &str
// Usage
let reader = StringReader::new(" config database localhost");
let mut doc = TerraceDocument::with_reader(reader);
if let Some(node) = doc.next().await {
assert_eq!(node.content(), "config database localhost");
assert_eq!(node.level(), 2);
}
Heading 3 TerraceNode::level()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | usize | The indentation level of the node.
Returns the number of indentation characters at the beginning of the line.
CodeBlock rust
// Function Signature
pub fn level(&self) -> usize
// Usage
let reader = StringReader::new("config\n database\n host localhost");
let mut doc = TerraceDocument::with_reader(reader);
let levels: Vec<usize> = doc.map(|node| node.level()).await;
assert_eq!(levels, vec![0, 1, 2]);
Heading 3 TerraceNode::is()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| value | &str | The value to compare against the node's head.
| **@returns** | bool | True if the node's head matches the given value.
Convenience method to check if the node's head matches a specific value.
CodeBlock rust
// Function Signature
pub fn is(&self, value: &str) -> bool
// Usage
let reader = StringReader::new("config\n database\n server");
let mut doc = TerraceDocument::with_reader(reader);
if let Some(node) = doc.next().await {
assert!(node.is("config"));
assert!(!node.is("database"));
}
Heading 3 TerraceDocument::collect()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| **@returns** | Vec<[TerraceNode](#terrace-node)> | A vector containing all nodes in the document.
Collects all nodes from the document into a vector for batch processing.
CodeBlock rust
// Function Signature
pub async fn collect(mut self) -> Vec<TerraceNode>
// Usage
let reader = StringReader::new("config\n database\n host localhost");
let doc = TerraceDocument::with_reader(reader);
let nodes = doc.collect().await;
assert_eq!(nodes.len(), 3);
assert_eq!(nodes[0].head(), "config");
assert_eq!(nodes[1].head(), "database");
assert_eq!(nodes[2].head(), "host");
Heading 3 TerraceDocument::filter()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| predicate | F | A closure that takes a &TerraceNode and returns bool.
| **@returns** | Vec<[TerraceNode](#terrace-node)> | A vector containing only nodes that match the predicate.
Filters nodes based on a predicate function.
CodeBlock rust
// Function Signature
pub async fn filter<F>(mut self, predicate: F) -> Vec<TerraceNode>
where
F: FnMut(&TerraceNode) -> bool,
// Usage
let reader = StringReader::new("config\n database\n server\n database");
let doc = TerraceDocument::with_reader(reader);
let databases = doc.filter(|node| node.head() == "database").await;
assert_eq!(databases.len(), 2);
Heading 3 TerraceDocument::find()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| predicate | F | A closure that takes a &TerraceNode and returns bool.
| **@returns** | Option<[TerraceNode](#terrace-node)> | The first node that matches the predicate, or None.
Finds the first node that matches a predicate function.
CodeBlock rust
// Function Signature
pub async fn find<F>(mut self, predicate: F) -> Option<TerraceNode>
where
F: FnMut(&TerraceNode) -> bool,
// Usage
let reader = StringReader::new("config\n database\n server");
let doc = TerraceDocument::with_reader(reader);
let server_node = doc.find(|node| node.head() == "server").await;
assert!(server_node.is_some());
assert_eq!(server_node.unwrap().head(), "server");
Heading 3 TerraceDocument::map()
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| mapper | F | A closure that takes a TerraceNode and returns a value of type T.
| **@returns** | Vec<T> | A vector containing the mapped values.
Transforms each node using a mapper function.
CodeBlock rust
// Function Signature
pub async fn map<F, T>(mut self, mapper: F) -> Vec<T>
where
F: FnMut(TerraceNode) -> T,
// Usage
let reader = StringReader::new("config\n database\n server");
let doc = TerraceDocument::with_reader(reader);
let heads: Vec<String> = doc.map(|node| node.head().to_string()).await;
assert_eq!(heads, vec!["config", "database", "server"]);

View File

@@ -0,0 +1,56 @@
layout layout.njk
title Rust Documentation - Terrace
description
Rust language documentation for the Terrace programming language
Section light
class flex flex-col md:flex-row gap-16
Block
class w-full lg:w-1/3
TableOfContents
Block
Heading 1 Terrace Rust Documentation
class -ml-2
Markdown
Documentation is available for the following languages:
- [C](/docs/c/) - 100% Complete
- [JavaScript](/docs/javascript/) - 75% Complete
- [Go](/docs/go/) - 50% Complete
- [Python](/docs/python/) - 100% Complete
- [Rust](/docs/rust/) - 100% Complete
Heading 2 Getting Started
class mt-12 mb-6
Markdown
Add Terrace to your `Cargo.toml`:
CodeBlock toml
[dependencies]
terrace = "0.1"
Markdown
Or use Cargo to add it:
CodeBlock bash
$ cargo add terrace
Include ./core-api.inc.tce
Include ./document-api.inc.tce
Include ./reader-api.inc.tce
Include ./recipes.inc.tce
Heading 2 Contributing
class mt-12
Markdown
The Rust implementation is fully open source. Contributions are welcome!
- [GitHub Repository](https://github.com/terrace-lang/terrace)
- [Issue Tracker](https://github.com/terrace-lang/terrace/issues)
- [Rust Package](https://crates.io/crates/terrace)
Section dark
Footer
class w-full

View File

@@ -0,0 +1,185 @@
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<Option<String>>;
}
Heading 3 StringReader
class mb-4 mt-12
Markdown
| Parameter | Type | Description
| -------------- | --------------------- | -----------------------------------------------------------------------
| source | impl Into<StringReaderSource> | 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<StringReaderSource>) -> 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)<R> | 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<R> {
// 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<Option<String>> {
// 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<String>,
index: usize,
}
impl VecReader {
fn new(lines: Vec<String>) -> Self {
Self { lines, index: 0 }
}
}
#[async_trait]
impl Reader for VecReader {
async fn read_line(&mut self) -> io::Result<Option<String>> {
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);

View File

@@ -0,0 +1,416 @@
Heading 2 Recipes
class mt-12
Heading 3 Basic Document Parsing
class mb-2
Markdown
Parse a simple Terrace document and print all nodes with their levels.
CodeBlock rust
use terrace::{TerraceDocument, StringReader};
#[tokio::main]
async fn main() {
let content = r#"
config
database
host localhost
port 5432
server
port 3000
host 0.0.0.0
"#;
let reader = StringReader::new(content);
let mut doc = TerraceDocument::with_reader(reader);
while let Some(node) = doc.next().await {
if !node.is_empty() {
println!("{:indent$}{}: '{}'",
"",
node.head(),
node.tail(),
indent = node.level() * 2);
}
}
}
Markdown
This will output:
```
config: ''
database: ''
host: 'localhost'
port: '5432'
server: ''
port: '3000'
host: '0.0.0.0'
```
Heading 3 Read Configuration into Struct
class mb-2
Markdown
Parse a Terrace configuration file and map it to a Rust struct.
CodeBlock rust
use terrace::{TerraceDocument, StringReader};
use std::collections::HashMap;
#[derive(Debug)]
struct Config {
database: DatabaseConfig,
server: ServerConfig,
}
#[derive(Debug)]
struct DatabaseConfig {
host: String,
port: u16,
name: String,
}
#[derive(Debug)]
struct ServerConfig {
host: String,
port: u16,
}
#[tokio::main]
async fn main() {
let content = r#"
config
database
host localhost
port 5432
name mydb
server
host 0.0.0.0
port 3000
"#;
let reader = StringReader::new(content);
let doc = TerraceDocument::with_reader(reader);
let mut config = Config {
database: DatabaseConfig {
host: String::new(),
port: 0,
name: String::new(),
},
server: ServerConfig {
host: String::new(),
port: 0,
},
};
let nodes = doc.collect().await;
for node in nodes {
match (node.level(), node.head()) {
(1, "database") => {
// Parse database section
// In a real implementation, you'd iterate through children
}
(1, "server") => {
// Parse server section
}
(2, "host") if node.tail().starts_with("localhost") => {
config.database.host = node.tail().to_string();
}
(2, "port") => {
if let Ok(port) = node.tail().parse::<u16>() {
if node.tail() == "5432" {
config.database.port = port;
} else if node.tail() == "3000" {
config.server.port = port;
}
}
}
(2, "name") => {
config.database.name = node.tail().to_string();
}
_ => {}
}
}
println!("{:?}", config);
}
Heading 3 Filter and Process Specific Nodes
class mb-2
Markdown
Find all nodes with a specific head value and process them.
CodeBlock rust
use terrace::{TerraceDocument, StringReader};
#[tokio::main]
async fn main() {
let content = r#"
users
user alice active
user bob inactive
user charlie active
user david inactive
groups
group admins
member alice
member charlie
group users
member bob
member david
"#;
let reader = StringReader::new(content);
let doc = TerraceDocument::with_reader(reader);
// Find all active users
let active_users = doc.filter(|node| {
node.head() == "user" && node.tail().contains("active")
}).await;
println!("Active users:");
for user in active_users {
let parts: Vec<&str> = user.tail().split_whitespace().collect();
if parts.len() >= 2 {
println!(" {} ({})", parts[0], parts[1]);
}
}
// Alternative: Process all users
let reader2 = StringReader::new(content);
let doc2 = TerraceDocument::with_reader(reader2);
let all_users: Vec<(String, String)> = doc2
.filter(|node| node.head() == "user")
.await
.into_iter()
.filter_map(|node| {
let parts: Vec<&str> = node.tail().split_whitespace().collect();
if parts.len() >= 2 {
Some((parts[0].to_string(), parts[1].to_string()))
} else {
None
}
})
.collect();
println!("\nAll users:");
for (name, status) in all_users {
println!(" {}: {}", name, status);
}
}
Heading 3 Build Hierarchical Data Structure
class mb-2
Markdown
Parse a Terrace document into a hierarchical data structure.
CodeBlock rust
use terrace::{TerraceDocument, StringReader};
use std::collections::HashMap;
#[derive(Debug)]
enum Value {
String(String),
Number(f64),
Boolean(bool),
Object(HashMap<String, Value>),
}
#[tokio::main]
async fn main() {
let content = r#"
app
name My Application
version 1.0.0
debug true
database
host localhost
port 5432
credentials
username admin
password secret
features
auth true
logging false
"#;
let reader = StringReader::new(content);
let mut doc = TerraceDocument::with_reader(reader);
let mut root = HashMap::new();
let mut stack: Vec<(String, HashMap<String, Value>)> = Vec::new();
let mut current = &mut root;
while let Some(node) = doc.next().await {
if node.is_empty() {
continue;
}
match node.level() {
0 => {
// Root level - should be the main object name
if node.head() == "app" {
// Already at root
}
}
level => {
// Adjust stack to match current level
while stack.len() >= level {
stack.pop();
}
// Update current reference
if let Some((_, ref mut obj)) = stack.last_mut() {
current = obj;
} else {
current = &mut root;
}
// Parse the value
let value = if let Ok(num) = node.tail().parse::<f64>() {
Value::Number(num)
} else if node.tail() == "true" {
Value::Boolean(true)
} else if node.tail() == "false" {
Value::Boolean(false)
} else if node.tail().is_empty() {
// This is a nested object
let mut nested = HashMap::new();
current.insert(node.head().to_string(), Value::Object(nested.clone()));
stack.push((node.head().to_string(), nested));
continue;
} else {
Value::String(node.tail().to_string())
};
current.insert(node.head().to_string(), value);
}
}
}
println!("Parsed configuration:");
println!("{:?}", root);
}
Heading 3 Async File Reading
class mb-2
Markdown
Read a Terrace document from a file asynchronously.
CodeBlock rust
use terrace::{TerraceDocument, readers::AsyncReader};
use tokio::fs::File;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Open the file asynchronously
let file = File::open("config.tce").await?;
let reader = AsyncReader::new(file);
let mut doc = TerraceDocument::with_reader(reader);
println!("Configuration from file:");
while let Some(node) = doc.next().await {
if !node.is_empty() {
println!("{:indent$}{}: '{}'",
"",
node.head(),
node.tail(),
indent = node.level() * 2);
}
}
Ok(())
}
Heading 3 Error Handling
class mb-2
Markdown
Handle parsing errors and edge cases gracefully.
CodeBlock rust
use terrace::{TerraceDocument, StringReader};
#[tokio::main]
async fn main() {
let content = r#"
config
database
host localhost
port not_a_number
timeout 30
server
port 3000
host
"#;
let reader = StringReader::new(content);
let mut doc = TerraceDocument::with_reader(reader);
while let Some(node) = doc.next().await {
if node.is_empty() {
continue;
}
match node.head() {
"port" => {
match node.tail().parse::<u16>() {
Ok(port) => println!("Port: {}", port),
Err(_) => eprintln!("Warning: Invalid port '{}'", node.tail()),
}
}
"host" => {
if node.tail().is_empty() {
eprintln!("Warning: Empty host value");
} else {
println!("Host: {}", node.tail());
}
}
"timeout" => {
match node.tail().parse::<u64>() {
Ok(timeout) => println!("Timeout: {}ms", timeout),
Err(_) => eprintln!("Warning: Invalid timeout '{}'", node.tail()),
}
}
_ => {
println!("{}: {}", node.head(), node.tail());
}
}
}
}
Heading 3 Streaming Large Documents
class mb-2
Markdown
Process very large documents without loading everything into memory.
CodeBlock rust
use terrace::{TerraceDocument, StringReader};
#[tokio::main]
async fn main() {
// Simulate a large document
let mut large_content = String::new();
for i in 0..10000 {
large_content.push_str(&format!("item{}\n value{}\n count {}\n", i, i * 2, i * 3));
}
let reader = StringReader::new(large_content);
let mut doc = TerraceDocument::with_reader(reader);
let mut item_count = 0;
let mut total_values = 0i64;
while let Some(node) = doc.next().await {
match node.head() {
"item" => {
item_count += 1;
}
"value" => {
if let Ok(value) = node.tail().parse::<i64>() {
total_values += value;
}
}
_ => {}
}
}
println!("Processed {} items", item_count);
println!("Total values: {}", total_values);
println!("Average value: {}", total_values as f64 / item_count as f64);
}

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env node
/**
* Simple renderer for Terrace Rust documentation
* This would be used by the documentation build system
*/
const fs = require('fs');
const path = require('path');
// Simple template rendering for the Rust docs
function renderRustDocs() {
console.log('Rendering Terrace Rust Documentation...');
const docsDir = path.dirname(__filename);
const files = [
'index.tce',
'core-api.inc.tce',
'document-api.inc.tce',
'reader-api.inc.tce',
'recipes.inc.tce'
];
files.forEach(file => {
const filePath = path.join(docsDir, file);
if (fs.existsSync(filePath)) {
console.log(`✓ Found ${file}`);
} else {
console.log(`✗ Missing ${file}`);
}
});
console.log('Rust documentation files are ready for the build system.');
}
// Export for use in build scripts
module.exports = { renderRustDocs };
// Run if called directly
if (require.main === module) {
renderRustDocs();
}