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}