package filter import ( "errors" "reflect" "strconv" "strings" ) const ( any = '*' anys = string(any) ) func checkFields(s []string, val string) error { for _, v := range s { if v == "" { return errors.New("invalid subfield: " + val) } } return nil } func clearFields(s string) []string { a := strings.Split(s, " ") b := make([]string, len(a)) c := 0 for _, v := range a { if v != "" { b[c] = v c++ } } return b[:c] } type less func(i, j int) bool func reverse(f less) less { return func(i, j int) bool { return f(j, i) } } func walkFields(v reflect.Value, fields []string) reflect.Value { for i := 0; i < len(fields); i++ { if v.Kind() != reflect.Struct { return reflect.ValueOf(nil) } v = v.FieldByName(fields[i]) } return v } func index(f Filter, i int, fields []string) (val reflect.Value) { return walkFields(reflect.ValueOf(f.Index(i)).FieldByName(fields[0]), fields[1:]) } func makeLess(f Filter, fields []string) less { switch index(f, 0, fields).Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return func(i, j int) bool { return index(f, i, fields).Int() < index(f, j, fields).Int() } case reflect.Float32, reflect.Float64: return func(i, j int) bool { return index(f, i, fields).Float() < index(f, j, fields).Float() } case reflect.String: return func(i, j int) bool { return index(f, i, fields).String() < index(f, j, fields).String() } case reflect.Bool: return func(i, _ int) bool { return index(f, i, fields).Bool() } } return nil } func getValue(v reflect.Value) (s string, b bool, err error) { switch v.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s = strconv.FormatInt(v.Int(), 10) case reflect.Float32, reflect.Float64: s = strconv.FormatFloat(v.Float(), 'f', -1, 64) case reflect.String: s = v.String() case reflect.Bool: b = v.Bool() default: err = errors.New("nil") } return } func matchFunc(v string) func(string) bool { vl := len(v) switch { case vl >= 3: if v[0] == any && v[vl-1] == any && v[1] != any && v[vl-2] != any { return func(s string) bool { return strings.Contains(s, v[1:vl-1]) } } fallthrough case vl >= 2: switch { case v[0] == any && v[1] != any: return func(s string) bool { return strings.HasSuffix(s, v[1:]) } case v[vl-1] == any && v[vl-2] != any: return func(s string) bool { return strings.HasPrefix(s, v[:vl-1]) } } } v = strings.Replace(v, anys+anys, anys, -1) return func(s string) bool { if s == v { return true } return false } } func ft(b bool) bool { if b { return true } return false } func ff(b bool) bool { if !b { return true } return false } func f(b bool) bool { return false } func boolFunc(v string) func(bool) bool { if len(v) == 0 { return f } if v[0] == 't' { return ft } if v[0] == 'f' { return ff } return f }