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 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21//#![feature(unboxed_closures)]
22#![feature(inherent_associated_types)]
23#![feature(type_alias_impl_trait)]
24#![feature(unboxed_closures)]
25
26pub mod cache;
27pub mod core;
28pub mod log;
29pub mod maths;
30pub mod net;
31pub mod queue;
32pub mod search;
33pub mod strings;
34pub mod threading;
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::cache::RUMCache;
40    use crate::search::rumtk_search::*;
41    use crate::strings::{RUMArrayConversions, RUMString, RUMStringConversions};
42    use compact_str::{format_compact, CompactString};
43    use std::future::IntoFuture;
44    use std::sync::Arc;
45    use tokio::sync::RwLock;
46
47    #[test]
48    fn test_escaping_control() {
49        let input = "\r\n\'\"";
50        let expected = "\\r\\n\\'\\\"";
51        let result = strings::escape(&input);
52        println!(
53            "Input: {} Expected: {} Got: {}",
54            input,
55            expected,
56            result.as_str()
57        );
58        assert_eq!(expected, result, "Incorrect string escaping!");
59        println!("Passed!")
60    }
61
62    #[test]
63    fn test_escaping_unicode() {
64        let input = "❤";
65        let expected = "\\u2764";
66        let result = strings::escape(&input);
67        println!(
68            "Input: {} Expected: {} Got: {}",
69            input,
70            expected,
71            result.as_str()
72        );
73        assert_eq!(expected, result, "Incorrect string escaping!");
74        println!("Passed!")
75    }
76
77    #[test]
78    fn test_unescaping_unicode() {
79        let input = "❤";
80        let escaped = strings::escape(&input);
81        let expected = "❤";
82        let result = RUMString::from_utf8(strings::unescape(&escaped.as_str()).unwrap()).unwrap();
83        println!(
84            "Input: {} Expected: {} Got: {}",
85            input,
86            expected,
87            result.as_str()
88        );
89        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
90        println!("Passed!")
91    }
92
93    #[test]
94    fn test_unescaping_string() {
95        let input = "I \\u2764 my wife!";
96        let expected = "I ❤ my wife!";
97        let result = strings::unescape_string(&input).unwrap();
98        println!(
99            "Input: {} Expected: {} Got: {}",
100            input,
101            expected,
102            result.as_str()
103        );
104        assert_eq!(expected, result.as_str(), "Incorrect string unescaping!");
105        println!("Passed!")
106    }
107
108    #[test]
109    fn test_escaping_string() {
110        let input = "I ❤ my wife!";
111        let expected = "I \\u2764 my wife!";
112        let result = strings::escape(&input);
113        println!(
114            "Input: {} Expected: {} Got: {}",
115            input,
116            expected,
117            result.as_str()
118        );
119        assert_eq!(expected, result.as_str(), "Incorrect string escaping!");
120        println!("Passed!")
121    }
122
123    #[test]
124    fn test_autodecode_utf8() {
125        let input = "I ❤ my wife!";
126        let result = strings::try_decode(input.as_bytes());
127        println!(
128            "Input: {} Expected: {} Got: {}",
129            input,
130            input,
131            result.as_str()
132        );
133        assert_eq!(input, result, "Incorrect string decoding!");
134        println!("Passed!")
135    }
136
137    #[test]
138    fn test_autodecode_other() {
139        //TODO: Need an example of other encoding texts.
140        let input = "I ❤ my wife!";
141        let expected = "I ❤ my wife!";
142        let result = input;
143        println!("Input: {} Expected: {} Got: {}", input, input, result);
144        assert_eq!(input, result, "Incorrect string decoding!");
145        println!("Passed!")
146    }
147
148    #[test]
149    fn test_decode() {
150        let input = "I ❤ my wife!";
151        let expected = "I ❤ my wife!";
152        let result = strings::try_decode_with(input.as_bytes(), "utf-8");
153        println!(
154            "Input: {} Expected: {} Got: {}",
155            input,
156            input,
157            result.as_str()
158        );
159        assert_eq!(input, result, "Incorrect string decoding!");
160        println!("Passed!")
161    }
162
163    #[test]
164    fn test_rumcache_insertion() {
165        let mut cache: RUMCache<&str, CompactString> = RUMCache::with_capacity(5);
166        cache.insert("❤", CompactString::from("I ❤ my wife!"));
167        println!("Contents: {:#?}", &cache);
168        assert_eq!(cache.len(), 1, "Incorrect number of items in cache!");
169        println!("Passed!")
170    }
171
172    #[test]
173    fn test_search_string_letters() {
174        let input = "Hello World!";
175        let expr = r"\w";
176        let result = string_search(input, expr, "");
177        let expected: RUMString = RUMString::from("HelloWorld");
178        println!(
179            "Input: {:?} Expected: {:?} Got: {:?}",
180            input, expected, result
181        );
182        assert_eq!(expected, result, "String search results mismatch");
183        println!("Passed!")
184    }
185
186    #[test]
187    fn test_search_string_words() {
188        let input = "Hello World!";
189        let expr = r"\w+";
190        let result = string_search(input, expr, " ");
191        let expected: RUMString = RUMString::from("Hello World");
192        println!(
193            "Input: {:?} Expected: {:?} Got: {:?}",
194            input, expected, result
195        );
196        assert_eq!(expected, result, "String search results mismatch");
197        println!("Passed!")
198    }
199
200    #[test]
201    fn test_search_string_named_groups() {
202        let input = "Hello World!";
203        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
204        let result = string_search_named_captures(input, expr, "");
205        let expected: RUMString = RUMString::from("World");
206        println!(
207            "Input: {:?} Expected: {:?} Got: {:?}",
208            input, expected, result
209        );
210        assert_eq!(expected, result["world"], "String search results mismatch");
211        println!("Passed!")
212    }
213
214    #[test]
215    fn test_search_string_all_groups() {
216        let input = "Hello World!";
217        let expr = r"(?<hello>\w{5}) (?<world>\w{5})";
218        let result = string_search_all_captures(input, expr, "");
219        let expected: Vec<&str> = vec!["Hello", "World"];
220        println!(
221            "Input: {:?} Expected: {:?} Got: {:?}",
222            input, expected, result
223        );
224        assert_eq!(expected, result, "String search results mismatch");
225        println!("Passed!")
226    }
227
228    ///////////////////////////////////Threading Tests/////////////////////////////////////////////////
229    #[test]
230    fn test_default_num_threads() {
231        use num_cpus;
232        let threads = threading::threading_functions::get_default_system_thread_count();
233        assert_eq!(
234            threads >= num_cpus::get(),
235            true,
236            "Default thread count is incorrect! We got {}, but expected {}!",
237            threads,
238            num_cpus::get()
239        );
240    }
241
242    #[test]
243    fn test_execute_job() {
244        let rt = rumtk_init_threads!();
245        let expected = vec![1, 2, 3];
246        let task_processor = async |args: &SafeTaskArgs<i32>| -> TaskResult<i32> {
247            let owned_args = Arc::clone(args);
248            let lock_future = owned_args.read();
249            let locked_args = lock_future.await;
250            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
251            print!("Contents: ");
252            for arg in locked_args.iter() {
253                results.push(arg.clone());
254                println!("{} ", &arg);
255            }
256            Ok(results)
257        };
258        let locked_args = RwLock::new(expected.clone());
259        let task_args = SafeTaskArgs::<i32>::new(locked_args);
260        let task_result = rumtk_wait_on_task!(rt, task_processor, &task_args);
261        let result = task_result.unwrap();
262        assert_eq!(&result, &expected, "{}", format_compact!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
263    }
264
265    #[test]
266    fn test_execute_job_macros() {
267        let rt = rumtk_init_threads!();
268        let expected = vec![1, 2, 3];
269        let task_processor = async |args: &SafeTaskArgs<i32>| -> TaskResult<i32> {
270            let owned_args = Arc::clone(args);
271            let lock_future = owned_args.read();
272            let locked_args = lock_future.await;
273            let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
274            print!("Contents: ");
275            for arg in locked_args.iter() {
276                results.push(arg.clone());
277                println!("{} ", &arg);
278            }
279            Ok(results)
280        };
281        let task_args = rumtk_create_task_args!(1, 2, 3);
282        let task_result = rumtk_wait_on_task!(rt, task_processor, &task_args);
283        let result = task_result.unwrap();
284        assert_eq!(&result, &expected, "{}", format_compact!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
285    }
286
287    #[test]
288    fn test_execute_job_macros_one_line() {
289        let rt = rumtk_init_threads!();
290        let expected = vec![1, 2, 3];
291        let result = rumtk_exec_task!(
292            async |args: &SafeTaskArgs<i32>| -> TaskResult<i32> {
293                let owned_args = Arc::clone(args);
294                let lock_future = owned_args.read();
295                let locked_args = lock_future.await;
296                let mut results = TaskItems::<i32>::with_capacity(locked_args.len());
297                print!("Contents: ");
298                for arg in locked_args.iter() {
299                    results.push(arg.clone());
300                    println!("{} ", &arg);
301                }
302                Ok(results)
303            },
304            vec![1, 2, 3]
305        )
306        .unwrap();
307        assert_eq!(&result, &expected, "{}", format_compact!("Task processing returned a different result than expected! Expected {:?} \nResults {:?}", &expected, &result));
308    }
309
310    ///////////////////////////////////Queue Tests/////////////////////////////////////////////////
311    use crate::net::tcp::LOCALHOST;
312    use crate::threading::thread_primitives::{SafeTaskArgs, TaskItems, TaskResult};
313    use crate::threading::threading_functions::sleep;
314    use queue::queue::*;
315
316    #[test]
317    fn test_queue_data() {
318        let expected = vec![
319            RUMString::from("Hello"),
320            RUMString::from("World!"),
321            RUMString::from("Overcast"),
322            RUMString::from("and"),
323            RUMString::from("Sad"),
324        ];
325        let mut queue = TaskQueue::<RUMString>::new(&5).unwrap();
326        let locked_args = RwLock::new(expected.clone());
327        let task_args = SafeTaskArgs::<RUMString>::new(locked_args);
328        let processor = rumtk_create_task!(
329            async |args: &SafeTaskArgs<RUMString>| -> TaskResult<RUMString> {
330                let owned_args = Arc::clone(args);
331                let lock_future = owned_args.read();
332                let locked_args = lock_future.await;
333                let mut results = TaskItems::<RUMString>::with_capacity(locked_args.len());
334                print!("Contents: ");
335                for arg in locked_args.iter() {
336                    print!("{} ", &arg);
337                    results.push(RUMString::new(arg));
338                }
339                Ok(results)
340            },
341            task_args
342        );
343        queue.add_task::<_>(processor);
344        let results = queue.wait();
345        let mut result_data = Vec::<RUMString>::with_capacity(5);
346        for r in results {
347            for v in r.unwrap().iter() {
348                result_data.push(v.clone());
349            }
350        }
351        assert_eq!(result_data, expected, "Results do not match expected!");
352    }
353
354    ///////////////////////////////////Net Tests/////////////////////////////////////////////////
355    #[test]
356    fn test_server_start() {
357        let mut server = match rumtk_create_server!("localhost", 55555) {
358            Ok(server) => server,
359            Err(e) => panic!("Failed to create server because {}", e),
360        };
361        match server.start(false) {
362            Ok(_) => (),
363            Err(e) => panic!("Failed to start server because {}", e),
364        }
365    }
366
367    #[test]
368    fn test_server_send() {
369        let msg = RUMString::from("Hello World!");
370        let mut server = match rumtk_create_server!(LOCALHOST, 55555, 1) {
371            Ok(server) => server,
372            Err(e) => panic!("Failed to create server because {}", e),
373        };
374        match server.start(false) {
375            Ok(_) => (),
376            Err(e) => panic!("Failed to start server because {}", e),
377        };
378        println!("Sleeping");
379        rumtk_sleep!(1);
380        let mut client = match rumtk_connect!(55555) {
381            Ok(client) => client,
382            Err(e) => panic!("Failed to create server because {}", e),
383        };
384        let client_id = client.get_address().unwrap();
385        rumtk_sleep!(1);
386        match server.send(&client_id, &msg.to_raw()) {
387            Ok(_) => (),
388            Err(e) => panic!("Server failed to send message because {}", e),
389        };
390        rumtk_sleep!(1);
391        let received_message = client.receive().unwrap();
392        assert_eq!(
393            &msg.to_raw(),
394            &received_message,
395            "{}",
396            format_compact!(
397                "Received message does not match sent message by server {:?}",
398                &received_message
399            )
400        );
401    }
402
403    #[test]
404    fn test_server_receive() {
405        let msg = RUMString::from("Hello World!");
406        let mut server = match rumtk_create_server!(LOCALHOST, 55555) {
407            Ok(server) => server,
408            Err(e) => panic!("Failed to create server because {}", e),
409        };
410        match server.start(false) {
411            Ok(_) => (),
412            Err(e) => panic!("Failed to start server because {}", e),
413        };
414        println!("Sleeping");
415        rumtk_sleep!(1);
416        let mut client = match rumtk_connect!(55555) {
417            Ok(client) => client,
418            Err(e) => panic!("Failed to create server because {}", e),
419        };
420        match client.send(&msg.to_raw()) {
421            Ok(_) => (),
422            Err(e) => panic!("Failed to send message because {}", e),
423        };
424        rumtk_sleep!(1);
425        let client_id = client.get_address().expect("Failed to get client id");
426        let incoming_message = server.receive(&client_id).unwrap().to_rumstring();
427        println!("Received message => {:?}", &incoming_message);
428        assert_eq!(&incoming_message, msg, "Received message corruption!");
429    }
430
431    #[test]
432    fn test_server_get_clients() {
433        let mut server = match rumtk_create_server!(LOCALHOST, 55555) {
434            Ok(server) => server,
435            Err(e) => panic!("Failed to create server because {}", e),
436        };
437        match server.start(false) {
438            Ok(_) => (),
439            Err(e) => panic!("Failed to start server because {}", e),
440        };
441        println!("Sleeping");
442        rumtk_sleep!(1);
443        let mut client = match rumtk_connect!(55555) {
444            Ok(client) => client,
445            Err(e) => panic!("Failed to create server because {}", e),
446        };
447        rumtk_sleep!(1);
448        let expected_client_id = client.get_address().expect("Failed to get client id");
449        let clients = server.get_client_ids();
450        let incoming_client_id = clients.get(0).expect("Expected client to have connected!");
451        println!("Connected client id => {}", &incoming_client_id);
452        assert_eq!(
453            &incoming_client_id, &expected_client_id,
454            "Connected client does not match the connecting client! Client id => {}",
455            &incoming_client_id
456        );
457    }
458
459    #[test]
460    fn test_server_stop() {
461        let msg = RUMString::from("Hello World!");
462        let mut server = match rumtk_create_server!("localhost", 55555) {
463            Ok(server) => server,
464            Err(e) => panic!("Failed to create server because {}", e),
465        };
466        match server.start(false) {
467            Ok(_) => (),
468            Err(e) => panic!("Failed to start server because {}", e),
469        };
470        println!("Sleeping");
471        rumtk_sleep!(1);
472        match server.stop() {
473            Ok(_) => (),
474            Err(e) => panic!("Failed to stop server because {}", e),
475        };
476    }
477
478    #[test]
479    fn test_server_get_address_info() {
480        let msg = RUMString::from("Hello World!");
481        let mut server = match rumtk_create_server!("localhost", 55555) {
482            Ok(server) => server,
483            Err(e) => panic!("Failed to create server because {}", e),
484        };
485        match server.start(false) {
486            Ok(_) => (),
487            Err(e) => panic!("Failed to start server because {}", e),
488        };
489        println!("Sleeping");
490        rumtk_sleep!(1);
491        match server.get_address_info() {
492            Some(addr) => println!("Server address info => {}", addr),
493            None => panic!("No address. Perhaps the server was never initialized?"),
494        };
495    }
496
497    #[test]
498    fn test_client_send() {
499        let msg = RUMString::from("Hello World!");
500        let mut server = match rumtk_create_server!(LOCALHOST, 55555) {
501            Ok(server) => server,
502            Err(e) => panic!("Failed to create server because {}", e),
503        };
504        match server.start(false) {
505            Ok(_) => (),
506            Err(e) => panic!("Failed to start server because {}", e),
507        };
508        println!("Sleeping");
509        rumtk_sleep!(1);
510        let mut client = match rumtk_connect!(55555) {
511            Ok(client) => client,
512            Err(e) => panic!("Failed to create server because {}", e),
513        };
514        rumtk_sleep!(1);
515        match client.send(&msg.to_raw()) {
516            Ok(_) => (),
517            Err(e) => panic!("Failed to send message because {}", e),
518        };
519        rumtk_sleep!(1);
520        let clients = server.get_client_ids();
521        let incoming_client_id = clients.get(0).expect("Expected client to have connected!");
522        let mut received_message = server.receive(&incoming_client_id).unwrap();
523        if received_message.is_empty() {
524            rumtk_sleep!(1);
525            received_message = server.receive(&incoming_client_id).unwrap();
526        }
527        assert_eq!(
528            &msg.to_raw(),
529            &received_message,
530            "{}",
531            format_compact!(
532                "Received message does not match sent message by client {:?}",
533                &received_message
534            )
535        );
536    }
537
538    //////////////////////////////////////////////////////////////////////////////////////////////
539}