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
use melodium_core::*;
use melodium_macro::{check, mel_function, mel_treatment};

/// Rescale stream of strings.
///
/// _Rescaling_ means that strings sent throught stream are rearranged according to the `delimiter`.
///
/// Unscaled stream can basically be cut at any position:
/// ```
/// "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean qua"
/// "m velit, tristique et arcu in, viverra pulvinar ante. Interdum et m"
/// "alesuada fames ac ante ipsum primis in faucibus. Cras varius, augue"
/// " ac fringilla placerat, nibh lorem laoreet enim, sed fermentum libe"
/// " ro justo ut sapien."
/// ```
///
/// While treatments may expect well-defined strings:
/// ```
/// "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
/// "Aenean quam velit, tristique et arcu in, viverra pulvinar ante."
/// "Interdum et malesuada fames ac ante ipsum primis in faucibus."
/// "Cras varius, augue ac fringilla placerat, nibh lorem laoreet enim, sed fermentum libero justo ut sapien."
/// ```
#[mel_treatment(
    default delimiter "\n"
    input unscaled Stream<string>
    output scaled Stream<string>
)]
pub async fn rescale(delimiter: string) {
    let mut previous = String::new();
    'main: while let Ok(input) = unscaled
        .recv_one()
        .await
        .map(|val| GetData::<string>::try_data(val).unwrap())
    {
        let splits: Vec<&str> = input.split_inclusive(&delimiter).collect();
        for split in splits {
            previous.push_str(split);
            if previous.ends_with(&delimiter) {
                check!('main, scaled.send_one(previous.into()).await);
                previous = String::new();
            }
        }
    }
}

/// Split strings with delimiter.
///
/// `text` is splitted according to `delimiter`, and streamed as `splitted` vector.
/// - `inclusive`: set if the delimiter must be kept at the end of splitted strings (if present).
///
/// ```mermaid
/// graph LR
///     T("split()")
///     B["🟦"] -->|vector| T
///     
///     T -->|value| O["[🟦 🟦 🟦]"]
///
///     style B fill:#ffff,stroke:#ffff
///     style O fill:#ffff,stroke:#ffff
/// ```
#[mel_treatment(
    default inclusive true
    input text Stream<string>
    output splitted Stream<Vec<string>>
)]
pub async fn split(delimiter: string, inclusive: bool) {
    while let Ok(input) = text
        .recv_many()
        .await
        .map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
    {
        let mut output = VecDeque::with_capacity(input.len());

        if inclusive {
            input.into_iter().for_each(|text| {
                output.push_back(Value::Vec(
                    text.split_inclusive(&delimiter)
                        .map(|s| s.to_string().into())
                        .collect(),
                ))
            });
        } else {
            input.into_iter().for_each(|text| {
                output.push_back(Value::Vec(
                    text.split(&delimiter)
                        .map(|s| s.to_string().into())
                        .collect(),
                ))
            });
        }

        check!(splitted.send_many(TransmissionValue::Other(output)).await);
    }
}

/// Split strings with delimiter.
///
/// `text` is splitted as `Vec<string>` according to `delimiter`.
/// - `inclusive`: set if the delimiter must be kept at the end of splitted strings (if present).
#[mel_function]
pub fn split(text: string, delimiter: string, inclusive: bool) -> Vec<string> {
    if inclusive {
        text.split_inclusive(&delimiter)
            .map(|s| s.to_string())
            .collect()
    } else {
        text.split(&delimiter).map(|s| s.to_string()).collect()
    }
}

/// Trim stream of strings.
///
/// Stream strings with leading and trailing whitespace removed.
/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
#[mel_treatment(
    input text Stream<string>
    output trimmed Stream<string>
)]
pub async fn trim() {
    while let Ok(mut text) = text
        .recv_many()
        .await
        .map(|values| TryInto::<Vec<string>>::try_into(values).unwrap())
    {
        text.iter_mut().for_each(|t| *t = t.trim().to_string());

        check!(trimmed.send_many(text.into()).await);
    }
}

/// Trim string.
///
/// Return string with leading and trailing whitespace removed.
/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
#[mel_function]
pub fn trim(text: string) -> string {
    text.trim().to_string()
}