API Documentation
Programmatic interface documentation for Two-Face.
Rust API Documentation
Two-Face’s internal API is documented using Rust’s built-in documentation system.
Viewing Rustdoc
Generate and view the API documentation:
# Generate documentation
cargo doc --no-deps
# Open in browser
cargo doc --no-deps --open
# Include private items
cargo doc --no-deps --document-private-items
Online Documentation
When available, API documentation is hosted at:
- Stable: docs.rs/two-face (when published)
- Development: Generated from source
Module Overview
Two-Face is organized into three main layers:
Data Layer (src/data/)
Core data structures and game state.
#![allow(unused)]
fn main() {
// Key types
pub struct GameState { ... }
pub struct ParsedElement { ... }
pub enum StreamId { ... }
pub struct Vitals { ... }
}
Key modules:
data::game_state- Central state managementdata::parsed- Parser output typesdata::vitals- Health/mana/staminadata::room- Room information
Core Layer (src/core/)
Business logic and widget management.
#![allow(unused)]
fn main() {
// Key types
pub struct WidgetManager { ... }
pub struct AppState { ... }
pub trait Widget { ... }
}
Key modules:
core::widget_manager- Widget lifecyclecore::app_state- Application statecore::sync- State synchronizationcore::layout- Layout management
Frontend Layer (src/frontend/)
User interface and rendering.
#![allow(unused)]
fn main() {
// Key types
pub struct TuiApp { ... }
pub struct InputHandler { ... }
}
Key modules:
frontend::tui- Terminal UIfrontend::tui::input- Input handlingfrontend::tui::render- Rendering
Key Traits
Widget Trait
All widgets implement the core widget trait:
#![allow(unused)]
fn main() {
pub trait Widget {
/// Widget name/identifier
fn name(&self) -> &str;
/// Widget type
fn widget_type(&self) -> WidgetType;
/// Render the widget to a frame region
fn render(&self, frame: &mut Frame, area: Rect);
/// Handle input events
fn handle_input(&mut self, event: KeyEvent) -> Option<WidgetAction>;
/// Update from game state
fn update(&mut self, state: &GameState) -> bool;
}
}
Browser Trait
Popup windows implement:
#![allow(unused)]
fn main() {
pub trait Browser {
/// Browser title
fn title(&self) -> &str;
/// Render browser content
fn render(&self, frame: &mut Frame, area: Rect);
/// Handle input
fn handle_input(&mut self, event: KeyEvent) -> BrowserAction;
/// Initialize with game state
fn init(&mut self, state: &GameState);
}
}
Configuration API
Loading Configuration
#![allow(unused)]
fn main() {
use two_face::config::{Config, Layout, Theme};
// Load from default location
let config = Config::load()?;
// Load from specific path
let config = Config::from_file("path/to/config.toml")?;
// Access settings
let port = config.connection.port;
let render_rate = config.performance.render_rate;
}
Layout Configuration
#![allow(unused)]
fn main() {
use two_face::config::Layout;
let layout = Layout::load("layout.toml")?;
for widget_config in layout.widgets {
println!("Widget: {} at ({}, {})",
widget_config.name,
widget_config.x,
widget_config.y);
}
}
Parser API
Parsing Game Data
#![allow(unused)]
fn main() {
use two_face::parser::Parser;
let mut parser = Parser::new();
// Feed data from game
let elements = parser.parse(raw_data)?;
// Process parsed elements
for element in elements {
match element {
ParsedElement::Text(text) => { /* ... */ }
ParsedElement::Prompt(time) => { /* ... */ }
ParsedElement::Vitals(vitals) => { /* ... */ }
// ... other variants
}
}
}
ParsedElement Variants
#![allow(unused)]
fn main() {
pub enum ParsedElement {
Text(String),
Prompt(u64),
StreamPush(StreamId),
StreamPop,
StreamClear(StreamId),
Vitals(VitalUpdate),
Roundtime(u64),
Casttime(u64),
Compass(Vec<Direction>),
Indicator(String, bool),
Component(String, String),
// ... and more
}
}
Network API
Lich Connection
#![allow(unused)]
fn main() {
use two_face::network::LichConnection;
let conn = LichConnection::new("127.0.0.1", 8000)?;
conn.connect()?;
// Send command
conn.send("look")?;
// Receive data
let data = conn.receive()?;
}
Direct Connection
#![allow(unused)]
fn main() {
use two_face::network::DirectConnection;
let conn = DirectConnection::new(
"account",
"password",
"prime",
"character_name"
)?;
conn.authenticate()?;
conn.connect()?;
}
Event System
Input Events
#![allow(unused)]
fn main() {
use two_face::events::{Event, KeyEvent};
loop {
match event_receiver.recv()? {
Event::Key(key_event) => {
// Handle keyboard input
}
Event::Mouse(mouse_event) => {
// Handle mouse input
}
Event::Resize(w, h) => {
// Handle terminal resize
}
Event::GameData(data) => {
// Handle incoming game data
}
}
}
}
Widget Actions
#![allow(unused)]
fn main() {
pub enum WidgetAction {
None,
SendCommand(String),
OpenBrowser(BrowserType),
CloseBrowser,
FocusWidget(String),
Scroll(ScrollDirection),
Quit,
}
}
Building Extensions
Adding a Widget Type
#![allow(unused)]
fn main() {
use two_face::widgets::{Widget, WidgetType};
pub struct CustomWidget {
name: String,
// Custom fields
}
impl Widget for CustomWidget {
fn name(&self) -> &str {
&self.name
}
fn widget_type(&self) -> WidgetType {
WidgetType::Custom
}
fn render(&self, frame: &mut Frame, area: Rect) {
// Render implementation
}
fn handle_input(&mut self, event: KeyEvent) -> Option<WidgetAction> {
// Input handling
None
}
fn update(&mut self, state: &GameState) -> bool {
// Update from state, return true if changed
false
}
}
}
Adding a Parser Extension
#![allow(unused)]
fn main() {
use two_face::parser::{Parser, ParsedElement};
impl Parser {
pub fn handle_custom_tag(&mut self, tag: &str, attrs: &[Attribute])
-> Option<ParsedElement>
{
if tag == "customtag" {
// Parse custom tag
Some(ParsedElement::Custom(/* ... */))
} else {
None
}
}
}
}
Error Handling
Two-Face uses the anyhow crate for error handling:
#![allow(unused)]
fn main() {
use anyhow::{Result, Context};
fn load_config() -> Result<Config> {
let content = std::fs::read_to_string("config.toml")
.context("Failed to read config file")?;
let config: Config = toml::from_str(&content)
.context("Failed to parse config")?;
Ok(config)
}
}
Testing
Unit Tests
#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parser_basic() {
let mut parser = Parser::new();
let result = parser.parse(b"<prompt>></prompt>").unwrap();
assert!(matches!(result[0], ParsedElement::Prompt(_)));
}
}
}
Integration Tests
#![allow(unused)]
fn main() {
// tests/integration_test.rs
use two_face::*;
#[test]
fn test_full_workflow() {
// Setup
let config = Config::default();
let mut app = App::new(config);
// Simulate game data
app.process_data(test_data());
// Verify state
assert!(app.game_state().vitals().health > 0);
}
}
Version Compatibility
API stability follows semantic versioning:
- 0.x.y: API may change between minor versions
- 1.x.y: Breaking changes only in major versions
See Also
- Project Structure - Code organization
- Adding Widgets - Widget development
- Parser Extensions - Parser development
- Contributing - Contribution guide