std_mel/text/
compose.rs

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