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()),
}
}
}