github.com/urso/go-structform@v0.0.2/gotype/fold_inline.go (about)

     1  package gotype
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/urso/go-structform"
     7  	"github.com/urso/go-structform/visitors"
     8  )
     9  
    10  // getReflectFoldMapKeys implements inline fold of a map[string]X type,
    11  // not reporting object start/end events
    12  func getReflectFoldMapKeys(c *foldContext, t reflect.Type) (reFoldFn, error) {
    13  	if t.Key().Kind() != reflect.String {
    14  		return nil, errMapRequiresStringKey
    15  	}
    16  
    17  	f := getMapInlineByPrimitiveElem(t.Elem())
    18  	if f != nil {
    19  		return f, nil
    20  	}
    21  
    22  	elemVisitor, err := getReflectFold(c, t.Elem())
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  
    27  	return makeMapKeysFold(elemVisitor), nil
    28  }
    29  
    30  func makeMapKeysFold(elemVisitor reFoldFn) reFoldFn {
    31  	return func(C *foldContext, rv reflect.Value) error {
    32  		if rv.IsNil() || !rv.IsValid() {
    33  			return nil
    34  		}
    35  
    36  		for _, k := range rv.MapKeys() {
    37  			if err := C.OnKey(k.String()); err != nil {
    38  				return err
    39  			}
    40  			if err := elemVisitor(C, rv.MapIndex(k)); err != nil {
    41  				return err
    42  			}
    43  		}
    44  		return nil
    45  	}
    46  }
    47  
    48  // getReflectFoldInlineInterface create an inline folder for an yet unknown type.
    49  // The actual types folder must open/close an object
    50  func getReflectFoldInlineInterface(C *foldContext, t reflect.Type) (reFoldFn, error) {
    51  	var (
    52  		// cache last used folder
    53  		lastType    reflect.Type
    54  		lastVisitor reFoldFn
    55  	)
    56  
    57  	return embeddObjReFold(C, func(C *foldContext, rv reflect.Value) error {
    58  		if rv.Type() != lastType {
    59  			elemVisitor, err := getReflectFold(C, rv.Type())
    60  			if err != nil {
    61  				return err
    62  			}
    63  
    64  			lastVisitor = elemVisitor
    65  			lastType = rv.Type()
    66  		}
    67  		return lastVisitor(C, rv)
    68  	}), nil
    69  }
    70  
    71  func embeddObjReFold(C *foldContext, objFold reFoldFn) reFoldFn {
    72  	var (
    73  		ctx = *C
    74  		vs  = visitors.NewExpectObjVisitor(nil)
    75  	)
    76  
    77  	ctx.visitor = structform.EnsureExtVisitor(vs).(visitor)
    78  	return func(C *foldContext, rv reflect.Value) error {
    79  		// don't inline missing/empty object
    80  		if rv.IsNil() || !rv.IsValid() {
    81  			return nil
    82  		}
    83  
    84  		vs.SetActive(C.visitor)
    85  		err := objFold(&ctx, rv)
    86  		if err == nil && !vs.Done() {
    87  			err = errExpectedObjectClose
    88  		}
    89  
    90  		vs.SetActive(nil)
    91  		return err
    92  	}
    93  }