oc2_hlapi_v2 0.2.0

A client for the new version of OpenComputers II's HLAPI
Documentation
//! The redstone device and its associated types
//!
//! [OC2 Docs](https://fnuecke.github.io/oc2/manual/en_us/device/redstone.html)

use std::error::Error;

use serde::{Deserialize, Serialize};
use thiserror::Error;
use uuid::Uuid;

use crate::{
    client::{DeviceBase, HlapiClient, HlapiClientError},
    devices::Side,
};

#[derive(Debug, Clone)]
/// A redstone device
pub struct Redstone {
    client: HlapiClient,
    uuid: Uuid,
}

/// The possible errors for device functions
#[non_exhaustive]
#[derive(Error, Debug)]
pub enum RedstoneError {
    #[error("HLAPI client error: {0}")]
    /// HLAPI client error
    HlapiClientError(#[from] HlapiClientError),
    #[error("Invalid signal strength given")]
    /// Invalid signal strength given
    SignalStrengthInvalid,
}

/// The event that is fired when the redstone signal strength on a side changes.
///
/// This event is fired whenever the value of [`get_redstone_input`] for a side changes, so calls to
/// [`set_redstone_output`] can cause this event to be fired.
///
/// [`get_redstone_input`]: Redstone::get_redstone_input
/// [`set_redstone_output`]: Redstone::set_redstone_output
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
pub struct RedstoneChangedEvent {
    /// The side that changed signal strength
    pub side: Side,
    /// The new strength on that side
    #[serde(rename = "value")]
    pub strength: u8,
}

impl Redstone {
    /// Gets the redstone signal strength on the specified side. Any output of this device on that
    /// side counts towards this value.
    pub fn get_redstone_input(&self, side: Side) -> Result<u8, RedstoneError> {
        Ok(self.call("getRedstoneInput", &[&side as _], &[])?.0)
    }

    /// Gets the redstone signal strength this device is emitting on the specified side
    pub fn get_redstone_output(&self, side: Side) -> Result<u8, RedstoneError> {
        Ok(self.call("getRedstoneOutput", &[&side as _], &[])?.0)
    }

    /// Sets the redstone signal strength this device is emitting on the specified side, from 0 to
    /// 15.
    pub fn set_redstone_output(&self, side: Side, strength: u8) -> Result<(), RedstoneError> {
        if strength > 15 {
            return Err(RedstoneError::SignalStrengthInvalid);
        }
        self.call::<()>("setRedstoneOutput", &[&side as _, &strength as _], &[])?;
        Ok(())
    }
}

impl DeviceBase for Redstone {
    const TYPE: &'static str = "redstone";

    type Event = RedstoneChangedEvent;

    fn new(client: HlapiClient, uuid: Uuid) -> Result<Self, HlapiClientError> {
        Ok(Self { client, uuid })
    }

    fn uuid_base(&self) -> Uuid {
        self.uuid
    }

    fn client(&self) -> &HlapiClient {
        &self.client
    }

    fn parse_event(
        typ: &str,
        data: &serde_json::Value,
    ) -> Result<Self::Event, Box<dyn Error + Send + Sync>> {
        if typ != "redstoneChanged" {
            return Err("invalid event type".into());
        }
        Ok(serde_json::from_value(data.clone())?)
    }
}