use std::time::Duration;
pub use crate::runtime::subscriptions::SubOp;
#[derive(Debug, Clone)]
#[allow(dead_code)] pub struct Subscription {
pub(crate) kind: SubscriptionKind,
pub(crate) tag: String,
pub(crate) max_rate: Option<u32>,
pub(crate) window_id: Option<String>,
}
#[derive(Debug, Clone)]
#[allow(dead_code)] pub(crate) enum SubscriptionKind {
Every(Duration),
OnKeyPress,
OnKeyRelease,
OnModifiersChanged,
OnWindowClose,
OnWindowEvent,
OnWindowOpen,
OnWindowResize,
OnWindowFocus,
OnWindowUnfocus,
OnWindowMove,
OnPointerMove,
OnPointerButton,
OnPointerScroll,
OnPointerTouch,
OnIme,
OnThemeChange,
OnAnimationFrame,
OnFileDrop,
OnEvent,
}
impl SubscriptionKind {
fn wire_str(&self) -> &'static str {
match self {
Self::Every(_) => "every",
Self::OnKeyPress => "on_key_press",
Self::OnKeyRelease => "on_key_release",
Self::OnModifiersChanged => "on_modifiers_changed",
Self::OnWindowClose => "on_window_close",
Self::OnWindowEvent => "on_window_event",
Self::OnWindowOpen => "on_window_open",
Self::OnWindowResize => "on_window_resize",
Self::OnWindowFocus => "on_window_focus",
Self::OnWindowUnfocus => "on_window_unfocus",
Self::OnWindowMove => "on_window_move",
Self::OnPointerMove => "on_pointer_move",
Self::OnPointerButton => "on_pointer_button",
Self::OnPointerScroll => "on_pointer_scroll",
Self::OnPointerTouch => "on_pointer_touch",
Self::OnIme => "on_ime",
Self::OnThemeChange => "on_theme_change",
Self::OnAnimationFrame => "on_animation_frame",
Self::OnFileDrop => "on_file_drop",
Self::OnEvent => "on_event",
}
}
}
impl Subscription {
pub fn every(interval: Duration, tag: &str) -> Self {
Self {
kind: SubscriptionKind::Every(interval),
tag: tag.to_string(),
max_rate: None,
window_id: None,
}
}
fn renderer(kind: SubscriptionKind) -> Self {
debug_assert!(
!matches!(kind, SubscriptionKind::Every(_)),
"SubscriptionKind::Every is constructed via `Subscription::every`, not `renderer`",
);
let tag = kind.wire_str().to_string();
Self {
kind,
tag,
max_rate: None,
window_id: None,
}
}
pub fn on_key_press() -> Self {
Self::renderer(SubscriptionKind::OnKeyPress)
}
pub fn on_key_release() -> Self {
Self::renderer(SubscriptionKind::OnKeyRelease)
}
pub fn on_modifiers_changed() -> Self {
Self::renderer(SubscriptionKind::OnModifiersChanged)
}
pub fn on_window_close() -> Self {
Self::renderer(SubscriptionKind::OnWindowClose)
}
pub fn on_window_event() -> Self {
Self::renderer(SubscriptionKind::OnWindowEvent)
}
pub fn on_window_open() -> Self {
Self::renderer(SubscriptionKind::OnWindowOpen)
}
pub fn on_window_resize() -> Self {
Self::renderer(SubscriptionKind::OnWindowResize)
}
pub fn on_window_focus() -> Self {
Self::renderer(SubscriptionKind::OnWindowFocus)
}
pub fn on_window_unfocus() -> Self {
Self::renderer(SubscriptionKind::OnWindowUnfocus)
}
pub fn on_window_move() -> Self {
Self::renderer(SubscriptionKind::OnWindowMove)
}
pub fn on_pointer_move() -> Self {
Self::renderer(SubscriptionKind::OnPointerMove)
}
pub fn on_pointer_button() -> Self {
Self::renderer(SubscriptionKind::OnPointerButton)
}
pub fn on_pointer_scroll() -> Self {
Self::renderer(SubscriptionKind::OnPointerScroll)
}
pub fn on_pointer_touch() -> Self {
Self::renderer(SubscriptionKind::OnPointerTouch)
}
pub fn on_ime() -> Self {
Self::renderer(SubscriptionKind::OnIme)
}
pub fn on_theme_change() -> Self {
Self::renderer(SubscriptionKind::OnThemeChange)
}
pub fn on_animation_frame() -> Self {
Self::renderer(SubscriptionKind::OnAnimationFrame)
}
pub fn on_file_drop() -> Self {
Self::renderer(SubscriptionKind::OnFileDrop)
}
pub fn on_event() -> Self {
Self::renderer(SubscriptionKind::OnEvent)
}
pub fn for_window(mut self, window_id: &str) -> Self {
self.window_id = Some(window_id.to_string());
if !matches!(self.kind, SubscriptionKind::Every(_)) {
self.tag = format!("{window_id}#{}", self.kind.wire_str());
}
self
}
pub fn window_group(
window_id: &str,
subs: impl IntoIterator<Item = Subscription>,
) -> Vec<Subscription> {
subs.into_iter().map(|s| s.for_window(window_id)).collect()
}
pub fn max_rate(mut self, rate: u32) -> Self {
self.max_rate = Some(rate);
self
}
pub fn tag(&self) -> &str {
&self.tag
}
pub fn kind(&self) -> &'static str {
self.kind.wire_str()
}
pub fn max_rate_hint(&self) -> Option<u32> {
self.max_rate
}
pub fn window_id(&self) -> Option<&str> {
self.window_id.as_deref()
}
pub fn interval(&self) -> Option<Duration> {
match self.kind {
SubscriptionKind::Every(d) => Some(d),
_ => None,
}
}
pub(crate) fn diff_key(&self) -> (&'static str, &str) {
(self.kind(), &self.tag)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn window_group_scopes_each_subscription() {
let subs = Subscription::window_group(
"secondary",
vec![
Subscription::on_key_press(),
Subscription::on_pointer_move(),
],
);
assert_eq!(subs.len(), 2);
for sub in &subs {
assert_eq!(sub.window_id.as_deref(), Some("secondary"));
assert!(sub.tag.starts_with("secondary#"));
}
}
#[test]
fn for_window_chains_on_single_subscription() {
let sub = Subscription::on_key_press().for_window("main");
assert_eq!(sub.window_id.as_deref(), Some("main"));
assert_eq!(sub.tag(), "main#on_key_press");
}
#[test]
fn for_window_keeps_timer_tag() {
let sub = Subscription::every(Duration::from_millis(16), "tick").for_window("main");
assert_eq!(sub.window_id.as_deref(), Some("main"));
assert_eq!(sub.tag(), "tick");
}
}