//This package is copied from Go library text/template. //The original private functions eq, ge, gt, le, lt, and ne //are exported as public functions. package template import ( "errors" "reflect" ) var ( errBadComparisonType = errors.New("invalid type for comparison") errBadComparison = errors.New("incompatible types for comparison") errNoComparison = errors.New("missing argument for comparison") ) type kind int const ( invalidKind kind = iota boolKind complexKind intKind floatKind integerKind stringKind uintKind ) func basicKind(v reflect.Value) (kind, error) { switch v.Kind() { case reflect.Bool: return boolKind, nil case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return intKind, nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return uintKind, nil case reflect.Float32, reflect.Float64: return floatKind, nil case reflect.Complex64, reflect.Complex128: return complexKind, nil case reflect.String: return stringKind, nil } return invalidKind, errBadComparisonType } // Equal evaluates the comparison a == b || a == c || ... func Equal(arg1 interface{}, arg2 ...interface{}) (bool, error) { v1 := reflect.ValueOf(arg1) k1, err := basicKind(v1) if err != nil { return false, err } if len(arg2) == 0 { return false, errNoComparison } for _, arg := range arg2 { v2 := reflect.ValueOf(arg) k2, err := basicKind(v2) if err != nil { return false, err } truth := false if k1 != k2 { // Special case: Can compare integer values regardless of type's sign. switch { case k1 == intKind && k2 == uintKind: truth = v1.Int() >= 0 && uint64(v1.Int()) == v2.Uint() case k1 == uintKind && k2 == intKind: truth = v2.Int() >= 0 && v1.Uint() == uint64(v2.Int()) default: return false, errBadComparison } } else { switch k1 { case boolKind: truth = v1.Bool() == v2.Bool() case complexKind: truth = v1.Complex() == v2.Complex() case floatKind: truth = v1.Float() == v2.Float() case intKind: truth = v1.Int() == v2.Int() case stringKind: truth = v1.String() == v2.String() case uintKind: truth = v1.Uint() == v2.Uint() default: panic("invalid kind") } } if truth { return true, nil } } return false, nil } // NotEqual evaluates the comparison a != b. func NotEqual(arg1, arg2 interface{}) (bool, error) { // != is the inverse of ==. equal, err := Equal(arg1, arg2) return !equal, err } // Less evaluates the comparison a < b. func Less(arg1, arg2 interface{}) (bool, error) { v1 := reflect.ValueOf(arg1) k1, err := basicKind(v1) if err != nil { return false, err } v2 := reflect.ValueOf(arg2) k2, err := basicKind(v2) if err != nil { return false, err } truth := false if k1 != k2 { // Special case: Can compare integer values regardless of type's sign. switch { case k1 == intKind && k2 == uintKind: truth = v1.Int() < 0 || uint64(v1.Int()) < v2.Uint() case k1 == uintKind && k2 == intKind: truth = v2.Int() >= 0 && v1.Uint() < uint64(v2.Int()) default: return false, errBadComparison } } else { switch k1 { case boolKind, complexKind: return false, errBadComparisonType case floatKind: truth = v1.Float() < v2.Float() case intKind: truth = v1.Int() < v2.Int() case stringKind: truth = v1.String() < v2.String() case uintKind: truth = v1.Uint() < v2.Uint() default: panic("invalid kind") } } return truth, nil } // LessEqual evaluates the comparison <= b. func LessEqual(arg1, arg2 interface{}) (bool, error) { // <= is < or ==. lessThan, err := Less(arg1, arg2) if lessThan || err != nil { return lessThan, err } return Equal(arg1, arg2) } // Greater evaluates the comparison a > b. func Greater(arg1, arg2 interface{}) (bool, error) { // > is the inverse of <=. lessOrEqual, err := LessEqual(arg1, arg2) if err != nil { return false, err } return !lessOrEqual, nil } // GreaterEqual evaluates the comparison a >= b. func GreaterEqual(arg1, arg2 interface{}) (bool, error) { // >= is the inverse of <. lessThan, err := Less(arg1, arg2) if err != nil { return false, err } return !lessThan, nil }