use std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub struct Media {
#[cfg_attr(feature = "serde", serde(rename = "@id", default))]
pub id: String,
#[cfg_attr(
feature = "serde",
serde(
rename = "display-text",
default,
skip_serializing_if = "Option::is_none"
)
)]
pub display_text: Option<String>,
#[cfg_attr(
feature = "serde",
serde(rename = "type", default, skip_serializing_if = "Option::is_none")
)]
pub media_type: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub label: Option<String>,
#[cfg_attr(
feature = "serde",
serde(rename = "src-id", default, skip_serializing_if = "Option::is_none")
)]
pub src_id: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub status: Option<MediaStatus>,
}
impl Media {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
display_text: None,
media_type: None,
label: None,
src_id: None,
status: None,
}
}
pub fn with_type(mut self, media_type: impl Into<String>) -> Self {
self.media_type = Some(media_type.into());
self
}
pub fn with_status(mut self, status: MediaStatus) -> Self {
self.status = Some(status);
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[non_exhaustive]
pub enum MediaStatus {
#[cfg_attr(feature = "serde", serde(rename = "recvonly"))]
RecvOnly,
#[cfg_attr(feature = "serde", serde(rename = "sendonly"))]
SendOnly,
#[cfg_attr(feature = "serde", serde(rename = "sendrecv"))]
SendRecv,
#[cfg_attr(feature = "serde", serde(rename = "inactive"))]
Inactive,
}
impl fmt::Display for MediaStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Self::RecvOnly => "recvonly",
Self::SendOnly => "sendonly",
Self::SendRecv => "sendrecv",
Self::Inactive => "inactive",
})
}
}
#[derive(Debug, Clone)]
pub struct ParseMediaStatusError(pub String);
impl fmt::Display for ParseMediaStatusError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"invalid media status ({} bytes)",
self.0
.len()
)
}
}
impl std::error::Error for ParseMediaStatusError {}
impl FromStr for MediaStatus {
type Err = ParseMediaStatusError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"recvonly" => Ok(Self::RecvOnly),
"sendonly" => Ok(Self::SendOnly),
"sendrecv" => Ok(Self::SendRecv),
"inactive" => Ok(Self::Inactive),
other => Err(ParseMediaStatusError(other.to_owned())),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "serde")]
use crate::conference_info::assert_serde_wire_names;
use crate::conference_info::assert_wire_names;
const MEDIA_STATUSES: &[MediaStatus] = &[
MediaStatus::RecvOnly,
MediaStatus::SendOnly,
MediaStatus::SendRecv,
MediaStatus::Inactive,
];
const _: fn(MediaStatus) = |v| match v {
MediaStatus::RecvOnly
| MediaStatus::SendOnly
| MediaStatus::SendRecv
| MediaStatus::Inactive => {}
};
#[test]
fn media_status_wire_names() {
assert_wire_names(MEDIA_STATUSES);
#[cfg(feature = "serde")]
assert_serde_wire_names(MEDIA_STATUSES);
}
#[test]
fn media_status_error_display_omits_input() {
let e = "secret"
.parse::<MediaStatus>()
.unwrap_err();
assert_eq!(e.0, "secret");
assert_eq!(e.to_string(), "invalid media status (6 bytes)");
}
}