use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum QuicVersion {
V1,
V2,
Draft(u8),
Other(u32),
}
impl QuicVersion {
#[inline]
pub fn from_raw(value: u32) -> Self {
match value {
0x0000_0001 => Self::V1,
0x6b33_43cf => Self::V2,
v if (0xff00_0000..=0xff00_007f).contains(&v) => Self::Draft((v & 0xff) as u8),
other => Self::Other(other),
}
}
#[inline]
pub fn as_u32(&self) -> u32 {
match self {
Self::V1 => 0x0000_0001,
Self::V2 => 0x6b33_43cf,
Self::Draft(n) => 0xff00_0000 | (*n as u32),
Self::Other(v) => *v,
}
}
#[inline]
pub fn is_v1(&self) -> bool {
matches!(self, Self::V1)
}
#[inline]
pub fn is_v2(&self) -> bool {
matches!(self, Self::V2)
}
#[inline]
pub fn is_draft(&self) -> bool {
matches!(self, Self::Draft(_))
}
}
impl From<u32> for QuicVersion {
#[inline]
fn from(value: u32) -> Self {
Self::from_raw(value)
}
}
impl From<QuicVersion> for u32 {
#[inline]
fn from(value: QuicVersion) -> Self {
value.as_u32()
}
}
impl fmt::Display for QuicVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::V1 => f.write_str("v1"),
Self::V2 => f.write_str("v2"),
Self::Draft(n) => write!(f, "draft-{n:02}"),
Self::Other(v) => write!(f, "0x{v:08x}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct QuicInitial {
pub version: QuicVersion,
pub dcid: Vec<u8>,
pub scid: Vec<u8>,
pub token_present: bool,
pub sni: Option<String>,
pub alpn: Vec<String>,
}