Fixing some issues discovered from tests...mostly to match GNU behavior

Signed-off-by: Hanif Bin Ariffin <hanif.ariffin.4326@gmail.com>
This commit is contained in:
Hanif Bin Ariffin 2021-07-26 07:59:51 +08:00
parent bf0f01714c
commit 2c8ba4ad2d
2 changed files with 58 additions and 62 deletions

View file

@ -99,17 +99,11 @@ impl Sequence {
} }
} }
pub fn last(&self) -> Option<char> {
match self {
Sequence::CharStar(c) => Some(*c),
rest => rest.flatten().last(),
}
}
// Hide all the nasty sh*t in here // Hide all the nasty sh*t in here
pub fn solve_set_characters( pub fn solve_set_characters(
set1: &Vec<Sequence>, set1: Vec<Sequence>,
set2: &Vec<Sequence>, set2: Vec<Sequence>,
truncate_set1_flag: bool,
) -> Result<(Vec<char>, Vec<char>), String> { ) -> Result<(Vec<char>, Vec<char>), String> {
let is_char_star = |s: &&Sequence| -> bool { let is_char_star = |s: &&Sequence| -> bool {
match s { match s {
@ -139,7 +133,8 @@ impl Sequence {
.flat_map(Sequence::flatten) .flat_map(Sequence::flatten)
.count(); .count();
let star_compensate_len = set1_len.saturating_sub(set2_len); let star_compensate_len = set1_len.saturating_sub(set2_len);
let set2_solved = match (partition.next(), partition.next()) { let (left, right) = (partition.next(), partition.next());
let set2_solved: Vec<char> = match (left, right) {
(None, None) => match char_star { (None, None) => match char_star {
Some(c) => std::iter::repeat(*c).take(star_compensate_len).collect(), Some(c) => std::iter::repeat(*c).take(star_compensate_len).collect(),
None => std::iter::empty().collect(), None => std::iter::empty().collect(),
@ -176,7 +171,10 @@ impl Sequence {
.collect(), .collect(),
}, },
}; };
let set1_solved = set1.iter().flat_map(Sequence::flatten).collect(); let mut set1_solved: Vec<char> = set1.iter().flat_map(Sequence::flatten).collect();
if truncate_set1_flag {
set1_solved.truncate(set2_solved.len());
}
return Ok((set1_solved, set2_solved)); return Ok((set1_solved, set2_solved));
} else { } else {
Err(format!( Err(format!(
@ -407,9 +405,9 @@ pub struct DeleteOperation {
} }
impl DeleteOperation { impl DeleteOperation {
pub fn new(set: Vec<Sequence>, complement_flag: bool) -> DeleteOperation { pub fn new(set: Vec<char>, complement_flag: bool) -> DeleteOperation {
DeleteOperation { DeleteOperation {
set: set.iter().flat_map(Sequence::flatten).collect::<Vec<_>>(), set,
complement_flag, complement_flag,
} }
} }
@ -427,18 +425,16 @@ pub struct TranslateOperationComplement {
set2_iter: usize, set2_iter: usize,
set1: Vec<char>, set1: Vec<char>,
set2: Vec<char>, set2: Vec<char>,
fallback: char,
translation_map: HashMap<char, char>, translation_map: HashMap<char, char>,
} }
impl TranslateOperationComplement { impl TranslateOperationComplement {
fn new(set1: Vec<char>, set2: Vec<char>, fallback: char) -> TranslateOperationComplement { fn new(set1: Vec<char>, set2: Vec<char>) -> TranslateOperationComplement {
TranslateOperationComplement { TranslateOperationComplement {
iter: 0, iter: 0,
set2_iter: 0, set2_iter: 0,
set1, set1,
set2, set2,
fallback,
translation_map: HashMap::new(), translation_map: HashMap::new(),
} }
} }
@ -450,12 +446,22 @@ pub struct TranslateOperationStandard {
} }
impl TranslateOperationStandard { impl TranslateOperationStandard {
fn new(set1: Vec<char>, set2: Vec<char>, fallback: char) -> TranslateOperationStandard { fn new(set1: Vec<char>, set2: Vec<char>) -> Result<TranslateOperationStandard, String> {
TranslateOperationStandard { if let Some(fallback) = set2.last().map(|s| *s) {
translation_map: set1 Ok(TranslateOperationStandard {
.into_iter() translation_map: set1
.zip(set2.into_iter().chain(std::iter::repeat(fallback))) .into_iter()
.collect::<HashMap<_, _>>(), .zip(set2.into_iter().chain(std::iter::repeat(fallback)))
.collect::<HashMap<_, _>>(),
})
} else {
if set1.is_empty() && set2.is_empty() {
Ok(TranslateOperationStandard {
translation_map: HashMap::new(),
})
} else {
Err("when not truncating set1, string2 must be non-empty".to_string())
}
} }
} }
} }
@ -478,29 +484,17 @@ impl TranslateOperation {
impl TranslateOperation { impl TranslateOperation {
pub fn new( pub fn new(
set1: Vec<Sequence>, set1: Vec<char>,
set2: Vec<Sequence>, set2: Vec<char>,
truncate_set1_flag: bool,
complement: bool, complement: bool,
) -> Result<TranslateOperation, String> { ) -> Result<TranslateOperation, String> {
let (mut set1_solved, set2_solved) = Sequence::solve_set_characters(&set1, &set2)?;
if truncate_set1_flag {
set1_solved.truncate(set2_solved.len());
}
let fallback = set2.last().map(Sequence::last).flatten().expect(
format!(
"{}: when not truncating set1, string2 must be non-empty",
executable!()
)
.as_str(),
);
if complement { if complement {
Ok(TranslateOperation::Complement( Ok(TranslateOperation::Complement(
TranslateOperationComplement::new(set1_solved, set2_solved, fallback), TranslateOperationComplement::new(set1, set2),
)) ))
} else { } else {
Ok(TranslateOperation::Standard( Ok(TranslateOperation::Standard(
TranslateOperationStandard::new(set1_solved, set2_solved, fallback), TranslateOperationStandard::new(set1, set2)?,
)) ))
} }
} }
@ -520,7 +514,6 @@ impl SymbolTranslator for TranslateOperation {
set2_iter, set2_iter,
set1, set1,
set2, set2,
fallback,
translation_map, translation_map,
}) => { }) => {
// First, try to see if current char is already mapped // First, try to see if current char is already mapped
@ -539,7 +532,7 @@ impl SymbolTranslator for TranslateOperation {
*set2_iter = set2_iter.saturating_add(1); *set2_iter = set2_iter.saturating_add(1);
translation_map.insert(next_key, *value); translation_map.insert(next_key, *value);
} else { } else {
translation_map.insert(current, *fallback); translation_map.insert(current, *set2.last().unwrap());
} }
} }
Some(*translation_map.get(&current).unwrap()) Some(*translation_map.get(&current).unwrap())
@ -557,9 +550,9 @@ pub struct SqueezeOperation {
} }
impl SqueezeOperation { impl SqueezeOperation {
pub fn new(set1: Vec<Sequence>, complement: bool) -> SqueezeOperation { pub fn new(set1: Vec<char>, complement: bool) -> SqueezeOperation {
SqueezeOperation { SqueezeOperation {
set1: set1.iter().flat_map(Sequence::flatten).collect(), set1,
complement, complement,
previous: None, previous: None,
} }

View file

@ -66,6 +66,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.values_of(options::SETS) .values_of(options::SETS)
.map(|v| v.map(ToString::to_string).collect::<Vec<_>>()) .map(|v| v.map(ToString::to_string).collect::<Vec<_>>())
.unwrap_or_default(); .unwrap_or_default();
let sets_len = sets.len();
if sets.is_empty() { if sets.is_empty() {
show_error!( show_error!(
@ -75,7 +76,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
return 1; return 1;
} }
if !(delete_flag || squeeze_flag) && sets.len() < 2 { if !(delete_flag || squeeze_flag) && sets_len < 2 {
show_error!( show_error!(
"missing operand after '{}'\nTry '{} --help' for more information.", "missing operand after '{}'\nTry '{} --help' for more information.",
sets[0], sets[0],
@ -84,7 +85,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
return 1; return 1;
} }
if sets.len() > 2 { if sets_len > 2 {
show_error!( show_error!(
"extra operand '{}'\nTry '{} --help' for more information.", "extra operand '{}'\nTry '{} --help' for more information.",
sets[0], sets[0],
@ -99,37 +100,44 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let locked_stdout = stdout.lock(); let locked_stdout = stdout.lock();
let mut buffered_stdout = BufWriter::new(locked_stdout); let mut buffered_stdout = BufWriter::new(locked_stdout);
let mut sets_iter = sets.into_iter();
let (set1, set2) = match Sequence::solve_set_characters(
Sequence::from_str(sets_iter.next().unwrap_or_default().as_str()),
Sequence::from_str(sets_iter.next().unwrap_or_default().as_str()),
truncate_set1_flag,
) {
Ok(r) => r,
Err(s) => {
show_error!("{}", s);
return 1;
}
};
if delete_flag { if delete_flag {
if squeeze_flag { if squeeze_flag {
let mut delete_buffer = vec![]; let mut delete_buffer = vec![];
{ {
let mut delete_writer = BufWriter::new(&mut delete_buffer); let mut delete_writer = BufWriter::new(&mut delete_buffer);
let delete_op = DeleteOperation::new(Sequence::from_str(&sets[0]), complement_flag); let delete_op = DeleteOperation::new(set1.clone(), complement_flag);
translate_input(&mut locked_stdin, &mut delete_writer, delete_op); translate_input(&mut locked_stdin, &mut delete_writer, delete_op);
} }
{ {
let mut squeeze_reader = BufReader::new(delete_buffer.as_bytes()); let mut squeeze_reader = BufReader::new(delete_buffer.as_bytes());
let op = SqueezeOperation::new(Sequence::from_str(&sets[1]), complement_flag); let op = SqueezeOperation::new(set2, complement_flag);
translate_input(&mut squeeze_reader, &mut buffered_stdout, op); translate_input(&mut squeeze_reader, &mut buffered_stdout, op);
} }
} else { } else {
let op = DeleteOperation::new(Sequence::from_str(&sets[0]), complement_flag); let op = DeleteOperation::new(set1, complement_flag);
translate_input(&mut locked_stdin, &mut buffered_stdout, op); translate_input(&mut locked_stdin, &mut buffered_stdout, op);
} }
} else if squeeze_flag { } else if squeeze_flag {
if sets.len() < 2 { if sets_len < 2 {
let op = SqueezeOperation::new(Sequence::from_str(&sets[0]), complement_flag); let op = SqueezeOperation::new(set1, complement_flag);
translate_input(&mut locked_stdin, &mut buffered_stdout, op); translate_input(&mut locked_stdin, &mut buffered_stdout, op);
} else { } else {
let mut translate_buffer = vec![]; let mut translate_buffer = vec![];
{ {
let mut writer = BufWriter::new(&mut translate_buffer); let mut writer = BufWriter::new(&mut translate_buffer);
match TranslateOperation::new( match TranslateOperation::new(set1.clone(), set2.clone(), complement_flag) {
Sequence::from_str(&sets[0]),
Sequence::from_str(&sets[1]),
truncate_set1_flag,
complement_flag,
) {
Ok(op) => translate_input(&mut locked_stdin, &mut writer, op), Ok(op) => translate_input(&mut locked_stdin, &mut writer, op),
Err(s) => { Err(s) => {
show_error!("{}", s); show_error!("{}", s);
@ -139,17 +147,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} }
{ {
let mut reader = BufReader::new(translate_buffer.as_bytes()); let mut reader = BufReader::new(translate_buffer.as_bytes());
let squeeze_op = SqueezeOperation::new(Sequence::from_str(&sets[1]), false); let squeeze_op = SqueezeOperation::new(set2, false);
translate_input(&mut reader, &mut buffered_stdout, squeeze_op); translate_input(&mut reader, &mut buffered_stdout, squeeze_op);
} }
} }
} else { } else {
match TranslateOperation::new( match TranslateOperation::new(set1, set2, complement_flag) {
Sequence::from_str(&sets[0]),
Sequence::from_str(&sets[1]),
truncate_set1_flag,
complement_flag,
) {
Ok(op) => translate_input(&mut locked_stdin, &mut buffered_stdout, op), Ok(op) => translate_input(&mut locked_stdin, &mut buffered_stdout, op),
Err(s) => { Err(s) => {
show_error!("{}", s); show_error!("{}", s);