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.
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 */
21use crate::strings::rumtk_format;
22use crate::strings::RUMString;
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>;
32
33pub fn is_unique<T: std::cmp::Eq + std::hash::Hash>(data: &Vec<T>) -> bool {
34    let mut keys = ahash::AHashSet::with_capacity(data.len());
35    for itm in data {
36        if !keys.insert(itm) {
37            return false;
38        }
39    }
40    true
41}
42
43///
44/// Take a requested index and the maximum size of the item container.
45/// Check if the index is valid and return an error if it is.
46/// The purpose of this function is to enable handling of out of bounds without triggering a panic.
47/// Also, add negative indices like Python does when doing a reverse search!
48///
49/// * If the index is 0, return Error
50/// * If the index is below 0, return the max - index iff max - index > 0
51/// * If the index is bigger than the defined max, return Error.
52/// * Otherwise, return the given index.
53///
54/// # Examples
55///
56/// ## Min
57/// ```
58/// use ::rumtk_core::core::clamp_index;
59/// use ::rumtk_core::strings::rumtk_format;
60/// let max: isize = 5;
61/// let i: isize = 1;
62/// let result = clamp_index(&i, &max).unwrap();
63/// assert_eq!(&1, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
64/// ```
65///
66/// ## Max
67/// ```
68/// use ::rumtk_core::core::clamp_index;
69/// use ::rumtk_core::strings::rumtk_format;
70/// let max: isize = 5;
71/// let i: isize = 5;
72/// let result = clamp_index(&i, &max).unwrap();
73/// assert_eq!(&5, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
74/// ```
75///
76/// ## Valid
77/// ```
78/// use ::rumtk_core::core::clamp_index;
79/// use ::rumtk_core::strings::rumtk_format;
80/// let max: isize = 5;
81/// let i: isize = 5;
82/// let result = clamp_index(&i, &max).unwrap();
83/// assert_eq!(&5, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
84/// ```
85///
86/// ## Valid Negative Index (reverse lookup)
87/// ```
88/// use ::rumtk_core::core::clamp_index;
89/// use ::rumtk_core::strings::rumtk_format;
90/// let max: isize = 5;
91/// let i: isize = -1;
92/// let result = clamp_index(&i, &max).unwrap();
93/// assert_eq!(&5, &result, "{}", rumtk_format!("Expected to receive 0 but got {}", &result))
94/// ```
95#[inline(always)]
96pub fn clamp_index(given_indx: &isize, max_size: &isize) -> RUMResult<usize> {
97    let neg_max_indx = *max_size * -1;
98    if *given_indx == 0 {
99        return Err(rumtk_format!(
100            "Index {} is invalid! Use 1-indexed values if using positive indices.",
101            given_indx
102        ));
103    }
104
105    if *given_indx >= neg_max_indx && *given_indx < 0 {
106        return Ok((max_size + given_indx + 1) as usize);
107    }
108
109    if *given_indx > 0 && given_indx <= max_size {
110        return Ok(*given_indx as usize);
111    }
112
113    Err(rumtk_format!(
114        "Index {} is outside {} < x < {} boundary!",
115        given_indx,
116        neg_max_indx,
117        max_size
118    ))
119}