That is about as good as you are going to get. Most of the other solutions are going to require just as much code as this. For example, you could turn it into an iterator chain to try to improve readability. That being said, the original was already quite readable, so this isn't much of an improvement.
fn copy(source: &[u8], target: &mut [u32]) {
source
.iter()
.copied()
.map(u32::from)
.enumerate()
.for_each(|(index, value)| target[index] = value);
}
Or as @ChayimFriedman mentioned, you could use itertools
's set_from
. Here is what that would look like:
fn copy(source: &[u8], target: &mut [u32]) {
target.iter_mut().set_from(source.iter().map(|x| *x as u32));
}
Alternatively, you could also choose to make the function generic. However, at its core it is the same thing so I'm not sure if you really gain any readability from doing this.
fn copy_into_slice_from<A, B>(src: &[A], dst: &mut [B])
where
A: Copy,
B: From<A>,
{
assert_eq!(src.len(), dst.len());
src.iter()
.copied()
.enumerate()
.for_each(|(index, value)| dst[index] = B::from(value));
}
I suppose another option would be some sort of map_between_slices
function to try to save on the amount of code needed while maintaining readability?
/// Ex: map_between_slices(&src, &mut dst, |x| *x as u32);
fn map_between_slices<A, B, F>(src: &[A], dst: &mut [B], mut func: F)
where
F: for<'a> FnMut(&'a A) -> B,
{
assert_eq!(src.len(), dst.len());
src.iter()
.enumerate()
.for_each(|(index, value)| dst[index] = func(value));
}