github.com/ovechkin-dm/go-dyno@v0.0.23/proxy/proxy.go (about)

     1  package proxy
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"unsafe"
     7  )
     8  
     9  func Create[T any](handler func(m *MethodInfo, values []reflect.Value) []reflect.Value) (T, error) {
    10  	ifaceInstance := new(T)
    11  	v := reflect.ValueOf(ifaceInstance).Elem()
    12  	ifaceValue := (*IFaceValue)(unsafe.Pointer(&v))
    13  	if v.Type().Kind() != reflect.Interface {
    14  		return *ifaceInstance, errors.New("cannot create proxy for non-interface type")
    15  	}
    16  	numMethods := v.NumMethod()
    17  
    18  	var ds = &DynamicStruct{
    19  		IFaceValue:       v,
    20  		IFaceValueSource: ifaceValue,
    21  	}
    22  	sv := reflect.ValueOf(ds)
    23  	st := (*refValue)(unsafe.Pointer(&sv)).typ
    24  	instancePtr := unsafe.Pointer(ds)
    25  	ifaceValue.Ptr.Word = instancePtr
    26  
    27  	arr := make([]int64, unsafe.Sizeof(itab{}))
    28  	ds.arr = arr
    29  	ntab := (*itab)(unsafe.Pointer(&arr[0]))
    30  	ntab.ityp = ifaceValue.Typ
    31  	ntab.typ = uintptr(unsafe.Pointer(st))
    32  	ifaceValue.Ptr.Itab = ntab
    33  
    34  	ds.methods = make([]*methodContext, numMethods)
    35  	for i := 0; i < numMethods; i++ {
    36  		methodCtx := createMethod(v, ds, handler, i)
    37  		ifaceValue.Ptr.Itab.fun[i] = unsafe.Pointer(reflect.ValueOf(methods[i]).Pointer())
    38  		ds.methods[i] = methodCtx
    39  	}
    40  
    41  	return *ifaceInstance, nil
    42  }
    43  
    44  func createMethod(
    45  	ifaceValue reflect.Value,
    46  	d *DynamicStruct,
    47  	handler func(m *MethodInfo, values []reflect.Value) []reflect.Value, num int,
    48  ) *methodContext {
    49  	methodValue := ifaceValue.Method(num)
    50  	tp := methodValue.Type()
    51  	inArgs := make([]reflect.Type, 0)
    52  	outArgs := make([]reflect.Type, 0)
    53  	inArgs = append(inArgs, reflect.TypeOf(d))
    54  	for nin := 0; nin < tp.NumIn(); nin++ {
    55  		inArgs = append(inArgs, tp.In(nin))
    56  	}
    57  	for nout := 0; nout < tp.NumOut(); nout++ {
    58  		outArgs = append(outArgs, tp.Out(nout))
    59  	}
    60  	ftype := reflect.FuncOf(inArgs, outArgs, tp.IsVariadic())
    61  	methodInfo := &MethodInfo{
    62  		Num:          num,
    63  		ReflectValue: methodValue,
    64  		Name:         ifaceValue.Type().Method(num).Name,
    65  		Type:         ifaceValue.Type().Method(num),
    66  	}
    67  	hf := func(values []reflect.Value) []reflect.Value {
    68  		withoutReceiver := values[1:]
    69  		return handler(methodInfo, withoutReceiver)
    70  	}
    71  	rv := reflect.MakeFunc(ftype, hf)
    72  	ptr := (*refValue)(unsafe.Pointer(&rv))
    73  	mfi := (*makeFuncImpl)(ptr.ptr)
    74  	result := &methodContext{
    75  		fn: mfi,
    76  		tp: tp,
    77  		rv: rv,
    78  	}
    79  	return result
    80  }