textfsm-rust 0.3.1

Template-based state machine for parsing semi-formatted text based on Google's TextFSM
Documentation
//! Example demonstrating that Template is Send + Sync.
//!
//! This example verifies that:
//! - Template can be shared across threads via Arc
//! - Parser can be created per-thread without copying regexes
//!
//! Run with: cargo run --example thread_safety

use std::sync::Arc;
use std::thread;
use textfsm_rust::Template;

fn main() {
    // Compile-time verification that Template is Send + Sync
    fn assert_send<T: Send>() {}
    fn assert_sync<T: Sync>() {}
    assert_send::<Template>();
    assert_sync::<Template>();
    println!("✓ Template is Send + Sync");

    // Create a template
    let template_str = r#"
Value Interface (\S+)
Value Status (up|down)
Value Speed (\d+)

Start
  ^Interface: ${Interface} is ${Status} at ${Speed}Mbps -> Record
"#;

    let template = Template::parse_str(template_str).expect("failed to parse template");
    let template = Arc::new(template);
    println!("✓ Template compiled and wrapped in Arc");

    // Sample inputs to parse in parallel
    let inputs = vec![
        "Interface: eth0 is up at 1000Mbps\nInterface: eth1 is down at 100Mbps\n",
        "Interface: ge-0/0/0 is up at 10000Mbps\n",
        "Interface: FastEthernet0/1 is down at 100Mbps\nInterface: FastEthernet0/2 is up at 100Mbps\n",
        "Interface: bond0 is up at 2000Mbps\n",
    ];

    // Spawn threads, each with its own Parser
    let handles: Vec<_> = inputs
        .into_iter()
        .enumerate()
        .map(|(i, input)| {
            let template = Arc::clone(&template);
            let input = input.to_string();

            thread::spawn(move || {
                // Each thread creates its own Parser (cheap - just borrows Template)
                let mut parser = template.parser();
                let results = parser.parse_text(&input).expect("failed to parse");

                println!("  Thread {}: parsed {} records", i, results.len());
                results.len()
            })
        })
        .collect();

    // Collect results
    let total_records: usize = handles
        .into_iter()
        .map(|h| h.join().expect("thread panicked"))
        .sum();

    println!("{} threads completed, {} total records parsed", 4, total_records);
    println!("\nTemplate was shared across all threads without cloning regexes.");
}