1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
//! Subscriptions — external event sources wired into the TEA loop.
//!
//! A [`Sub`] pairs an identity string with a [`Stream`] of messages,
//! **or** with a factory that constructs the stream on demand.
//! The identity enables lifecycle management: the runner can diff
//! subscriptions between updates, starting new ones and cancelling
//! stale ones automatically.
//!
//! [`Stream`]: futures_core::Stream
use Pin;
/// Boxed pinned stream used inside the [`Sub`] internal representation.
type BoxStream<Msg> = ;
/// Internal kind: eagerly-owned stream vs. lazy factory.
/// A subscription to an external event source.
///
/// Subscriptions produce messages from outside the normal update cycle:
/// timers, file watchers, channels, WebSocket connections, etc.
///
/// The `id` field is a stable identity for lifecycle management. The
/// optional [`runner`](crate::runner) uses it to diff subscriptions:
/// - Same `id` across updates: keep the existing stream running.
/// - New `id`: start the stream and forward its items as messages.
/// - Missing `id`: cancel the stream.
///
/// If you manage your own event loop, you handle subscription lifecycle
/// yourself — the `id` is just a convenience.
///
/// # Construction
///
/// - [`Sub::new`] — eagerly-owned stream. Stream construction must be
/// **side-effect-free**: `subscriptions()` is called on every update,
/// and a `Sub` whose `id` is already active is dropped without ever
/// being polled. If construction acquires a resource (a channel, a
/// thread registration, a global singleton) you will leak/corrupt
/// that resource on every update iteration.
/// - [`Sub::lazy`] — factory invoked **only at spawn-time**. Use this
/// whenever construction is non-trivial or has side effects.
///
/// # Examples
///
/// ```
/// use osteak::Sub;
///
/// // A subscription from a pre-built, cheap-to-construct stream
/// fn from_stream(stream: impl futures_core::Stream<Item = String> + Send + 'static) -> Sub<String> {
/// Sub::new("messages", stream)
/// }
/// ```