smux_rust 0.2.1

A simple multiplexing library for Rust, inspired by xtaci/smux
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::fmt;

/// 协议命令
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cmd {
    /// 流打开
    Syn = 0,
    /// 流关闭
    Fin = 1,
    /// 数据推送
    Psh = 2,
    /// 无操作
    Nop = 3,
    /// 窗口更新(仅版本2支持)
    Upd = 4,
}

impl From<u8> for Cmd {
    fn from(b: u8) -> Self {
        match b {
            0 => Cmd::Syn,
            1 => Cmd::Fin,
            2 => Cmd::Psh,
            3 => Cmd::Nop,
            4 => Cmd::Upd,
            _ => Cmd::Nop,
        }
    }
}

/// 帧头大小:版本(1) + 命令(1) + 长度(2) + 流ID(4) = 8字节
pub const HEADER_SIZE: usize = 8;

/// cmdUPD 数据大小:已消费(4) + 窗口(4) = 8字节
pub const UPD_SIZE: usize = 8;

/// 初始对端窗口大小(慢启动)
pub const INITIAL_PEER_WINDOW: u32 = 262144;

/// 帧结构
#[derive(Debug, Clone)]
pub struct Frame {
    /// 协议版本
    pub ver: u8,
    /// 命令
    pub cmd: Cmd,
    /// 流ID
    pub sid: u32,
    /// 数据负载
    pub data: Bytes,
}

impl Frame {
    /// 创建新帧
    pub fn new(ver: u8, cmd: Cmd, sid: u32) -> Self {
        Self {
            ver,
            cmd,
            sid,
            data: Bytes::new(),
        }
    }

    /// 编码帧为字节
    pub fn encode(&self) -> BytesMut {
        let mut buf = BytesMut::with_capacity(HEADER_SIZE + self.data.len());
        buf.put_u8(self.ver);
        buf.put_u8(self.cmd as u8);
        buf.put_u16_le(self.data.len() as u16);
        buf.put_u32_le(self.sid);
        buf.put_slice(&self.data);
        buf
    }

    /// 从字节解码帧头
    pub fn decode_header(buf: &[u8]) -> Option<(u8, Cmd, u16, u32)> {
        if buf.len() < HEADER_SIZE {
            return None;
        }
        let mut reader = buf;
        let ver = reader.get_u8();
        let cmd = Cmd::from(reader.get_u8());
        let length = reader.get_u16_le();
        let sid = reader.get_u32_le();
        Some((ver, cmd, length, sid))
    }
}

/// 原始帧头
#[derive(Debug, Clone, Copy)]
pub struct RawHeader {
    pub ver: u8,
    pub cmd: Cmd,
    pub length: u16,
    pub sid: u32,
}

impl RawHeader {
    pub fn from_bytes(buf: &[u8]) -> Option<Self> {
        if buf.len() < HEADER_SIZE {
            return None;
        }
        let mut reader = &buf[..];
        Some(Self {
            ver: reader.get_u8(),
            cmd: Cmd::from(reader.get_u8()),
            length: reader.get_u16_le(),
            sid: reader.get_u32_le(),
        })
    }
}

/// 更新头(cmdUPD)
#[derive(Debug, Clone, Copy)]
pub struct UpdHeader {
    pub consumed: u32,
    pub window: u32,
}

impl UpdHeader {
    pub fn from_bytes(buf: &[u8]) -> Option<Self> {
        if buf.len() < UPD_SIZE {
            return None;
        }
        let mut reader = &buf[..];
        Some(Self {
            consumed: reader.get_u32_le(),
            window: reader.get_u32_le(),
        })
    }

    pub fn encode(&self) -> Bytes {
        let mut buf = BytesMut::with_capacity(UPD_SIZE);
        buf.put_u32_le(self.consumed);
        buf.put_u32_le(self.window);
        buf.freeze()
    }
}

impl fmt::Display for Frame {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Version:{} Cmd:{} StreamID:{} Length:{}",
            self.ver,
            self.cmd as u8,
            self.sid,
            self.data.len()
        )
    }
}