diff --git a/Cargo.lock b/Cargo.lock index e4583c6..6a2a190 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -26,6 +37,15 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "indoc" version = "2.0.4" @@ -54,6 +74,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "lyagushka" +version = "1.1.0" +dependencies = [ + "atty", + "pyo3", + "serde", + "serde_json", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -101,15 +131,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "pyagushka" -version = "1.1.0" -dependencies = [ - "pyo3", - "serde", - "serde_json", -] - [[package]] name = "pyo3" version = "0.20.2" @@ -267,6 +288,28 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-targets" version = "0.48.5" diff --git a/Cargo.toml b/Cargo.toml index 0827562..d6aedab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,11 @@ [package] -name = "pyagushka" +name = "lyagushka" version = "1.1.0" edition = "2021" - -[lib] -name = "pyagushka" crate-type = ["cdylib"] [dependencies] -pyo3 = "0.20.2" +atty = "0.2.14" +pyo3 = { version = "0.20.2", features = ["extension-module"] } serde = { version = "1.0.196", features = ["derive"] } -serde_json = "1.0.113" - -[features] -extension-module = ["pyo3/extension-module"] -default = ["extension-module"] \ No newline at end of file +serde_json = "1.0.113" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 7a799c9..dd09518 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ impl Anomaly { } #[pyclass] -struct Lyagushka { +pub struct Lyagushka { dataset: Vec, anomalies: Vec, } @@ -154,7 +154,7 @@ impl Lyagushka { } #[pymodule] -fn pyagushka(_py: Python, m: &PyModule) -> PyResult<()> { +fn lyagushka(_py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; Ok(()) } diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..0dfe6d2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,70 @@ +use std::fs::File; +use std::io::{self, BufRead, BufReader, stdin}; +use std::env; +use std::process; +use lyagushka::Lyagushka; + +/// The entry point for the command-line tool that reads a dataset of integers from either a file or stdin, +/// performs cluster and gap analysis using specified parameters, and prints the results as a JSON string. +/// +/// This tool expects either a filename as an argument or a list of integers piped into stdin. It also requires +/// two additional command-line arguments: a factor for adjusting clustering and gap detection thresholds, +/// and a minimum cluster size. The tool reads the dataset, performs the analysis by identifying clusters +/// and significant gaps, calculates z-scores for each, and prints the JSON-serialized results to stdout. +/// +/// # Usage +/// To read from a file: +/// ``` +/// cargo run -- filename.txt 0.5 2 +/// ``` +/// +/// To read from stdin: +/// ``` +/// echo "1\n2\n10\n20" | cargo run -- 0.5 2 +/// ``` +/// +/// # Arguments +/// - A filename (if not receiving piped input) to read the dataset from. +/// - `factor`: A floating-point value used to adjust the sensitivity of cluster and gap detection. +/// - `min_cluster_size`: The minimum number of contiguous points required to be considered a cluster. +/// +/// # Exit Codes +/// - `0`: Success. +/// - `1`: Incorrect usage or failure to parse the input data. +/// +/// # Errors +/// This tool will exit with an error if the required arguments are not provided, if the specified file cannot be opened, +/// or if the input data cannot be parsed into integers. +/// +/// # Note +/// This function does not return a value but directly exits the process in case of failure. +/// +fn main() -> io::Result<()> { + let args: Vec = env::args().collect(); + + // Input handling + let dataset: Vec = if atty::is(atty::Stream::Stdin) { + if args.len() != 4 { + eprintln!("Usage: {} ", args[0]); + process::exit(1); + } + let filename = &args[1]; + let file = File::open(filename)?; + BufReader::new(file).lines().filter_map(Result::ok) + .filter_map(|line| line.trim().parse::().ok()) // Directly parse to i32 + .collect() + } else { + stdin().lock().lines().filter_map(Result::ok) + .filter_map(|line| line.trim().parse::().ok()) // Directly parse to i32 + .collect() + }; + + let factor: f32 = args[args.len() - 2].parse().expect("Factor must be a float"); + let min_cluster_size: usize = args[args.len() - 1].parse().expect("Min cluster size must be an integer"); + + // Analysis and output + let mut zhaba = Lyagushka::new(dataset); + println!("{}", zhaba.search(factor, min_cluster_size)); + + Ok(()) +} \ No newline at end of file