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
use Future;
use Pin;
use crateResult;
use crateBlockMeta;
use crateMessageOutputs;
use crateWorkIo;
use crateKernelInterface;
/// 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 and generated block interface.
/// 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 or finish. Blocks that need
/// to wait on their own future can provide it through [`Kernel::block_on`].
///
/// 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: &BlockMeta,
/// ) -> Result<()> {
/// let input = self.input.slice();
/// let output = self.output.slice();
/// let input_len = input.len();
/// 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() && n == input_len {
/// io.finished = true;
/// }
///
/// Ok(())
/// }
/// }
/// ```