jdeastwood
jdeastwood

Reputation: 185

Type mismatch between type parameter and std::ops::BitXor Output associated type

I'm in the process of learning Rust. I find "over-engineering"toy examples to be a useful thing to do in the early stages, which has led me to this situation.

Starting with this simple function:

extern crate data_encoding;

use std::ops::BitXor;
use data_encoding::hex;
use std::iter::FromIterator;


fn fixed_xor_basic(l: &[u8], r: &[u8]) -> Vec<u8> {
    l.iter().zip(r.iter()).map(|(x, y)| *x ^ *y).collect()
}

#[test]
fn test_fixed_xor_basic() {
    let input_1 = hex::decode(b"1C0111001F010100061A024B53535009181C").unwrap();
    let input_2 = hex::decode(b"686974207468652062756C6C277320657965").unwrap();

    let expected_output = hex::decode(b"746865206B696420646F6E277420706C6179").unwrap();

    assert_eq!(fixed_xor_basic(&input_1, &input_2), expected_output);
}

I moved onto a simple variant getting rid of the allocation:

fn fixed_xor_basic_inplace(l: &mut [u8], r: &[u8]) {
    for (left, right) in l.iter_mut().zip(r.iter()) {
        *left = *left ^ *right;
    }
}

And another which accepts any type which can be XORed:

fn fixed_xor_generic<T>(l: &[T], r: &[T]) -> Vec<T>
    where T: BitXor + Copy,
          Vec<T>: FromIterator<<T as BitXor>::Output> {
    l.iter().zip(r.iter()).map(|(x, y)| *x ^ *y).collect()
}

This second variant initially didn't compile -- but the error message hinted me towards adding the constraint Vec<T>: FromIterator<<T as BitXor>::Output>. Presumably this constraint has given the compiler some hint that BitXor::Output is in fact the same thing as T, but I'm not clear on what exactly that hint is.

Now... combining the two has me stumped:

fn fixed_xor_generic_inplace<T>(l: &mut [T], r: &[T])
    where T: BitXor + Copy {
    for (left, right) in l.iter_mut().zip(r.iter()) {
        *left = *left ^ *right;
    }
}

Produces an error:

error[E0308]: mismatched types
  --> src/xor_lib.rs:27:17
   |
27 |         *left = *left ^ *right;
   |                 ^^^^^^^^^^^^^^ expected type parameter, found associated type
   |
   = note: expected type `T`
   = note:    found type `<T as std::ops::BitXor>::Output`

error: aborting due to previous error

I strongly suspect that the two situations are similar and that I need to provide some extra bit of context to help the compiler figure out the T is in fact <T as std::ops::BitXor>::Output by another name.

Am I on the right track? If so, what would this hint be?

(also the next challenge is making the function accept IntoIterator types rather than slices -- if that might affect the solution at all).

Upvotes: 3

Views: 134

Answers (1)

Peter Hall
Peter Hall

Reputation: 58815

You just need to tell the compiler that the associated type Output is the same as T.

fn fixed_xor_generic_inplace<T>(l: &mut [T], r: &[T])
    where T: BitXor<Output = T> + Copy {
    for (left, right) in l.iter_mut().zip(r.iter()) {
        *left = *left ^ *right;
    }
}

Upvotes: 2

Related Questions