github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/conv/evalargs.go (about)

     1  package conv
     2  
     3  // stolen from the Go standard library, text/template package.
     4  import (
     5  	"fmt"
     6  	"reflect"
     7  )
     8  
     9  var (
    10  	errorType       = reflect.TypeOf((*error)(nil)).Elem()
    11  	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
    12  )
    13  
    14  // printableValue returns the, possibly indirected, interface value inside v that
    15  // is best for a call to formatted printer.
    16  func printableValue(v reflect.Value) (interface{}, bool) {
    17  	if v.Kind() == reflect.Ptr {
    18  		v, _ = indirect(v) // fmt.Fprint handles nil.
    19  	}
    20  	if !v.IsValid() {
    21  		return "<no value>", true
    22  	}
    23  
    24  	if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
    25  		if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
    26  			v = v.Addr()
    27  		} else {
    28  			switch v.Kind() {
    29  			case reflect.Chan, reflect.Func:
    30  				return nil, false
    31  			}
    32  		}
    33  	}
    34  	return v.Interface(), true
    35  }
    36  
    37  // indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
    38  func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
    39  	for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
    40  		if v.IsNil() {
    41  			return v, true
    42  		}
    43  	}
    44  	return v, false
    45  }