std_mel/ops/option/
block.rs

1use futures::{pin_mut, select, FutureExt};
2use melodium_core::*;
3use melodium_macro::mel_treatment;
4
5/// Unwrap option block
6///
7/// Unwrap blocking option, ignoring it if set to _none_.
8#[mel_treatment(
9    generic T ()
10    input option Block<Option<T>>
11    output value Block<T>
12)]
13pub async fn unwrap() {
14    if let Ok(pos_val) = option.recv_one().await {
15        match pos_val {
16            Value::Option(Some(val)) => {
17                let _ = value.send_one(*val).await;
18            }
19            _ => {}
20        }
21    }
22}
23
24/// Unwrap option block with default value
25///
26/// Unwrap blocking option, sending `default` value if option is _none_.
27#[mel_treatment(
28    generic T ()
29    input option Block<Option<T>>
30    output value Block<T>
31)]
32pub async fn unwrap_or(default: T) {
33    if let Ok(pos_val) = option.recv_one().await {
34        match pos_val {
35            Value::Option(Some(val)) => {
36                let _ = value.send_one(*val).await;
37            }
38            Value::Option(None) => {
39                let _ = value.send_one(default).await;
40            }
41            _ => {}
42        }
43    }
44}
45
46/// Wrap a block value into option
47///
48/// Takes a blocking value and turn if into filled option.
49#[mel_treatment(
50    generic T ()
51    input value Block<T>
52    output option Block<Option<T>>
53)]
54pub async fn wrap() {
55    if let Ok(val) = value.recv_one().await {
56        let _ = option.send_one(Value::Option(Some(Box::new(val)))).await;
57    }
58}
59
60/// Map an option
61///
62/// Takes a blocking option and either emit the contained value on `value` or `none` if empty.
63///
64/// ℹ️ This treatment aims to be used in conjuction with `reduce`.
65#[mel_treatment(
66    generic T ()
67    input option Block<Option<T>>
68    output none Block<void>
69    output value Block<T>
70)]
71pub async fn map() {
72    if let Ok(val) = option.recv_one().await {
73        match val {
74            Value::Option(Some(val)) => {
75                let _ = value.send_one(*val).await;
76            }
77            Value::Option(None) => {
78                let _ = none.send_one(().into()).await;
79            }
80            _ => unreachable!(),
81        }
82    }
83}
84
85/// Reduce an option
86///
87/// Takes either `value` or `none` and emit the corresponding `option`.
88///
89/// ℹ️ This treatment aims to be used in conjuction with `map`.
90#[mel_treatment(
91    generic T ()
92    input value Block<T>
93    input none Block<void>
94    output option Block<Option<T>>
95)]
96pub async fn reduce() {
97    let value_arrived = async { (&value).recv_one().await }.fuse();
98    let none_arrived = async { (&none).recv_one().await }.fuse();
99
100    pin_mut!(value_arrived, none_arrived);
101
102    loop {
103        select! {
104            value = value_arrived => {
105                if let Ok(value) = value {
106                    let _ = option.send_one(Value::Option(Some(Box::new(value)))).await;
107                    break;
108                }
109            },
110            none = none_arrived => {
111                if let Ok(_) = none {
112                    let _ = option.send_one(Value::Option(None)).await;
113                    break;
114                }
115            },
116            complete => break,
117        };
118    }
119}