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}