This commit is contained in:
lbl
2026-02-10 18:20:39 +08:00
parent 71da72da34
commit b4301a8106
261 changed files with 20179 additions and 21547 deletions
+98
View File
@@ -0,0 +1,98 @@
mod proto {
include!(concat!(env!("OUT_DIR"), "/protocol.client.rs"));
}
use anyhow::bail;
use bytes::BytesMut;
use prost::Message;
use std::net::{Ipv4Addr, Ipv6Addr};
use crate::protocol::ProtoToBytesMut;
pub use proto::*;
pub fn encode_nat_info(nat_info: &rust_p2p_core::nat::NatInfo) -> proto::NatInfo {
let nat_type = match nat_info.nat_type {
rust_p2p_core::nat::NatType::Cone => proto::NatType::Cone,
rust_p2p_core::nat::NatType::Symmetric => proto::NatType::Symmetric,
};
proto::NatInfo {
nat_type: nat_type.into(),
public_ips: nat_info.public_ips.iter().map(|v| (*v).into()).collect(),
public_udp_ports: nat_info
.public_udp_ports
.iter()
.map(|v| (*v).into())
.collect(),
public_port_range: nat_info.public_port_range.into(),
local_ipv4s: nat_info.local_ipv4s.iter().map(|v| (*v).into()).collect(),
ipv6: nat_info.ipv6.map(|v| v.octets().to_vec()),
local_udp_ports: nat_info
.local_udp_ports
.iter()
.map(|v| (*v).into())
.collect(),
local_tcp_port: nat_info.local_tcp_port.into(),
public_tcp_port: nat_info.public_tcp_port.into(),
}
}
pub fn decode_nat_info(msg: proto::NatInfo) -> anyhow::Result<rust_p2p_core::nat::NatInfo> {
let nat_type = match msg.nat_type() {
proto::NatType::Cone => rust_p2p_core::nat::NatType::Cone,
proto::NatType::Symmetric => rust_p2p_core::nat::NatType::Symmetric,
};
let ipv6: Option<[u8; 16]> = msg.ipv6.and_then(|v| v.as_slice().try_into().ok());
// Validate all ports fit in u16
let validate_port = |p: u32| -> anyhow::Result<u16> {
u16::try_from(p).map_err(|_| anyhow::anyhow!("invalid port number: {}", p))
};
let public_udp_ports: Result<Vec<_>, _> = msg
.public_udp_ports
.into_iter()
.map(validate_port)
.collect();
let local_udp_ports: Result<Vec<_>, _> =
msg.local_udp_ports.into_iter().map(validate_port).collect();
Ok(rust_p2p_core::nat::NatInfo {
nat_type,
public_ips: msg.public_ips.into_iter().map(|v| v.into()).collect(),
public_udp_ports: public_udp_ports?,
mapping_tcp_addr: vec![],
mapping_udp_addr: vec![],
public_port_range: validate_port(msg.public_port_range)?,
local_ipv4: msg
.local_ipv4s
.first()
.map(|v| (*v).into())
.unwrap_or(Ipv4Addr::UNSPECIFIED),
local_ipv4s: msg.local_ipv4s.into_iter().map(|v| v.into()).collect(),
ipv6: ipv6.map(Ipv6Addr::from),
local_udp_ports: local_udp_ports?,
local_tcp_port: validate_port(msg.local_tcp_port)?,
public_tcp_port: validate_port(msg.public_tcp_port)?,
})
}
#[derive(Clone, Debug)]
pub struct PunchInfo {
pub nat_info: rust_p2p_core::nat::NatInfo,
}
impl PunchInfo {
pub fn from_slice(buf: &[u8]) -> anyhow::Result<Self> {
let msg = proto::PunchInfo::decode(buf)?;
let Some(nat_info) = msg.nat_info else {
bail!("Punched info decode failed.");
};
let nat_info = decode_nat_info(nat_info)?;
Ok(Self { nat_info })
}
pub fn encode(&self) -> BytesMut {
let message = proto::PunchInfo {
nat_info: Some(encode_nat_info(&self.nat_info)),
};
message.encode_bytes_mut()
}
}
+275
View File
@@ -0,0 +1,275 @@
use crate::protocol::ProtoToBytesMut;
pub(crate) use crate::protocol::control_message::proto::SelectiveBroadcast;
use crate::protocol::control_message::proto::request_message::RequestPayload;
use crate::protocol::control_message::proto::response_message::ResponsePayload;
use anyhow::bail;
use bytes::BytesMut;
use prost::Message;
use std::net::Ipv4Addr;
mod proto {
include!(concat!(env!("OUT_DIR"), "/protocol.control_message.rs"));
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub enum RegistrationMode {
#[default]
Normal = 0,
PreRegister = 1,
}
impl From<RegistrationMode> for proto::RegistrationMode {
fn from(mode: RegistrationMode) -> Self {
match mode {
RegistrationMode::Normal => proto::RegistrationMode::Normal,
RegistrationMode::PreRegister => proto::RegistrationMode::PreRegister,
}
}
}
impl From<proto::RegistrationMode> for RegistrationMode {
fn from(mode: proto::RegistrationMode) -> Self {
match mode {
proto::RegistrationMode::Normal => RegistrationMode::Normal,
proto::RegistrationMode::PreRegister => RegistrationMode::PreRegister,
}
}
}
pub(crate) struct RegRequestMsg {
pub network_code: String,
pub device_id: String,
pub ip: Option<Ipv4Addr>,
pub name: String,
pub version: String,
pub key_sign: Option<String>,
pub ip_variable: bool,
pub server_id: u32,
pub registration_mode: RegistrationMode,
}
impl RegRequestMsg {
// pub fn check(&self) -> anyhow::Result<()> {
// if self.network_code.is_empty() {
// return Err(anyhow!("network_code cannot be empty"));
// }
// if self.network_code.len() > MAX_NETWORK_CODE_LEN {
// return Err(anyhow!(
// "network_code length exceeds {} characters (current: {})",
// MAX_NETWORK_CODE_LEN,
// self.network_code.len()
// ));
// }
// if self.device_id.is_empty() {
// return Err(anyhow!("device_id cannot be empty"));
// }
// if self.device_id.len() > MAX_DEVICE_ID_LEN {
// return Err(anyhow!(
// "device_id length exceeds {} characters (current: {})",
// MAX_DEVICE_ID_LEN,
// self.device_id.len()
// ));
// }
//
// if self.name.len() > MAX_NAME_LEN {
// return Err(anyhow!(
// "name length exceeds {} characters (current: {})",
// MAX_NAME_LEN,
// self.name.len()
// ));
// }
//
// if self.version.len() > MAX_VERSION_LEN {
// return Err(anyhow!(
// "version length exceeds {} characters (current: {})",
// MAX_VERSION_LEN,
// self.version.len()
// ));
// }
//
// Ok(())
// }
// pub fn from(msg: proto::RegRequestMsg) -> anyhow::Result<Self> {
// Ok(Self {
// network_code: msg.network_code,
// device_id: msg.device_id,
// ip: msg.ip.map(|ip| ip.into()),
// name: msg.name,
// version: msg.version,
// key_sign: msg.key_sign,
// ip_variable: msg.ip_variable,
// server_id: msg.server_id,
// })
// }
pub fn to(self) -> proto::RegRequestMsg {
proto::RegRequestMsg {
network_code: self.network_code,
device_id: self.device_id,
ip: self.ip.map(|ip| ip.into()),
name: self.name,
version: self.version,
key_sign: self.key_sign,
ip_variable: self.ip_variable,
server_id: self.server_id,
registration_mode: proto::RegistrationMode::from(self.registration_mode).into(),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct RegResponseMsg {
pub ip: Ipv4Addr,
pub prefix_len: u8,
pub gateway: Ipv4Addr,
pub server_version: String,
}
impl RegResponseMsg {
pub fn from(msg: proto::RegResponseMsg) -> anyhow::Result<Self> {
Ok(Self {
ip: msg.ip.into(),
prefix_len: (msg.prefix_len & 0xFF) as u8,
gateway: msg.gateway.into(),
server_version: msg.server_version,
})
}
pub fn to(self) -> proto::RegResponseMsg {
proto::RegResponseMsg {
ip: self.ip.into(),
prefix_len: self.prefix_len as _,
gateway: self.gateway.into(),
server_version: self.server_version,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ErrorResponseMsg {
pub code: u32,
pub message: String,
}
impl ErrorResponseMsg {
pub fn from(msg: proto::ErrorResponseMsg) -> anyhow::Result<Self> {
Ok(Self {
code: msg.code,
message: msg.message,
})
}
pub fn to(self) -> proto::ErrorResponseMsg {
proto::ErrorResponseMsg {
code: self.code,
message: self.message,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ConfirmRegResponseMsg {
pub success: bool,
}
impl ConfirmRegResponseMsg {
pub fn from(msg: proto::ConfirmRegResponseMsg) -> anyhow::Result<Self> {
Ok(Self {
success: msg.success,
})
}
pub fn to(self) -> proto::ConfirmRegResponseMsg {
proto::ConfirmRegResponseMsg {
success: self.success,
}
}
}
pub(crate) enum RequestMessage {
Reg(RegRequestMsg),
ConfirmReg,
}
impl RequestMessage {
pub fn encode(self) -> BytesMut {
let request_payload = match self {
RequestMessage::Reg(reg) => RequestPayload::Reg(reg.to()),
RequestMessage::ConfirmReg => RequestPayload::ConfirmReg(proto::ConfirmRegMsg {}),
};
proto::RequestMessage {
request_payload: Some(request_payload),
}
.encode_bytes_mut()
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ResponseMessage {
Reg(RegResponseMsg),
Error(ErrorResponseMsg),
ConfirmReg(ConfirmRegResponseMsg),
}
impl ResponseMessage {
pub fn from_slice(buf: &[u8]) -> anyhow::Result<Self> {
let msg = proto::ResponseMessage::decode(buf)?;
let Some(payload) = msg.response_payload else {
bail!("unsupported")
};
match payload {
ResponsePayload::Reg(reg) => Ok(ResponseMessage::Reg(RegResponseMsg::from(reg)?)),
ResponsePayload::Error(e) => Ok(ResponseMessage::Error(ErrorResponseMsg::from(e)?)),
ResponsePayload::ConfirmReg(c) => {
Ok(ResponseMessage::ConfirmReg(ConfirmRegResponseMsg::from(c)?))
}
}
}
pub fn encode(self) -> BytesMut {
let response_payload = match self {
ResponseMessage::Reg(reg) => ResponsePayload::Reg(reg.to()),
ResponseMessage::Error(e) => ResponsePayload::Error(e.to()),
ResponseMessage::ConfirmReg(c) => ResponsePayload::ConfirmReg(c.to()),
};
proto::ResponseMessage {
response_payload: Some(response_payload),
}
.encode_bytes_mut()
}
}
impl SelectiveBroadcast {
pub fn new(ips: &[Ipv4Addr], data: Vec<u8>) -> Self {
SelectiveBroadcast {
ips: ips.iter().map(|v| (*v).into()).collect(),
data,
}
}
}
#[derive(Debug, Clone)]
pub struct ClientSimpleInfo {
pub ip: Ipv4Addr,
pub online: bool,
}
impl ClientSimpleInfo {
pub fn from(msg: proto::ClientSimpleInfo) -> anyhow::Result<Self> {
Ok(Self {
ip: msg.ip.into(),
online: msg.online,
})
}
pub fn to(self) -> proto::ClientSimpleInfo {
proto::ClientSimpleInfo {
ip: self.ip.into(),
online: self.online,
}
}
}
#[derive(Debug)]
pub struct ClientSimpleInfoList {
pub data_version: u64,
pub list: Vec<ClientSimpleInfo>,
pub is_all: bool,
pub time: i64,
}
impl ClientSimpleInfoList {
pub fn from_slice(buf: &[u8]) -> anyhow::Result<Self> {
let msg = proto::ClientSimpleInfoList::decode(buf)?;
let mut list = Vec::with_capacity(msg.list.len());
for x in msg.list {
list.push(ClientSimpleInfo::from(x)?);
}
Ok(Self {
data_version: msg.data_version,
list,
is_all: msg.is_all,
time: msg.time,
})
}
}
+302
View File
@@ -0,0 +1,302 @@
/*
0 15 31
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 1 | msg_type(7) |max ttl(4) |curr ttl(4)| C | G | R | reserve(13) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| seq(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| src ID(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| dest ID(32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| payload(n) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
#![allow(dead_code)]
use crate::protocol::transmission::TransmissionBytes;
use bytes::{Bytes, BytesMut};
use std::io;
use zerocopy::byteorder::{NetworkEndian, U32};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, Unaligned};
#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
#[repr(C)]
pub struct NetHeader {
/// Byte 0: bit7 = 1, bit0..6 = msg_type
pub type_byte: u8,
/// Byte 1: high 4 = max ttl, low 4 = curr ttl
pub ttl_byte: u8,
/// Byte 2: C(0x80) | G(0x40) | reserve
pub flags_byte: u8,
/// Byte 3: reserve
pub _reserved: u8,
pub seq: U32<NetworkEndian>,
pub src_id: U32<NetworkEndian>,
pub dest_id: U32<NetworkEndian>,
}
const COMPRESSED: u8 = 0x80;
const GATEWAY: u8 = 0x40;
const FEC: u8 = 0x20;
impl NetHeader {
#[inline]
pub fn msg_type(&self) -> u8 {
self.type_byte & 0x7F
}
#[inline]
pub fn set_msg_type(&mut self, msg_type: u8) {
self.type_byte = (msg_type & 0x7F) | 0x80;
}
#[inline]
pub fn max_ttl(&self) -> u8 {
self.ttl_byte >> 4
}
#[inline]
pub fn curr_ttl(&self) -> u8 {
self.ttl_byte & 0x0F
}
#[inline]
pub fn set_ttl(&mut self, max: u8, curr: u8) {
self.ttl_byte = (max << 4) | (curr & 0x0F);
}
#[inline]
pub fn decr_ttl(&mut self) {
let curr = self.curr_ttl();
if curr == 0 {
return;
}
self.ttl_byte = (self.ttl_byte & 0xF0) | (curr - 1);
}
fn set_flag(&mut self, mask: u8, val: bool) {
if val {
self.flags_byte |= mask;
} else {
self.flags_byte &= !mask;
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum MsgType {
Turn = 1,
Broadcast = 2,
ExcludeBroadcast = 3,
TargetBroadcast = 4,
Ping = 5,
Pong = 6,
PingTurn = 7,
PongTurn = 8,
PunchStart1 = 9,
PunchStart2 = 10,
PunchReq = 11,
PunchRes = 12,
PushClientIps = 13,
RpcReq = 14,
RpcRes = 15,
Quic = 17,
}
impl From<MsgType> for u8 {
fn from(val: MsgType) -> Self {
val as u8
}
}
impl TryFrom<u8> for MsgType {
type Error = io::Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
let val = match value {
1 => MsgType::Turn,
2 => MsgType::Broadcast,
3 => MsgType::ExcludeBroadcast,
4 => MsgType::TargetBroadcast,
5 => MsgType::Ping,
6 => MsgType::Pong,
7 => MsgType::PingTurn,
8 => MsgType::PongTurn,
9 => MsgType::PunchStart1,
10 => MsgType::PunchStart2,
11 => MsgType::PunchReq,
12 => MsgType::PunchRes,
13 => MsgType::PushClientIps,
14 => MsgType::RpcReq,
15 => MsgType::RpcRes,
17 => MsgType::Quic,
_ => {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("invalid msg type:{value}"),
));
}
};
Ok(val)
}
}
pub const HEAD_LENGTH: usize = std::mem::size_of::<NetHeader>();
pub struct NetPacket<B> {
buffer: B,
}
impl<B: AsRef<[u8]>> NetPacket<B> {
pub fn new(buffer: B) -> io::Result<NetPacket<B>> {
if buffer.as_ref().len() < HEAD_LENGTH {
return Err(io::ErrorKind::InvalidInput.into());
}
Ok(NetPacket { buffer })
}
fn header(&self) -> Ref<&[u8], NetHeader> {
// Safe: NetHeader is Unaligned and length is validated in new()
let (header, _) = Ref::<&[u8], NetHeader>::from_prefix(self.buffer.as_ref()).unwrap();
header
}
pub fn buffer(&self) -> &[u8] {
self.buffer.as_ref()
}
pub fn into_buffer(self) -> B {
self.buffer
}
pub fn source_buf(&self) -> &B {
&self.buffer
}
pub fn msg_type(&self) -> io::Result<MsgType> {
self.header().msg_type().try_into()
}
pub fn max_ttl(&self) -> u8 {
self.header().max_ttl()
}
pub fn ttl(&self) -> u8 {
self.header().curr_ttl()
}
pub fn seq(&self) -> u32 {
self.header().seq.get()
}
pub fn src_id(&self) -> u32 {
self.header().src_id.get()
}
pub fn dest_id(&self) -> u32 {
self.header().dest_id.get()
}
pub fn is_compressed(&self) -> bool {
(self.header().flags_byte & COMPRESSED) != 0
}
pub fn is_gateway(&self) -> bool {
(self.header().flags_byte & GATEWAY) != 0
}
pub fn is_fec(&self) -> bool {
(self.header().flags_byte & FEC) != 0
}
pub fn head(&self) -> &[u8] {
&self.buffer.as_ref()[..HEAD_LENGTH]
}
pub fn payload(&self) -> &[u8] {
&self.buffer.as_ref()[HEAD_LENGTH..]
}
}
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
fn header_mut(&mut self) -> Ref<&mut [u8], NetHeader> {
// Safe: NetHeader is Unaligned and length is validated in new()
let (header, _) = Ref::<&mut [u8], NetHeader>::from_prefix(self.buffer.as_mut()).unwrap();
header
}
pub fn set_msg_type(&mut self, msg_type: MsgType) {
self.header_mut().set_msg_type(msg_type.into());
}
pub fn decr_ttl(&mut self){
self.header_mut().decr_ttl()
}
pub fn set_ttl(&mut self, ttl: u8) {
self.header_mut().set_ttl(ttl, ttl);
}
pub fn set_seq(&mut self, seq: u32) {
self.header_mut().seq.set(seq);
}
pub fn set_src_id(&mut self, id: u32) {
self.header_mut().src_id.set(id);
}
pub fn set_dest_id(&mut self, id: u32) {
self.header_mut().dest_id.set(id);
}
pub fn set_compressed_flag(&mut self, compressed: bool) {
self.header_mut().set_flag(COMPRESSED, compressed);
}
pub fn set_gateway_flag(&mut self, gateway: bool) {
self.header_mut().set_flag(GATEWAY, gateway);
}
pub fn set_fec_flag(&mut self, fec: bool) {
self.header_mut().set_flag(FEC, fec);
}
pub fn set_payload(&mut self, data: &[u8]) -> io::Result<()> {
let buf = self.buffer.as_mut();
if buf.len() < HEAD_LENGTH + data.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Invalid message length",
));
}
buf[HEAD_LENGTH..HEAD_LENGTH + data.len()].copy_from_slice(data);
Ok(())
}
pub fn head_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[..HEAD_LENGTH]
}
pub fn payload_mut(&mut self) -> &mut [u8] {
&mut self.buffer.as_mut()[HEAD_LENGTH..]
}
pub fn source_buf_mut(&mut self) -> &mut B {
&mut self.buffer
}
}
impl Clone for NetPacket<Bytes> {
fn clone(&self) -> Self {
NetPacket {
buffer: self.buffer.clone(),
}
}
}
impl NetPacket<BytesMut> {
pub fn into_bytes(self) -> NetPacket<Bytes> {
NetPacket {
buffer: self.buffer.freeze(),
}
}
}
impl NetPacket<TransmissionBytes> {
pub fn into_bytes(self) -> NetPacket<Bytes> {
NetPacket {
buffer: self.buffer.into_bytes().freeze(),
}
}
}
+21
View File
@@ -0,0 +1,21 @@
use bytes::BytesMut;
use prost::Message;
pub(crate) mod client_message;
pub mod control_message;
pub(crate) mod ip_packet_protocol;
pub(crate) mod rpc_message;
pub(crate) mod transmission;
pub trait ProtoToBytesMut: Message {
fn encode_bytes_mut(&self) -> BytesMut
where
Self: Sized,
{
let mut bytes_mut = BytesMut::with_capacity(self.encoded_len());
self.encode_raw(&mut bytes_mut);
bytes_mut
}
}
impl<T: Message> ProtoToBytesMut for T {}
+4
View File
@@ -0,0 +1,4 @@
mod proto {
include!(concat!(env!("OUT_DIR"), "/protocol.rpc.rs"));
}
pub use proto::*;
+266
View File
@@ -0,0 +1,266 @@
use bytes::{Buf, Bytes, BytesMut};
use std::borrow::{Borrow, BorrowMut};
use std::io;
use std::ops::{Deref, DerefMut};
const DEFAULT_BUF_SIZE: usize = 2048;
#[derive(Clone)]
pub struct TransmissionBytes {
buf: BytesMut,
start: usize,
end: usize,
}
impl From<BytesMut> for TransmissionBytes {
fn from(buf: BytesMut) -> TransmissionBytes {
let end = buf.len();
Self { buf, start: 0, end }
}
}
impl From<Bytes> for TransmissionBytes {
fn from(buf: Bytes) -> TransmissionBytes {
let end = buf.len();
Self {
buf: BytesMut::from(buf),
start: 0,
end,
}
}
}
impl From<&[u8]> for TransmissionBytes {
fn from(buf: &[u8]) -> TransmissionBytes {
let end = buf.len();
Self {
buf: BytesMut::from(buf),
start: 0,
end,
}
}
}
impl TransmissionBytes {
pub fn new_offset(start: usize) -> Self {
TransmissionBytes {
buf: BytesMut::zeroed(DEFAULT_BUF_SIZE),
start,
end: start,
}
}
pub fn new_offset_zeroed(start: usize) -> Self {
TransmissionBytes {
buf: BytesMut::zeroed(DEFAULT_BUF_SIZE),
start,
end: DEFAULT_BUF_SIZE,
}
}
pub fn zeroed(cap: usize) -> Self {
TransmissionBytes {
buf: BytesMut::zeroed(cap),
start: 0,
end: cap,
}
}
pub fn zeroed_size(size: usize, reserve: usize) -> Self {
TransmissionBytes {
buf: BytesMut::zeroed(size + reserve),
start: 0,
end: size,
}
}
#[allow(dead_code)]
pub fn with_capacity(head_room: usize, capacity: usize) -> Self {
TransmissionBytes {
buf: BytesMut::zeroed(capacity),
start: head_room,
end: head_room,
}
}
pub fn len(&self) -> usize {
self.end - self.start
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[allow(dead_code)]
pub fn capacity(&self) -> usize {
self.buf.capacity()
}
/// 头部可用空间(可向前扩展的字节数)
#[inline]
pub fn head_room(&self) -> usize {
self.start
}
/// 尾部可用空间(可向后扩展的字节数)
#[inline]
#[allow(dead_code)]
pub fn tail_room(&self) -> usize {
self.buf.capacity() - self.end
}
#[inline]
fn as_slice(&self) -> &[u8] {
&self.buf[self.start..self.end]
}
#[inline]
fn as_slice_mut(&mut self) -> &mut [u8] {
&mut self.buf[self.start..self.end]
}
pub fn put(&mut self, data: &[u8]) -> io::Result<()> {
let need = data.len();
let free = self.buf.capacity() - self.end;
if need > free {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("data too large:need={need},free={free}"),
));
}
self.buf[self.end..self.end + need].copy_from_slice(data);
self.end += need;
Ok(())
}
pub fn retreat_head(&mut self, len: usize) -> io::Result<()> {
if len > self.head_room() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"retreat_head beyond start: len={len}, head_room={}",
self.head_room()
),
));
}
self.start -= len;
Ok(())
}
pub fn advance_head(&mut self, len: usize) -> io::Result<()> {
if len > self.len() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"advance_head beyond end: len={len}, data_len={}",
self.len()
),
));
}
self.start += len;
Ok(())
}
pub fn set_len(&mut self, new_len: usize) -> io::Result<()> {
let new_end = self.start + new_len;
if new_end > self.buf.capacity() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"set_len exceeds capacity: new_len={new_len}, max={}",
self.buf.capacity() - self.start
),
));
}
self.end = new_end;
Ok(())
}
pub fn resize(&mut self, new_len: usize, value: u8) {
let new_end = self.start + new_len;
self.buf.resize(new_end, value);
self.end = new_end;
}
pub fn extend_end(&mut self, n: usize) {
if self.end + n > self.buf.len() {
self.buf.resize(self.end + n, 0);
}
self.end += n;
}
pub fn shrink_end(&mut self, n: usize) {
if n >= self.end - self.start {
self.end = self.start;
} else {
self.end -= n;
}
}
#[allow(dead_code)]
pub fn clear(&mut self) {
self.start = 0;
self.end = 0;
}
pub fn into_bytes(mut self) -> BytesMut {
self.buf.truncate(self.end);
if self.start > 0 {
self.buf.advance(self.start);
}
self.buf
}
}
impl AsRef<[u8]> for TransmissionBytes {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl Deref for TransmissionBytes {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_ref()
}
}
impl AsMut<[u8]> for TransmissionBytes {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl DerefMut for TransmissionBytes {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
}
impl Borrow<[u8]> for TransmissionBytes {
fn borrow(&self) -> &[u8] {
self.as_ref()
}
}
impl BorrowMut<[u8]> for TransmissionBytes {
fn borrow_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
}
pub trait ShrinkEnd {
fn shrink_end(&mut self, n: usize);
}
pub trait ExtendEnd {
fn extend_end(&mut self, n: usize);
}
impl ShrinkEnd for TransmissionBytes {
fn shrink_end(&mut self, n: usize) {
self.shrink_end(n);
}
}
impl ExtendEnd for TransmissionBytes {
fn extend_end(&mut self, n: usize) {
self.extend_end(n);
}
}
impl ShrinkEnd for &mut TransmissionBytes {
fn shrink_end(&mut self, n: usize) {
TransmissionBytes::shrink_end(self, n);
}
}
impl ExtendEnd for &mut TransmissionBytes {
fn extend_end(&mut self, n: usize) {
TransmissionBytes::extend_end(self, n);
}
}