g_str/
lib.rs

1//! La estructura `GStr` es una envoltura segura para cadenas que evita la duplicación de las mismas.
2//! ```rust
3//! use g_str::GStr;
4//! fn main() {
5//!     let cadena = GStr::new("hola");
6//! }
7//! ```
8//! GStr ofrece metodos para:
9
10//! - **Evitar la duplicación de cadenas**: 
11//! Al internar cadenas, se asegura de que cada cadena única 
12//! se almacene solo una vez, evitando duplicaciones innecesarias.
13
14//! <br/><br/>
15
16//! - **Contar caracteres rápidamente**: Proporciona una forma rápida de obtener el número de caracteres en una cadena.
17
18//! <br/><br/>
19
20//! - **Comparación eficiente**: Permite comparar cadenas sin tener que recorrer cada carácter, utilizando referencias para una comparación más rápida.
21
22//! <br/><br/>
23
24//! - **Envoltorio seguro**: Permite que una cadena esté presente en varias variables a la vez, utilizando un contador de referencias para gestionar la vida útil de la cadena. Esto asegura que la cadena se mantenga en memoria mientras sea necesaria y se elimine automáticamente cuando ya no se use.
25
26//! 
27//! `GStr` utiliza un **contador de referencias** para gestionar la vida útil de las cadenas (Similar a lo que hace la estructura Rc). Esto significa que cada vez que una nueva variable hace referencia a una cadena, el contador de referencias aumenta. Cuando una variable deja de usar la cadena, el contador disminuye.
28mod g_norep;
29use crate::g_norep::*;
30use std::ops::Deref;
31use std::ptr;
32use std::fmt::{
33    Display,Formatter
34};
35
36/// La trait `StringInfo` es esencial para trabajar con GStr. 
37/// Su propósito principal es manejar valores de manera 
38/// generalizada. Esto significa que proporciona métodos que 
39/// la estructura `GStr` puede utilizar sin importar el **tipo de 
40/// valor que se le pase**. En otras palabras, `StringInfo` define una serie de **métodos y comportamientos** que `GStr` puede aplicar a cualquier valor, asegurando que la manipulación de cadenas sea **eficiente y sin duplicación**.
41pub trait StringInfo {
42    /// Devuelve una referencia a una cadena constante utilizada para la búsqueda de cadenas existentes.
43    fn get_str_ref(&self) -> &str;
44
45    /// Esta función se invoca cuando se ha realizado una búsqueda y no se ha encontrado ninguna coincidencia. En este caso, la función debe proceder a crear una nueva cadena.
46    fn get_str(self) -> String; 
47}
48#[doc(hidden)]
49impl StringInfo for String {
50    fn get_str_ref(&self) -> &str {
51        self.as_ref()
52    }
53    fn get_str(self) -> String {
54        self
55    } 
56}
57#[doc(hidden)]
58impl StringInfo for &String {
59    fn get_str_ref(&self) -> &str {
60        self.as_ref()
61    }
62    fn get_str(self) -> String {
63        String::from(self)
64    }
65}
66#[doc(hidden)]
67impl StringInfo for &str {
68    fn get_str_ref(&self) -> &str {
69        self
70    }
71    fn get_str(self) -> String {
72        self.to_string()
73    }
74}
75/// estructura que envuelve la cadena de manera segura y evita la duplicación de la cadena.
76/// ```rust
77/// use g_str::GStr;
78/// fn main() {
79///     let cadena = GStr::new("hola");
80/// }
81/// ```
82/// GStr utiliza un contador de referencias para gestionar la vida útil de las cadenas (Similar a lo que hace la estructura Rc). Esto significa que cada vez que una nueva variable hace referencia a una cadena, el contador de referencias aumenta. Cuando una variable deja de usar la cadena, el contador disminuye.
83pub struct GStr {
84    value: *mut GStrInterner
85}
86
87impl GStr {
88    fn search_value(strn: &str, len: usize, hash: u32, mut value: *mut GStrInterner) -> Option<GStr>{
89        // recorrer la lista
90        unsafe {
91            while value != ptr::null_mut() {
92                if (*value).compare(hash,len, strn) {
93
94                    (*value).count+=1;
95                    return Some(GStr {
96                        value: value
97                    });
98
99                }
100                value = (*value).next;
101            }
102        }
103        None
104    }
105    fn create_gstr(vstr: String, len: usize, hash: u32) -> GStr {
106        unsafe {    
107            let gstr = GStrInterner {
108                value: vstr,
109                len,hash,
110                count: 1,
111                next: ptr::null_mut(),
112                prev: GLIST_NODO.end
113            };
114            let pun_str = Box::into_raw(Box::new(gstr));
115        
116            // si hay un elemento anterior, actualizar su valor next
117            if GLIST_NODO.end != ptr::null_mut(){
118                (*GLIST_NODO.end).next = pun_str;
119            }
120            GLIST_NODO.end = pun_str;
121            // se debe colocar un valor a begin si no tiene
122            if GLIST_NODO.begin == ptr::null_mut(){
123                GLIST_NODO.begin = GLIST_NODO.end;
124            }
125            GStr {
126                value: GLIST_NODO.end
127            }
128        }
129    }
130    /// Esta función realiza una búsqueda en las cadenas previamente creadas para encontrar una que coincida con la cadena recibida.
131    /// - **Si la cadena existe**, la función te devuelve un `GStr` que apunta a esa cadena existente.
132    /// - **Si la cadena no existe**, la función crea una nueva cadena y te devuelve un `GStr` que apunta a esta nueva cadena.
133    pub fn new<T: StringInfo>(strn: T) -> GStr{
134        let mut len : usize = 0;
135        let hash : u32 = ohash(strn.get_str_ref(),&mut len);
136        unsafe {
137            // bloquear mutex
138            let _unused = GNOREP_LOOCK.lock().expect("No se pudo bloquear el mutex");
139            let value : *mut GStrInterner = GLIST_NODO.begin;
140
141            match GStr::search_value(strn.get_str_ref(), len, hash, value) {
142                Some(v) => return v,
143                _=> {}
144            } 
145
146           
147            GStr::create_gstr(strn.get_str(), len, hash)
148        }
149    }
150    /// Esta función devuelve la cantidad de caracteres que contiene la cadena.
151    pub fn chars_count(&self) -> usize {
152        unsafe { (*self.value).len } 
153    }
154}
155impl AsRef<str> for GStr {
156    /// Esta función retorna una referencia inmutable a la cadena.
157    fn as_ref(&self) -> &str {
158        unsafe { &(*self.value).value }
159    }
160}
161impl Clone for GStr {
162    /// Clona el `GStr`. No crea una copia de la cadena, simplemente crea un nuevo `GStr` que apunta a la **cadena existente**.
163    fn clone(&self) -> Self{ 
164        unsafe {(*self.value).count+= 1;}
165        GStr {
166            value: self.value
167        }
168    }
169}   
170
171impl Drop for GStr {
172    /// funcion para determinar si eliminar la cadena.
173    fn drop(&mut self) {
174        let value = self.value;
175        unsafe {
176            (*value).count-= 1;
177            if (*value).count == 0 {
178                (*value).remove();
179                let _ = Box::from_raw(value); // dejar que rust elimine el valor
180            }
181        }
182    }
183}
184
185impl Display for GStr {
186    /// permite imprimir el `GStr` en una cadena directamente sin acceder a la cadena.
187    /// ```rust
188    /// use g_str::GStr;
189    /// fn main() {
190    ///     let nombre = GStr::new("hola");
191    ///     println!("hola {nombre}");
192    /// }
193    /// ```
194    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
195        write!(f, "{}",self.as_ref())
196    }
197}
198
199impl PartialEq for GStr {
200    /// sobrecarga al operador `==` para ver si dos cadenas son las mismas, comparando su ubicacion de memoria, es decir, comparar dos referencias en vez de hacer un analisis caracter por caracter.
201    fn eq(&self, other: &Self) -> bool {
202        self.value == other.value
203    }
204    /// igual que lo anterior, pero sobrecargando el operador `!=` para ver si dos cadenas son diferentes
205    fn ne(&self, other: &Self) -> bool {
206        self.value != other.value
207    }
208}
209
210#[doc(hidden)]
211impl Deref for GStr {
212    type Target = str;
213    /// devuelve la cadena que envuelve
214    fn deref(&self) -> &Self::Target {
215        self.as_ref()
216    }
217}