ev3robot 0.3.1

Rust library for ev3dev
Documentation
use derive_more::*;

use super::tacho::{
    Rotate, StopAction, TachoMotorPositionUnit, TachoMotorSpeedUnit,
};
use super::{
    Brake, Coast, DutyCycleController, Hold, IsHolding, IsRunning, Run,
    RunDirect,
};
use crate::percentage::SignedPercentage;

#[derive(Debug, Index, IndexMut, IntoIterator)]
pub struct MotorsBunch<Motor>(Vec<Motor>);

impl<Motor> MotorsBunch<Motor> {
    pub fn new<I: IntoIterator<Item = Motor>>(iter: I) -> Self {
        iter.into_iter().collect()
    }

    pub fn exec<'a, T, U, F>(&'a mut self, f: F) -> anyhow::Result<U>
    where
        F: FnMut(&'a mut Motor) -> anyhow::Result<T>,
        U: FromIterator<T>,
    {
        self.0.iter_mut().map(f).collect()
    }
}

impl<Motor> FromIterator<Motor> for MotorsBunch<Motor> {
    fn from_iter<I: IntoIterator<Item = Motor>>(iter: I) -> Self {
        MotorsBunch(iter.into_iter().collect())
    }
}

impl<Motor, SpeedUnit> Run<SpeedUnit> for MotorsBunch<Motor>
where
    Motor: Run<SpeedUnit>,
    SpeedUnit: Clone,
{
    fn run(&mut self, speed: SpeedUnit) -> anyhow::Result<()> {
        self.exec(|it| it.run(speed.clone()))
    }
}

impl<Motor: IsRunning> IsRunning for MotorsBunch<Motor> {
    fn is_running(&mut self) -> anyhow::Result<bool> {
        let mut is_running = false;
        self.exec(|it| it.is_running().map(|b| is_running |= b))?;
        Ok(is_running)
    }
}

impl<Motor: IsHolding> IsHolding for MotorsBunch<Motor> {
    fn is_holding(&mut self) -> anyhow::Result<bool> {
        let mut is_holding = false;
        self.exec(|it| it.is_holding().map(|b| is_holding |= b))?;
        Ok(is_holding)
    }
}

impl<Motor: Coast> Coast for MotorsBunch<Motor> {
    fn coast(&mut self) -> anyhow::Result<()> {
        self.exec(Coast::coast)
    }
}

impl<Motor: Brake> Brake for MotorsBunch<Motor> {
    fn brake(&mut self) -> anyhow::Result<()> {
        self.exec(Brake::brake)
    }
}

impl<Motor: Hold> Hold for MotorsBunch<Motor> {
    fn hold(&mut self) -> anyhow::Result<()> {
        self.exec(Hold::hold)
    }
}

impl<Motor: Rotate> Rotate for MotorsBunch<Motor> {
    fn rotate(
        &mut self,
        speed: impl TachoMotorSpeedUnit,
        shift: impl TachoMotorPositionUnit,
        stop_action: StopAction,
    ) -> anyhow::Result<()> {
        self.exec(|it| it.rotate(speed.clone(), shift.clone(), stop_action))
    }
}

impl<Motor: RunDirect> RunDirect for MotorsBunch<Motor> {
    fn run_direct<'a>(
        &'a mut self,
        duty_cycle: SignedPercentage,
    ) -> anyhow::Result<Box<dyn DutyCycleController + 'a>> {
        let mut controllers: Vec<_> =
            self.exec(|it| it.run_direct(duty_cycle))?;
        Ok(Box::new(move |duty_cycle| {
            controllers
                .iter_mut()
                .try_for_each(|it| it.set_duty_cycle(duty_cycle))
        }))
    }
}