1use clap::Parser;
2use rustutils_runnable::Runnable;
3use std::error::Error;
4
5#[derive(Parser, Clone, Debug)]
7#[clap(author, version, about, long_about = None)]
8pub struct Factor {
9 #[clap(short, long)]
11 unique: bool,
12 #[clap(short, long)]
14 json: bool,
15 number: Vec<u64>,
19}
20
21#[derive(thiserror::Error, Debug)]
22pub enum StdinError {
23 #[error("Error reading a line from standard input: {0:}")]
24 ReadingLine(#[from] std::io::Error),
25 #[error("Error parsing {0:?} as a number: {1:}")]
26 ParsingNumber(String, std::num::ParseIntError),
27}
28
29impl Factor {
30 pub fn run(&self) -> Result<(), Box<dyn Error>> {
31 if self.json {
32 let mut output = std::collections::BTreeMap::new();
35 self.handle(|num, factors| {
36 output.insert(num.to_string(), factors.to_vec());
37 })?;
38 println!("{}", serde_json::to_string(&output)?);
39 } else {
40 self.handle(|num, factors| {
41 let factors: String = factors.iter().map(|factor| format!(" {factor}")).collect();
42 println!("{num}:{}", factors);
43 })?;
44 }
45 Ok(())
46 }
47
48 pub fn handle(&self, callback: impl FnMut(u64, &[u64])) -> Result<(), Box<dyn Error>> {
51 if self.number.is_empty() {
52 self.handle_stdin(callback)?;
53 } else {
54 self.handle_numbers(callback);
55 }
56 Ok(())
57 }
58
59 pub fn handle_numbers(&self, mut callback: impl FnMut(u64, &[u64])) {
61 for number in &self.number {
62 let factors = self.factor(*number);
63 callback(*number, &factors);
64 }
65 }
66
67 pub fn handle_stdin(&self, mut callback: impl FnMut(u64, &[u64])) -> Result<(), StdinError> {
70 let stdin = std::io::stdin();
71 for line in stdin.lines() {
72 let line = line.map_err(|e| StdinError::ReadingLine(e))?;
73 let number: u64 = line
74 .parse()
75 .map_err(|e| StdinError::ParsingNumber(line, e))?;
76 let factors = self.factor(number);
77 callback(number, &factors);
78 }
79 Ok(())
80 }
81
82 pub fn factor(&self, number: u64) -> Vec<u64> {
85 if self.unique {
86 primes::factors_uniq(number)
87 } else {
88 primes::factors(number)
89 }
90 }
91}
92
93impl Runnable for Factor {
94 fn run(&self) -> Result<(), Box<dyn Error>> {
95 self.run()?;
96 Ok(())
97 }
98}