I'm trying to create a struct that enables a pin and then disables it after a period of time. I'm running into an issue of ownership and I'm not quite sure how to resolve it.
Here's the code I'm working with:
pub trait PumpPin {
    fn enable(self);
    fn disable(self);
}
impl PumpPin for Gpio4<Output> {
    fn enable(mut self: Gpio4<Output>) {
        self.set_high().unwrap();
    }
    fn disable(mut self: Gpio4<Output>) {
        self.set_low().unwrap();
    }
}
pub struct PumpManager<T: PumpPin + std::marker::Send + 'static + std::marker::Sync> {
    pin: T,
}
impl<T: PumpPin + std::marker::Send + 'static + std::marker::Sync> PumpManager<T> {
    pub fn new(pin: T) -> PumpManager<T> {
        PumpManager { pin }
    }
    pub fn run_pump(self, time: u64) -> Result<(), EspError> {
        self.pin.enable();
        // Configure the timer to disable the pin
        let once_timer = EspTimerService::new()
            .unwrap()
            .timer(move || self.pin.disable());
        //actually set a time for the timer
        once_timer.unwrap().after(Duration::from_secs(time))
    }
}
My goal was to encapsulate all of the logic that handles the timing of the pump.
The error I get below is at self.pin.disable()
cannot move out of `self.pin`, as `self` is a captured variable in an `FnMut` closure
move occurs because `self.pin` has type `T`, which does not implement the `Copy` trait
I thought the ownership of pin would belong to PumpManager itself but it actually belongs to whatever function is calling it. Is there a way I can refactor this to accomplish what I'm trying to do?
 
                        
Your intuition is almost correct:
pinis owned byPumpManager, butPumpManageris owned byrun_pump()because that method takes ownership viaself.There is a confluence of expectations here:
PumpPin::disable()takes ownership viaself, butesp_idf_svc::timer::EspTimerService::timer()expects aFnMut(), that is, it expects a closure that can be called multiple times (think of a periodic timer). But we can't move ownership ofself.pininto the closure, movepinout of the closure viapin.disable(), and call the closure again - becausepinwould be gone by then. This is why the requirement forFnMutis not satisfied.Essentially, your problem is that
EspTimerService::timer()enforces a closure that can be called from periodic timers, whilePumpPin::disable()enforces that it can be called only exactly once, yet is called from what could be a periodic timer; one might say theesp_idf_svc-API is poorly designed, but the contradiction is what it is.If you can change
PumpPin::disable()to not take ownership (but e.g.&mut self), your closure can become aFnMutas is.If you can't change
PumpPin::disable(), you may moveself.pininto anOptionand.take()thepinout of thatOptioninside the closure. The call to.take()will give you an owned value on the first call (the only time the timer executes), and would returnNonethereafter if the timer fired multiple times (which does not happen, but it would be correct as far as the compiler is concerned). For instance: