Skip to main content

rust_elm/
sub.rs

1use std::time::Duration;
2
3/// Subscription descriptions — interpreted in `runtime.rs`.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub enum Sub<M> {
6    None,
7    Tick { id: u64, every: Duration },
8    Stream { id: u64, name: &'static str },
9    WebSocket { id: u64, url: &'static str },
10    MapMsg {
11        inner: Box<Sub<()>>,
12        map: fn(()) -> M,
13    },
14    Batch(Vec<Sub<M>>),
15}
16
17impl<M> Sub<M> {
18    pub fn none() -> Self {
19        Self::None
20    }
21
22    pub fn tick(id: u64, every: Duration) -> Self {
23        Self::Tick { id, every }
24    }
25
26    pub fn stream(id: u64, name: &'static str) -> Self {
27        Self::Stream { id, name }
28    }
29
30    pub fn websocket(id: u64, url: &'static str) -> Self {
31        Self::WebSocket { id, url }
32    }
33
34    pub fn map<N>(self, map: fn(M) -> N) -> Sub<N> {
35        match self {
36            Self::None => Sub::None,
37            Self::Tick { id, every } => Sub::Tick { id, every },
38            Self::Stream { id, name } => Sub::Stream { id, name },
39            Self::WebSocket { id, url } => Sub::WebSocket { id, url },
40            Self::Batch(items) => Sub::Batch(items.into_iter().map(|s| s.map(map)).collect()),
41            Self::MapMsg { .. } => Sub::None,
42        }
43    }
44
45    pub fn batch(subs: impl IntoIterator<Item = Sub<M>>) -> Self {
46        let subs: Vec<_> = subs.into_iter().collect();
47        if subs.is_empty() {
48            Self::None
49        } else if subs.len() == 1 {
50            subs.into_iter().next().unwrap()
51        } else {
52            Self::Batch(subs)
53        }
54    }
55
56    pub fn id(&self) -> Option<u64> {
57        match self {
58            Self::None => None,
59            Self::Tick { id, .. } | Self::Stream { id, .. } | Self::WebSocket { id, .. } => {
60                Some(*id)
61            }
62            Self::MapMsg { inner, .. } => inner.id(),
63            Self::Batch(items) => items.first().and_then(Sub::id),
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn tick_has_stable_id() {
74        let sub = Sub::<u32>::tick(42, Duration::from_secs(1));
75        assert_eq!(sub.id(), Some(42));
76    }
77}