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

     1  package gotype
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  
     7  	structform "github.com/urso/go-structform"
     8  )
     9  
    10  type liftedReflUnfolder struct{ unfolder ptrUnfolder }
    11  
    12  type unfolderReflSlice struct {
    13  	elem reflUnfolder
    14  }
    15  
    16  type unfolderReflSliceStart struct {
    17  	unfolderErrArrayStart
    18  }
    19  
    20  type unfolderReflMap struct {
    21  	shared unfolderReflMapShared
    22  }
    23  
    24  type unfolderReflMapShared struct {
    25  	waitKey  *unfolderReflMapOnKey
    26  	waitElem *unfolderReflMapOnElem
    27  }
    28  
    29  type unfolderReflMapStart struct {
    30  	unfolderErrObjectStart
    31  }
    32  
    33  type unfolderReflMapOnKey struct {
    34  	unfolderErrExpectKey
    35  	shared *unfolderReflMapShared
    36  }
    37  
    38  type unfolderReflMapOnElem struct {
    39  	shared *unfolderReflMapShared
    40  	elem   reflUnfolder
    41  }
    42  
    43  type unfolderReflPtr struct {
    44  	elem reflUnfolder
    45  }
    46  
    47  var (
    48  	_singletonUnfolderReflSliceStart = &unfolderReflSliceStart{}
    49  	_singletonUnfolderReflMapStart   = &unfolderReflMapStart{}
    50  )
    51  
    52  func liftGoUnfolder(u ptrUnfolder) *liftedReflUnfolder { return &liftedReflUnfolder{u} }
    53  
    54  func (u *liftedReflUnfolder) initState(ctx *unfoldCtx, v reflect.Value) {
    55  	ptr := unsafe.Pointer(v.Pointer())
    56  	u.unfolder.initState(ctx, ptr)
    57  }
    58  
    59  func newUnfolderReflSlice(elem reflUnfolder) *unfolderReflSlice {
    60  	return &unfolderReflSlice{elem}
    61  }
    62  
    63  func (u *unfolderReflSlice) initState(ctx *unfoldCtx, v reflect.Value) {
    64  	ctx.value.push(v)
    65  	ctx.unfolder.push(u)
    66  	ctx.idx.push(0)
    67  	ctx.unfolder.push(_singletonUnfolderReflSliceStart)
    68  }
    69  
    70  func (u *unfolderReflSlice) cleanup(ctx *unfoldCtx) {
    71  	ctx.idx.pop()
    72  	ctx.value.pop()
    73  	ctx.unfolder.pop()
    74  }
    75  
    76  func (u *unfolderReflSliceStart) cleanup(ctx *unfoldCtx) {
    77  	ctx.unfolder.pop()
    78  }
    79  
    80  func (u *unfolderReflSliceStart) OnArrayStart(ctx *unfoldCtx, l int, baseType structform.BaseType) error {
    81  
    82  	ptr := ctx.value.current
    83  	v := ptr.Elem()
    84  
    85  	if l < 0 {
    86  		l = 0
    87  	}
    88  
    89  	if v.IsNil() && l > 0 {
    90  		v.Set(reflect.MakeSlice(v.Type(), l, l))
    91  	} else if !v.IsNil() && l < v.Len() {
    92  		v.SetLen(l)
    93  	}
    94  
    95  	u.cleanup(ctx)
    96  	return nil
    97  }
    98  
    99  func (u *unfolderReflSlice) OnArrayFinished(ctx *unfoldCtx) error {
   100  	u.cleanup(ctx)
   101  	return nil
   102  }
   103  
   104  func (u *unfolderReflSlice) prepare(ctx *unfoldCtx) reflect.Value {
   105  	// make space for some more element
   106  	ptr := ctx.value.current
   107  	idx := &ctx.idx
   108  	v := ptr.Elem()
   109  
   110  	switch {
   111  	case v.Len() > idx.current:
   112  
   113  	case v.Cap() > idx.current:
   114  		v.SetLen(idx.current + 1)
   115  
   116  	default:
   117  		v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem())))
   118  	}
   119  
   120  	elem := v.Index(idx.current).Addr()
   121  	idx.current++
   122  
   123  	return elem
   124  }
   125  
   126  func (u *unfolderReflSlice) OnObjectFinished(_ *unfoldCtx) error {
   127  	return errUnsupported
   128  }
   129  
   130  func newUnfolderReflMap(elem reflUnfolder) *unfolderReflMap {
   131  	u := &unfolderReflMap{}
   132  	u.shared.waitKey = &unfolderReflMapOnKey{shared: &u.shared}
   133  	u.shared.waitElem = &unfolderReflMapOnElem{shared: &u.shared, elem: elem}
   134  	return u
   135  }
   136  
   137  func (u *unfolderReflMap) initState(ctx *unfoldCtx, v reflect.Value) {
   138  	ctx.value.push(v)
   139  	ctx.unfolder.push(u.shared.waitKey)
   140  	ctx.unfolder.push(_singletonUnfolderReflMapStart)
   141  }
   142  
   143  func (u *unfolderReflMapStart) OnObjectStart(ctx *unfoldCtx, l int, bt structform.BaseType) error {
   144  	ctx.unfolder.pop()
   145  	return nil
   146  }
   147  
   148  func (u *unfolderReflMapOnKey) OnKey(ctx *unfoldCtx, key string) error {
   149  	ctx.key.push(key)
   150  	ctx.unfolder.current = u.shared.waitElem
   151  	return nil
   152  }
   153  
   154  func (u *unfolderReflMapOnKey) OnKeyRef(ctx *unfoldCtx, key []byte) error {
   155  	return u.OnKey(ctx, ctx.keyCache.get(key))
   156  }
   157  
   158  func (u *unfolderReflMapOnKey) OnObjectFinished(ctx *unfoldCtx) error {
   159  	ctx.unfolder.pop()
   160  	ctx.value.pop()
   161  	return nil
   162  }
   163  
   164  func (u *unfolderReflMapOnElem) prepare(ctx *unfoldCtx) reflect.Value {
   165  	ptr := ctx.value.current
   166  	v := ptr.Elem()
   167  	et := v.Type().Elem()
   168  
   169  	targetPtr := ctx.buf.alloc(int(et.Size()))
   170  	target := reflect.NewAt(et, targetPtr)
   171  	ctx.value.push(target)
   172  	return target
   173  }
   174  
   175  func (u *unfolderReflMapOnElem) process(ctx *unfoldCtx) {
   176  	ptr := ctx.value.pop()
   177  	v := ptr.Elem()
   178  
   179  	ptr = ctx.value.current
   180  	m := ptr.Elem()
   181  	m.SetMapIndex(reflect.ValueOf(ctx.key.pop()), v)
   182  
   183  	ctx.buf.release()
   184  	ctx.unfolder.current = u.shared.waitKey
   185  }
   186  
   187  func (u *unfolderReflMapOnElem) OnObjectFinished(_ *unfoldCtx) error { return errExpectedObjectValue }
   188  func (u *unfolderReflMapOnElem) OnArrayFinished(_ *unfoldCtx) error  { return errUnsupported }
   189  
   190  func newUnfolderReflPtr(elem reflUnfolder) *unfolderReflPtr {
   191  	return &unfolderReflPtr{elem}
   192  }
   193  
   194  func (u *unfolderReflPtr) initState(ctx *unfoldCtx, v reflect.Value) {
   195  	ctx.value.push(v)
   196  	ctx.unfolder.push(u)
   197  }
   198  
   199  func (u *unfolderReflPtr) cleanup(ctx *unfoldCtx) {
   200  	ctx.value.pop()
   201  	ctx.unfolder.pop()
   202  }
   203  
   204  func (u *unfolderReflPtr) prepare(ctx *unfoldCtx) reflect.Value {
   205  	ptr := ctx.value.current
   206  
   207  	v := ptr.Elem()
   208  	target := reflect.New(v.Type().Elem())
   209  	ctx.value.push(target)
   210  	return target
   211  }
   212  
   213  func (u *unfolderReflPtr) process(ctx *unfoldCtx) {
   214  	v := ctx.value.pop()
   215  	ptr := ctx.value.current.Elem()
   216  	ptr.Set(v)
   217  	u.cleanup(ctx)
   218  }
   219  
   220  func (u *unfolderReflPtr) OnObjectFinished(_ *unfoldCtx) error { return errUnsupported }
   221  func (u *unfolderReflPtr) OnArrayFinished(_ *unfoldCtx) error  { return errUnsupported }