Skip to content

Instantly share code, notes, and snippets.

@kaleocheng
Created September 25, 2017 13:36
Show Gist options
  • Save kaleocheng/53f4b6bdd4d80c008bc9d79e96546b26 to your computer and use it in GitHub Desktop.
Save kaleocheng/53f4b6bdd4d80c008bc9d79e96546b26 to your computer and use it in GitHub Desktop.
package valid
import (
"reflect"
)
const tagName = "valid"
func IsZero(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
func Valid(obj interface{}) bool {
ok := true
original := reflect.ValueOf(obj)
validRecursive(original, &ok)
return ok
}
func validRecursive(original reflect.Value, ok *bool) {
switch original.Kind() {
case reflect.Ptr:
originalValue := original.Elem()
// Check if the pointer is nil
if !originalValue.IsValid() {
*ok = false
return
}
validRecursive(originalValue, ok)
case reflect.Interface:
originalValue := original.Elem()
validRecursive(originalValue, ok)
case reflect.Struct:
for i := 0; i < original.NumField(); i++ {
tag := original.Type().Field(i).Tag.Get(tagName)
// Skip if tag is not defined or ignored
if tag == "" || tag == "-" {
continue
}
validRecursive(original.Field(i), ok)
}
case reflect.Slice:
for i := 0; i < original.Len(); i++ {
validRecursive(original.Index(i), ok)
}
case reflect.Map:
for _, key := range original.MapKeys() {
originalValue := original.MapIndex(key)
validRecursive(originalValue, ok)
}
// We don't check the bool value
case reflect.Bool:
break
// And everything else will simply be taken from the original
default:
if IsZero(original.Interface()) {
*ok = false
return
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment