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
use Future;
use Pin;
use crateResult;
use crateBlockMeta;
use crateMessageOutputs;
use crateWorkIo;
/// Send-capable marker for normal runtime blocks.
///
/// This keeps verbose return-type-notation bounds in one place: normal blocks
/// must have a `Send` value, `Send` block-on future, and `Send` futures returned
/// from the kernel lifecycle methods.
/// Processing logic for a block.
///
/// `Kernel` is the central trait custom block authors implement. The
/// `#[derive(Block)]` macro declares stream and message ports from annotated
/// fields and methods; the `Kernel` implementation supplies initialization,
/// work, and shutdown behavior.
///
/// The runtime calls [`Kernel::init`] once, then repeatedly calls
/// [`Kernel::work`] until the block marks itself finished or the flowgraph is
/// stopped, and finally calls [`Kernel::deinit`]. A `work()` implementation
/// should consume and produce exactly the number of stream items it handled and
/// use [`WorkIo`] to request another immediate call, wait on a future, or finish.
///
/// Normal runtime entry points accept only kernels whose value, block-on future,
/// and returned futures are `Send`. Kernels that do not satisfy these bounds can
/// still run in a local domain.
///
/// ```
/// use futuresdr::runtime::dev::prelude::*;
///
/// #[derive(Block)]
/// struct Scale {
/// #[input]
/// input: DefaultCpuReader<f32>,
/// #[output]
/// output: DefaultCpuWriter<f32>,
/// gain: f32,
/// }
///
/// impl Kernel for Scale {
/// async fn work(
/// &mut self,
/// io: &mut WorkIo,
/// _mo: &mut MessageOutputs,
/// _meta: &mut BlockMeta,
/// ) -> Result<()> {
/// let input = self.input.slice();
/// let output = self.output.slice();
/// let n = input.len().min(output.len());
///
/// for i in 0..n {
/// output[i] = input[i] * self.gain;
/// }
///
/// self.input.consume(n);
/// self.output.produce(n);
///
/// if self.input.finished() {
/// io.finished = true;
/// }
///
/// Ok(())
/// }
/// }
/// ```