use getset::Getters;
use nutype::nutype;
use typed_builder::TypedBuilder;
use crate::domain::value::{PaneId, ProcessName};
#[nutype(
validate(
not_empty,
predicate = |identifier: &str| identifier.bytes().all(|byte| byte.is_ascii_alphanumeric()
|| matches!(byte, b'_' | b'-' | b'+' | b'.'))
),
derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Display)
)]
pub struct NotificationId(String);
#[nutype(derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display))]
pub struct NotificationScope(u64);
impl NotificationScope {
pub fn next(self) -> Self {
Self::new(self.into_inner().wrapping_add(1))
}
}
#[derive(Clone, Debug, Getters, TypedBuilder)]
#[getset(get = "pub")]
pub struct Notification {
pane: PaneId,
scope: NotificationScope,
source: ProcessName,
#[builder(default)]
title: Option<String>,
#[builder(default)]
body: Option<String>,
#[builder(default)]
identifier: Option<NotificationId>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kitty_identifiers_accept_only_protocol_safe_characters() {
assert!(NotificationId::try_new("build_1-done+now.").is_ok());
assert!(NotificationId::try_new("").is_err());
assert!(NotificationId::try_new("unsafe/id").is_err());
}
#[test]
fn notification_scopes_advance_without_raw_integer_arithmetic() {
assert_eq!(NotificationScope::new(0).next(), NotificationScope::new(1));
}
}