How to fix value used after being moved?

Hi everyone !

I want to move the vector of features into my method that returns tokio::spawn task. I process this vector inside to spread its data among variables. But for one variable I got an error:

Value used after being moved

This is the place where I got this error:

loop {
        tokio::select! {
            _ = signal_receiver.recv() => {
                // the error is here, on realm_processors assignment
                processors = realm_processors;
            },
            result = Self::read_packet(&reader) => {

This is my full code of the method + types I use there:

pub trait Feature: Send {
    fn new() -> Self where Self: Sized;
    fn set_broadcast_channel(
        &mut self,
        sender: BroadcastSender<HandlerOutput>,
        receiver: BroadcastReceiver<HandlerOutput>,
    );
    fn get_tasks(&mut self) -> AnyResult<Vec<JoinHandle<()>>>;
    fn get_login_processors(&self) -> Vec<ProcessorFunction> {
        vec![]
    }

    fn get_realm_processors(&self) -> Vec<ProcessorFunction> {
        vec![]
    }
    fn get_one_time_handler_maps(&self) -> Vec<BTreeMap<u16, ProcessorResult>> {
        vec![]
    }
}
#[async_trait]
pub trait PacketHandler {
    async fn handle(&mut self, input: &mut HandlerInput) -> HandlerResult;
}
#[derive(Debug, Clone)]
pub enum HandlerOutput {
    // ... some fields here
}
pub type HandlerResult = AnyResult<Vec<HandlerOutput>>;
pub type ProcessorResult = Vec<Box<dyn PacketHandler + Send>>;
pub type ProcessorFunction = Box<dyn Fn(&mut HandlerInput) -> ProcessorResult + Send>;

fn handle_read(
        &mut self,
        mut signal_receiver: Receiver<Signal>,
        query_sender: BroadcastSender<HandlerOutput>,
        notify: Arc<Notify>,
        features: Vec<Box<dyn Feature>>,
    ) -> JoinHandle<()> {
        let reader = Arc::clone(&self._reader);
        let session = Arc::clone(&self.session);
        let data_storage = Arc::clone(&self.data_storage);

        tokio::spawn(async move {
            let mut realm_processors: Vec<ProcessorFunction> = Self::get_realm_processors();
            let mut processors: Vec<ProcessorFunction> = Self::get_login_processors();
            let mut one_time_handler_maps = Self::get_one_time_handler_maps();

            for feature in features.into_iter() {
                realm_processors.extend(feature.get_realm_processors());
                processors.extend(feature.get_login_processors());
                one_time_handler_maps.extend(feature.get_one_time_handler_maps());
            }

            loop {
                tokio::select! {
                    _ = signal_receiver.recv() => {
                        // the error is here, on realm_processors assignment
                        processors = realm_processors;
                    },
                    result = Self::read_packet(&reader) => {
                        match result {
                            Ok(packet) => {
                                let IncomingPacket { opcode, body: data, .. } = packet;

                                let mut input = HandlerInput {
                                    session: Arc::clone(&session),
                                    data,
                                    data_storage: Arc::clone(&data_storage),
                                    opcode,
                                };

                                let mut handler_list = processors
                                    .iter()
                                    .flat_map(|processor| processor(&mut input))
                                    .collect::<ProcessorResult>();

                                // ...
                            },
                            Err(err) => {
                                // ...
                            }
                        }
                    },
                }
            }
        })
    }

in the code above I use features.into_iter() to free memory, because I do not need this variable outside of the for loop.

Could somebody explain how to correctly assign the realm_processors into processors, to replace the old value and why I got that error ?

At the second iteration of the loop it may not be able to move out the value of the realm_processors as it may already be moved out at the previous iteration. What do you want to do in such case?

1 Like

Actually, this code:

_ = signal_receiver.recv() => {
    processors = realm_processors;
},

will be called only once. But I guess you mean that compiler do not know that, right ?
Could you tell, how to correctly solve the issue in this case ? I cannot clone, because the type not impl Clone.

You can put the value of realm_processors in an Option before the loop, and use realm_processors.take().unwrap() inside. This will panic if it does end up being called twice somehow.

1 Like

Nice approach. Thank you, this helps !

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.