diff --git a/src/set.rs b/src/set.rs index adf0ad3..9302e47 100644 --- a/src/set.rs +++ b/src/set.rs @@ -6,7 +6,11 @@ use kakplugin::{ use linked_hash_map::LinkedHashMap; use linked_hash_set::LinkedHashSet; use regex::Regex; -use std::{io::Write, str::FromStr}; +use std::{ + borrow::{Borrow, Cow}, + io::Write, + str::FromStr, +}; #[derive(clap::StructOpt, Debug)] pub struct Options { @@ -71,46 +75,54 @@ pub fn set(options: &Options) -> Result { // Get the selections for the left register and the right register, depending on the arguments // Underscore is a special case. We will treat it as the current selection - let (left_selections, right_selections) = match (&left_register, &right_register) { - (Register::Underscore, r) => { - let l_selections = get_selections(None)?; - let r_selections = get_selections(Some(&format!("\"{r}z")))?; + let (left_selections, right_selections): (Vec>, Vec>) = { + let (l, r): (Vec, Vec) = match (&left_register, &right_register) { + (Register::Underscore, r) => { + let l_selections = get_selections(None)?; + let r_selections = get_selections(Some(&format!("\"{r}z")))?; - (l_selections, r_selections) - } - (l, Register::Underscore) => { - let r_selections = get_selections(None)?; - let l_selections = get_selections(Some(&format!("\"{l}z")))?; + (l_selections, r_selections) + } + (l, Register::Underscore) => { + let r_selections = get_selections(None)?; + let l_selections = get_selections(Some(&format!("\"{l}z")))?; - (l_selections, r_selections) - } - (l, r) => { - let l_selections = get_selections(Some(&format!("\"{l}z")))?; - let r_selections = get_selections(Some(&format!("\"{r}z")))?; + (l_selections, r_selections) + } + (l, r) => { + let l_selections = get_selections(Some(&format!("\"{l}z")))?; + let r_selections = get_selections(Some(&format!("\"{r}z")))?; - (l_selections, r_selections) - } + (l_selections, r_selections) + } + }; + ( + l.into_iter().map(|s| Cow::Owned(s)).collect(), + r.into_iter().map(|s| Cow::Owned(s)).collect(), + ) }; // Get the frequency of each selection. The count does not matter as much as presence // Count is used only for compare let (left_ordered_counts, right_ordered_counts) = ( - to_ordered_counts(options, left_selections), - to_ordered_counts(options, right_selections), + to_ordered_counts(options, &left_selections[..]), + to_ordered_counts(options, &right_selections[..]), ); // Get an ordered set of every key for each register let (left_keys, right_keys) = ( left_ordered_counts .keys() - .collect::>(), + .map(|c| Cow::Borrowed(c.borrow())) + .collect(), right_ordered_counts .keys() - .collect::>(), + .map(|c| Cow::Borrowed(c.borrow())) + .collect(), ); // Run the actual set operation - let result = key_set_operation(&operation, &left_keys, &right_keys); + let result = key_set_operation(&operation, left_keys, right_keys); match &operation { Operation::Compare => compare( @@ -149,9 +161,9 @@ pub fn set(options: &Options) -> Result { } /// Reduces selections to those that are in the `key_set_operation_result` -fn reduce_selections( +fn reduce_selections<'sel>( options: &Options, - key_set_operation_result: &LinkedHashSet<&Selection>, + key_set_operation_result: &LinkedHashSet>, ) -> Result<(), KakError> { // The registers should have been read in a draft context // So the current selection will be unmodified @@ -162,7 +174,7 @@ fn reduce_selections( // Since key_set_operation_result contains elements that should be in the resulting set, // we can just use contains here let key = crate::utils::get_key( - &swd.content, + Cow::Owned(swd.content), options.skip_whitespace, options.regex.as_ref(), options.ignore_case, @@ -178,7 +190,7 @@ fn reduce_selections( Ok(()) } -fn print_result(key_set_operation_result: &LinkedHashSet<&Selection>) -> Result<(), KakError> { +fn print_result(key_set_operation_result: &LinkedHashSet>) -> Result<(), KakError> { // Manually set selections so we don't have to allocate a string let mut f = kakplugin::open_command_fifo()?; @@ -207,12 +219,12 @@ fn print_result(key_set_operation_result: &LinkedHashSet<&Selection>) -> Result< Ok(()) } -fn compare( +fn compare<'sel>( left_register: Register, right_register: Register, - key_set_operation_result: &LinkedHashSet<&Selection>, - left_ordered_counts: &LinkedHashMap, - right_ordered_counts: &LinkedHashMap, + key_set_operation_result: &LinkedHashSet>, + left_ordered_counts: &LinkedHashMap, usize>, + right_ordered_counts: &LinkedHashMap, usize>, ) -> Result<(), KakError> { // Manually set selections so we don't have to allocate a string let mut f = kakplugin::open_command_fifo()?; @@ -232,8 +244,8 @@ fn compare( )?; for k in key_set_operation_result { - let left_count = left_ordered_counts.get(k as &str).unwrap_or(&0); - let right_count = right_ordered_counts.get(k as &str).unwrap_or(&0); + let left_count = left_ordered_counts.get(k).unwrap_or(&0); + let right_count = right_ordered_counts.get(k).unwrap_or(&0); write!( f, @@ -263,12 +275,15 @@ fn compare( Ok(()) } -fn to_ordered_counts(options: &Options, sels: Vec) -> LinkedHashMap { +fn to_ordered_counts<'sel>( + options: &Options, + sels: &'sel [Cow<'sel, str>], +) -> LinkedHashMap, usize> { let mut ret = LinkedHashMap::new(); for i in sels { let key = crate::utils::get_key( - &i, + Cow::Borrowed(&*i), options.skip_whitespace, options.regex.as_ref(), options.ignore_case, @@ -285,29 +300,28 @@ fn to_ordered_counts(options: &Options, sels: Vec) -> LinkedHashMap( - operation: &Operation, - left_keys: &LinkedHashSet<&'a Selection>, - right_keys: &LinkedHashSet<&'a Selection>, -) -> LinkedHashSet<&'a Selection> { +fn key_set_operation<'a, 'sel>( + operation: &'a Operation, + left_keys: LinkedHashSet>, + right_keys: LinkedHashSet>, +) -> LinkedHashSet> { match operation { Operation::Intersect => left_keys - .intersection(right_keys) - // .into_iter() - .copied() + .intersection(&right_keys) + .map(|s| Cow::Borrowed(s.borrow())) .collect(), Operation::Subtract => left_keys - .difference(right_keys) - .into_iter() - .copied() + .difference(&right_keys) + .map(|s| Cow::Borrowed(s.borrow())) .collect(), - Operation::Compare | Operation::Union => { - left_keys.union(right_keys).into_iter().copied().collect() - } // TODO: Symmetric difference? + Operation::Compare | Operation::Union => left_keys + .union(&right_keys) + .map(|s| Cow::Borrowed(s.borrow())) + .collect(), // TODO: Symmetric difference? } }