Building on top. Another useful function to map the &mut could look like this:
/// finds multiple items in a collection and maps the elements to &muts.
///
/// ```
/// # use contracts_common::map::find_map_many;
/// # fn test_find_many() {
/// let mut v = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
/// let [left, right] =
/// find_map_many(&mut v, [&2, &3], |item, key| &item.0 == key, |item| &mut item.1).unwrap();
/// assert_eq!(*left, 3);
/// assert_eq!(*right, 4);
/// # }
/// ```
pub fn find_map_many<'a, I, T, U, F, M, K, const LEN: usize>(
collection: I, keys: [&K; LEN], mut find: F, mut map: M,
) -> Option<[&'a mut U; LEN]>
where
I: IntoIterator<Item = &'a mut T>,
T: Debug + 'a,
U: Debug,
F: FnMut(&T, &K) -> bool,
M: FnMut(&'a mut T) -> &'a mut U,
{
let mut remaining = LEN;
// When inline_const is stabilized this unsafe block can be removed
let mut output: [Option<&'a mut U>; LEN] = unsafe { std::mem::zeroed() };
'collection: for elem in collection {
for (key, out) in std::iter::zip(&keys, &mut output) {
if out.is_none() && find(elem, key) {
*out = Some(map(elem));
remaining -= 1;
if remaining == 0 {
break 'collection;
}
break;
}
}
}
// When array_try_map is stabilized this can be made better.
let vec = output.into_iter().collect::<Option<Vec<&mut U>>>();
vec.map(|x| x.try_into().unwrap())
}