Search code examples
rustownership

Take ownership of local object field


I created a Task struct that holds two files and an enum. For this struct, I want to implement a method that reads and decodes the input file as a WAV (audio). For that, I'm using the wav crate. This method should return a Header holding some metadata on the file and a Vec<f32>, which is the audio data itself.

The problem is that I only have ways to get a reference to this audio vector (as_thirty_two_float()). This reference is owned by the read object created in the first line. I am not allowed to return the reference because read will be disposed soon after. I am also not allowed to return the content (*data_vector) because "cannot move out of *data_vector which is behind a shared reference: move occurs because *data_vector has type Vec<f32>, which does not implement the Copy trait".

Obviously I could just clone the vector and be done with it, but I want to believe that there is a way to just take the ownership of *data_vector by destroying read in the process. Could anyone throw some light on this for me?

struct Task {
    input_file: File,
    output_file: File,
    effect: Effect,
}

impl Task {
    fn decode_input(&mut self) -> (Header, Vec<f32>) {
        let read = wav::read(&mut self.input_file)
            .expect("Failed to decode the input file");
        let data_vector = read.1.as_thirty_two_float() // &Vec<f32>
            .expect("Failed to extract the audio channel data");
        return (read.0, *data_vector);
    }
}

Solution

  • You could use try_into_thirty_two_float() which moves the vector out of the BitDepth on success or returns the BitDepth unchanged on failure.

    let (header, bitdepth) = wav::read(&mut self.input_file)
        .expect("Failed to decode the input file");
    let data_vector = bitdepth.try_into_thirty_two_float()
        .expect("Failed to extract the audio channel data");
    (header, data_vector)