bitbroker 0.1.0

A language agnostic message broker designed for real-time communication.
Documentation
use prost::Message;

use crate::{proto::InitialMessageProto, Action, Error, Result};

pub struct BitBrokerMessage {
    inner: Vec<u8>,
}

impl BitBrokerMessage {
    pub fn new(opcode: u8, operand: u8, mut body: Vec<u8>) -> Self {
        let mut inner = Vec::with_capacity(body.len() + 2);
        inner.push(opcode);
        inner.push(operand);
        inner.append(&mut body);
        Self { inner }
    }

    pub fn new_proto<B>(opcode: u8, operand: u8, body: B) -> Self
    where
        B: Message,
    {
        Self::new(opcode, operand, body.encode_to_vec())
    }

    pub fn initial_game_message() -> Self {
        Self {
            inner: vec![0x00, 0x01],
        }
    }

    pub fn initial_bot_message() -> Self {
        Self {
            inner: vec![0x00, 0x02],
        }
    }

    pub fn bot_info_message(name: impl ToString) -> Self {
        let body = InitialMessageProto {
            bot_index: 0,
            bot_name: name.to_string(),
        };
        Self::new_proto(0x00, 0x22, body)
    }

    pub fn termination_message() -> Self {
        Self {
            inner: vec![0x00, 0xFF],
        }
    }

    pub fn trigger_message() -> Self {
        Self {
            inner: vec![0x01, 0x00],
        }
    }

    pub fn opcode(&self) -> &u8 {
        &self.inner[0]
    }

    pub fn operand(&self) -> &u8 {
        &self.inner[1]
    }

    pub fn codes(&self) -> (&u8, &u8) {
        (self.opcode(), self.operand())
    }

    pub fn body(&self) -> &[u8] {
        &self.inner[2..]
    }

    pub fn body_proto<B>(&self) -> Result<B>
    where
        B: Message + Default,
    {
        B::decode(self.body()).map_err(Error::from)
    }
}

impl From<Vec<u8>> for BitBrokerMessage {
    fn from(value: Vec<u8>) -> Self {
        Self { inner: value }
    }
}

impl AsRef<[u8]> for BitBrokerMessage {
    fn as_ref(&self) -> &[u8] {
        &self.inner
    }
}

impl<S> From<Action<S>> for BitBrokerMessage
where
    S: Into<Vec<u8>>,
{
    fn from(value: Action<S>) -> Self {
        match value {
            Action::EndGame => Self::new(0x00, 0xFE, vec![]),
            Action::PlayerAction(player, state) => Self::new(0x01, player, state.into()),
        }
    }
}