use std::{fmt, str::FromStr};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Urgency {
Low = 0,
Normal = 1,
Critical = 2,
}
impl From<u8> for Urgency {
fn from(value: u8) -> Self {
match value {
0 => Self::Low,
2 => Self::Critical,
_ => Self::Normal,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum ClosedReason {
Expired = 1,
DismissedByUser = 2,
Closed = 3,
Unknown = 4,
}
impl From<u32> for ClosedReason {
fn from(value: u32) -> Self {
match value {
1 => Self::Expired,
2 => Self::DismissedByUser,
3 => Self::Closed,
_ => Self::Unknown,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Capabilities {
ActionIcons,
Actions,
Body,
BodyHyperlinks,
BodyImages,
BodyMarkup,
IconMulti,
IconStatic,
Persistence,
Sound,
Vendor(String),
}
impl FromStr for Capabilities {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"action-icons" => Self::ActionIcons,
"actions" => Self::Actions,
"body" => Self::Body,
"body-hyperlinks" => Self::BodyHyperlinks,
"body-images" => Self::BodyImages,
"body-markup" => Self::BodyMarkup,
"icon-multi" => Self::IconMulti,
"icon-static" => Self::IconStatic,
"persistence" => Self::Persistence,
"sound" => Self::Sound,
s if s.starts_with("x-") => Self::Vendor(s.to_string()),
_ => Self::Vendor(format!("x-unknown-{s}")),
})
}
}
impl Capabilities {
pub fn as_str(&self) -> &str {
match self {
Self::ActionIcons => "action-icons",
Self::Actions => "actions",
Self::Body => "body",
Self::BodyHyperlinks => "body-hyperlinks",
Self::BodyImages => "body-images",
Self::BodyMarkup => "body-markup",
Self::IconMulti => "icon-multi",
Self::IconStatic => "icon-static",
Self::Persistence => "persistence",
Self::Sound => "sound",
Self::Vendor(s) => s,
}
}
}
impl fmt::Display for Capabilities {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Category {
Call,
CallEnded,
CallIncoming,
CallUnanswered,
Device,
DeviceAdded,
DeviceError,
DeviceRemoved,
Email,
EmailArrived,
EmailBounced,
Im,
ImError,
ImReceived,
Network,
NetworkConnected,
NetworkDisconnected,
NetworkError,
Presence,
PresenceOffline,
PresenceOnline,
Transfer,
TransferComplete,
TransferError,
Vendor(String),
}
impl FromStr for Category {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"call" => Self::Call,
"call.ended" => Self::CallEnded,
"call.incoming" => Self::CallIncoming,
"call.unanswered" => Self::CallUnanswered,
"device" => Self::Device,
"device.added" => Self::DeviceAdded,
"device.error" => Self::DeviceError,
"device.removed" => Self::DeviceRemoved,
"email" => Self::Email,
"email.arrived" => Self::EmailArrived,
"email.bounced" => Self::EmailBounced,
"im" => Self::Im,
"im.error" => Self::ImError,
"im.received" => Self::ImReceived,
"network" => Self::Network,
"network.connected" => Self::NetworkConnected,
"network.disconnected" => Self::NetworkDisconnected,
"network.error" => Self::NetworkError,
"presence" => Self::Presence,
"presence.offline" => Self::PresenceOffline,
"presence.online" => Self::PresenceOnline,
"transfer" => Self::Transfer,
"transfer.complete" => Self::TransferComplete,
"transfer.error" => Self::TransferError,
s if s.starts_with("x-") => Self::Vendor(s.to_string()),
_ => Self::Vendor(format!("x-unknown-{s}")),
})
}
}
impl Category {
pub fn as_str(&self) -> &str {
match self {
Self::Call => "call",
Self::CallEnded => "call.ended",
Self::CallIncoming => "call.incoming",
Self::CallUnanswered => "call.unanswered",
Self::Device => "device",
Self::DeviceAdded => "device.added",
Self::DeviceError => "device.error",
Self::DeviceRemoved => "device.removed",
Self::Email => "email",
Self::EmailArrived => "email.arrived",
Self::EmailBounced => "email.bounced",
Self::Im => "im",
Self::ImError => "im.error",
Self::ImReceived => "im.received",
Self::Network => "network",
Self::NetworkConnected => "network.connected",
Self::NetworkDisconnected => "network.disconnected",
Self::NetworkError => "network.error",
Self::Presence => "presence",
Self::PresenceOffline => "presence.offline",
Self::PresenceOnline => "presence.online",
Self::Transfer => "transfer",
Self::TransferComplete => "transfer.complete",
Self::TransferError => "transfer.error",
Self::Vendor(s) => s,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Action {
pub id: String,
pub label: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn urgency_from_u8_with_zero_returns_low() {
let result = Urgency::from(0);
assert_eq!(result, Urgency::Low);
}
#[test]
fn urgency_from_u8_with_two_returns_critical() {
let result = Urgency::from(2);
assert_eq!(result, Urgency::Critical);
}
#[test]
fn urgency_from_u8_with_one_returns_normal() {
let result = Urgency::from(1);
assert_eq!(result, Urgency::Normal);
}
#[test]
fn urgency_from_u8_with_five_returns_normal() {
let result = Urgency::from(5);
assert_eq!(result, Urgency::Normal);
}
#[test]
fn closed_reason_from_u32_with_one_returns_expired() {
let result = ClosedReason::from(1);
assert_eq!(result, ClosedReason::Expired);
}
#[test]
fn closed_reason_from_u32_with_two_returns_dismissed_by_user() {
let result = ClosedReason::from(2);
assert_eq!(result, ClosedReason::DismissedByUser);
}
#[test]
fn closed_reason_from_u32_with_three_returns_closed() {
let result = ClosedReason::from(3);
assert_eq!(result, ClosedReason::Closed);
}
#[test]
fn closed_reason_from_u32_with_zero_returns_unknown() {
let result = ClosedReason::from(0);
assert_eq!(result, ClosedReason::Unknown);
}
#[test]
fn closed_reason_from_u32_with_five_returns_unknown() {
let result = ClosedReason::from(5);
assert_eq!(result, ClosedReason::Unknown);
}
#[test]
fn capabilities_from_str_with_action_icons_returns_correct_variant() {
let result = "action-icons".parse::<Capabilities>().unwrap();
assert_eq!(result, Capabilities::ActionIcons);
}
#[test]
fn capabilities_from_str_with_actions_returns_correct_variant() {
let result = "actions".parse::<Capabilities>().unwrap();
assert_eq!(result, Capabilities::Actions);
}
#[test]
fn capabilities_from_str_with_persistence_returns_correct_variant() {
let result = "persistence".parse::<Capabilities>().unwrap();
assert_eq!(result, Capabilities::Persistence);
}
#[test]
fn capabilities_from_str_with_vendor_prefix_returns_vendor() {
let result = "x-custom-cap".parse::<Capabilities>().unwrap();
assert_eq!(result, Capabilities::Vendor("x-custom-cap".to_string()));
}
#[test]
fn capabilities_from_str_with_unknown_wraps_in_vendor_format() {
let result = "unknown-capability".parse::<Capabilities>().unwrap();
assert_eq!(
result,
Capabilities::Vendor("x-unknown-unknown-capability".to_string())
);
}
#[test]
fn capabilities_as_str_for_action_icons_returns_correct_string() {
let cap = Capabilities::ActionIcons;
let result = cap.as_str();
assert_eq!(result, "action-icons");
}
#[test]
fn capabilities_as_str_for_persistence_returns_correct_string() {
let cap = Capabilities::Persistence;
let result = cap.as_str();
assert_eq!(result, "persistence");
}
#[test]
fn capabilities_as_str_with_vendor_returns_inner_string() {
let cap = Capabilities::Vendor("x-custom".to_string());
let result = cap.as_str();
assert_eq!(result, "x-custom");
}
#[test]
fn category_from_str_with_call_returns_correct_variant() {
let result = "call".parse::<Category>().unwrap();
assert_eq!(result, Category::Call);
}
#[test]
fn category_from_str_with_email_arrived_returns_correct_variant() {
let result = "email.arrived".parse::<Category>().unwrap();
assert_eq!(result, Category::EmailArrived);
}
#[test]
fn category_from_str_with_network_error_returns_correct_variant() {
let result = "network.error".parse::<Category>().unwrap();
assert_eq!(result, Category::NetworkError);
}
#[test]
fn category_from_str_with_vendor_prefix_returns_vendor() {
let result = "x-custom-category".parse::<Category>().unwrap();
assert_eq!(result, Category::Vendor("x-custom-category".to_string()));
}
#[test]
fn category_from_str_with_unknown_wraps_in_vendor_format() {
let result = "unknown-category".parse::<Category>().unwrap();
assert_eq!(
result,
Category::Vendor("x-unknown-unknown-category".to_string())
);
}
#[test]
fn category_as_str_for_call_returns_correct_string() {
let cat = Category::Call;
let result = cat.as_str();
assert_eq!(result, "call");
}
#[test]
fn category_as_str_for_email_arrived_returns_correct_string() {
let cat = Category::EmailArrived;
let result = cat.as_str();
assert_eq!(result, "email.arrived");
}
#[test]
fn category_as_str_with_vendor_returns_inner_string() {
let cat = Category::Vendor("x-custom".to_string());
let result = cat.as_str();
assert_eq!(result, "x-custom");
}
}