1use std::cmp::Ordering;
2use std::hash::{BuildHasher, Hash, Hasher};
3
4use bytemuck::TransparentWrapper;
5use num_traits::Zero;
6
7use crate::float16::pf16;
8use crate::hashing::{BytesHash, DirtyHash};
9use crate::nulls::IsNull;
10
11#[inline]
14pub fn canonical_f16(x: pf16) -> pf16 {
15 let convert_zero = x + pf16::zero(); if convert_zero.is_nan() {
18 pf16(half::f16::from_bits(0x7e00)) } else {
20 convert_zero
21 }
22}
23
24#[inline]
27pub fn canonical_f32(x: f32) -> f32 {
28 let convert_zero = x + 0.0;
30 if convert_zero.is_nan() {
31 f32::from_bits(0x7fc00000) } else {
33 convert_zero
34 }
35}
36
37#[inline]
40pub fn canonical_f64(x: f64) -> f64 {
41 let convert_zero = x + 0.0;
43 if convert_zero.is_nan() {
44 f64::from_bits(0x7ff8000000000000) } else {
46 convert_zero
47 }
48}
49
50pub trait TotalEq {
53 fn tot_eq(&self, other: &Self) -> bool;
54
55 #[inline]
56 fn tot_ne(&self, other: &Self) -> bool {
57 !(self.tot_eq(other))
58 }
59}
60
61pub trait TotalOrd: TotalEq {
64 fn tot_cmp(&self, other: &Self) -> Ordering;
65
66 #[inline]
67 fn tot_lt(&self, other: &Self) -> bool {
68 self.tot_cmp(other) == Ordering::Less
69 }
70
71 #[inline]
72 fn tot_gt(&self, other: &Self) -> bool {
73 self.tot_cmp(other) == Ordering::Greater
74 }
75
76 #[inline]
77 fn tot_le(&self, other: &Self) -> bool {
78 self.tot_cmp(other) != Ordering::Greater
79 }
80
81 #[inline]
82 fn tot_ge(&self, other: &Self) -> bool {
83 self.tot_cmp(other) != Ordering::Less
84 }
85}
86
87pub trait TotalHash {
90 fn tot_hash<H>(&self, state: &mut H)
91 where
92 H: Hasher;
93
94 fn tot_hash_slice<H>(data: &[Self], state: &mut H)
95 where
96 H: Hasher,
97 Self: Sized,
98 {
99 for piece in data {
100 piece.tot_hash(state)
101 }
102 }
103}
104
105pub trait BuildHasherTotalExt: BuildHasher {
106 fn tot_hash_one<T>(&self, x: T) -> u64
107 where
108 T: TotalHash,
109 Self: Sized,
110 <Self as BuildHasher>::Hasher: Hasher,
111 {
112 let mut hasher = self.build_hasher();
113 x.tot_hash(&mut hasher);
114 hasher.finish()
115 }
116}
117
118impl<T: BuildHasher> BuildHasherTotalExt for T {}
119
120#[derive(Debug)]
121#[cfg_attr(
122 feature = "serde",
123 derive(serde::Serialize, serde::Deserialize),
124 serde(transparent)
125)]
126#[cfg_attr(
127 feature = "dsl-schema",
128 derive(schemars::JsonSchema),
129 schemars(transparent)
130)]
131#[repr(transparent)]
132pub struct TotalOrdWrap<T>(pub T);
133unsafe impl<T> TransparentWrapper<T> for TotalOrdWrap<T> {}
134
135impl<T: TotalOrd> PartialOrd for TotalOrdWrap<T> {
136 #[inline(always)]
137 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
138 Some(self.cmp(other))
139 }
140
141 #[inline(always)]
142 fn lt(&self, other: &Self) -> bool {
143 self.0.tot_lt(&other.0)
144 }
145
146 #[inline(always)]
147 fn le(&self, other: &Self) -> bool {
148 self.0.tot_le(&other.0)
149 }
150
151 #[inline(always)]
152 fn gt(&self, other: &Self) -> bool {
153 self.0.tot_gt(&other.0)
154 }
155
156 #[inline(always)]
157 fn ge(&self, other: &Self) -> bool {
158 self.0.tot_ge(&other.0)
159 }
160}
161
162impl<T: TotalOrd> Ord for TotalOrdWrap<T> {
163 #[inline(always)]
164 fn cmp(&self, other: &Self) -> Ordering {
165 self.0.tot_cmp(&other.0)
166 }
167}
168
169impl<T: TotalEq> PartialEq for TotalOrdWrap<T> {
170 #[inline(always)]
171 fn eq(&self, other: &Self) -> bool {
172 self.0.tot_eq(&other.0)
173 }
174
175 #[inline(always)]
176 #[allow(clippy::partialeq_ne_impl)]
177 fn ne(&self, other: &Self) -> bool {
178 self.0.tot_ne(&other.0)
179 }
180}
181
182impl<T: TotalEq> Eq for TotalOrdWrap<T> {}
183
184impl<T: TotalHash> Hash for TotalOrdWrap<T> {
185 #[inline(always)]
186 fn hash<H: Hasher>(&self, state: &mut H) {
187 self.0.tot_hash(state);
188 }
189}
190
191impl<T: Clone> Clone for TotalOrdWrap<T> {
192 #[inline]
193 fn clone(&self) -> Self {
194 Self(self.0.clone())
195 }
196}
197
198impl<T: Copy> Copy for TotalOrdWrap<T> {}
199
200impl<T: IsNull> IsNull for TotalOrdWrap<T> {
201 const HAS_NULLS: bool = T::HAS_NULLS;
202 type Inner = T::Inner;
203
204 #[inline(always)]
205 fn is_null(&self) -> bool {
206 self.0.is_null()
207 }
208
209 #[inline(always)]
210 fn unwrap_inner(self) -> Self::Inner {
211 self.0.unwrap_inner()
212 }
213}
214
215impl DirtyHash for pf16 {
216 #[inline(always)]
217 fn dirty_hash(&self) -> u64 {
218 canonical_f16(*self).0.to_bits().dirty_hash()
219 }
220}
221
222impl DirtyHash for f32 {
223 #[inline(always)]
224 fn dirty_hash(&self) -> u64 {
225 canonical_f32(*self).to_bits().dirty_hash()
226 }
227}
228
229impl DirtyHash for f64 {
230 #[inline(always)]
231 fn dirty_hash(&self) -> u64 {
232 canonical_f64(*self).to_bits().dirty_hash()
233 }
234}
235
236impl<T: DirtyHash> DirtyHash for TotalOrdWrap<T> {
237 #[inline(always)]
238 fn dirty_hash(&self) -> u64 {
239 self.0.dirty_hash()
240 }
241}
242
243macro_rules! impl_trivial_total {
244 ($T: ty) => {
245 impl TotalEq for $T {
246 #[inline(always)]
247 fn tot_eq(&self, other: &Self) -> bool {
248 self == other
249 }
250
251 #[inline(always)]
252 fn tot_ne(&self, other: &Self) -> bool {
253 self != other
254 }
255 }
256
257 impl TotalOrd for $T {
258 #[inline(always)]
259 fn tot_cmp(&self, other: &Self) -> Ordering {
260 self.cmp(other)
261 }
262
263 #[inline(always)]
264 fn tot_lt(&self, other: &Self) -> bool {
265 self < other
266 }
267
268 #[inline(always)]
269 fn tot_gt(&self, other: &Self) -> bool {
270 self > other
271 }
272
273 #[inline(always)]
274 fn tot_le(&self, other: &Self) -> bool {
275 self <= other
276 }
277
278 #[inline(always)]
279 fn tot_ge(&self, other: &Self) -> bool {
280 self >= other
281 }
282 }
283
284 impl TotalHash for $T {
285 #[inline(always)]
286 fn tot_hash<H>(&self, state: &mut H)
287 where
288 H: Hasher,
289 {
290 self.hash(state);
291 }
292 }
293 };
294}
295
296impl_trivial_total!(());
299impl_trivial_total!(bool);
300impl_trivial_total!(u8);
301impl_trivial_total!(u16);
302impl_trivial_total!(u32);
303impl_trivial_total!(u64);
304impl_trivial_total!(u128);
305impl_trivial_total!(usize);
306impl_trivial_total!(i8);
307impl_trivial_total!(i16);
308impl_trivial_total!(i32);
309impl_trivial_total!(i64);
310impl_trivial_total!(i128);
311impl_trivial_total!(isize);
312impl_trivial_total!(char);
313impl_trivial_total!(&str);
314impl_trivial_total!(&[u8]);
315impl_trivial_total!(String);
316impl_trivial_total!(Vec<u8>);
317
318macro_rules! impl_float_eq_ord {
319 ($T:ty) => {
320 impl TotalEq for $T {
321 #[inline]
322 fn tot_eq(&self, other: &Self) -> bool {
323 if self.is_nan() {
324 other.is_nan()
325 } else {
326 self == other
327 }
328 }
329 }
330
331 impl TotalOrd for $T {
332 #[inline(always)]
333 fn tot_cmp(&self, other: &Self) -> Ordering {
334 if self.tot_lt(other) {
335 Ordering::Less
336 } else if self.tot_gt(other) {
337 Ordering::Greater
338 } else {
339 Ordering::Equal
340 }
341 }
342
343 #[inline(always)]
344 fn tot_lt(&self, other: &Self) -> bool {
345 !self.tot_ge(other)
346 }
347
348 #[inline(always)]
349 fn tot_gt(&self, other: &Self) -> bool {
350 other.tot_lt(self)
351 }
352
353 #[inline(always)]
354 fn tot_le(&self, other: &Self) -> bool {
355 other.tot_ge(self)
356 }
357
358 #[inline(always)]
359 fn tot_ge(&self, other: &Self) -> bool {
360 self.is_nan() | (self >= other)
366 }
367 }
368 };
369}
370
371impl_float_eq_ord!(pf16);
372impl_float_eq_ord!(f32);
373impl_float_eq_ord!(f64);
374
375impl TotalHash for pf16 {
376 #[inline(always)]
377 fn tot_hash<H>(&self, state: &mut H)
378 where
379 H: Hasher,
380 {
381 canonical_f16(*self).to_bits().hash(state)
382 }
383}
384
385impl TotalHash for f32 {
386 #[inline(always)]
387 fn tot_hash<H>(&self, state: &mut H)
388 where
389 H: Hasher,
390 {
391 canonical_f32(*self).to_bits().hash(state)
392 }
393}
394
395impl TotalHash for f64 {
396 #[inline(always)]
397 fn tot_hash<H>(&self, state: &mut H)
398 where
399 H: Hasher,
400 {
401 canonical_f64(*self).to_bits().hash(state)
402 }
403}
404
405impl<T: TotalEq> TotalEq for Option<T> {
407 #[inline(always)]
408 fn tot_eq(&self, other: &Self) -> bool {
409 match (self, other) {
410 (None, None) => true,
411 (Some(a), Some(b)) => a.tot_eq(b),
412 _ => false,
413 }
414 }
415
416 #[inline(always)]
417 fn tot_ne(&self, other: &Self) -> bool {
418 match (self, other) {
419 (None, None) => false,
420 (Some(a), Some(b)) => a.tot_ne(b),
421 _ => true,
422 }
423 }
424}
425
426impl<T: TotalOrd> TotalOrd for Option<T> {
427 #[inline(always)]
428 fn tot_cmp(&self, other: &Self) -> Ordering {
429 match (self, other) {
430 (None, None) => Ordering::Equal,
431 (None, Some(_)) => Ordering::Less,
432 (Some(_), None) => Ordering::Greater,
433 (Some(a), Some(b)) => a.tot_cmp(b),
434 }
435 }
436
437 #[inline(always)]
438 fn tot_lt(&self, other: &Self) -> bool {
439 match (self, other) {
440 (None, Some(_)) => true,
441 (Some(a), Some(b)) => a.tot_lt(b),
442 _ => false,
443 }
444 }
445
446 #[inline(always)]
447 fn tot_gt(&self, other: &Self) -> bool {
448 other.tot_lt(self)
449 }
450
451 #[inline(always)]
452 fn tot_le(&self, other: &Self) -> bool {
453 match (self, other) {
454 (Some(_), None) => false,
455 (Some(a), Some(b)) => a.tot_lt(b),
456 _ => true,
457 }
458 }
459
460 #[inline(always)]
461 fn tot_ge(&self, other: &Self) -> bool {
462 other.tot_le(self)
463 }
464}
465
466impl<T: TotalHash> TotalHash for Option<T> {
467 #[inline]
468 fn tot_hash<H>(&self, state: &mut H)
469 where
470 H: Hasher,
471 {
472 self.is_some().tot_hash(state);
473 if let Some(slf) = self {
474 slf.tot_hash(state)
475 }
476 }
477}
478
479impl<T: TotalEq + ?Sized> TotalEq for &T {
480 #[inline(always)]
481 fn tot_eq(&self, other: &Self) -> bool {
482 (*self).tot_eq(*other)
483 }
484
485 #[inline(always)]
486 fn tot_ne(&self, other: &Self) -> bool {
487 (*self).tot_ne(*other)
488 }
489}
490
491impl<T: TotalHash + ?Sized> TotalHash for &T {
492 #[inline(always)]
493 fn tot_hash<H>(&self, state: &mut H)
494 where
495 H: Hasher,
496 {
497 (*self).tot_hash(state)
498 }
499}
500
501impl<T: TotalEq, U: TotalEq> TotalEq for (T, U) {
502 #[inline]
503 fn tot_eq(&self, other: &Self) -> bool {
504 self.0.tot_eq(&other.0) && self.1.tot_eq(&other.1)
505 }
506}
507
508impl<T: TotalOrd, U: TotalOrd> TotalOrd for (T, U) {
509 #[inline]
510 fn tot_cmp(&self, other: &Self) -> Ordering {
511 self.0
512 .tot_cmp(&other.0)
513 .then_with(|| self.1.tot_cmp(&other.1))
514 }
515}
516
517impl TotalHash for BytesHash<'_> {
518 #[inline(always)]
519 fn tot_hash<H>(&self, state: &mut H)
520 where
521 H: Hasher,
522 {
523 self.hash(state)
524 }
525}
526
527impl TotalEq for BytesHash<'_> {
528 #[inline(always)]
529 fn tot_eq(&self, other: &Self) -> bool {
530 self == other
531 }
532}
533
534pub trait ToTotalOrd {
536 type TotalOrdItem: Hash + Eq;
537 type SourceItem;
538
539 fn to_total_ord(&self) -> Self::TotalOrdItem;
540
541 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem;
542}
543
544macro_rules! impl_to_total_ord_identity {
545 ($T: ty) => {
546 impl ToTotalOrd for $T {
547 type TotalOrdItem = $T;
548 type SourceItem = $T;
549
550 #[inline]
551 fn to_total_ord(&self) -> Self::TotalOrdItem {
552 self.clone()
553 }
554
555 #[inline]
556 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
557 ord_item
558 }
559 }
560 };
561}
562
563impl_to_total_ord_identity!(bool);
564impl_to_total_ord_identity!(u8);
565impl_to_total_ord_identity!(u16);
566impl_to_total_ord_identity!(u32);
567impl_to_total_ord_identity!(u64);
568impl_to_total_ord_identity!(u128);
569impl_to_total_ord_identity!(usize);
570impl_to_total_ord_identity!(i8);
571impl_to_total_ord_identity!(i16);
572impl_to_total_ord_identity!(i32);
573impl_to_total_ord_identity!(i64);
574impl_to_total_ord_identity!(i128);
575impl_to_total_ord_identity!(isize);
576impl_to_total_ord_identity!(char);
577impl_to_total_ord_identity!(String);
578
579macro_rules! impl_to_total_ord_lifetimed_ref_identity {
580 ($T: ty) => {
581 impl<'a> ToTotalOrd for &'a $T {
582 type TotalOrdItem = &'a $T;
583 type SourceItem = &'a $T;
584
585 #[inline]
586 fn to_total_ord(&self) -> Self::TotalOrdItem {
587 *self
588 }
589
590 #[inline]
591 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
592 ord_item
593 }
594 }
595 };
596}
597
598impl_to_total_ord_lifetimed_ref_identity!(str);
599impl_to_total_ord_lifetimed_ref_identity!([u8]);
600
601macro_rules! impl_to_total_ord_wrapped {
602 ($T: ty) => {
603 impl ToTotalOrd for $T {
604 type TotalOrdItem = TotalOrdWrap<$T>;
605 type SourceItem = $T;
606
607 #[inline]
608 fn to_total_ord(&self) -> Self::TotalOrdItem {
609 TotalOrdWrap(self.clone())
610 }
611
612 #[inline]
613 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
614 ord_item.0
615 }
616 }
617 };
618}
619
620impl_to_total_ord_wrapped!(pf16);
621impl_to_total_ord_wrapped!(f32);
622impl_to_total_ord_wrapped!(f64);
623
624impl<T: Copy + TotalEq + TotalHash> ToTotalOrd for Option<T> {
630 type TotalOrdItem = TotalOrdWrap<Option<T>>;
631 type SourceItem = Option<T>;
632
633 #[inline]
634 fn to_total_ord(&self) -> Self::TotalOrdItem {
635 TotalOrdWrap(*self)
636 }
637
638 #[inline]
639 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
640 ord_item.0
641 }
642}
643
644impl<T: ToTotalOrd> ToTotalOrd for &T {
645 type TotalOrdItem = T::TotalOrdItem;
646 type SourceItem = T::SourceItem;
647
648 #[inline]
649 fn to_total_ord(&self) -> Self::TotalOrdItem {
650 (*self).to_total_ord()
651 }
652
653 #[inline]
654 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
655 T::peel_total_ord(ord_item)
656 }
657}
658
659impl<'a> ToTotalOrd for BytesHash<'a> {
660 type TotalOrdItem = BytesHash<'a>;
661 type SourceItem = BytesHash<'a>;
662
663 #[inline]
664 fn to_total_ord(&self) -> Self::TotalOrdItem {
665 *self
666 }
667
668 #[inline]
669 fn peel_total_ord(ord_item: Self::TotalOrdItem) -> Self::SourceItem {
670 ord_item
671 }
672}