//! # Isabelle's Lazy Message Protocol #![allow(dead_code)] use futures_util::io::{AsyncReadExt, AsyncWriteExt}; use std::convert::TryInto; use std::marker::Unpin; mod message; pub use message::Message; /// lazy error pub type Error = Box; /// lazy result pub type Result = std::result::Result; struct NetworkPacket(Vec); /// A type of data that can be sent pub trait Sendable: Sized { fn to_packet(self) -> Result; fn from_packet(packet: Packet) -> Result; } /// Data to be sent pub struct Packet { kind: PacketKind, contents: Vec, } impl Packet { /// Create a new `Packet` pub fn new(kind: PacketKind, contents: Vec) -> Packet { Packet { kind, contents } } fn to_network_packet(self) -> NetworkPacket { let mut contents: Vec = Vec::new(); // write packet kind byte contents.push(self.kind as u8); // write the packet length let contents_length = self.contents.len() as u32; contents.extend_from_slice(&contents_length.to_le_bytes()); // write contents contents.extend_from_slice(&self.contents); NetworkPacket(contents) } } /// reads a `Packet` from a stream /// /// if `Ok(None)` is returned the stream has been disconnected. pub async fn read(stream: &mut S) -> Result> where S: AsyncReadExt + Unpin, { let mut info_buf = [0u8; 5]; let check = stream.read(&mut info_buf).await?; if check == 0 { return Ok(None); } let packet_kind = PacketKind::from_u8(info_buf[0]).unwrap(); let length = u32::from_le_bytes(info_buf[1..5].try_into().unwrap()) as usize; let mut contents: Vec = vec![0; length]; stream.read(&mut contents).await?; let packet = Packet::new(packet_kind, contents); Ok(Some(packet)) } /// Writes a `Sendable` packet to a stream pub async fn write(stream: &mut S, packet: P) -> Result<()> where S: AsyncWriteExt + Unpin, P: Sendable, { let network_packet = packet.to_packet()?.to_network_packet(); stream.write(&network_packet.0).await?; Ok(()) } /// Kinds of packets that can be sent #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum PacketKind { Message = 0, PublicKey = 1, } impl PacketKind { /// returns `Option given valid matching variant pub fn from_u8(kind: u8) -> Option { match kind { 0 => Some(PacketKind::Message), _ => None, } } }