From c4fc2fde1d1f82196709c492e2e4e81155218002 Mon Sep 17 00:00:00 2001 From: Avril Date: Tue, 11 Feb 2025 23:36:35 +0000 Subject: [PATCH] Cli: Added basic chain save+load & dynamic num of output lines (1..) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Version bump to 2.0 Fortune for genmarkov's current commit: Curse − 凶 --- Cargo.lock | 255 ++++++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 12 ++- src/main.rs | 91 ++++++++++++++++++- 3 files changed, 334 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3d3df23..68cc4d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,57 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys", +] + [[package]] name = "autocfg" version = "1.0.1" @@ -12,6 +64,52 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "clap" +version = "4.5.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "dtoa" version = "0.4.6" @@ -50,12 +148,24 @@ dependencies = [ "wasi", ] +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + [[package]] name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "indexmap" version = "1.6.0" @@ -66,6 +176,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.9.0" @@ -89,9 +205,12 @@ checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" [[package]] name = "markov" -version = "0.1.1" +version = "0.2.0" dependencies = [ + "clap", "markov 1.1.0", + "serde", + "serde_cbor", ] [[package]] @@ -109,6 +228,12 @@ dependencies = [ "serde_yaml", ] +[[package]] +name = "once_cell" +version = "1.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + [[package]] name = "petgraph" version = "0.5.1" @@ -127,18 +252,18 @@ checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -186,15 +311,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.116" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -213,17 +351,29 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" -version = "1.0.42" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + [[package]] name = "unicode-width" version = "0.1.8" @@ -231,10 +381,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] -name = "unicode-xid" -version = "0.2.1" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasi" @@ -242,6 +392,79 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "yaml-rust" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 060089c..9406f0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "markov" -version = "0.1.2" -description = "Generate string of text from Markov chain fed by stdin" +version = "0.2.0" +description = "Generate string of text from Markov chain fed by stdin or file(s)" authors = ["Avril "] edition = "2018" @@ -9,8 +9,12 @@ edition = "2018" [profile.release] opt-level = 3 -lto = "fat" +lto = true +#"fat" codegen-units = 1 [dependencies] -chain = {package = "markov", version = "1.1.0"} +chain = {package = "markov", version = "1.1.0" } +clap = { version = "4.5.29", features = ["derive"] } +serde = { version = "1.0.217", features = ["derive"] } +serde_cbor = { version = "0.11.2", features = ["alloc"] } diff --git a/src/main.rs b/src/main.rs index 2d773a5..208a57a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,41 @@ +//#[macro_use] extern crate serde; + +use clap::{ + Parser, Subcommand, ValueEnum, +}; use chain::{ Chain, }; use std::{ + num::NonZeroUsize, + path::{ + PathBuf, Path, + }, io::{ BufRead, self, }, }; +#[derive(Debug, Parser)] +#[command(name = env!("CARGO_PKG_NAME"), version, about = env!("CARGO_PKG_DESCRIPTION"), long_about = None)] +pub struct Cli { + /// Save the chain to the provided output file name after appending to it. + #[arg(short, long)] + save: Option, + /// Load the chain from the provided output file name before appending to it. + #[arg(short, long)] + load: Option, + /// Force over-writes of files, and force output of binary data to TTY. + #[arg(short, long)] + force: bool, + + /// The number of lines to output from the chain. + lines: Option, + + //TODO: Num of lines, etc. +} + fn buffered_read_all_lines io::Result<()>>(input: &mut T, mut then: F) -> io::Result { let mut buffer = String::new(); @@ -23,10 +51,63 @@ fn buffered_read_all_lines io::Result<()>>( Ok(total) } +#[inline] +fn parse_cli() -> Cli { + use clap::Parser; + Cli::parse() +} + +fn load_chain(stream: &mut S) -> io::Result> +where S: io::Read + ?Sized +{ + let mut stream = io::BufReader::new(stream); + Ok(serde_cbor::from_reader(&mut stream).expect("Failed to read chain from input stream")) // TODO: Error type +} + +fn save_chain(stream: &mut S, chain: &Chain) -> io::Result<()> +where S: io::Write + ?Sized +{ + use io::Write; + + let mut stream = io::BufWriter::new(stream); + serde_cbor::to_writer(&mut stream, chain).expect("Failed to write chain to output stream"); // TODO: Error type + stream.flush() +} + +fn create_chain(cli: &Cli) -> Chain +{ + if let Some(load) = &cli.load { + let mut input = std::fs::OpenOptions::new() + .read(true) + .open(&load).expect("Failed to open chain load file"); + load_chain(&mut input).expect("Failed to load chain from file") + } else { + Chain::new() + } +} + +fn complete_chain(cli: &Cli, chain: Chain) -> io::Result<()> +{ + if let Some(save) = &cli.save { + let mut output = std::fs::OpenOptions::new() + .create_new(! cli.force) + + .create(cli.force) + .write(true) + .truncate(cli.force) + .open(&save).expect("Failed to open chain save file"); + save_chain(&mut output, &chain).expect("Failed to save chain to file") // TODO: Error type + } + + Ok(()) +} + fn main() { + let cli = parse_cli(); + let stdin = io::stdin(); let mut stdin = stdin.lock(); - let mut chain = Chain::new(); + let mut chain = create_chain(&cli); buffered_read_all_lines(&mut stdin, |string| { chain.feed(&string.split_whitespace() @@ -37,13 +118,15 @@ fn main() { }).expect("Failed to read from stdin"); if !chain.is_empty() { - if let Some(num) = std::env::args().skip(1).next() { - let sz: usize = num.parse().expect("Cannot parse number of tokens to generate"); - for string in chain.str_iter_for(sz) { + let lines = cli.lines.map(NonZeroUsize::get).unwrap_or(1); + if lines > 1 { + for string in chain.str_iter_for(lines) { println!("{}", string); } } else { println!("{}", chain.generate_str()); } } + + complete_chain(&cli, chain).unwrap(); }