1use crate::Val;
2use crate::utils::utils_fns::{natural_text_segments, natural_text_segments_cs};
3use alloc::format;
4use alloc::string::{String, ToString};
5use alloc::vec::Vec;
6use bigdecimal::ToPrimitive;
7use bigdecimal::num_bigint::{BigInt, Sign};
8use deep_time::{Dt, Lang};
9
10#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
12pub struct OrderedF64(pub f64);
13
14impl Eq for OrderedF64 {}
15impl Ord for OrderedF64 {
16 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
17 self.0.total_cmp(&other.0)
18 }
19}
20impl From<f64> for OrderedF64 {
21 fn from(f: f64) -> Self {
22 OrderedF64(f)
23 }
24}
25impl From<i64> for OrderedF64 {
26 fn from(i: i64) -> Self {
27 OrderedF64(i as f64)
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
32pub enum NaturalKey {
33 Blank, Empty, Bool(bool), HugeNegative(bigdecimal::BigDecimal), Number(OrderedF64), HugePositive(bigdecimal::BigDecimal), Date(Dt), Text(Vec<Vec<NaturalSegment>>), Lexical(String), Unknown(String), }
44
45#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
46pub enum XKey {
47 Numeric(OrderedF64), Text(String), Bool(bool), Nil, }
52
53#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
54pub enum NaturalSegment {
55 Text(String),
56 Number(OrderedF64),
57}
58
59impl Val {
60 pub fn x_key(&self) -> XKey {
61 match self {
62 Val::Un8(_)
63 | Val::Un16(_)
64 | Val::Un32(_)
65 | Val::Un64(_)
66 | Val::Un128(_)
67 | Val::Sn8(_)
68 | Val::Sn16(_)
69 | Val::Sn32(_)
70 | Val::Sn64(_)
71 | Val::Sn128(_)
72 | Val::Fl64(_)
73 | Val::Dec(_)
74 | Val::Bigdec(_)
75 | Val::Bigint(_)
76 | Val::Dt(_)
77 | Val::Dur(_) => XKey::Numeric(self.x_numeric_value().unwrap_or(0.0).into()),
78 Val::Str(_) | Val::Chr(_) => XKey::Text(self.x_text_value()),
80 Val::Bl(b) => XKey::Bool(*b),
82 Val::Nil(_) | Val::Undf(_) => XKey::Nil,
84 }
85 }
86
87 pub fn cmp_x(&self, other: &Val) -> core::cmp::Ordering {
88 self.x_key().cmp(&other.x_key())
89 }
90
91 fn x_text_value(&self) -> String {
92 match self {
93 Val::Str(s) => s.to_lowercase(),
94 Val::Chr(c) => c.to_lowercase().collect(),
95 _ => String::new(),
96 }
97 }
98
99 pub fn x_numeric_value(&self) -> Option<f64> {
101 match self {
102 Val::Un8(v) => Some(*v as f64),
103 Val::Un16(v) => Some(*v as f64),
104 Val::Un32(v) => Some(*v as f64),
105 Val::Un64(v) => Some(*v as f64),
106 Val::Un128(v) => Some(*v as f64),
107 Val::Sn8(v) => Some(*v as f64),
108 Val::Sn16(v) => Some(*v as f64),
109 Val::Sn32(v) => Some(*v as f64),
110 Val::Sn64(v) => Some(*v as f64),
111 Val::Sn128(v) => Some(*v as f64),
112 Val::Fl64(v) => Some(*v),
113 Val::Dec(v) => v.to_f64(),
114 Val::Bigdec(v) => v.to_f64().or_else(|| {
116 Some(if v < &bigdecimal::BigDecimal::from(0) {
117 f64::NEG_INFINITY
118 } else {
119 f64::INFINITY
120 })
121 }),
122 Val::Bigint(v) => v.to_f64().or_else(|| {
123 Some(if v.sign() == Sign::Minus {
124 f64::NEG_INFINITY
125 } else {
126 f64::INFINITY
127 })
128 }),
129 Val::Dt(dt) => Some(dt.to_f64()),
130 Val::Dur(d) => Some(d.to_f64()),
131 _ => None,
132 }
133 }
134
135 fn make_key<F>(&self, string_to_key: F) -> NaturalKey
136 where
137 F: Fn(&str) -> NaturalKey,
138 {
139 match self {
140 Val::Nil(_) | Val::Undf(_) => NaturalKey::Blank,
141 Val::Bl(b) => NaturalKey::Bool(*b),
142 Val::Dt(dt) => NaturalKey::Date(*dt),
143 Val::Dur(d) => NaturalKey::Number(d.to_f64().into()),
144 Val::Bigint(v) => bigint_key(v),
145 Val::Bigdec(v) => bigdec_key(v),
146 other => {
147 if let Some(n) = other.x_numeric_value() {
148 NaturalKey::Number(n.into())
149 } else {
150 match other {
151 Val::Str(s) => {
152 let trimmed = s.trim();
153 if trimmed.is_empty() {
154 NaturalKey::Empty
155 } else {
156 string_to_key(trimmed)
157 }
158 }
159 Val::Chr(c) if c.is_whitespace() => NaturalKey::Empty,
160 Val::Chr(c) => string_to_key(&c.to_string()),
161 _ => NaturalKey::Unknown(format!("{:?}", other)),
162 }
163 }
164 }
165 }
166 }
167
168 #[inline(always)]
169 pub fn natural_key(&self) -> NaturalKey {
170 self.make_key(Self::natural_key_from_string)
171 }
172
173 #[inline(always)]
174 pub fn date_key(&self) -> NaturalKey {
175 self.make_key(Self::date_key_from_string)
176 }
177
178 #[inline(always)]
179 pub fn version_key(&self) -> NaturalKey {
180 self.make_key(Self::version_key_from_string)
181 }
182
183 #[inline(always)]
184 pub fn fast_key(&self) -> NaturalKey {
185 self.make_key(Self::fast_key_from_string)
186 }
187
188 #[inline(always)]
189 pub fn natural_key_cs(&self) -> NaturalKey {
190 self.make_key(Self::natural_key_cs_from_string)
191 }
192
193 #[inline(always)]
194 pub fn lexical_key(&self) -> NaturalKey {
195 NaturalKey::Lexical(self.to_string().to_lowercase())
196 }
197
198 #[inline(always)]
199 pub fn lexical_cs_key(&self) -> NaturalKey {
200 NaturalKey::Lexical(self.to_string())
201 }
202
203 #[inline(always)]
206 pub fn natural_cmp(&self, other: &Val) -> core::cmp::Ordering {
207 self.natural_key().cmp(&other.natural_key())
208 }
209
210 #[inline(always)]
211 pub fn date_cmp(&self, other: &Val) -> core::cmp::Ordering {
212 self.date_key().cmp(&other.date_key())
213 }
214
215 #[inline(always)]
216 pub fn version_cmp(&self, other: &Val) -> core::cmp::Ordering {
217 self.version_key().cmp(&other.version_key())
218 }
219
220 #[inline(always)]
221 pub fn fast_cmp(&self, other: &Val) -> core::cmp::Ordering {
222 self.fast_key().cmp(&other.fast_key())
223 }
224
225 #[inline(always)]
226 pub fn natural_cs_cmp(&self, other: &Val) -> core::cmp::Ordering {
227 self.natural_key_cs().cmp(&other.natural_key_cs())
228 }
229
230 #[inline(always)]
231 pub fn lexical_cmp(&self, other: &Val) -> core::cmp::Ordering {
232 self.lexical_key().cmp(&other.lexical_key())
233 }
234
235 #[inline(always)]
236 pub fn lexical_cs_cmp(&self, other: &Val) -> core::cmp::Ordering {
237 self.lexical_cs_key().cmp(&other.lexical_cs_key())
238 }
239
240 fn natural_key_from_string(trimmed: &str) -> NaturalKey {
241 if let Ok(f) = trimmed.parse::<f64>() {
242 if f.is_finite() {
243 return NaturalKey::Number(f.into());
244 }
245 }
246 if let Ok(dur) = Dt::from_str_duration(trimmed, Lang::En) {
247 return NaturalKey::Number(dur.to_f64().into());
248 }
249 if let Ok(ts) = Dt::from_str_parse(trimmed, &None) {
250 return NaturalKey::Date(ts);
251 }
252 NaturalKey::Text(natural_components(trimmed))
253 }
254
255 fn natural_key_cs_from_string(trimmed: &str) -> NaturalKey {
256 if let Ok(f) = trimmed.parse::<f64>() {
257 if f.is_finite() {
258 return NaturalKey::Number(f.into());
259 }
260 }
261 if let Ok(ts) = Dt::from_str_parse(trimmed, &None) {
262 return NaturalKey::Date(ts);
263 }
264 if let Ok(dur) = Dt::from_str_duration(trimmed, Lang::En) {
265 return NaturalKey::Number(dur.to_f64().into());
266 }
267 NaturalKey::Text(cs_natural_components(trimmed))
268 }
269
270 fn date_key_from_string(trimmed: &str) -> NaturalKey {
271 if let Ok(ts) = Dt::from_str_parse(trimmed, &None) {
272 return NaturalKey::Date(ts);
273 }
274 if let Ok(f) = trimmed.parse::<f64>() {
275 if f.is_finite() {
276 return NaturalKey::Number(f.into());
277 }
278 }
279 if let Ok(dur) = Dt::from_str_duration(trimmed, Lang::En) {
280 return NaturalKey::Number(dur.to_f64().into());
281 }
282 NaturalKey::Text(natural_components(trimmed))
283 }
284
285 fn version_key_from_string(trimmed: &str) -> NaturalKey {
286 NaturalKey::Text(version_components(trimmed))
287 }
288
289 fn fast_key_from_string(trimmed: &str) -> NaturalKey {
290 if let Ok(f) = trimmed.parse::<f64>() {
291 if f.is_finite() {
292 return NaturalKey::Number(f.into());
293 }
294 }
295 NaturalKey::Text(natural_components(trimmed))
296 }
297}
298
299fn bigint_key(v: &BigInt) -> NaturalKey {
300 if let Some(f) = v.to_f64() {
301 if f.is_finite() {
302 return NaturalKey::Number(f.into());
303 }
304 }
305 if v.sign() == Sign::Minus {
306 NaturalKey::HugeNegative(bigdecimal::BigDecimal::from(v.clone()))
307 } else {
308 NaturalKey::HugePositive(bigdecimal::BigDecimal::from(v.clone()))
309 }
310}
311
312fn bigdec_key(bd: &bigdecimal::BigDecimal) -> NaturalKey {
313 if let Some(f) = bd.to_f64() {
314 if f.is_finite() {
315 return NaturalKey::Number(f.into());
316 }
317 }
318 if bd < &bigdecimal::BigDecimal::from(0) {
319 NaturalKey::HugeNegative(bd.clone())
320 } else {
321 NaturalKey::HugePositive(bd.clone())
322 }
323}
324
325#[inline(always)]
326fn split_components(s: &str, separators: &[char]) -> Vec<Vec<NaturalSegment>> {
327 s.split(|c| separators.contains(&c))
328 .map(|comp| comp.trim())
329 .filter(|comp| !comp.is_empty())
330 .map(natural_text_segments)
331 .collect()
332}
333
334#[inline(always)]
335fn cs_split_components(s: &str, separators: &[char]) -> Vec<Vec<NaturalSegment>> {
336 s.split(|c| separators.contains(&c))
337 .map(|comp| comp.trim())
338 .filter(|comp| !comp.is_empty())
339 .map(natural_text_segments_cs)
340 .collect()
341}
342
343#[inline(always)]
345fn natural_components(s: &str) -> Vec<Vec<NaturalSegment>> {
346 split_components(s, &['/', '\\', '-'])
347}
348
349#[inline(always)]
350fn cs_natural_components(s: &str) -> Vec<Vec<NaturalSegment>> {
351 cs_split_components(s, &['/', '\\', '-'])
352}
353
354#[inline(always)]
356fn version_components(s: &str) -> Vec<Vec<NaturalSegment>> {
357 split_components(s, &['/', '\\', '.', '_', '-'])
358}