use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NotificationType {
NotImplemented,
NotSupported,
Warning,
Error,
}
impl fmt::Display for NotificationType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotImplemented => write!(f, "NotImplemented"),
Self::NotSupported => write!(f, "NotSupported"),
Self::Warning => write!(f, "Warning"),
Self::Error => write!(f, "Error"),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Notification {
pub notification_type: NotificationType,
pub message: String,
}
impl Notification {
pub fn new(notification_type: NotificationType, message: impl Into<String>) -> Self {
Self {
notification_type,
message: message.into(),
}
}
}
impl fmt::Display for Notification {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}] {}", self.notification_type, self.message)
}
}
#[derive(Debug, Clone, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NotificationCollection {
items: Vec<Notification>,
}
impl NotificationCollection {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn notify(&mut self, notification_type: NotificationType, message: impl Into<String>) {
self.items.push(Notification::new(notification_type, message));
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn iter(&self) -> std::slice::Iter<'_, Notification> {
self.items.iter()
}
pub fn of_type(&self, nt: NotificationType) -> Vec<&Notification> {
self.items.iter().filter(|n| n.notification_type == nt).collect()
}
pub fn has_type(&self, nt: NotificationType) -> bool {
self.items.iter().any(|n| n.notification_type == nt)
}
pub fn extend(&mut self, other: NotificationCollection) {
self.items.extend(other.items);
}
pub fn into_vec(self) -> Vec<Notification> {
self.items
}
}
impl IntoIterator for NotificationCollection {
type Item = Notification;
type IntoIter = std::vec::IntoIter<Notification>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<'a> IntoIterator for &'a NotificationCollection {
type Item = &'a Notification;
type IntoIter = std::slice::Iter<'a, Notification>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_notification_creation() {
let n = Notification::new(NotificationType::Warning, "handle missing");
assert_eq!(n.notification_type, NotificationType::Warning);
assert_eq!(n.message, "handle missing");
}
#[test]
fn test_collection_basics() {
let mut c = NotificationCollection::new();
assert!(c.is_empty());
c.notify(NotificationType::Warning, "w1");
c.notify(NotificationType::Error, "e1");
c.notify(NotificationType::Warning, "w2");
assert_eq!(c.len(), 3);
assert_eq!(c.of_type(NotificationType::Warning).len(), 2);
assert!(c.has_type(NotificationType::Error));
assert!(!c.has_type(NotificationType::NotImplemented));
}
#[test]
fn test_display() {
let n = Notification::new(NotificationType::NotImplemented, "THUMBNAILIMAGE section");
assert_eq!(format!("{}", n), "[NotImplemented] THUMBNAILIMAGE section");
}
}