// Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 package utilfn import ( "reflect" ) // this is a shallow equal, but with special handling for numeric types // it will up convert to float64 and compare func JsonValEqual(a, b any) bool { if a == nil && b == nil { return true } if a == nil || b == nil { return false } typeA := reflect.TypeOf(a) typeB := reflect.TypeOf(b) if typeA == typeB && typeA.Comparable() { return a == b } if IsNumericType(a) && IsNumericType(b) { return CompareAsFloat64(a, b) } if typeA != typeB { return false } // for slices and maps, compare their pointers valA := reflect.ValueOf(a) valB := reflect.ValueOf(b) switch valA.Kind() { case reflect.Slice, reflect.Map: return valA.Pointer() == valB.Pointer() } return false } // Helper to check if a value is a numeric type func IsNumericType(val any) bool { switch val.(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64: return true default: return false } } // Helper to handle numeric comparisons as float64 func CompareAsFloat64(a, b any) bool { valA, okA := ToFloat64(a) valB, okB := ToFloat64(b) return okA && okB && valA == valB } // Convert various numeric types to float64 for comparison func ToFloat64(val any) (float64, bool) { if val == nil { return 0, false } switch v := val.(type) { case int: return float64(v), true case int8: return float64(v), true case int16: return float64(v), true case int32: return float64(v), true case int64: return float64(v), true case uint: return float64(v), true case uint8: return float64(v), true case uint16: return float64(v), true case uint32: return float64(v), true case uint64: return float64(v), true case float32: return float64(v), true case float64: return v, true default: return 0, false } } func ToInt64(val any) (int64, bool) { if val == nil { return 0, false } switch v := val.(type) { case int: return int64(v), true case int8: return int64(v), true case int16: return int64(v), true case int32: return int64(v), true case int64: return v, true case uint: return int64(v), true case uint8: return int64(v), true case uint16: return int64(v), true case uint32: return int64(v), true case uint64: return int64(v), true case float32: return int64(v), true case float64: return int64(v), true default: return 0, false } } func ToInt(val any) (int, bool) { i, ok := ToInt64(val) if !ok { return 0, false } return int(i), true } func ToStr(val any) (string, bool) { if val == nil { return "", false } switch v := val.(type) { case string: return v, true default: return "", false } }