use std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct SfuRid(str0m::media::Rid);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SfuMid(str0m::media::Mid);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SfuPt(str0m::media::Pt);
impl FromStr for SfuRid {
type Err = InvalidRid;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(InvalidRid);
}
if s.len() > 8 {
return Err(InvalidRid);
}
if !s.bytes().all(|b| b.is_ascii_alphanumeric()) {
return Err(InvalidRid);
}
Ok(SfuRid(str0m::media::Rid::from(s)))
}
}
impl fmt::Display for SfuRid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InvalidRid;
impl fmt::Display for InvalidRid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid RID: must be short ASCII")
}
}
impl std::error::Error for InvalidRid {}
#[allow(dead_code)]
impl SfuRid {
pub(crate) fn from_str0m(r: str0m::media::Rid) -> Self {
Self(r)
}
pub(crate) fn to_str0m(self) -> str0m::media::Rid {
self.0
}
pub const LOW: Self = Self(str0m::media::Rid::from_array(*b"q "));
pub const MEDIUM: Self = Self(str0m::media::Rid::from_array(*b"h "));
pub const HIGH: Self = Self(str0m::media::Rid::from_array(*b"f "));
}
#[allow(dead_code)]
impl SfuMid {
pub(crate) fn from_str0m(m: str0m::media::Mid) -> Self {
Self(m)
}
pub(crate) fn to_str0m(self) -> str0m::media::Mid {
self.0
}
}
impl std::str::FromStr for SfuMid {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(str0m::media::Mid::from(s)))
}
}
#[allow(dead_code)]
impl SfuPt {
pub(crate) fn from_str0m(p: str0m::media::Pt) -> Self {
Self(p)
}
pub(crate) fn to_str0m(self) -> str0m::media::Pt {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rid_roundtrip() {
let rid = "h".parse::<SfuRid>().expect("parse h");
assert_eq!(rid.to_string(), "h");
let raw = rid.to_str0m();
let back = SfuRid::from_str0m(raw);
assert_eq!(rid, back);
}
#[test]
fn rid_rejects_empty() {
assert!("".parse::<SfuRid>().is_err());
}
#[test]
fn rid_rejects_non_alphanumeric() {
assert!(SfuRid::from_str("low-res").is_err());
assert!(SfuRid::from_str("a b").is_err());
assert!(SfuRid::from_str("x!").is_err());
}
#[test]
fn rid_rejects_overlong() {
assert!(SfuRid::from_str("123456789").is_err());
}
#[test]
fn rid_accepts_all_alphanumeric() {
for s in &["q", "h", "f", "a1", "LAYER1", "12345678"] {
assert!(SfuRid::from_str(s).is_ok(), "expected {s} to parse");
}
}
#[test]
fn rid_roundtrip_fidelity() {
for s in &["q", "h", "f", "hi1080"] {
let rid: SfuRid = s.parse().expect("parse");
assert_eq!(rid.to_string(), *s);
}
}
#[test]
fn mid_roundtrip() {
let raw = str0m::media::Mid::from("0");
let mid = SfuMid::from_str0m(raw);
assert_eq!(mid.to_str0m(), raw);
}
#[test]
fn pt_roundtrip() {
let raw = str0m::media::Pt::from(96u8);
let pt = SfuPt::from_str0m(raw);
assert_eq!(pt.to_str0m(), raw);
}
}