Skip to main content

rumtk_core/
lib.rs

1/*
2 * rumtk attempts to implement HL7 and medical protocols for interoperability in medicine.
3 * This toolkit aims to be reliable, simple, performant, and standards compliant.
4 * Copyright (C) 2024  Luis M. Santos, M.D.
5 * Copyright (C) 2025  MedicalMasses L.L.C.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22//#![feature(unboxed_closures)]
23//#![feature(inherent_associated_types)]
24#![feature(type_alias_impl_trait)]
25#![feature(unboxed_closures)]
26#![feature(buf_read_has_data_left)]
27#![feature(mapped_lock_guards)]
28#![feature(str_as_str)]
29
30pub mod cache;
31pub mod cli;
32pub mod core;
33pub mod dependencies;
34pub mod hash;
35pub mod id;
36pub mod json;
37pub mod log;
38pub mod maths;
39pub mod net;
40pub mod pipelines;
41pub mod scripting;
42pub mod search;
43pub mod strings;
44pub mod threading;
45pub mod types;
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50    use crate::cache::RUMCache;
51    use crate::core::{clamp_index, RUMResult};
52    use crate::search::rumtk_search::*;
53    use crate::strings::{
54        rumtk_format, RUMArrayConversions, RUMString, RUMStringConversions, StringUtils,
55    };
56    use crate::types::{RUMDeserialize, RUMDeserializer, RUMSerialize, RUMSerializer};
57    use compact_str::CompactString;
58    use serde_json::to_string;
59    use std::process::Stdio;
60    use std::sync::Arc;
61    use tokio::sync::RwLock;
62
63    #[test]
64    fn test_is_escaped_str() {
65        let input = "\r\n\'\\\"";
66        let expected = false;
67        let result = strings::is_escaped_str(input);
68        println!("Input: {} Expected: {} Got: {}", input, expected, result);
69        assert_eq!(
70            expected, result,
71            "Incorrect detection of unescaped string as escaped!!"
72        );
73        println!("Passed!")
74    }
75
76    #[test]
77    fn test_escaping_control() {
78        let input = "\r\n\'\"\\";
79        let expected = "\\r\\n\\'\\\"\\\\";
80        let result = strings::escape(input);
81        println!(
82            "Input: {} Expected: {} Got: {}",
83            input,
84            expected,
85            result.as_str()
86        );
87        assert_eq!(expected, result, "Incorrect string escaping!");
88        println!("Passed!")
89    }
90
91    #[test]
92    fn test_escaping_unicode() {
93        let input = "❤";
94        let expected = "\\u2764";
95        let result = strings::escape(input);
96        println!(
97            "Input: {} Expected: {} Got: {}",
98            input,
99            expected,
100            result.as_str()
101        );
102        assert_eq!(expected, result, "Incorrect string escaping!");
103        println!("Passed!")
104    }
105
106    #[test]
107    fn test_unescaping_unicode() {
108        let input = "❤";
109        let escaped = strings::escape(input);
110        let expected = "❤";
111        let result = RUMString::from_utf8(strings::unescape(escaped.as_str()).unwrap()).unwrap();
112        println!(
113            "Input: {} Expected: {} Got: {}",
114            input,
115            expected,
116            result.as_str()
117        );
118        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
119        println!("Passed!")
120    }
121
122    #[test]
123    fn test_unescaping_string() {
124        let input = "I \\u2764 my wife!";
125        let expected = "I ❤ my wife!";
126        let result = strings::unescape_string(input).unwrap();
127        println!(
128            "Input: {} Expected: {} Got: {}",
129            input,
130            expected,
131            result.as_str()
132        );
133        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
134        println!("Passed!")
135    }
136
137    #[test]
138    fn test_is_escaped_string() {
139        let input = "I \\u2764 my wife!";
140        let expected = true;
141        let result = strings::is_escaped_str(input);
142        println!("Input: {} Expected: {} Got: {}", input, expected, result);
143        assert_eq!(
144            expected, result,
145            "Escaped string detected as unescaped string!"
146        );
147        println!("Passed!")
148    }
149
150    #[test]
151    fn test_is_unescaped_string() {
152        let input = "I ❤ my wife!";
153        let expected = false;
154        let result = strings::is_escaped_str(input);
155        println!("Input: {} Expected: {} Got: {}", input, expected, result);
156        assert_eq!(
157            expected, result,
158            "Unescaped string detected as escaped string!"
159        );
160        println!("Passed!")
161    }
162
163    #[test]
164    fn test_unique_string() {
165        let input = "I❤mywife!";
166        assert!(input.is_unique(), "String was not detected as unique.");
167    }
168
169    #[test]
170    fn test_non_unique_string() {
171        let input = "I❤❤mywife!";
172        assert!(!input.is_unique(), "String was detected as unique.");
173    }
174
175    #[test]
176    fn test_escaping_string() {
177        let input = "I ❤ my wife!";
178        let expected = "I \\u2764 my wife!";
179        let result = strings::escape(input);
180        println!(
181            "Input: {} Expected: {} Got: {}",
182            input,
183            expected,
184            result.as_str()
185        );
186        assert_eq!(expected, result.as_str(), "Incorrect string escaping!");
187        println!("Passed!")
188    }
189
190    #[test]
191    fn test_autodecode_utf8() {
192        let input = "I ❤ my wife!";
193        let result = strings::try_decode(input.as_bytes());
194        println!(
195            "Input: {} Expected: {} Got: {}",
196            input,
197            input,
198            result.as_str()
199        );
200        assert_eq!(input, result, "Incorrect string decoding!");
201        println!("Passed!")
202    }
203
204    #[test]
205    fn test_autodecode_other() {
206        //TODO: Need an example of other encoding texts.
207        let input = "I ❤ my wife!";
208        let result = input;
209        println!("Input: {} Expected: {} Got: {}", input, input, result);
210        assert_eq!(input, result, "Incorrect string decoding!");
211        println!("Passed!")
212    }
213
214    #[test]
215    fn test_decode() {
216        let input = "I ❤ my wife!";
217        let result = strings::try_decode_with(input.as_bytes(), "utf-8");
218        println!(
219            "Input: {} Expected: {} Got: {}",
220            input,
221            input,
222            result.as_str()
223        );
224        assert_eq!(input, result, "Incorrect string decoding!");
225        println!("Passed!")
226    }
227
228    #[test]
229    fn test_rumcache_insertion() {
230        let mut cache: RUMCache<&str, CompactString> = RUMCache::with_capacity(5);
231        cache.insert("❤", CompactString::from("I ❤ my wife!"));
232        println!("Contents: {:#?}", &cache);
233        assert_eq!(cache.len(), 1, "Incorrect number of items in cache!");
234        println!("Passed!")
235    }
236
237    #[test]
238    fn test_search_string_letters() {
239        let input = "Hello World!";
240        let expr = r"\w";
241        let result = string_search(input, expr, "");
242        let expected: RUMString = RUMString::from("HelloWorld");
243        println!(
244            "Input: {:?} Expected: {:?} Got: {:?}",
245            input, expected, result
246        );
247        assert_eq!(expected, result, "String search results mismatch");
248        println!("Passed!")
249    }
250
251    #[test]
252    fn test_search_string_words() {
253        let input = "Hello World!";
254        let expr = r"\w+";
255        let result = string_search(input, expr, " ");
256        let expected: RUMString = RUMString::from("Hello World");
257        println!(
258            "Input: {:?} Expected: {:?} Got: {:?}",
259            input, expected, result
260        );
261        assert_eq!(expected, result, "String search results mismatch");
262        println!("Passed!")
263    }
264
265    #[test]
266    fn test_search_string_named_groups() {
267        let input = "Hello World!";
268        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
269        let result = string_search_named_captures(input, expr, "");
270        let expected: RUMString = RUMString::from("World");
271        println!(
272            "Input: {:?} Expected: {:?} Got: {:?}",
273            input, expected, result
274        );
275        assert_eq!(expected, result["world"], "String search results mismatch");
276        println!("Passed!")
277    }
278
279    #[test]
280    fn test_search_string_all_groups() {
281        let input = "Hello World!";
282        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
283        let result = string_search_all_captures(input, expr, "");
284        let expected: Vec<&str> = vec!["Hello", "World"];
285        println!(
286            "Input: {:?} Expected: {:?} Got: {:?}",
287            input, expected, result
288        );
289        assert_eq!(expected, result, "String search results mismatch");
290        println!("Passed!")
291    }
292
293    ///////////////////////////////////Threading Tests/////////////////////////////////////////////////
294    #[test]
295    fn test_default_num_threads() {
296        use num_cpus;
297        let threads = threading::threading_functions::get_default_system_thread_count();
298        assert_eq!(
299            threads >= num_cpus::get(),
300            true,
301            "Default thread count is incorrect! We got {}, but expected {}!",
302            threads,
303            num_cpus::get()
304        );
305    }
306
307    #[test]
308    fn test_execute_job() {
309        let expected = vec![1, 2, 3];
310        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
311            let owned_args = Arc::clone(args);
312            let lock_future = owned_args.read();
313            let locked_args = lock_future.await;
314            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
315            print!("Contents: ");
316            for arg in locked_args.iter() {
317                results.push(arg.clone());
318                println!("{} ", &arg);
319            }
320            Ok(results)
321        };
322        let locked_args = RwLock::new(expected.clone());
323        let task_args = SafeTaskArgs::<i32>::new(locked_args);
324        let task_result = rumtk_wait_on_task!(task_processor, &task_args);
325        let result = task_result.unwrap().unwrap();
326        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
327    }
328
329    #[test]
330    fn test_execute_job_macros() {
331        let expected = vec![1, 2, 3];
332        let task_processor = async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
333            let owned_args = Arc::clone(args);
334            let lock_future = owned_args.read();
335            let locked_args = lock_future.await;
336            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
337            print!("Contents: ");
338            for arg in locked_args.iter() {
339                results.push(arg.clone());
340                println!("{} ", &arg);
341            }
342            Ok(results)
343        };
344        let task_args = rumtk_create_task_args!(1, 2, 3);
345        let task_result = rumtk_wait_on_task!(task_processor, &task_args);
346        let result = task_result.unwrap().unwrap();
347        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
348    }
349
350    #[test]
351    fn test_execute_job_macros_one_line() {
352        let expected = vec![1, 2, 3];
353        let result = rumtk_exec_task!(
354            async |args: &SafeTaskArgs<i32>| -> RUMResult<Vec<i32>> {
355                let owned_args = Arc::clone(args);
356                let lock_future = owned_args.read();
357                let locked_args = lock_future.await;
358                let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
359                print!("Contents: ");
360                for arg in locked_args.iter() {
361                    results.push(arg.clone());
362                    println!("{} ", &arg);
363                }
364                Ok(results)
365            },
366            vec![1, 2, 3]
367        )
368        .unwrap()
369        .unwrap();
370        assert_eq!(&result, &expected, "{}", rumtk_format!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
371    }
372
373    #[test]
374    fn test_clamp_index_positive_index() {
375        let values = vec![1, 2, 3, 4];
376        let given_index = 3isize;
377        let max_size = values.len() as isize;
378        let index = clamp_index(&given_index, &max_size).unwrap();
379        assert_eq!(
380            index, 3,
381            "Index mismatch! Requested index {} but got {}",
382            &given_index, &index
383        );
384        assert_eq!(
385            values[index], 4,
386            "Value mismatch! Expected {} but got {}",
387            &values[3], &values[index]
388        );
389    }
390
391    #[test]
392    fn test_clamp_index_reverse_index() {
393        let values = vec![1, 2, 3, 4];
394        let given_index = -1isize;
395        let max_size = values.len() as isize;
396        let index = clamp_index(&given_index, &max_size).unwrap();
397        assert_eq!(
398            index, 4,
399            "Index mismatch! Requested index {} but got {}",
400            &given_index, &index
401        );
402        assert_eq!(
403            values[index - 1],
404            4,
405            "Value mismatch! Expected {} but got {}",
406            &values[3],
407            &values[index]
408        );
409    }
410
411    ///////////////////////////////////Queue Tests/////////////////////////////////////////////////
412    use crate::cli::cli_utils::print_license_notice;
413    use crate::net::tcp::LOCALHOST;
414    use crate::pipelines::pipeline_functions::{
415        pipeline_generate_command, pipeline_pipe_processes, pipeline_spawn_process,
416    };
417    use crate::pipelines::pipeline_types::RUMCommand;
418    use crate::threading::threading_manager::*;
419
420    #[test]
421    fn test_queue_data() {
422        let expected = vec![
423            RUMString::from("Hello"),
424            RUMString::from("World!"),
425            RUMString::from("Overcast"),
426            RUMString::from("and"),
427            RUMString::from("Sad"),
428        ];
429        type TestResult = RUMResult<Vec<RUMString>>;
430        let mut queue: TaskManager<TestResult> = TaskManager::new(&5).unwrap();
431        let locked_args = RwLock::new(expected.clone());
432        let task_args = SafeTaskArgs::<RUMString>::new(locked_args);
433        let processor = rumtk_create_task!(
434            async |args: &SafeTaskArgs<RUMString>| -> TestResult {
435                let owned_args = Arc::clone(args);
436                let lock_future = owned_args.read();
437                let locked_args = lock_future.await;
438                let mut results = TaskItems::<RUMString>::with_capacity(locked_args.len());
439                print!("Contents: ");
440                for arg in locked_args.iter() {
441                    print!("{} ", &arg);
442                    results.push(RUMString::new(arg));
443                }
444                Ok(results)
445            },
446            task_args
447        );
448
449        queue.add_task::<_>(processor);
450        let results = queue.wait();
451
452        let mut result_data = Vec::<RUMString>::with_capacity(5);
453        for r in results {
454            for v in r.unwrap().result.clone().unwrap().iter() {
455                for value in v.iter() {
456                    result_data.push(value.clone());
457                }
458            }
459        }
460        assert_eq!(result_data, expected, "Results do not match expected!");
461    }
462
463    ///////////////////////////////////Net Tests/////////////////////////////////////////////////
464    #[test]
465    fn test_server_start() {
466        let server = match rumtk_create_server!("localhost", 0) {
467            Ok(server) => server,
468            Err(e) => panic!("Failed to create server because {}", e),
469        };
470    }
471
472    #[test]
473    fn test_server_send() {
474        let msg = RUMString::from("Hello World!");
475        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
476            Ok(server) => server,
477            Err(e) => panic!("Failed to create server because {}", e),
478        };
479        let address_info = server.get_address_info().unwrap();
480        let (ip, port) = rumtk_get_ip_port!(address_info);
481        let mut client = match rumtk_connect!(port) {
482            Ok(client) => client,
483            Err(e) => panic!("Failed to create server because {}", e),
484        };
485        let client_id = client.get_address().unwrap();
486        match server.send(&client_id, &msg.to_raw()) {
487            Ok(_) => (),
488            Err(e) => panic!("Server failed to send message because {}", e),
489        };
490        let received_message = client.receive().unwrap();
491        assert_eq!(
492            &msg.len(),
493            &received_message.len(),
494            "Received message does not match expected length!"
495        );
496        assert_eq!(
497            &msg.to_raw(),
498            &received_message,
499            "{}",
500            rumtk_format!(
501                "Received message does not match sent message by server {:?}",
502                &received_message
503            )
504        );
505    }
506
507    #[test]
508    fn test_server_receive() {
509        let msg = RUMString::from("Hello World!");
510        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
511            Ok(server) => server,
512            Err(e) => panic!("Failed to create server because {}", e),
513        };
514        let address_info = server.get_address_info().unwrap();
515        let (ip, port) = rumtk_get_ip_port!(address_info);
516        println!("Sleeping");
517        let mut client = match rumtk_connect!(port) {
518            Ok(client) => client,
519            Err(e) => panic!("Failed to create server because {}", e),
520        };
521        match client.send(msg.to_raw()) {
522            Ok(_) => (),
523            Err(e) => panic!("Failed to send message because {}", e),
524        };
525        let client_id = client.get_address().expect("Failed to get client id");
526        let incoming_message = server.receive(&client_id, true).unwrap().to_rumstring();
527        println!("Received message => {:?}", &incoming_message);
528        assert_eq!(&incoming_message, msg, "Received message corruption!");
529    }
530
531    #[test]
532    fn test_server_get_clients() {
533        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
534            Ok(server) => server,
535            Err(e) => panic!("Failed to create server because {}", e),
536        };
537        let address_info = server.get_address_info().unwrap();
538        let (ip, port) = rumtk_get_ip_port!(address_info);
539        println!("Sleeping");
540        let mut client = match rumtk_connect!(port) {
541            Ok(client) => client,
542            Err(e) => panic!("Failed to create server because {}", e),
543        };
544        let expected_client_id = client.get_address().expect("Failed to get client id");
545        let clients = server.get_client_ids();
546        let incoming_client_id = clients.get(0).expect("Expected client to have connected!");
547        println!("Connected client id => {}", &incoming_client_id);
548        assert_eq!(
549            &incoming_client_id, &expected_client_id,
550            "Connected client does not match the connecting client! Client id => {}",
551            &incoming_client_id
552        );
553    }
554
555    #[test]
556    fn test_server_stop() {
557        let msg = RUMString::from("Hello World!");
558        let server = match rumtk_create_server!("localhost", 0) {
559            Ok(server) => server,
560            Err(e) => panic!("Failed to create server because {}", e),
561        };
562        println!("Sleeping");
563    }
564
565    #[test]
566    fn test_server_get_address_info() {
567        let msg = RUMString::from("Hello World!");
568        let mut server = match rumtk_create_server!("localhost", 0) {
569            Ok(server) => server,
570            Err(e) => panic!("Failed to create server because {}", e),
571        };
572        let addr = server.get_address_info().unwrap();
573        assert!(!addr.is_empty(), "No address returned....Got => {}", addr)
574    }
575
576    #[test]
577    fn test_client_send() {
578        let msg = RUMString::from("Hello World!");
579        let mut server = match rumtk_create_server!(LOCALHOST, 0) {
580            Ok(server) => server,
581            Err(e) => panic!("Failed to create server because {}", e),
582        };
583        let address_info = server.get_address_info().unwrap();
584        let (ip, port) = rumtk_get_ip_port!(address_info);
585        println!("Sleeping");
586        let mut client = match rumtk_connect!(port) {
587            Ok(client) => client,
588            Err(e) => panic!("Failed to create server because {}", e),
589        };
590        match client.send(msg.to_raw()) {
591            Ok(_) => (),
592            Err(e) => panic!("Failed to send message because {}", e),
593        };
594        let clients = server.get_client_ids();
595        let incoming_client_id = clients.first().expect("Expected client to have connected!");
596        let mut received_message = server.receive(incoming_client_id, true).unwrap();
597        if received_message.is_empty() {
598            received_message = server.receive(incoming_client_id, true).unwrap();
599        }
600        assert_eq!(
601            &msg.to_raw(),
602            &received_message,
603            "{}",
604            rumtk_format!(
605                "Received message does not match sent message by client {:?}",
606                &received_message
607            )
608        );
609    }
610
611    ////////////////////////////JSON Tests/////////////////////////////////
612
613    #[test]
614    fn test_serialize_json() {
615        #[derive(RUMSerialize)]
616        struct MyStruct {
617            hello: RUMString,
618        }
619
620        let hw = MyStruct {
621            hello: RUMString::from("World"),
622        };
623        let hw_str = rumtk_serialize!(&hw, true).unwrap();
624
625        assert!(
626            !hw_str.is_empty(),
627            "Empty JSON string generated from the test struct!"
628        );
629    }
630
631    #[test]
632    fn test_deserialize_serde_json() {
633        use serde_json::{from_str, to_string};
634
635        #[derive(RUMSerialize, RUMDeserialize, PartialEq, Debug, Clone)]
636        struct MyStruct {
637            hello: RUMString,
638        }
639
640        let hw = MyStruct {
641            hello: RUMString::from("World"),
642        };
643        let hw_str = to_string(&hw).unwrap();
644        let new_hw: MyStruct = from_str(&hw_str).unwrap();
645
646        assert_eq!(
647            new_hw, hw,
648            "Deserialized JSON does not match the expected value!"
649        );
650    }
651
652    #[test]
653    fn test_deserialize_json() {
654        #[derive(RUMSerialize, RUMDeserialize, PartialEq)]
655        struct MyStruct {
656            hello: RUMString,
657        }
658
659        let hw = MyStruct {
660            hello: RUMString::from("World"),
661        };
662        let hw_str = rumtk_serialize!(&hw, true).unwrap();
663        let new_hw: MyStruct = rumtk_deserialize!(&hw_str).unwrap();
664
665        assert!(
666            new_hw == hw,
667            "Deserialized JSON does not match the expected value!"
668        );
669    }
670
671    /*
672    #[test]
673    fn test_escape_unescape_json() {
674        #[derive(Serialize, Deserialize, PartialEq)]
675        struct MyStruct {
676            hello: RUMString,
677        }
678
679        let hw = MyStruct {
680            hello: RUMString::from("World"),
681        };
682
683        let hw_str = rumtk_serialize!(&hw, true).unwrap();
684        let hw_escaped_str = strings::basic_escape(&hw_str);
685        println!("Escaped => {}", hw_escaped_str);
686
687        let hw_unescaped_str = strings::unescape_string(&hw_escaped_str).unwrap();
688        println!("Unescaped => {}", hw_unescaped_str);
689        assert_eq!(
690            hw_str.to_rumstring(),
691            hw_unescaped_str.to_rumstring(),
692            "Unescaped serialized JSON mismatch!"
693        );
694
695        let new_hw: MyStruct = rumtk_deserialize!(&hw_unescaped_str).unwrap();
696
697        assert!(
698            new_hw == hw,
699            "Deserialized JSON does not match the expected value!"
700        );
701    }
702    */
703
704    ////////////////////////////CLI Tests/////////////////////////////////
705
706    #[test]
707    fn test_print_license_notice() {
708        print_license_notice("RUMTK", "2025", &vec!["Luis M. Santos, M.D."]);
709    }
710
711    //////////////////////////////////////////////////////////////////////////////////////////////
712
713    ////////////////////////////Pipeline Tests/////////////////////////////////
714
715    #[test]
716    fn test_pipe_processes() {
717        let ls_name = "ls";
718        let mut ls_command = RUMCommand::default();
719        ls_command.path = RUMString::from(ls_name);
720        let mut sys_ls_command = pipeline_generate_command(&ls_command);
721        sys_ls_command.stdin(Stdio::piped());
722        sys_ls_command.stdout(Stdio::piped());
723
724        let wc_name = "wc";
725        let mut wc_command = RUMCommand::default();
726        wc_command.path = RUMString::from(wc_name);
727        let mut sys_wc_command = pipeline_generate_command(&wc_command);
728
729        let mut sys_ls_process = pipeline_spawn_process(&mut sys_ls_command).unwrap();
730        pipeline_pipe_processes(&mut sys_ls_process, &mut sys_wc_command).unwrap();
731        let mut sys_wc_process = pipeline_spawn_process(&mut sys_wc_command).unwrap();
732
733        sys_ls_process.wait();
734        sys_wc_process.wait();
735    }
736
737    //////////////////////////////////////////////////////////////////////////////////////////////
738}