opensymphony 2.11.3

A Rust implementation of the OpenAI Symphony orchestration design
Documentation
use std::{
    env,
    ffi::OsString,
    fs,
    path::{Path, PathBuf},
    time::Instant,
};

use opensymphony::opensymphony_code_intel::{ParsedDocumentSummary, parse_path, parse_rust_source};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args = env::args_os().skip(1).collect::<Vec<_>>();
    if let Some(repeat) = repeat_count(&args)? {
        return parse_fixture_repeatedly(repeat);
    }

    let paths = args.into_iter().map(PathBuf::from).collect::<Vec<_>>();
    if !paths.is_empty() {
        let summaries = paths
            .iter()
            .map(|path| parse_file(path))
            .collect::<Result<Vec<_>, _>>()?;
        println!("{}", serde_json::to_string_pretty(&summaries)?);
        return Ok(());
    }

    let source = include_str!("../crates/opensymphony-code-intel/fixtures/rust/complete.rs");
    let path = PathBuf::from("crates/opensymphony-code-intel/fixtures/rust/complete.rs");
    let summary = parse_rust_source(Some(path), source)?;

    println!("{}", serde_json::to_string_pretty(&summary)?);
    Ok(())
}

fn parse_fixture_repeatedly(repeat: usize) -> Result<(), Box<dyn std::error::Error>> {
    let source = include_str!("../crates/opensymphony-code-intel/fixtures/rust/complete.rs");
    let path = PathBuf::from("crates/opensymphony-code-intel/fixtures/rust/complete.rs");

    if repeat == 1 {
        let summary = parse_rust_source(Some(path), source)?;
        println!("{}", serde_json::to_string_pretty(&summary)?);
        return Ok(());
    }

    let started = Instant::now();
    let mut symbols = 0;
    let mut captures = 0;
    for _ in 0..repeat {
        let summary = parse_rust_source(Some(path.clone()), source)?;
        symbols = summary.symbols.len();
        captures = summary.captures.len();
    }
    let elapsed = started.elapsed();
    let parses_per_second = repeat as f64 / elapsed.as_secs_f64();
    println!(
        "parsed {repeat} iteration(s) in {:.3}s ({parses_per_second:.2} parses/s); last symbols={symbols}; last captures={captures}",
        elapsed.as_secs_f64()
    );
    Ok(())
}

fn parse_file(path: &Path) -> Result<ParsedDocumentSummary, Box<dyn std::error::Error>> {
    let source = fs::read_to_string(path)?;
    Ok(parse_path(path, &source)?)
}

fn repeat_count(args: &[OsString]) -> Result<Option<usize>, Box<dyn std::error::Error>> {
    let Some(first) = args.first() else {
        return Ok(None);
    };
    let Some(first) = first.to_str() else {
        return Ok(None);
    };

    if first == "--repeat" {
        if args.len() != 2 {
            return Err("--repeat requires exactly one count".into());
        }
        let value = args[1]
            .to_str()
            .ok_or("--repeat count must be valid utf-8")?;
        return Ok(Some(parse_repeat_value(value)?));
    }

    if let Some(value) = first.strip_prefix("--repeat=") {
        if args.len() != 1 {
            return Err("--repeat=<count> cannot be combined with paths".into());
        }
        return Ok(Some(parse_repeat_value(value)?));
    }

    Ok(None)
}

fn parse_repeat_value(value: &str) -> Result<usize, Box<dyn std::error::Error>> {
    let repeat = value.parse::<usize>()?;
    if repeat == 0 {
        return Err("--repeat must be greater than zero".into());
    }
    Ok(repeat)
}