Skip to main content

icydb_core/value/ops/
partial_ord.rs

1//! Module: value::ops::partial_ord
2//!
3//! Responsibility: Rust `PartialOrd` implementation for dynamic values.
4//! Does not own: canonical ordering or predicate-level ordering semantics.
5//! Boundary: compatibility implementation for value-local partial comparison.
6
7use crate::value::Value;
8use std::cmp::Ordering;
9
10// NOTE:
11// Value::partial_cmp is NOT the canonical ordering for database semantics.
12// Some orderable scalar types (e.g. Account, Unit) intentionally do not
13// participate here. Use canonical_cmp / strict ordering for ORDER BY,
14// planning, and key-range validation.
15impl PartialOrd for Value {
16    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
17        match (self, other) {
18            (Self::Bool(a), Self::Bool(b)) => a.partial_cmp(b),
19            (Self::Date(a), Self::Date(b)) => a.partial_cmp(b),
20            (Self::Decimal(a), Self::Decimal(b)) => a.partial_cmp(b),
21            (Self::Duration(a), Self::Duration(b)) => a.partial_cmp(b),
22            (Self::Enum(a), Self::Enum(b)) => a.partial_cmp(b),
23            (Self::Float32(a), Self::Float32(b)) => a.partial_cmp(b),
24            (Self::Float64(a), Self::Float64(b)) => a.partial_cmp(b),
25            (Self::Int64(a), Self::Int64(b)) => a.partial_cmp(b),
26            (Self::Int128(a), Self::Int128(b)) => a.partial_cmp(b),
27            (Self::Principal(a), Self::Principal(b)) => a.partial_cmp(b),
28            (Self::Subaccount(a), Self::Subaccount(b)) => a.partial_cmp(b),
29            (Self::Text(a), Self::Text(b)) => a.partial_cmp(b),
30            (Self::Timestamp(a), Self::Timestamp(b)) => a.partial_cmp(b),
31            (Self::Nat64(a), Self::Nat64(b)) => a.partial_cmp(b),
32            (Self::Nat128(a), Self::Nat128(b)) => a.partial_cmp(b),
33            (Self::Ulid(a), Self::Ulid(b)) => a.partial_cmp(b),
34            (Self::U256(a), Self::U256(b)) => a.partial_cmp(b),
35            (Self::Map(a), Self::Map(b)) => partial_cmp_map(a.as_slice(), b.as_slice()),
36
37            // Cross-type comparisons: no ordering
38            _ => None,
39        }
40    }
41}
42
43fn partial_cmp_map(left: &[(Value, Value)], right: &[(Value, Value)]) -> Option<Ordering> {
44    for ((left_key, left_value), (right_key, right_value)) in left.iter().zip(right.iter()) {
45        let key_cmp = Value::canonical_cmp_key(left_key, right_key);
46        if key_cmp != Ordering::Equal {
47            return Some(key_cmp);
48        }
49
50        match left_value.partial_cmp(right_value) {
51            Some(Ordering::Equal) => {}
52            non_eq => return non_eq,
53        }
54    }
55
56    left.len().partial_cmp(&right.len())
57}