Ganesh Rathinavel
Ganesh Rathinavel

Reputation: 1335

Rust Lifetime Error: Cannot Return Value Referencing Local Variable

I am working on a Rust project using rusb to interact with USB devices. I'm facing a lifetime management issue where I cannot return a struct containing a reference due to it referencing a local variable within a nested loop. Here's the simplified code that leads to the issue:

The below code snippet provided is part of the rusb crate, which is a third-party library for handling USB communications in Rust.

pub struct InterfaceDescriptors<'a> {
    iter: slice::Iter<'a, libusb_interface_descriptor>,
}

impl<'a> Iterator for InterfaceDescriptors<'a> {
    type Item = InterfaceDescriptor<'a>;

    fn next(&mut self) -> Option<InterfaceDescriptor<'a>> {
        self.iter.next().map(|descriptor| InterfaceDescriptor { descriptor })
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.iter.size_hint()
    }
}

pub struct InterfaceDescriptor<'a> {
    descriptor: &'a libusb_interface_descriptor,
}

Here is the code snippet from my crate:

use rusb::{Device, Context, UsbContext};

pub struct ABC<'a> {
    /// Descriptor of the USB interface.
    usb_interface_descriptor: &'a rusb::InterfaceDescriptor<'a>,
}

impl<'a> ABC<'a> {
    pub fn find_compatible_device(
        usb_device: &'a Device<Context>,
    ) -> anyhow::Result<Option<ABC<'a>>, rusb::Error> {
        let dev_descriptor = usb_device.device_descriptor()?;
        for cfg_index in 0..dev_descriptor.num_configurations() {
            let cfg_descriptor = usb_device.config_descriptor(cfg_index)?;
            for interface in cfg_descriptor.interfaces() {
                for descriptor in interface.descriptors() {
                    // <!------ Error occurs here  ------>
                    return Ok(Some(ABC {
                        usb_interface_descriptor: &descriptor,
                    }));
                }
            }
        }
        Ok(None)
    }
}

The usb_interface_descriptor cannot be cloned. I understand that cfg_descriptor is dropped at the end of the loop, making any references to its contents invalid.

I am attempting to return an instance of ABC that holds a reference to an InterfaceDescriptor. However, I get the following compilation error:

error[E0515]: cannot return value referencing local variable `cfg_descriptor`
  --> src/test.rs:20:28
   |
17 |               for interface in cfg_descriptor.interfaces() {
   |                                -------------- `cfg_descriptor` is borrowed here
...
20 |                       return Ok(Some(ABC {
   |  ____________________________^
21 | |                         usb_interface_descriptor: &descriptor,
22 | |                     }));
   | |_______________________^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing local variable `descriptor`
  --> src/test.rs:20:28
   |
20 |                       return Ok(Some(ABC {
   |  ____________________________^
21 | |                         usb_interface_descriptor: &descriptor,
   | |                                                   ----------- `descriptor` is borrowed here
22 | |                     }));
   | |_______________________^ returns a value referencing data owned by the current function

What would be the best way to refactor this code to avoid the lifetime issue while still returning necessary data from the function?

Upvotes: 0

Views: 72

Answers (1)

DrGo
DrGo

Reputation: 521

Looking at the definition

pub struct InterfaceDescriptor<'a> {
    descriptor: &'a libusb_interface_descriptor,
}

InterfaceDescriptor is nothing but a thin wrapper over a reference, so you do not gain much by trying to avoid copying it (via using a reference).

I would just define ABC to hold InterfaceDescriptor directly (not a reference to it).

Upvotes: 1

Related Questions