radiate-expr 1.2.22

A Rust library for genetic algorithms and artificial evolution.
Documentation
use crate::AnyValue;
use std::cmp::Ordering;

impl<'a> AnyValue<'a> {
    #[inline]
    fn variant_rank(&self) -> u8 {
        match self {
            AnyValue::Null => 0,
            AnyValue::Bool(_) => 1,

            AnyValue::UInt8(_) => 2,
            AnyValue::UInt16(_) => 3,
            AnyValue::UInt32(_) => 4,
            AnyValue::UInt64(_) => 5,
            AnyValue::UInt128(_) => 6,

            AnyValue::Int8(_) => 7,
            AnyValue::Int16(_) => 8,
            AnyValue::Int32(_) => 9,
            AnyValue::Int64(_) => 10,
            AnyValue::Int128(_) => 11,

            AnyValue::Float32(_) => 12,
            AnyValue::Float64(_) => 13,

            AnyValue::Duration(_) => 14,

            AnyValue::Char(_) => 15,
            AnyValue::Str(_) => 16,
            AnyValue::StrOwned(_) => 17,

            AnyValue::Slice(_) => 18,
            AnyValue::Vector(_) => 19,

            AnyValue::Struct(_) => 20,
        }
    }

    fn cmp_same_variant(&self, other: &Self) -> Ordering {
        use AnyValue::*;

        match (self, other) {
            (Null, Null) => Ordering::Equal,
            (Bool(a), Bool(b)) => a.cmp(b),

            (UInt8(a), UInt8(b)) => a.cmp(b),
            (UInt16(a), UInt16(b)) => a.cmp(b),
            (UInt32(a), UInt32(b)) => a.cmp(b),
            (UInt64(a), UInt64(b)) => a.cmp(b),
            (UInt128(a), UInt128(b)) => a.cmp(b),

            (Int8(a), Int8(b)) => a.cmp(b),
            (Int16(a), Int16(b)) => a.cmp(b),
            (Int32(a), Int32(b)) => a.cmp(b),
            (Int64(a), Int64(b)) => a.cmp(b),
            (Int128(a), Int128(b)) => a.cmp(b),

            (Float32(a), Float32(b)) => a.total_cmp(b),
            (Float64(a), Float64(b)) => a.total_cmp(b),

            (Duration(a), Duration(b)) => a.cmp(b),

            (Char(a), Char(b)) => a.cmp(b),
            (Str(a), Str(b)) => a.cmp(b),
            (StrOwned(a), StrOwned(b)) => a.cmp(b),

            (Slice(a), Slice(b)) => a.iter().cmp(b.iter()),
            (Vector(a), Vector(b)) => a.iter().cmp(b.iter()),

            (Struct(a), Struct(b)) => {
                let mut i = 0;
                while i < a.len() && i < b.len() {
                    let (fa, va) = &a[i];
                    let (fb, vb) = &b[i];

                    match fa.name().cmp(fb.name()) {
                        Ordering::Equal => {}
                        non_eq => return non_eq,
                    }

                    match va.cmp(vb) {
                        Ordering::Equal => {}
                        non_eq => return non_eq,
                    }

                    i += 1;
                }

                a.len().cmp(&b.len())
            }
            _ => unreachable!("cmp_same_variant called with different variants"),
        }
    }

    fn fuzzy_cmp(&self, other: &Self) -> Option<Ordering> {
        use AnyValue::*;

        if self.is_float() && other.is_float() {
            return self.cmp_float(other);
        } else if self.is_int() && other.is_int() {
            return self.cmp_int(other);
        } else if self.is_string() && other.is_string() {
            return self.cmp_str(other);
        } else if self.is_int() && other.is_float() {
            return self
                .clone()
                .cast(&other.dtype())
                .and_then(|v| v.fuzzy_cmp(other));
        } else if self.is_float() && other.is_int() {
            return self
                .clone()
                .cast(&other.dtype())
                .and_then(|v| v.fuzzy_cmp(other));
        } else {
            let res = match (self, other) {
                (Null, Null) => Ordering::Equal,
                (Bool(a), Bool(b)) => a.cmp(b),

                (Vector(a), Vector(b)) => a.iter().cmp(b.iter()),
                (Slice(a), Slice(b)) => a.iter().cmp(b.iter()),

                _ => return None,
            };

            Some(res)
        }
    }

