Expand description
This crate provides the [shadowquic::SEncode] and [shadowquic::SDecode] derive macros.
These two macros automatically implement the SEncode and SDecode traits for structs and enums as long as
the member or variants are themselves SEncode or SDecode.
Below is the example of how to use, below example defines the protocol header for socks5 address.
use shadowquic_macros::{SDecode, SEncode};
use shadowquic::msgs::{SDecode, SEncode};
use shadowquic::error::SError;
/// derive SDecode and SEncode automatically.
#[derive(SDecode, SEncode)]
pub struct SocksAddr {
pub addr: AddrOrDomain,
pub port: u16,
}
/// SDecode/SEncode will define SDecode/SEncode automatically.
/// `#[repr(u8)]` is required to specify the type of discriminant for enum.
#[derive(SDecode, SEncode)]
#[repr(u8)]
pub enum AddrOrDomain {
V4([u8; 4]) = 0x1,
V6([u8; 16]) = 0x4,
Domain(VarVec) = 0x3,
}
/// You need to define SEncode/SDecode traits yourself
/// since they are not defined for Vec.
pub struct VarVec {
pub len: u8,
pub contents: Vec<u8>,
}You can send the socks5 address by
let addr: SocksAddr = ...;
let mut tcp_stream: TcpStream = ...;
addr.encode(&mut tcp_stream).await?;or you can receive the socks5 address by
let mut tcp_stream: TcpStream = ...;
let addr = SocksAddr::decode(&mut tcp_stream).await?;Based on these two macros, you can easily define your own protocol header and implement them fast and clean.
Structs may use #[size_tag] with both derives to prefix the encoded struct
payload with a u32 byte length. During decode, the tagged payload is read
before the fields are decoded. If the payload is longer than the current
struct definition needs, trailing bytes are ignored. If the payload is
shorter, missing trailing bytes are read as zeroes up to a bounded
compatibility limit. This allows fields to be appended to size-tagged structs
while still decoding older messages.
Check [shadowquic::msgs::socks5] to see how socks5 protocol header is defined.
A full protocol implementation can be seen in [shadowquic::socks] module
Derive Macros§
- SDecode
- Derive [
shadowquic::SDecode] automatically for the struct or enum. For struct, it decodes each field in order. For enum, it first decodes a u8/u16… defined by#[repr(*)]as discriminant and then decodes the content based on the value of disriminant. For enum variants, at most one field is supported. Named field/or tuple field is not supported for enum.#[repr(*)]is required for enum to specify the type of discriminant. For structs,#[size_tag]reads au32byte length before the field payload, ignores trailing payload bytes, and zero-pads missing trailing bytes up to a bounded compatibility limit. - SEncode
- Derive [
shadowquic::SEncode] automatically for the struct or enum. For struct, it encodes each field in order. For enum, it first encodes the discriminant as a u8/u16… defined by#[repr(*)]and then encodes the content based on the value of disriminant. For enum variants, at most one field is supported. Named field/or tuple field is not supported for enum.#[repr(*)]is required for enum to specify the type of discriminant. For structs,#[size_tag]prefixes the encoded field payload with au32byte length.