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

     1  package gotype
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"unsafe"
     8  
     9  	structform "github.com/urso/go-structform"
    10  	stunsafe "github.com/urso/go-structform/internal/unsafe"
    11  )
    12  
    13  type userFoldFn func(unsafe.Pointer, structform.ExtVisitor) error
    14  
    15  func makeUserFoldFn(fn reflect.Value) (userFoldFn, error) {
    16  	t := fn.Type()
    17  
    18  	if fn.Kind() != reflect.Func {
    19  		return nil, errors.New("function type required")
    20  	}
    21  
    22  	if t.NumIn() != 2 {
    23  		return nil, fmt.Errorf("function '%v' must accept 2 arguments", t.Name())
    24  	}
    25  	if t.NumOut() != 1 || t.Out(0) != tError {
    26  		return nil, fmt.Errorf("function '%v' does not return errors", t.Name())
    27  	}
    28  
    29  	ta0 := t.In(0)
    30  	if ta0.Kind() != reflect.Ptr {
    31  		return nil, fmt.Errorf("first argument in function '%v' must be a pointer", t.Name())
    32  	}
    33  
    34  	ta1 := t.In(1)
    35  	if ta1 != tExtVisitor {
    36  		return nil, fmt.Errorf("second arument in function '%v' must be structform.ExtVisitor", t.Name())
    37  	}
    38  
    39  	fptr := *((*userFoldFn)(stunsafe.UnsafeFnPtr(fn)))
    40  	return fptr, nil
    41  }
    42  
    43  func liftUserPtrFn(f userFoldFn) reFoldFn {
    44  	return func(c *foldContext, v reflect.Value) error {
    45  		if v.IsNil() {
    46  			return f(nil, c.visitor)
    47  		}
    48  		return f(stunsafe.ReflValuePtr(v.Elem()), c.visitor)
    49  	}
    50  }
    51  
    52  func liftUserValueFn(f userFoldFn) reFoldFn {
    53  	return func(c *foldContext, v reflect.Value) error {
    54  		return f(stunsafe.ReflValuePtr(v), c.visitor)
    55  	}
    56  }