Search code examples
validationrustmutability

Prae:Wrapper: need to use iter_mut of interior Vec but Prae:Wrapper only provides immutable access


I'm using the prae crate for validation and the following function gives me errors:

fn advance_rotors(&mut self) {
  self.rotors.get()[0].rotate();

  let mut iterhandle = self.rotors.iter_mut().peekable(); // Error at iter_mut() #0599

  while let Some(el) = iterhandle.next() {
    match iterhandle.peek_mut() {
      Some(next_rotor) => match el.should_advance_next() {
        true => {
          next_rotor.rotate(); // This line requires mutable access to next_rotor
        }
        false => (),
      },
      None => (),
    }
  }
}

and the definition of my struct here:

pub struct Enigma {
    reflector: Reflector,
    rotors: RotorConfig, // Only mutable via getter and setter functions
}

the struct of interest here is RotorConfig which is generated using the define! macro from prae. Here's the code:


prae::define! {
  #[derive(Debug)]
  RotorConfig: Vec<Rotor>; // I need to be able to call the rotate method of each rotor in this vec. This requires mutability
  validate(RotorConfigError) |config| {
    match config.len(){
      3..=4 => (),
      _ => return Err(RotorConfigError::Size)
    }

    match config.iter().unique().count(){
      3..=4 =>(),
      _ => return Err(RotorConfigError::Duplicate)
    }

    Ok(())
  };
}

the issue stems from the fact that prae only allows for immutable access to the internal representation via getter and setter functions so as to ensure the validity of the values inside. As you can see in my advance_rotors function I wrote before implementing validation I'm getting an error because I need to call rotor.rotate mutably. I'm at a loss as to how to accomplish this


Solution

  • After posting this I realized that I can simply provide interior mutability by using the following impl block

    
    impl RotorConfig{
        fn advance_rotors(&mut self)
        {
            self.0[0].rotate();
    
            let mut iterhandle = self.0.iter_mut().peekable();
    
            while let Some(el) = iterhandle.next() {
                match iterhandle.peek_mut() {
                    Some(next_rotor) => match el.should_advance_next() {
                        true => {
                            next_rotor.rotate();
                        }
                        false => (),
                    },
                    None => (),
                }
            }
        }
    
    }
    

    As you can see the function largely remains unchanged except that we replace self.rotors with self.0