use crate::varint::VarInt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DraftVersion {
Draft07,
Draft08,
Draft09,
Draft10,
Draft11,
Draft12,
Draft13,
Draft14,
Draft15,
Draft16,
Draft17,
}
impl DraftVersion {
pub fn version_varint(&self) -> VarInt {
let n = match self {
DraftVersion::Draft07 => 7,
DraftVersion::Draft08 => 8,
DraftVersion::Draft09 => 9,
DraftVersion::Draft10 => 10,
DraftVersion::Draft11 => 11,
DraftVersion::Draft12 => 12,
DraftVersion::Draft13 => 13,
DraftVersion::Draft14 => 14,
DraftVersion::Draft15 => 15,
DraftVersion::Draft16 => 16,
DraftVersion::Draft17 => 17,
};
VarInt::from_usize(0xff000000 + n as usize)
}
pub fn quic_alpn(&self) -> &'static [u8] {
match self {
DraftVersion::Draft07
| DraftVersion::Draft08
| DraftVersion::Draft09
| DraftVersion::Draft10
| DraftVersion::Draft11
| DraftVersion::Draft12
| DraftVersion::Draft13
| DraftVersion::Draft14 => b"moq-00",
DraftVersion::Draft15 => b"moqt-15",
DraftVersion::Draft16 => b"moqt-16",
DraftVersion::Draft17 => b"moqt-17",
}
}
pub fn from_alpn(alpn: &[u8]) -> Option<DraftVersion> {
match alpn {
b"moqt-15" => Some(DraftVersion::Draft15),
b"moqt-16" => Some(DraftVersion::Draft16),
b"moqt-17" => Some(DraftVersion::Draft17),
_ => None,
}
}
pub fn from_number(n: u8) -> Option<DraftVersion> {
match n {
7 => Some(DraftVersion::Draft07),
8 => Some(DraftVersion::Draft08),
9 => Some(DraftVersion::Draft09),
10 => Some(DraftVersion::Draft10),
11 => Some(DraftVersion::Draft11),
12 => Some(DraftVersion::Draft12),
13 => Some(DraftVersion::Draft13),
14 => Some(DraftVersion::Draft14),
15 => Some(DraftVersion::Draft15),
16 => Some(DraftVersion::Draft16),
17 => Some(DraftVersion::Draft17),
_ => None,
}
}
pub fn uses_fixed_length_framing(&self) -> bool {
self.number() >= 11
}
pub fn number(&self) -> u8 {
match self {
DraftVersion::Draft07 => 7,
DraftVersion::Draft08 => 8,
DraftVersion::Draft09 => 9,
DraftVersion::Draft10 => 10,
DraftVersion::Draft11 => 11,
DraftVersion::Draft12 => 12,
DraftVersion::Draft13 => 13,
DraftVersion::Draft14 => 14,
DraftVersion::Draft15 => 15,
DraftVersion::Draft16 => 16,
DraftVersion::Draft17 => 17,
}
}
}
impl std::fmt::Display for DraftVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "draft-{:02}", self.number())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_alpn_resolves_drafts_15_plus() {
assert_eq!(DraftVersion::from_alpn(b"moqt-15"), Some(DraftVersion::Draft15));
assert_eq!(DraftVersion::from_alpn(b"moqt-16"), Some(DraftVersion::Draft16));
assert_eq!(DraftVersion::from_alpn(b"moqt-17"), Some(DraftVersion::Draft17));
}
#[test]
fn from_alpn_none_for_moq_00_and_unknown() {
assert_eq!(DraftVersion::from_alpn(b"moq-00"), None);
assert_eq!(DraftVersion::from_alpn(b"h3"), None);
assert_eq!(DraftVersion::from_alpn(b""), None);
assert_eq!(DraftVersion::from_alpn(b"moqt-99"), None);
}
#[test]
fn from_alpn_round_trips_with_quic_alpn() {
for d in [DraftVersion::Draft15, DraftVersion::Draft16, DraftVersion::Draft17] {
assert_eq!(DraftVersion::from_alpn(d.quic_alpn()), Some(d));
}
}
#[test]
fn from_number_resolves_supported_range() {
for n in 7..=17u8 {
assert!(DraftVersion::from_number(n).is_some(), "draft {n} should resolve");
}
}
#[test]
fn from_number_none_outside_range() {
assert_eq!(DraftVersion::from_number(0), None);
assert_eq!(DraftVersion::from_number(6), None);
assert_eq!(DraftVersion::from_number(18), None);
assert_eq!(DraftVersion::from_number(255), None);
}
}