    fn cmp_float(&self, other: &Self) -> Option<Ordering> {
        use AnyValue::*;

        match (self, other) {
            (Float32(a), Float32(b)) => Some(a.total_cmp(b)),
            (Float64(a), Float64(b)) => Some(a.total_cmp(b)),
            (Float32(a), Float64(b)) => Some((*a as f64).total_cmp(b)),
            (Float64(a), Float32(b)) => Some(a.total_cmp(&(*b as f64))),
            _ => None,
        }
    }

    fn cmp_str(&self, other: &Self) -> Option<Ordering> {
        use AnyValue::*;

        match (self, other) {
            (Str(a), Str(b)) => Some(a.cmp(b)),
            (StrOwned(a), StrOwned(b)) => Some(a.cmp(b)),
            (Char(a), Char(b)) => Some(a.cmp(b)),

            (Str(a), StrOwned(b)) => Some(a.cmp(&b.as_str())),
            (StrOwned(a), Str(b)) => Some(a.as_str().cmp(b)),
            _ => None,
        }
    }

    fn cmp_int(&self, other: &Self) -> Option<Ordering> {
        use AnyValue::*;

        match (self, other) {
            (Int8(a), Int8(b)) => Some(a.cmp(b)),
            (Int16(a), Int16(b)) => Some(a.cmp(b)),
            (Int32(a), Int32(b)) => Some(a.cmp(b)),
            (Int64(a), Int64(b)) => Some(a.cmp(b)),
            (Int128(a), Int128(b)) => Some(a.cmp(b)),

            (UInt8(a), UInt8(b)) => Some(a.cmp(b)),
            (UInt16(a), UInt16(b)) => Some(a.cmp(b)),
            (UInt32(a), UInt32(b)) => Some(a.cmp(b)),
            (UInt64(a), UInt64(b)) => Some(a.cmp(b)),
            (UInt128(a), UInt128(b)) => Some(a.cmp(b)),

            (Int8(a), Int16(b)) => Some((*a as i16).cmp(b)),
            (Int8(a), Int32(b)) => Some((*a as i32).cmp(b)),
            (Int8(a), Int64(b)) => Some((*a as i64).cmp(b)),
            (Int8(a), Int128(b)) => Some((*a as i128).cmp(b)),
            (Int8(a), UInt8(b)) => Some((*a as i16).cmp(&(*b as i16))),
            (Int8(a), UInt16(b)) => Some((*a as i32).cmp(&(*b as i32))),
            (Int8(a), UInt32(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (Int8(a), UInt64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (Int16(a), Int8(b)) => Some(a.cmp(&(*b as i16))),
            (Int16(a), Int32(b)) => Some((*a as i32).cmp(b)),
            (Int16(a), Int64(b)) => Some((*a as i64).cmp(b)),
            (Int16(a), Int128(b)) => Some((*a as i128).cmp(b)),
            (Int16(a), UInt8(b)) => Some((*a as i32).cmp(&(*b as i32))),
            (Int16(a), UInt16(b)) => Some((*a as i32).cmp(&(*b as i32))),
            (Int16(a), UInt32(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (Int16(a), UInt64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (Int32(a), Int8(b)) => Some(a.cmp(&(*b as i32))),
            (Int32(a), Int16(b)) => Some(a.cmp(&(*b as i32))),
            (Int32(a), Int64(b)) => Some((*a as i64).cmp(b)),
            (Int32(a), Int128(b)) => Some((*a as i128).cmp(b)),
            (Int32(a), UInt8(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (Int32(a), UInt16(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (Int32(a), UInt32(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (Int32(a), UInt64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (Int64(a), Int8(b)) => Some(a.cmp(&(*b as i64))),
            (Int64(a), Int16(b)) => Some(a.cmp(&(*b as i64))),
            (Int64(a), Int32(b)) => Some(a.cmp(&(*b as i64))),
            (Int64(a), Int128(b)) => Some((*a as i128).cmp(b)),
            (Int64(a), UInt8(b)) => Some((*a as i128).cmp(&(*b as i128))),
            (Int64(a), UInt16(b)) => Some((*a as i128).cmp(&(*b as i128))),
            (Int64(a), UInt32(b)) => Some((*a as i128).cmp(&(*b as i128))),
            (Int64(a), UInt64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (UInt8(a), UInt16(b)) => Some((*a as u16).cmp(b)),
            (UInt8(a), UInt32(b)) => Some((*a as u32).cmp(b)),
            (UInt8(a), UInt64(b)) => Some((*a as u64).cmp(b)),
            (UInt8(a), UInt128(b)) => Some((*a as u128).cmp(b)),
            (UInt8(a), Int8(b)) => Some((*a as i16).cmp(&(*b as i16))),
            (UInt8(a), Int16(b)) => Some((*a as i32).cmp(&(*b as i32))),
            (UInt8(a), Int32(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (UInt8(a), Int64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (UInt16(a), UInt8(b)) => Some(a.cmp(&(*b as u16))),
            (UInt16(a), UInt32(b)) => Some((*a as u32).cmp(b)),
            (UInt16(a), UInt64(b)) => Some((*a as u64).cmp(b)),
            (UInt16(a), UInt128(b)) => Some((*a as u128).cmp(b)),
            (UInt16(a), Int8(b)) => Some((*a as i32).cmp(&(*b as i32))),
            (UInt16(a), Int16(b)) => Some((*a as i32).cmp(&(*b as i32))),
            (UInt16(a), Int32(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (UInt16(a), Int64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (UInt32(a), UInt8(b)) => Some(a.cmp(&(*b as u32))),
            (UInt32(a), UInt16(b)) => Some(a.cmp(&(*b as u32))),
            (UInt32(a), UInt64(b)) => Some((*a as u64).cmp(b)),
            (UInt32(a), UInt128(b)) => Some((*a as u128).cmp(b)),
            (UInt32(a), Int8(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (UInt32(a), Int16(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (UInt32(a), Int32(b)) => Some((*a as i64).cmp(&(*b as i64))),
            (UInt32(a), Int64(b)) => Some((*a as i128).cmp(&(*b as i128))),

            (UInt64(a), UInt8(b)) => Some(a.cmp(&(*b as u64))),
            (UInt64(a), UInt16(b)) => Some(a.cmp(&(*b as u64))),
            (UInt64(a), UInt32(b)) => Some(a.cmp(&(*b as u64))),
            (UInt64(a), UInt128(b)) => Some((*a as u128).cmp(b)),
            (UInt64(a), Int8(b)) => Some((*a as i128).cmp(&(*b as i128))),
            (UInt64(a), Int16(b)) => Some((*a as i128).cmp(&(*b as i128))),
            (UInt64(a), Int32(b)) => Some((*a as i128).cmp(&(*b as i128))),
            (UInt64(a), Int64(b)) => Some((*a as i128).cmp(&(*b as i128))),
            _ => None,
        }
    }
}

impl<'a> PartialOrd for AnyValue<'a> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a> Ord for AnyValue<'a> {
    fn cmp(&self, other: &Self) -> Ordering {
        if let Some(like_cmp) = self.fuzzy_cmp(other) {
            like_cmp
        } else {
            match self.variant_rank().cmp(&other.variant_rank()) {
                Ordering::Equal => self.cmp_same_variant(other),
                non_eq => non_eq,
            }
        }
    }
}