roblib-client 0.1.0

A client library for a dank engine
Documentation
use anyhow::Result;
use roblib::{cmd, gpio::event::GpioPin};

use crate::{
    transports::{Subscribable, Transport},
    Robot,
};

impl<T: Transport> roblib::gpio::Gpio for Robot<T> {
    fn read_pin(&self, pin: u8) -> Result<bool> {
        self.transport.cmd(cmd::ReadPin(pin))
    }

    fn write_pin(&self, pin: u8, value: bool) -> Result<()> {
        self.transport.cmd(cmd::WritePin(pin, value))
    }

    fn pwm(&self, pin: u8, hz: f64, cycle: f64) -> Result<()> {
        self.transport.cmd(cmd::Pwm(pin, hz, cycle))
    }

    fn servo(&self, pin: u8, degree: f64) -> Result<()> {
        self.transport.cmd(cmd::Servo(pin, degree))
    }

    fn pin_mode(&self, pin: u8, mode: roblib::gpio::Mode) -> Result<()> {
        self.transport.cmd(cmd::PinMode(pin, mode))
    }
}

pub struct Pin<'r, T: Transport> {
    robot: &'r Robot<T>,
    pin: u8,
}
pub struct InputPin<'r, T: Transport> {
    robot: &'r Robot<T>,
    pin: u8,
}
pub struct OutputPin<'r, T: Transport> {
    robot: &'r Robot<T>,
    pin: u8,
}

impl<'r, T: Transport + 'r> roblib::gpio::TypedGpio<'r> for Robot<T> {
    type O = OutputPin<'r, T>;
    type I = InputPin<'r, T>;
    type P = Pin<'r, T>;

    fn pin(&'r self, pin: u8) -> Result<Self::P> {
        Ok(Pin { pin, robot: self })
    }

    fn input_pin(&'r self, pin: u8) -> Result<Self::I> {
        self.transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Input))?;
        Ok(InputPin { pin, robot: self })
    }

    fn output_pin(&'r self, pin: u8) -> Result<Self::O> {
        self.transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))?;
        Ok(OutputPin { pin, robot: self })
    }
}

impl<'r, T: Transport> roblib::gpio::Pin for Pin<'r, T> {
    type I = InputPin<'r, T>;
    type O = OutputPin<'r, T>;

    fn get_pin(&self) -> u8 {
        self.pin
    }

    fn set_to_input(self) -> Result<Self::I> {
        let Self { pin, robot } = self;
        robot
            .transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Input))?;
        Ok(InputPin { pin, robot })
    }

    fn set_to_output(self) -> Result<Self::O> {
        let Self { pin, robot } = self;
        robot
            .transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Input))?;
        Ok(OutputPin { pin, robot })
    }
}

impl<'r, T: Transport> roblib::gpio::Pin for InputPin<'r, T> {
    type I = InputPin<'r, T>;
    type O = OutputPin<'r, T>;

    fn get_pin(&self) -> u8 {
        self.pin
    }

    fn set_to_input(self) -> Result<Self::I> {
        Ok(self)
    }

    fn set_to_output(self) -> Result<Self::O> {
        let Self { pin, robot } = self;
        robot
            .transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))?;
        Ok(OutputPin { pin, robot })
    }
}
impl<'r, T: Transport> roblib::gpio::InputPin for InputPin<'r, T> {
    type O = OutputPin<'r, T>;
    type P = Pin<'r, T>;

    fn read(&self) -> Result<bool> {
        self.robot.transport.cmd(cmd::ReadPin(self.pin))
    }

    fn set_to_pin(self) -> Result<Self::P> {
        Ok(Pin {
            pin: self.pin,
            robot: self.robot,
        })
    }
}

impl<'r, T: Transport + Subscribable + Send + Sync> roblib::gpio::SubscribablePin
    for InputPin<'r, T>
{
    fn subscribe(
        &mut self,
        handler: impl FnMut(bool) -> Result<()> + Send + Sync + 'static,
    ) -> Result<()> {
        self.robot.transport.subscribe(GpioPin(self.pin), handler)
    }
}

