Files
opencloud/vendor/github.com/lestrrat-go/blackmagic/blackmagic.go
dependabot[bot] 76ac20e9e8 build(deps): bump github.com/open-policy-agent/opa from 1.6.0 to 1.8.0
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 1.6.0 to 1.8.0.
- [Release notes](https://github.com/open-policy-agent/opa/releases)
- [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-policy-agent/opa/compare/v1.6.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/open-policy-agent/opa
  dependency-version: 1.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-23 10:28:55 +02:00

126 lines
3.4 KiB
Go

package blackmagic
import (
"fmt"
"reflect"
)
type errInvalidValue struct{}
func (*errInvalidValue) Error() string {
return "invalid value (probably an untyped nil)"
}
// InvalidValueError is a sentinel error that can be used to
// indicate that a value is invalid. This can happen when the
// source value is an untyped nil, and we have no further information
// about the type of the value, obstructing the assignment.
func InvalidValueError() error {
return &errInvalidValue{}
}
// AssignField is a convenience function to assign a value to
// an optional struct field. In Go, an optional struct field is
// usually denoted by a pointer to T instead of T:
//
// type Object struct {
// Optional *T
// }
//
// This gets a bit cumbersome when you want to assign literals
// or you do not want to worry about taking the address of a
// variable.
//
// Object.Optional = &"foo" // doesn't compile!
//
// Instead you can use this function to do it in one line:
//
// blackmagic.AssignOptionalField(&Object.Optionl, "foo")
func AssignOptionalField(dst, src interface{}) error {
dstRV := reflect.ValueOf(dst)
srcRV := reflect.ValueOf(src)
if dstRV.Kind() != reflect.Pointer || dstRV.Elem().Kind() != reflect.Pointer {
return fmt.Errorf(`dst must be a pointer to a field that is turn a pointer of src (%T)`, src)
}
if !dstRV.Elem().CanSet() {
return fmt.Errorf(`dst (%T) is not assignable`, dstRV.Elem().Interface())
}
if !reflect.PointerTo(srcRV.Type()).AssignableTo(dstRV.Elem().Type()) {
return fmt.Errorf(`cannot assign src (%T) to dst (%T)`, src, dst)
}
ptr := reflect.New(srcRV.Type())
ptr.Elem().Set(srcRV)
dstRV.Elem().Set(ptr)
return nil
}
// 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
// src can be a pointer or a slice, and the code will slightly change
// depending on this
var srcIsPtr bool
var srcIsSlice bool
switch result.Kind() {
case reflect.Ptr:
srcIsPtr = true
case reflect.Slice:
srcIsSlice = true
}
rv := reflect.ValueOf(dst)
if rv.Kind() != reflect.Ptr {
return fmt.Errorf(`destination argument to AssignIfCompatible() must be a pointer: %T`, dst)
}
actualDst := rv
for {
if !actualDst.IsValid() {
return fmt.Errorf(`could not find a valid destination for AssignIfCompatible() (%T)`, dst)
}
if actualDst.CanSet() {
break
}
actualDst = actualDst.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 !srcIsSlice && srcIsPtr {
result = result.Elem()
}
}
if !result.IsValid() {
// At this point there's nothing we can do. return an error
return fmt.Errorf(`source value is invalid (%T): %w`, src, InvalidValueError())
}
if actualDst.Kind() == reflect.Ptr {
actualDst.Set(result.Addr())
return nil
}
if !result.Type().AssignableTo(actualDst.Type()) {
return fmt.Errorf(`argument to AssignIfCompatible() must be compatible with %T (was %T)`, orv.Interface(), dst)
}
if !actualDst.CanSet() {
return fmt.Errorf(`argument to AssignIfCompatible() must be settable`)
}
actualDst.Set(result)
return nil
}