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 }