Description
A coworker pointed me to the Xorcism exercise, and pointed out some difficulty with it. We both ultimately worked through it, and the exercise overall was a great stress test of the interaction of lifetimes and impl Trait
. However, IMO, in its current incarnation it deserves to be bumped from Medium to Hard. And even so, I would recommend providing some additional guidance in the instructions, and perhaps some simplifications.
Some parts of the exercise, in particular the ExactSizeIterator
, seem to be unnecessary. My solution ultimately did not leverage that trait, and it's unclear why it would be needed from the test suite.
use std::borrow::Borrow;
#[derive(Clone)]
pub struct Xorcism<'a> {
key: &'a [u8],
index: usize,
}
fn next_key(key: &[u8], index: &mut usize) -> u8 {
let b = key[*index];
*index += 1;
if *index >= key.len() {
*index = 0;
}
b
}
impl<'a> Xorcism<'a> {
pub fn new<Key: AsRef<[u8]> + ?Sized>(key: &'a Key) -> Xorcism<'a> {
Xorcism {
key: key.as_ref(),
index: 0,
}
}
pub fn munge_in_place(&mut self, data: &mut [u8]) {
for b in data {
*b ^= next_key(self.key, &mut self.index);
}
}
pub fn munge<'b, Data>(&'b mut self, data: Data) -> impl Iterator<Item=u8> + 'b
where
Data: IntoIterator,
Data::Item: Borrow<u8>,
Data::IntoIter: 'b,
{
let key = &self.key;
let index = &mut self.index;
data.into_iter().map(move |b| *b.borrow() ^ next_key(key, index))
}
}
I would also recommend introducing a few simple test cases of munge_in_place
before munge
, so that someone implementing it can get a feel for how munging is supposed to work before diving into the more complicated issues with streaming and lifetimes.
Finally, I would recommend making the impl Trait
approach a bonus point, and instead recommend starting with a concrete struct
. I looked at a number of the existing solutions on Exercism, and it seems like that is the most intuitive place to start. It also avoids the major complexity around lifetimes and impl Trait
.
I'd be happy to open a PR to make some of these modifications, but wanted to start with a discussion issue first.
Note that I've also opened rust-lang/rust#80518 for some surprising compiler behavior around this exercise.