github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/validator/enum/enum.go (about) 1 // Copyright (c) 2018-2021, R.I. Pienaar and the Choria Project contributors 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package enum 6 7 import ( 8 "fmt" 9 "reflect" 10 "regexp" 11 "strings" 12 ) 13 14 // ValidateSlice validates that all items in target is one of valid 15 func ValidateSlice(target []string, valid []string) (bool, error) { 16 for _, item := range target { 17 found, _ := ValidateString(item, valid) 18 if !found { 19 return false, fmt.Errorf("'%s' is not in the allowed list: %s", item, strings.Join(valid, ", ")) 20 } 21 } 22 23 return true, nil 24 } 25 26 // ValidateString validates that a string is in the list of allowed values 27 func ValidateString(target string, valid []string) (bool, error) { 28 found := false 29 30 for _, e := range valid { 31 if e == target { 32 found = true 33 } 34 } 35 36 if !found { 37 return false, fmt.Errorf("'%s' is not in the allowed list: %s", target, strings.Join(valid, ", ")) 38 } 39 40 return true, nil 41 } 42 43 // ValidateStructField validates a structure field, only []string and string types are supported 44 func ValidateStructField(value reflect.Value, tag string) (bool, error) { 45 re := regexp.MustCompile(`^enum=(.+,*?)+$`) 46 parts := re.FindStringSubmatch(tag) 47 48 if len(parts) != 2 { 49 return false, fmt.Errorf("invalid tag '%s', must be enum=v1,v2,v3", tag) 50 } 51 52 evs := strings.Split(parts[1], ",") 53 54 switch value.Kind() { 55 case reflect.Slice: 56 slice, ok := value.Interface().([]string) 57 if !ok { 58 return false, fmt.Errorf("only []string slices can be validated for enums") 59 } 60 61 return ValidateSlice(slice, evs) 62 case reflect.String: 63 str, _ := value.Interface().(string) 64 65 return ValidateString(str, evs) 66 67 default: 68 return false, fmt.Errorf("cannot valid data of type %s for enums", value.Kind().String()) 69 } 70 }