rumtk_core/core.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) 2025 Luis M. Santos, M.D. <lsantos@medicalmasses.com>
5 * Copyright (C) 2025 MedicalMasses L.L.C. <contact@medicalmasses.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20use crate::strings::rumtk_format;
21use crate::strings::RUMString;
22use std::collections::VecDeque;
23
24pub type RUMError = RUMString;
25
26///
27/// Type used for propagating error messages.
28///
29pub type RUMResult<T> = Result<T, RUMError>;
30
31pub type RUMVec<T> = Vec<T>;
32pub type RUMVecDeque<T> = VecDeque<T>;
33
34pub fn is_unique<T: std::cmp::Eq + std::hash::Hash>(data: &Vec<T>) -> bool {
35 let mut keys = ahash::AHashSet::with_capacity(data.len());
36 for itm in data {
37 if !keys.insert(itm) {
38 return false;
39 }
40 }
41 true
42}
43
44///
45/// Take a requested index and the maximum size of the item container.
46/// Check if the index is valid and return an error if it is.
47/// The purpose of this function is to enable handling of out of bounds without triggering a panic.
48/// Also, add negative indices like Python does when doing a reverse search!
49///
50/// * If the index is 0, return Error
51/// * If the index is below 0, return the max - index iff max - index > 0
52/// * If the index is bigger than the defined max, return Error.
53/// * Otherwise, return the given index.
54///
55/// # Examples
56///
57/// ## Min
58/// ```
59/// use ::rumtk_core::core::clamp_index;
60/// use ::rumtk_core::strings::rumtk_format;
61/// let max: isize = 5;
62/// let i: isize = 1;
63/// let result = clamp_index(&i, &max).unwrap();
64/// assert_eq!(&1, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
65/// ```
66///
67/// ## Max
68/// ```
69/// use ::rumtk_core::core::clamp_index;
70/// use ::rumtk_core::strings::rumtk_format;
71/// let max: isize = 5;
72/// let i: isize = 5;
73/// let result = clamp_index(&i, &max).unwrap();
74/// assert_eq!(&5, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
75/// ```
76///
77/// ## Valid
78/// ```
79/// use ::rumtk_core::core::clamp_index;
80/// use ::rumtk_core::strings::rumtk_format;
81/// let max: isize = 5;
82/// let i: isize = 5;
83/// let result = clamp_index(&i, &max).unwrap();
84/// assert_eq!(&5, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
85/// ```
86///
87/// ## Valid Negative Index (reverse lookup)
88/// ```
89/// use ::rumtk_core::core::clamp_index;
90/// use ::rumtk_core::strings::rumtk_format;
91/// let max: isize = 5;
92/// let i: isize = -1;
93/// let result = clamp_index(&i, &max).unwrap();
94/// assert_eq!(&5, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
95/// ```
96#[inline(always)]
97pub fn clamp_index(given_indx: &isize, max_size: &isize) -> RUMResult<usize> {
98 let neg_max_indx = *max_size * -1;
99 if *given_indx == 0 {
100 return Err(rumtk_format!(
101 "Index {} is invalid! Use 1-indexed values if using positive indices.",
102 given_indx
103 ));
104 }
105
106 if *given_indx >= neg_max_indx && *given_indx < 0 {
107 return Ok((max_size + given_indx + 1) as usize);
108 }
109
110 if *given_indx > 0 && given_indx <= max_size {
111 return Ok(*given_indx as usize);
112 }
113
114 Err(rumtk_format!(
115 "Index {} is outside {} < x < {} boundary!",
116 given_indx,
117 neg_max_indx,
118 max_size
119 ))
120}