Skip to main content

std_mel/text/
compose.rs

1use crate::data::string_map::*;
2use melodium_core::*;
3use melodium_macro::{check, mel_function, mel_treatment};
4use std::sync::Arc;
5
6/// Rescale stream of strings.
7///
8/// _Rescaling_ means that strings sent throught stream are rearranged according to the `delimiter`.
9///
10/// Unscaled stream can basically be cut at any position:
11/// ```
12/// "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean qua"
13/// "m velit, tristique et arcu in, viverra pulvinar ante. Interdum et m"
14/// "alesuada fames ac ante ipsum primis in faucibus. Cras varius, augue"
15/// " ac fringilla placerat, nibh lorem laoreet enim, sed fermentum libe"
16/// " ro justo ut sapien."
17/// ```
18///
19/// While treatments may expect well-defined strings:
20/// ```
21/// "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
22/// "Aenean quam velit, tristique et arcu in, viverra pulvinar ante."
23/// "Interdum et malesuada fames ac ante ipsum primis in faucibus."
24/// "Cras varius, augue ac fringilla placerat, nibh lorem laoreet enim, sed fermentum libero justo ut sapien."
25/// ```
26#[mel_treatment(
27    default delimiter "\n"
28    input unscaled Stream<string>
29    output scaled Stream<string>
30)]
31pub async fn rescale(delimiter: string) {
32    let mut previous = String::new();
33    'main: while let Ok(input) = unscaled.recv_one_as::<string>().await {
34        let splits: Vec<&str> = input.split_inclusive(&delimiter).collect();
35        for split in splits {
36            previous.push_str(split);
37            if previous.ends_with(&delimiter) {
38                let sendable = previous;
39                previous = String::new();
40                check!('main, scaled.send_one_as(sendable).await);
41            }
42        }
43    }
44    if !previous.is_empty() {
45        let _ = scaled.send_one_as(previous).await;
46    }
47}
48
49/// Split strings with delimiter.
50///
51/// `text` is splitted according to `delimiter`, and streamed as `splitted` vector.
52/// - `inclusive`: set if the delimiter must be kept at the end of splitted strings (if present).
53///
54/// ```mermaid
55/// graph LR
56///     T("split()")
57///     B["🟦"] -->|vector| T
58///     
59///     T -->|value| O["[🟦 🟦 🟦]"]
60///
61///     style B fill:#ffffff,stroke:#ffffff
62///     style O fill:#ffffff,stroke:#ffffff
63/// ```
64#[mel_treatment(
65    default inclusive true
66    input text Stream<string>
67    output splitted Stream<Vec<string>>
68)]
69pub async fn split(delimiter: string, inclusive: bool) {
70    while let Ok(input) = text.recv_many_as::<string>().await {
71        let mut output = VecDeque::with_capacity(input.len());
72
73        if inclusive {
74            input.into_iter().for_each(|text| {
75                output.push_back(Value::Vec(
76                    text.split_inclusive(&delimiter)
77                        .map(|s| s.to_string().into())
78                        .collect(),
79                ))
80            });
81        } else {
82            input.into_iter().for_each(|text| {
83                output.push_back(Value::Vec(
84                    text.split(&delimiter)
85                        .map(|s| s.to_string().into())
86                        .collect(),
87                ))
88            });
89        }
90
91        check!(splitted.send_many(TransmissionValue::Other(output)).await);
92    }
93}
94
95/// Split strings with delimiter.
96///
97/// `text` is splitted as `Vec<string>` according to `delimiter`.
98/// - `inclusive`: set if the delimiter must be kept at the end of splitted strings (if present).
99#[mel_function]
100pub fn split(text: string, delimiter: string, inclusive: bool) -> Vec<string> {
101    if inclusive {
102        text.split_inclusive(&delimiter)
103            .map(|s| s.to_string())
104            .collect()
105    } else {
106        text.split(&delimiter).map(|s| s.to_string()).collect()
107    }
108}
109
110/// Trim stream of strings.
111///
112/// Stream strings with leading and trailing whitespace removed.
113/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
114#[mel_treatment(
115    input text Stream<string>
116    output trimmed Stream<string>
117)]
118pub async fn trim() {
119    while let Ok(mut text) = text.recv_many_as::<string>().await {
120        text.iter_mut().for_each(|t| *t = t.trim().to_string());
121
122        check!(trimmed.send_many_as(text).await);
123    }
124}
125
126/// Trim string.
127///
128/// Return string with leading and trailing whitespace removed.
129/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
130#[mel_function]
131pub fn trim(text: string) -> string {
132    text.trim().to_string()
133}
134
135/// Trim end of streamed strings.
136///
137/// Stream strings with trailing whitespace removed.
138/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
139#[mel_treatment(
140    input text Stream<string>
141    output trimmed Stream<string>
142)]
143pub async fn trim_end() {
144    while let Ok(mut text) = text.recv_many_as::<string>().await {
145        text.iter_mut().for_each(|t| *t = t.trim_end().to_string());
146
147        check!(trimmed.send_many_as(text).await);
148    }
149}
150
151/// Trim end of string.
152///
153/// Return string with trailing whitespace removed.
154/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
155#[mel_function]
156pub fn trim_end(text: string) -> string {
157    text.trim_end().to_string()
158}
159
160/// Trim start of streamed strings.
161///
162/// Stream strings with leading whitespace removed.
163/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
164#[mel_treatment(
165    input text Stream<string>
166    output trimmed Stream<string>
167)]
168pub async fn trim_start() {
169    while let Ok(mut text) = text.recv_many_as::<string>().await {
170        text.iter_mut()
171            .for_each(|t| *t = t.trim_start().to_string());
172
173        check!(trimmed.send_many_as(text).await);
174    }
175}
176
177/// Trim start of string.
178///
179/// Return string with trailing whitespace removed.
180/// _Whitespace_ is defined according to the terms of the Unicode Derived Core Property `White_Space`, which includes newlines.
181#[mel_function]
182pub fn trim_start(text: string) -> string {
183    text.trim_start().to_string()
184}
185
186/// Format string.
187///
188/// Return string formatted with given entries.
189/// Format string is expected to contains braced placeholders, like: `"Hello {name}!"`.
190///
191/// If a formatting error happens, like missing key of incorrect format string, an empty string is returned.
192#[mel_function]
193pub fn format(format: string, entries: StringMap) -> string {
194    strfmt::strfmt(&format, &entries.map).unwrap_or_default()
195}
196
197/// Checked format string.
198///
199/// Return string formatted with given entries.
200/// Format string is expected to contains braced placeholders, like: `"Hello {name}!"`.
201///
202/// If a formatting error happens, like missing key of incorrect format string, _none_ is returned.
203#[mel_function]
204pub fn checked_format(format: string, entries: StringMap) -> Option<string> {
205    strfmt::strfmt(&format, &entries.map).ok()
206}
207
208/// Format stream.
209///
210/// Stream string formatted with given entries.
211/// Format string is expected to contains braced placeholders, like: `"Hello {name}!"`.
212///
213/// If a formatting error happens, like missing key of incorrect format string, an empty string is sent.
214#[mel_treatment(
215    input entries Stream<StringMap>
216    output formatted Stream<string>
217)]
218pub async fn format(format: string) {
219    while let Ok(maps) = entries.recv_many_as::<Arc<StringMap>>().await {
220        let formatted_str = maps
221            .into_iter()
222            .map(|map| strfmt::strfmt(&format, &map.map).unwrap_or_default())
223            .collect::<Vec<_>>();
224
225        check!(formatted.send_many_as(formatted_str).await);
226    }
227}
228
229/// Format stream.
230///
231/// Stream string formatted with given entries.
232/// Format string is expected to contains braced placeholders, like: `"Hello {name}!"`.
233///
234/// If a formatting error happens, like missing key of incorrect format string, _none_ is sent.
235#[mel_treatment(
236    input entries Stream<StringMap>
237    output formatted Stream<Option<string>>
238)]
239pub async fn checked_format(format: string) {
240    while let Ok(maps) = entries.recv_many_as::<Arc<StringMap>>().await {
241        let formatted_str = maps
242            .into_iter()
243            .map(|map| {
244                Value::Option(
245                    strfmt::strfmt(&format, &map.map)
246                        .map(|formatted| Box::new(Value::String(formatted)))
247                        .ok(),
248                )
249            })
250            .collect::<VecDeque<_>>();
251
252        check!(
253            formatted
254                .send_many(TransmissionValue::Other(formatted_str))
255                .await
256        );
257    }
258}