Idiomatic Rust code for zipped mutable vector iterator

3.8k views Asked by At

I am doing the Matasano crypto challenge while trying to use Rust (in an idomatic way).

The second assignment is to xor two vectors. The code I have now is:

extern crate rustc_serialize;

use rustc_serialize::hex::{FromHex,ToHex};

pub fn fixed_xor(l: &str, r: &str) -> String {
    let mut l = l.from_hex().unwrap();
    let r = r.from_hex().unwrap();
    for i in 0..l.len() {
        l[i] ^= r[i];
    }
    return l.to_hex();
}

This works, but it doesn't feel idiomatic code because of the range in the for-loop.

Is it possible to zip l and r and get a mutable reference to the element from l and a non-mutable reference to the element from r?

(Note, I don't check the length of the vectors. I know this would blow up in real life, but I would like to focus now on the for loop)

2

There are 2 answers

2
bluss On

You would use the .zip() iterator adaptor, for example like this:

pub fn xor_in_place(l: &mut [u8], r: &[u8]) {
    for (x, y) in l.iter_mut().zip(r) {
        *x ^= *y;
    }
}

You could consider generalizing this XOR operation by either

  1. Accepting all element types that implement BitXor.
  2. Accepting generic IntoIterator arguments instead of just slices.

Note that zip will stop whenever the shorter of the two iterators does.

2
Phoebe Queen On

This was my solution. I believe it covers all the required cases for Matasano's xor (presuming for single character xor you use a single-byte key vector) and it seems relatively tidy and in keeping with the Rust tutorial.

pub fn xor(text: &Vec<u8>, key: &Vec<u8>) -> Vec<u8> {
    let key_iter = key.iter().cycle();
    text.iter().zip(key_iter).map(|&a, b)| a ^ b ).collect()
}