go-sample-webpage/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go
2021-11-04 02:14:51 +01:00

55 lines
1.5 KiB
Go

package blackmagic
import (
"reflect"
"github.com/pkg/errors"
)
// AssignIfCompatible is a convenience function to safely
// assign arbitrary values. dst must be a pointer to an
// empty interface, or it must be a pointer to a compatible
// variable type that can hold src.
func AssignIfCompatible(dst, src interface{}) error {
orv := reflect.ValueOf(src) // save this value for error reporting
result := orv
// t can be a pointer or a slice, and the code will slightly change
// depending on this
var isSlice bool
switch result.Kind() {
case reflect.Ptr:
// no op
case reflect.Slice:
isSlice = true
default:
return errors.Errorf("argument t to AssignIfCompatible must be a pointer or a slice: %T", src)
}
rv := reflect.ValueOf(dst)
if rv.Kind() != reflect.Ptr {
return errors.Errorf(`argument to AssignIfCompatible() must be a pointer: %T`, dst)
}
actualDst := rv.Elem()
switch actualDst.Kind() {
case reflect.Interface:
// If it's an interface, we can just assign the pointer to the interface{}
default:
// If it's a pointer to the struct we're looking for, we need to set
// the de-referenced struct
if !isSlice {
result = result.Elem()
}
}
if !result.Type().AssignableTo(actualDst.Type()) {
return errors.Errorf(`argument to AssignIfCompatible() must be compatible with %T (was %T)`, orv.Interface(), dst)
}
if !actualDst.CanSet() {
return errors.Errorf(`argument to AssignIfCompatible() must be settable`)
}
actualDst.Set(result)
return nil
}