You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
genmarkov/src/main.rs

133 lines
3.3 KiB

//#[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<PathBuf>,
/// Load the chain from the provided output file name before appending to it.
#[arg(short, long)]
load: Option<PathBuf>,
/// 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<NonZeroUsize>,
//TODO: Num of lines, etc.
}
fn buffered_read_all_lines<T: BufRead+?Sized, F: FnMut(&str) -> io::Result<()>>(input: &mut T, mut then: F) -> io::Result<usize>
{
let mut buffer = String::new();
let mut read;
let mut total=0;
while {read = input.read_line(&mut buffer)?; read!=0} {
if buffer.trim().len() > 0 {
then(&buffer[..])?;
}
buffer.clear();
total += read;
}
Ok(total)
}
#[inline]
fn parse_cli() -> Cli {
use clap::Parser;
Cli::parse()
}
fn load_chain<S>(stream: &mut S) -> io::Result<Chain<String>>
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<S>(stream: &mut S, chain: &Chain<String>) -> 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<String>
{
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<String>) -> 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 = create_chain(&cli);
buffered_read_all_lines(&mut stdin, |string| {
chain.feed(&string.split_whitespace()
.filter(|word| !word.is_empty())
.map(|s| s.to_owned()).collect::<Vec<_>>());
Ok(())
}).expect("Failed to read from stdin");
if !chain.is_empty() {
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();
}