Skip to main content

std_mel/flow/
mod.rs

1use futures::{pin_mut, select, FutureExt};
2use melodium_core::common::executive::{InputExt, OutputExt, Value};
3use melodium_macro::{check, mel_treatment};
4use std::collections::VecDeque;
5
6pub mod concentrate;
7pub mod vec;
8
9/// Chain two streams.
10///
11///
12/// ```mermaid
13/// graph LR
14///     T("chain()")
15///     A["🟨 🟨 🟨 🟨 🟨 🟨"] -->|first| T
16///     B["… 🟪 🟪 🟪"] -->|second| T
17///     
18///     T -->|chained| O["… 🟪 🟪 🟪 🟨 🟨 🟨 🟨 🟨 🟨"]
19///
20///     style A fill:#ffffff,stroke:#ffffff
21///     style B fill:#ffffff,stroke:#ffffff
22///     style O fill:#ffffff,stroke:#ffffff
23/// ```
24#[mel_treatment(
25    generic T ()
26    input first Stream<T>
27    input second Stream<T>
28    output chained Stream<T>
29)]
30pub async fn chain() {
31    while let Ok(values) = first.recv_many().await {
32        check!(chained.send_many(values).await)
33    }
34
35    while let Ok(values) = second.recv_many().await {
36        check!(chained.send_many(values).await)
37    }
38}
39
40/// Trigger on a stream start and end.
41///
42/// Emit `start` when a first value is send through the stream.
43/// Emit `end` when stream is finally over.
44///
45/// Emit `first` with the first value coming in the stream.
46/// Emit `last` with the last value coming in the stream.
47///
48/// ℹ️ `start` and `first` are always emitted together.
49/// If the stream only contains one element, `first` and `last` both contains it.
50/// If the stream never transmit any data before being ended, only `end` is emitted.
51///
52/// ```mermaid
53/// graph LR
54///     T("trigger()")
55///     B["🟥 … 🟨 🟨 🟨 🟨 🟨 🟨 … 🟩"] -->|stream| T
56///     
57///     T -->|start| S["〈🟦〉"]
58///     T -->|first| F["〈🟩〉"]
59///     T -->|last| L["〈🟥〉"]
60///     T -->|end| E["〈🟦〉"]
61///
62///     style B fill:#ffffff,stroke:#ffffff
63///     style S fill:#ffffff,stroke:#ffffff
64///     style F fill:#ffffff,stroke:#ffffff
65///     style L fill:#ffffff,stroke:#ffffff
66///     style E fill:#ffffff,stroke:#ffffff
67/// ```
68#[mel_treatment(
69    generic T ()
70    input stream Stream<T>
71    output start Block<void>
72    output end Block<void>
73    output first Block<T>
74    output last Block<T>
75)]
76pub async fn trigger() {
77    let mut last_value = None;
78
79    if let Ok(mut values) = stream.recv_many().await {
80        let _ = start.send_one_as(()).await;
81        if let Some(val) = values.pop_front() {
82            let _ = first.send_one(val.clone()).await;
83            last_value = Some(val);
84        }
85        if let Some(val) = Into::<VecDeque<Value>>::into(values).pop_back() {
86            last_value = Some(val);
87        }
88
89        let _ = futures::join!(start.close(), first.close());
90    }
91
92    while let Ok(values) = stream.recv_many().await {
93        last_value = Into::<VecDeque<Value>>::into(values).pop_back();
94    }
95
96    let _ = end.send_one_as(()).await;
97    if let Some(val) = last_value {
98        let _ = last.send_one(val).await;
99    }
100
101    // We don't close `end` and `last` explicitly here,
102    // because it would be redundant with boilerplate
103    // implementation of treatments.
104}
105
106/// Check a blocking value.
107///
108/// When `value` block is received, `check` is emitted.
109///
110/// ```mermaid
111/// graph LR
112///     T("check()")
113///     B["〈🟨〉"] -->|value| T
114///         
115///     T -->|check| S["〈🟦〉"]
116///     
117///     style B fill:#ffffff,stroke:#ffffff
118///     style S fill:#ffffff,stroke:#ffffff
119/// ```
120#[mel_treatment(
121    generic T ()
122    input value Block<T>
123    output check Block<void>
124)]
125pub async fn check() {
126    if let Ok(_) = value.recv_one().await {
127        let _ = check.send_one_as(()).await;
128    }
129}
130
131/// Uncheck a blocking value.
132///
133/// When `value` block stream is closed without receiving anything, `uncheck` is emitted.
134///
135/// ```mermaid
136/// graph LR
137///     T("uncheck()")
138///     B["〈🟨〉"] -->|value| T
139///         
140///     T -->|uncheck| S["〈🟦〉"]
141///     
142///     style B fill:#ffffff,stroke:#ffffff
143///     style S fill:#ffffff,stroke:#ffffff
144/// ```
145#[mel_treatment(
146    generic T ()
147    input value Block<T>
148    output uncheck Block<void>
149)]
150pub async fn uncheck() {
151    if let Err(_) = value.recv_one().await {
152        let _ = uncheck.send_one_as(()).await;
153    }
154}
155
156/// Emit a blocking value.
157///
158/// When `trigger` is enabled, `value` is emitted as block.
159///
160/// ```mermaid
161/// graph LR
162///     T("emit(value=🟨)")
163///     B["〈🟦〉"] -->|trigger| T
164///         
165///     T -->|emit| S["〈🟨〉"]
166///     
167///     style B fill:#ffffff,stroke:#ffffff
168///     style S fill:#ffffff,stroke:#ffffff
169/// ```
170#[mel_treatment(
171    generic T ()
172    input trigger Block<void>
173    output emit Block<T>
174)]
175pub async fn emit(value: T) {
176    if let Ok(_) = trigger.recv_one().await {
177        let _ = emit.send_one(value).await;
178    }
179}
180
181/// Stream a blocking value.
182///
183/// ```mermaid
184/// graph LR
185///     T("stream()")
186///     B["〈🟦〉"] -->|block| T
187///         
188///     T -->|stream| S["🟦"]
189///     
190///     
191///     style B fill:#ffffff,stroke:#ffffff
192///     style S fill:#ffffff,stroke:#ffffff
193/// ```
194#[mel_treatment(
195    generic T ()
196    input block Block<T>
197    output stream Stream<T>
198)]
199pub async fn stream() {
200    if let Ok(val) = block.recv_one().await {
201        let _ = stream.send_one(val).await;
202    }
203}
204
205/// Merge two streams.
206///
207/// The two streams are merged without predictible order.
208///
209/// ℹ️ Merge continues as long as `a` or `b` continues too, while the other can be ended.
210///
211/// ```mermaid
212/// graph LR
213///     T("merge()")
214///     A["… 🟦 🟫 …"] -->|a| T
215///     B["… 🟧 🟪 🟨 …"] -->|b| T
216///     
217///
218///     T -->|value| V["… 🟦 🟧 🟪 🟫 🟨 …"]
219///
220///     style V fill:#ffffff,stroke:#ffffff
221///     style A fill:#ffffff,stroke:#ffffff
222///     style B fill:#ffffff,stroke:#ffffff
223/// ```
224#[mel_treatment(
225    generic T ()
226    input a Stream<T>
227    input b Stream<T>
228    output value Stream<T>
229)]
230pub async fn merge() {
231    let xa = async {
232        while let Ok(a) = (&a).recv_many().await {
233            check!(value.send_many(a).await);
234        }
235    }
236    .fuse();
237    let xb = async {
238        while let Ok(b) = (&b).recv_many().await {
239            check!(value.send_many(b).await);
240        }
241    }
242    .fuse();
243
244    pin_mut!(xa, xb);
245
246    loop {
247        select! {
248            () = xa => {},
249            () = xb => {},
250            complete => break,
251        };
252    }
253}
254
255/// Arrange two streams as one.
256///
257/// The two streams are merged using the `select` stream:
258/// - when `true`, value from `a` is used;
259/// - when `false`, value from `b` is used.
260///
261/// ℹ️ No value from either `a` or `b` are discarded, they are used when `select` give turn.
262///
263/// ⚠️ When `select` ends merge terminates without treating the remaining values from `a` and `b`.
264/// When `select` give turn to `a` or `b` while the concerned stream is ended, the merge terminates.
265/// Merge continues as long as `select` and concerned stream does, while the other can be ended.
266///
267/// ```mermaid
268/// graph LR
269///     T("arrange()")
270///     A["… 🟦 🟫 …"] -->|a| T
271///     B["… 🟧 🟪 🟨 …"] -->|b| T
272///     O["… 🟩 🟥 🟥 🟩 🟥 …"] -->|select|T
273///     
274///
275///     T -->|value| V["… 🟦 🟧 🟪 🟫 🟨 …"]
276///
277///     style V fill:#ffffff,stroke:#ffffff
278///     style O fill:#ffffff,stroke:#ffffff
279///     style A fill:#ffffff,stroke:#ffffff
280///     style B fill:#ffffff,stroke:#ffffff
281/// ```
282#[mel_treatment(
283    generic T ()
284    input a Stream<T>
285    input b Stream<T>
286    input select Stream<bool>
287    output value Stream<T>
288)]
289pub async fn arrange() {
290    while let Ok(select) = select.recv_one_as::<bool>().await {
291        let val;
292        if select {
293            if let Ok(v) = a.recv_one().await {
294                val = v;
295            } else {
296                break;
297            }
298        } else {
299            if let Ok(v) = b.recv_one().await {
300                val = v;
301            } else {
302                break;
303            }
304        }
305
306        check!(value.send_one(val).await)
307    }
308}
309
310/// Fill a pattern stream with a `value.
311///
312/// ```mermaid
313/// graph LR
314/// T("fill(value=🟧)")
315/// B["… 🟦 🟦 🟦 …"] -->|pattern| T
316///
317/// T -->|filled| O["… 🟧 🟧 🟧 …"]
318///
319/// style B fill:#ffffff,stroke:#ffffff
320/// style O fill:#ffffff,stroke:#ffffff
321/// ```
322#[mel_treatment(
323    generic T ()
324    input pattern Stream<void>
325    output filled Stream<T>
326)]
327pub async fn fill(value: T) {
328    while let Ok(pat) = pattern.recv_many().await {
329        let mut transmission = melodium_core::TransmissionValue::new(value.clone());
330        for _ in 1..pat.len() {
331            transmission.push(value.clone());
332        }
333        check!(filled.send_many(transmission).await)
334    }
335}
336
337/// Filter a stream according to `bool` stream.
338///
339/// ℹ️ If both streams are not the same size nothing is sent through accepted nor rejected.
340///  
341/// ```mermaid
342/// graph LR
343///     T("filter()")
344///     V["… 🟦 🟧 🟪 🟫 🟨 …"] -->|value| T
345///     D["… 🟩 🟥 🟥 🟩 🟥 …"] -->|select|T
346///     
347///     T -->|accepted| A["… 🟦 🟫 …"]
348///     T -->|rejected| R["… 🟧 🟪 🟨 …"]
349///
350///     style V fill:#ffffff,stroke:#ffffff
351///     style D fill:#ffffff,stroke:#ffffff
352///     style A fill:#ffffff,stroke:#ffffff
353///     style R fill:#ffffff,stroke:#ffffff
354/// ```
355#[mel_treatment(
356    generic T ()
357    input value Stream<T>
358    input select Stream<bool>
359    output accepted Stream<T>
360    output rejected Stream<T>
361)]
362pub async fn filter() {
363    let mut accepted_op = true;
364    let mut rejected_op = true;
365
366    while let (Ok(value), Ok(select)) = futures::join!(value.recv_one(), select.recv_one()) {
367        let select = select.try_data::<bool>().unwrap();
368        if select {
369            if let Err(_) = accepted.send_one(value).await {
370                // If we cannot send anymore on accepted, we note it,
371                // and check if rejected is still valid, else just terminate.
372                accepted_op = false;
373                if !rejected_op {
374                    break;
375                }
376            }
377        } else {
378            if let Err(_) = rejected.send_one(value).await {
379                // If we cannot send anymore on rejected, we note it,
380                // and check if accepted is still valid, else just terminate.
381                rejected_op = false;
382                if !accepted_op {
383                    break;
384                }
385            }
386        }
387    }
388}
389
390/// Filter a block according to `bool` value.
391///
392/// ℹ️ If `select` is never received nothing is emitted.
393///  
394/// ```mermaid
395/// graph LR
396///     T("filterBlock()")
397///     V["〈🟦〉"] -->|value| T
398///     D["〈🟩〉"] -->|select|T
399///     
400///     T -->|accepted| A["〈🟦〉"]
401///     T -->|rejected| R[" "]
402///
403///     style V fill:#ffffff,stroke:#ffffff
404///     style D fill:#ffffff,stroke:#ffffff
405///     style A fill:#ffffff,stroke:#ffffff
406///     style R fill:#ffffff,stroke:#ffffff
407/// ```
408#[mel_treatment(
409    generic T ()
410    input value Block<T>
411    input select Block<bool>
412    output accepted Block<T>
413    output rejected Block<T>
414)]
415pub async fn filterBlock() {
416    if let (Ok(value), Ok(select)) = futures::join!(value.recv_one(), select.recv_one()) {
417        let select = select.try_data::<bool>().unwrap();
418        if select {
419            let _ = accepted.send_one(value).await;
420        } else {
421            let _ = rejected.send_one(value).await;
422        }
423    }
424}
425
426/// Fit a stream into a pattern.
427///
428/// ℹ️ If some remaining values doesn't fit into the pattern, they are trashed.
429///
430/// ```mermaid
431/// graph LR
432///     T("fit()")
433///     A["… 🟨 🟨 🟨 🟨 🟨 🟨"] -->|value| T
434///     B["🟦 🟦 🟦 🟦"] -->|pattern| T
435///     
436///     T -->|fitted| O["🟨 🟨 🟨 🟨"]
437///
438///     style A fill:#ffffff,stroke:#ffffff
439///     style B fill:#ffffff,stroke:#ffffff
440///     style O fill:#ffffff,stroke:#ffffff
441/// ```
442#[mel_treatment(
443    generic T ()
444    input value Stream<T>
445    input pattern Stream<void>
446    output fitted Stream<T>
447)]
448pub async fn fit() {
449    'main: while let Ok(pattern) = pattern.recv_many_as::<()>().await {
450        for _ in pattern {
451            if let Ok(val) = value.recv_one().await {
452                check!('main, fitted.send_one(val).await)
453            } else {
454                break 'main;
455            }
456        }
457    }
458}
459
460/// Gives count of elements passing through stream.
461///
462/// This count increment one for each element within the stream, starting at 1.
463///
464/// ```mermaid
465/// graph LR
466///     T("count()")
467///     V["🟦 🟦 🟦 …"] -->|iter| T
468///     
469///     T -->|count| P["1️⃣ 2️⃣ 3️⃣ …"]
470///
471///     style V fill:#ffffff,stroke:#ffffff
472///     style P fill:#ffffff,stroke:#ffffff
473/// ```
474#[mel_treatment(
475    generic T ()
476    input stream Stream<T>
477    output count Stream<u128>
478)]
479pub async fn count() {
480    let mut i: u128 = 1;
481    while let Ok(iter) = stream.recv_many().await {
482        let next_i = i + iter.len() as u128;
483        check!(count.send_many_as((i..next_i).collect::<Vec<_>>()).await);
484        i = next_i;
485    }
486}
487
488/// Generate a stream with a given length.
489///
490/// ```mermaid
491/// graph LR
492///     T("generate()")
493///     B["〈🟨〉"] -->|length| T
494///         
495///     T -->|stream| S["… 🟦 🟦 🟦 🟦 🟦 🟦"]
496///     
497///     
498///     style B fill:#ffffff,stroke:#ffffff
499///     style S fill:#ffffff,stroke:#ffffff
500/// ```
501#[mel_treatment(
502    generic T ()
503    input length Block<u128>
504    output stream Stream<T>
505)]
506pub async fn generate(data: T) {
507    if let Ok(length) = length.recv_one_as::<u128>().await {
508        const CHUNK: u128 = 2u128.pow(20);
509        let mut total = 0u128;
510        while total < length {
511            let chunk = u128::min(CHUNK, length - total) as usize;
512            let mut transmission = melodium_core::TransmissionValue::new(data.clone());
513            for _ in 1..chunk {
514                transmission.push(data.clone());
515            }
516            check!(stream.send_many(transmission).await);
517            total += chunk as u128;
518        }
519    }
520}
521
522/// Generate a stream indefinitely.
523///
524/// This generates a continuous stream, until stream consumers closes it.
525///
526/// ```mermaid
527/// graph LR
528///     T("generateIndefinitely()")
529///     B["〈🟦〉"] -->|trigger| T
530///         
531///     T -->|stream| S["… 🟦 🟦 🟦 🟦 🟦 🟦"]
532///     
533///     
534///     style B fill:#ffffff,stroke:#ffffff
535///     style S fill:#ffffff,stroke:#ffffff
536/// ```
537#[mel_treatment(
538    generic T ()
539    input trigger Block<void>
540    output stream Stream<T>
541)]
542pub async fn generate_indefinitely(data: T) {
543    if let Ok(_) = trigger.recv_one().await {
544        const CHUNK: usize = 2usize.pow(20);
545        loop {
546            let mut transmission = melodium_core::TransmissionValue::new(data.clone());
547            for _ in 1..CHUNK {
548                transmission.push(data.clone());
549            }
550            check!(stream.send_many(transmission).await);
551        }
552    }
553}
554
555/// Insert a block into a stream.
556///
557/// `block` is inserted into `stream` when it comes and everything is streamed to `output`.
558///
559/// ℹ️ No assumption on block insertion position in stream can be made.
560///
561/// ```mermaid
562/// graph LR
563///     T("insert()")
564///     A["… 🟦 🟦 🟦 🟦 …"] -->|stream| T
565///     B["〈🟧〉"] -->|block| T
566///     
567///
568///     T -->|output| V["… 🟦 🟧 🟦 🟦 🟦 …"]
569///
570///     style V fill:#ffffff,stroke:#ffffff
571///     style A fill:#ffffff,stroke:#ffffff
572///     style B fill:#ffffff,stroke:#ffffff
573/// ```
574#[mel_treatment(
575    generic T ()
576    input stream Stream<T>
577    input block Block<T>
578    output output Stream<T>
579)]
580pub async fn insert() {
581    let streaming = async {
582        while let Ok(values) = (&stream).recv_many().await {
583            check!(output.send_many(values).await);
584        }
585    }
586    .fuse();
587    let insert_block = async {
588        if let Ok(val) = (&block).recv_one().await {
589            let _ = output.send_one(val).await;
590        }
591    }
592    .fuse();
593
594    pin_mut!(streaming, insert_block);
595
596    loop {
597        select! {
598            () = streaming => {},
599            () = insert_block => {},
600            complete => break,
601        };
602    }
603}
604
605/// Merge two incoming blocks as a stream.
606///
607/// Each block is taken when it arrives and send through `stream`.
608///
609/// ℹ️ No priority on blocks order in stream can be assumed.
610///
611/// ```mermaid
612/// graph LR
613///     T("flock()")
614///     A["〈🟦〉"] -->|a| T
615///     B["〈🟧〉"] -->|b| T
616///     
617///
618///     T -->|stream| V["🟧 🟦"]
619///
620///     style V fill:#ffffff,stroke:#ffffff
621///     style A fill:#ffffff,stroke:#ffffff
622///     style B fill:#ffffff,stroke:#ffffff
623/// ```
624#[mel_treatment(
625    generic T ()
626    input a Block<T>
627    input b Block<T>
628    output stream Stream<T>
629)]
630pub async fn flock() {
631    let xa = async {
632        if let Ok(a) = (&a).recv_one().await {
633            let _ = stream.send_one(a).await;
634        }
635    }
636    .fuse();
637    let xb = async {
638        if let Ok(b) = (&b).recv_one().await {
639            let _ = stream.send_one(b).await;
640        }
641    }
642    .fuse();
643
644    pin_mut!(xa, xb);
645
646    loop {
647        select! {
648            () = xa => {},
649            () = xb => {},
650            complete => break,
651        };
652    }
653}
654
655/// Emit one block.
656///
657/// Take first block coming among `a` or `b` and emit it in `value`, ignoring the remaining one.
658///
659/// ℹ️ No priority between blocks can be assumed if they are ready at same moment.
660///
661/// ```mermaid
662/// graph LR
663///     T("one()")
664///     A["〈〉"] -->|a| T
665///     B["〈🟧〉"] -->|b| T
666///     
667///
668///     T -->|value| V["〈🟧〉"]
669///
670///     style V fill:#ffffff,stroke:#ffffff
671///     style A fill:#ffffff,stroke:#ffffff
672///     style B fill:#ffffff,stroke:#ffffff
673/// ```
674#[mel_treatment(
675    generic T ()
676    input a Block<T>
677    input b Block<T>
678    output value Block<T>
679)]
680pub async fn one() {
681    let xa = async { (&a).recv_one().await.ok() }.fuse();
682    let xb = async { (&b).recv_one().await.ok() }.fuse();
683
684    pin_mut!(xa, xb);
685
686    loop {
687        let val = select! {
688            val = xa => val,
689            val = xb => val,
690            complete => break,
691        };
692
693        if let Some(val) = val {
694            let _ = value.send_one(val).await;
695            break;
696        }
697    }
698}
699
700/// Never send any value.
701///
702/// No value is ever sent on `closed` output, which is immediately closed.
703///
704#[mel_treatment(
705    generic T ()
706    input trigger Block<void>
707    output closed Stream<T>
708)]
709pub async fn close() {
710    // Nothing to do
711}
712
713/// Never send any value.
714///
715/// No value is ever sent on `closed` output, which is immediately closed.
716///
717#[mel_treatment(
718    generic T ()
719    input trigger Block<void>
720    output closed Block<T>
721)]
722pub async fn close_block() {
723    // Nothing to do
724}
725
726/// Consume stream indefinitely.
727///
728/// Input `stream` is consumed indefinitely until it becomes closed by previous treatment.
729///
730#[mel_treatment(
731    generic T ()
732    input stream Stream<T>
733)]
734pub async fn consume() {
735    while let Ok(_) = stream.recv_many().await {
736        // Nothing to do.
737    }
738}
739
740/// Pass stream under condition.
741///
742/// If `if` is `true`, pass the stream, else closes it.
743///
744#[mel_treatment(
745    generic T ()
746    input stream Stream<T>
747    output passed Stream<T>
748)]
749pub async fn pass(cond: bool) {
750    if cond {
751        while let Ok(data) = stream.recv_many().await {
752            check!(passed.send_many(data).await)
753        }
754    }
755}
756
757/// Pass block under condition.
758///
759/// If `if` is `true`, pass the block, else nothing.
760///
761#[mel_treatment(
762    generic T ()
763    input block Block<T>
764    output passed Block<T>
765)]
766pub async fn passBlock(cond: bool) {
767    if cond {
768        if let Ok(data) = block.recv_one().await {
769            let _ = passed.send_one(data).await;
770        }
771    }
772}
773
774/// Barrier stream under condition.
775///
776/// Awaits `leverage` to let stream pass if it is `true`, else closes the stream.
777///
778#[mel_treatment(
779    generic T ()
780    input leverage Block<bool>
781    input stream Stream<T>
782    output passed Stream<T>
783)]
784pub async fn barrier() {
785    if let Ok(true) = leverage.recv_one_as::<bool>().await {
786        while let Ok(data) = stream.recv_many().await {
787            check!(passed.send_many(data).await)
788        }
789    }
790}
791
792/// Pass stream until cut signal.
793///
794/// Let stream pass until `cut` signal si received.
795///
796#[mel_treatment(
797    generic T ()
798    input cut Block<void>
799    input stream Stream<T>
800    output passed Stream<T>
801)]
802pub async fn cut() {
803    let cut = async { cut.recv_one().await.is_ok() }.fuse();
804    let pass = async {
805        while let Ok(values) = stream.recv_many().await {
806            check!(passed.send_many(values).await)
807        }
808    }
809    .fuse();
810
811    pin_mut!(cut, pass);
812
813    loop {
814        select! {
815            () = pass => break,
816            do_cut = cut => if do_cut {
817                break
818            },
819            complete => break,
820        }
821    }
822}
823
824/// Release stream once signal is received.
825///
826/// Awaits `leverage` to let stream pass, else closes the stream.
827///
828#[mel_treatment(
829    generic T ()
830    input leverage Block<void>
831    input data Stream<T>
832    output released Stream<T>
833)]
834pub async fn release() {
835    if let Ok(_) = leverage.recv_one().await {
836        while let Ok(data) = data.recv_many().await {
837            check!(released.send_many(data).await)
838        }
839    }
840}
841
842/// Release block once signal is received.
843///
844/// Awaits `leverage` to let block pass, else closes the flow.
845///
846#[mel_treatment(
847    generic T ()
848    input leverage Block<void>
849    input data Block<T>
850    output released Block<T>
851)]
852pub async fn releaseBlock() {
853    if let Ok(_) = leverage.recv_one().await {
854        if let Ok(data) = data.recv_one().await {
855            let _ = released.send_one(data).await;
856        }
857    }
858}
859
860/// Await blocks.
861///
862/// Wait for two blocks and send `awaited` once both are received.
863///
864/// ℹ️ If one block is never received, `awaited` is never emitted.
865#[mel_treatment(
866    generic T ()
867    input a Block<T>
868    input b Block<T>
869    output awaited Block<void>
870)]
871pub async fn waitBlock() {
872    let (a, b) = futures::join!(async { a.recv_one().await.is_ok() }, async {
873        b.recv_one().await.is_ok()
874    });
875
876    if a && b {
877        let _ = awaited.send_one_as(()).await;
878    }
879}