impl<'r, T: Transport> roblib::gpio::Pin for OutputPin<'r, T> {
    type I = InputPin<'r, T>;
    type O = OutputPin<'r, T>;

    fn get_pin(&self) -> u8 {
        self.pin
    }

    fn set_to_input(self) -> Result<Self::I> {
        let Self { pin, robot } = self;
        robot
            .transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))?;
        Ok(InputPin { pin, robot })
    }
    fn set_to_output(self) -> Result<Self::O> {
        let Self { pin, robot } = self;
        robot
            .transport
            .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))?;
        Ok(OutputPin { pin, robot })
    }
}
impl<'r, T: Transport> roblib::gpio::OutputPin for OutputPin<'r, T> {
    type I = InputPin<'r, T>;
    type P = Pin<'r, T>;

    fn set(&mut self, value: bool) -> Result<()> {
        self.robot.transport.cmd(cmd::WritePin(self.pin, value))
    }

    fn pwm(&mut self, hz: f64, cycle: f64) -> Result<()> {
        self.robot.transport.cmd(cmd::Pwm(self.pin, hz, cycle))
    }

    fn servo(&mut self, degree: f64) -> Result<()> {
        self.robot.transport.cmd(cmd::Servo(self.pin, degree))
    }

    fn set_to_pin(self) -> Result<Self::P> {
        Ok(Pin {
            pin: self.pin,
            robot: self.robot,
        })
    }
}

#[cfg(feature = "async")]
pub mod gpio_async {
    use crate::{
        async_robot::RobotAsync,
        transports::{SubscribableAsync, TransportAsync},
    };
    use anyhow::Result;
    use async_trait::async_trait;
    use roblib::{cmd, gpio::event::GpioPin};

    #[async_trait]
    impl<T: TransportAsync> roblib::gpio::GpioAsync for RobotAsync<T> {
        async fn read_pin(&self, pin: u8) -> Result<bool> {
            self.transport.cmd(cmd::ReadPin(pin)).await
        }

        async fn write_pin(&self, pin: u8, value: bool) -> Result<()> {
            self.transport.cmd(cmd::WritePin(pin, value)).await
        }

        async fn pwm(&self, pin: u8, hz: f64, cycle: f64) -> Result<()> {
            self.transport.cmd(cmd::Pwm(pin, hz, cycle)).await
        }

        async fn servo(&self, pin: u8, degree: f64) -> Result<()> {
            self.transport.cmd(cmd::Servo(pin, degree)).await
        }

        async fn pin_mode(&self, pin: u8, mode: roblib::gpio::Mode) -> Result<()> {
            self.transport.cmd(cmd::PinMode(pin, mode)).await
        }
    }

    pub struct PinAsync<'r, T: TransportAsync> {
        robot: &'r RobotAsync<T>,
        pin: u8,
    }
    pub struct InputPinAsync<'r, T: TransportAsync> {
        robot: &'r RobotAsync<T>,
        pin: u8,
    }
    pub struct OutputPinAsync<'r, T: TransportAsync> {
        robot: &'r RobotAsync<T>,
        pin: u8,
    }

    #[async_trait]
    impl<'r, T: TransportAsync + 'r> roblib::gpio::TypedGpioAsync<'r> for RobotAsync<T> {
        type O = OutputPinAsync<'r, T>;
        type I = InputPinAsync<'r, T>;
        type P = PinAsync<'r, T>;

        async fn pin(&'r self, pin: u8) -> Result<Self::P> {
            Ok(PinAsync { pin, robot: self })
        }

        async fn input_pin(&'r self, pin: u8) -> Result<Self::I> {
            self.transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Input))
                .await?;
            Ok(InputPinAsync { pin, robot: self })
        }

        async fn output_pin(&'r self, pin: u8) -> Result<Self::O> {
            self.transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))
                .await?;
            Ok(OutputPinAsync { pin, robot: self })
        }
    }

    #[async_trait]
    impl<'r, T: TransportAsync> roblib::gpio::PinAsync for PinAsync<'r, T> {
        type I = InputPinAsync<'r, T>;
        type O = OutputPinAsync<'r, T>;

        async fn get_pin(&self) -> u8 {
            self.pin
        }

        async fn set_to_input(self) -> Result<Self::I> {
            let Self { pin, robot } = self;
            robot
                .transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Input))
                .await?;
            Ok(InputPinAsync { pin, robot })
        }

        async fn set_to_output(self) -> Result<Self::O> {
            let Self { pin, robot } = self;
            robot
                .transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Input))
                .await?;
            Ok(OutputPinAsync { pin, robot })
        }
    }

    #[async_trait]
    impl<'r, T: TransportAsync> roblib::gpio::PinAsync for InputPinAsync<'r, T> {
        type I = InputPinAsync<'r, T>;
        type O = OutputPinAsync<'r, T>;

        async fn get_pin(&self) -> u8 {
            self.pin
        }

        async fn set_to_input(self) -> Result<Self::I> {
            Ok(self)
        }

        async fn set_to_output(self) -> Result<Self::O> {
            let Self { pin, robot } = self;
            robot
                .transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))
                .await?;
            Ok(OutputPinAsync { pin, robot })
        }
    }
    #[async_trait]
    impl<'r, T: TransportAsync> roblib::gpio::InputPinAsync for InputPinAsync<'r, T> {
        type O = OutputPinAsync<'r, T>;
        type P = PinAsync<'r, T>;

        async fn read(&self) -> Result<bool> {
            self.robot.transport.cmd(cmd::ReadPin(self.pin)).await
        }

        async fn set_to_pin(self) -> Result<Self::P> {
            Ok(PinAsync {
                pin: self.pin,
                robot: self.robot,
            })
        }
    }

    #[async_trait]
    impl<'r, T: TransportAsync + SubscribableAsync + Send + Sync> roblib::gpio::SubscribablePinAsync
        for InputPinAsync<'r, T>
    {
        async fn subscribe(&self) -> Result<tokio::sync::broadcast::Receiver<bool>> {
            self.robot.transport.subscribe(GpioPin(self.pin)).await
        }
    }

    #[async_trait]
    impl<'r, T: TransportAsync> roblib::gpio::PinAsync for OutputPinAsync<'r, T> {
        type I = InputPinAsync<'r, T>;
        type O = OutputPinAsync<'r, T>;

        async fn get_pin(&self) -> u8 {
            self.pin
        }

        async fn set_to_input(self) -> Result<Self::I> {
            let Self { pin, robot } = self;
            robot
                .transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))
                .await?;
            Ok(InputPinAsync { pin, robot })
        }
        async fn set_to_output(self) -> Result<Self::O> {
            let Self { pin, robot } = self;
            robot
                .transport
                .cmd(cmd::PinMode(pin, roblib::gpio::Mode::Output))
                .await?;
            Ok(OutputPinAsync { pin, robot })
        }
    }
    #[async_trait]
    impl<'r, T: TransportAsync> roblib::gpio::OutputPinAsync for OutputPinAsync<'r, T> {
        type I = InputPinAsync<'r, T>;
        type P = PinAsync<'r, T>;

        async fn set(&mut self, value: bool) -> Result<()> {
            self.robot
                .transport
                .cmd(cmd::WritePin(self.pin, value))
                .await
        }

        async fn pwm(&mut self, hz: f64, cycle: f64) -> Result<()> {
            self.robot
                .transport
                .cmd(cmd::Pwm(self.pin, hz, cycle))
                .await
        }

        async fn servo(&mut self, degree: f64) -> Result<()> {
            self.robot.transport.cmd(cmd::Servo(self.pin, degree)).await
        }

        async fn set_to_pin(self) -> Result<Self::P> {
            Ok(PinAsync {
                pin: self.pin,
                robot: self.robot,
            })
        }
    }
}