github.com/urso/go-structform@v0.0.2/gotype/unfold.go (about) 1 package gotype 2 3 import ( 4 "reflect" 5 "sync" 6 "unsafe" 7 8 structform "github.com/urso/go-structform" 9 ) 10 11 type Unfolder struct { 12 unfoldCtx 13 } 14 15 type unfoldCtx struct { 16 opts options 17 18 buf buffer 19 20 unfolder unfolderStack 21 value reflectValueStack 22 baseType structformTypeStack 23 ptr ptrStack 24 key keyStack 25 idx idxStack 26 27 keyCache symbolCache 28 } 29 30 type ptrUnfolder interface { 31 initState(*unfoldCtx, unsafe.Pointer) 32 } 33 34 type reflUnfolder interface { 35 initState(*unfoldCtx, reflect.Value) 36 } 37 38 type unfolder interface { 39 // primitives 40 OnNil(*unfoldCtx) error 41 OnBool(*unfoldCtx, bool) error 42 OnString(*unfoldCtx, string) error 43 OnStringRef(*unfoldCtx, []byte) error 44 OnInt8(*unfoldCtx, int8) error 45 OnInt16(*unfoldCtx, int16) error 46 OnInt32(*unfoldCtx, int32) error 47 OnInt64(*unfoldCtx, int64) error 48 OnInt(*unfoldCtx, int) error 49 OnByte(*unfoldCtx, byte) error 50 OnUint8(*unfoldCtx, uint8) error 51 OnUint16(*unfoldCtx, uint16) error 52 OnUint32(*unfoldCtx, uint32) error 53 OnUint64(*unfoldCtx, uint64) error 54 OnUint(*unfoldCtx, uint) error 55 OnFloat32(*unfoldCtx, float32) error 56 OnFloat64(*unfoldCtx, float64) error 57 58 // array types 59 OnArrayStart(*unfoldCtx, int, structform.BaseType) error 60 OnArrayFinished(*unfoldCtx) error 61 OnChildArrayDone(*unfoldCtx) error 62 63 // object types 64 OnObjectStart(*unfoldCtx, int, structform.BaseType) error 65 OnObjectFinished(*unfoldCtx) error 66 OnKey(*unfoldCtx, string) error 67 OnKeyRef(*unfoldCtx, []byte) error 68 OnChildObjectDone(*unfoldCtx) error 69 } 70 71 type typeUnfoldRegistry struct { 72 mu sync.RWMutex 73 m map[reflect.Type]reflUnfolder 74 } 75 76 var unfoldRegistry = newTypeUnfoldRegistry() 77 78 func NewUnfolder(to interface{}) (*Unfolder, error) { 79 u := &Unfolder{} 80 u.opts = options{tag: "struct"} 81 82 u.unfolder.init(&unfolderNoTarget{}) 83 u.value.init(reflect.Value{}) 84 u.ptr.init() 85 u.key.init() 86 u.idx.init() 87 u.baseType.init() 88 89 // TODO: make allocation buffer size configurable 90 u.buf.init(1024) 91 92 if to != nil { 93 err := u.SetTarget(to) 94 if err != nil { 95 return nil, err 96 } 97 } 98 99 return u, nil 100 } 101 102 func (u *Unfolder) EnableKeyCache(max int) { 103 u.keyCache.init(max) 104 } 105 106 func (u *Unfolder) SetTarget(to interface{}) error { 107 ctx := &u.unfoldCtx 108 109 if ptr, u := lookupGoTypeUnfolder(to); u != nil { 110 u.initState(ctx, ptr) 111 return nil 112 } 113 114 t := reflect.TypeOf(to) 115 if t.Kind() != reflect.Ptr { 116 return errRequiresPointer 117 } 118 119 ru, err := lookupReflUnfolder(&u.unfoldCtx, t) 120 if err != nil { 121 return err 122 } 123 if ru != nil { 124 ru.initState(ctx, reflect.ValueOf(to)) 125 return nil 126 } 127 128 return errUnsupported 129 } 130 131 func (u *unfoldCtx) OnObjectStart(len int, baseType structform.BaseType) error { 132 return u.unfolder.current.OnObjectStart(u, len, baseType) 133 } 134 135 func (u *unfoldCtx) OnObjectFinished() error { 136 lBefore := len(u.unfolder.stack) + 1 137 138 if err := u.unfolder.current.OnObjectFinished(u); err != nil { 139 return err 140 } 141 142 lAfter := len(u.unfolder.stack) + 1 143 if old := u.unfolder.current; lAfter > 1 && lBefore != lAfter { 144 return old.OnChildObjectDone(u) 145 } 146 147 return nil 148 } 149 150 func (u *unfoldCtx) OnKey(s string) error { 151 return u.unfolder.current.OnKey(u, s) 152 } 153 154 func (u *unfoldCtx) OnKeyRef(s []byte) error { 155 return u.unfolder.current.OnKeyRef(u, s) 156 } 157 158 func (u *unfoldCtx) OnArrayStart(len int, baseType structform.BaseType) error { 159 return u.unfolder.current.OnArrayStart(u, len, baseType) 160 } 161 162 func (u *unfoldCtx) OnArrayFinished() error { 163 lBefore := len(u.unfolder.stack) + 1 164 165 if err := u.unfolder.current.OnArrayFinished(u); err != nil { 166 return err 167 } 168 169 lAfter := len(u.unfolder.stack) + 1 170 if old := u.unfolder.current; lAfter > 1 && lBefore != lAfter { 171 return old.OnChildArrayDone(u) 172 } 173 174 return nil 175 } 176 177 func (u *unfoldCtx) OnNil() error { 178 return u.unfolder.current.OnNil(u) 179 } 180 181 func (u *unfoldCtx) OnBool(b bool) error { 182 return u.unfolder.current.OnBool(u, b) 183 } 184 185 func (u *unfoldCtx) OnString(s string) error { 186 return u.unfolder.current.OnString(u, s) 187 } 188 189 func (u *unfoldCtx) OnStringRef(s []byte) error { 190 return u.unfolder.current.OnStringRef(u, s) 191 } 192 193 func (u *unfoldCtx) OnInt8(i int8) error { 194 return u.unfolder.current.OnInt8(u, i) 195 } 196 197 func (u *unfoldCtx) OnInt16(i int16) error { 198 return u.unfolder.current.OnInt16(u, i) 199 } 200 201 func (u *unfoldCtx) OnInt32(i int32) error { 202 return u.unfolder.current.OnInt32(u, i) 203 } 204 205 func (u *unfoldCtx) OnInt64(i int64) error { 206 return u.unfolder.current.OnInt64(u, i) 207 } 208 209 func (u *unfoldCtx) OnInt(i int) error { 210 return u.unfolder.current.OnInt(u, i) 211 } 212 213 func (u *unfoldCtx) OnByte(b byte) error { 214 return u.unfolder.current.OnByte(u, b) 215 } 216 217 func (u *unfoldCtx) OnUint8(v uint8) error { 218 return u.unfolder.current.OnUint8(u, v) 219 } 220 221 func (u *unfoldCtx) OnUint16(v uint16) error { 222 return u.unfolder.current.OnUint16(u, v) 223 } 224 225 func (u *unfoldCtx) OnUint32(v uint32) error { 226 return u.unfolder.current.OnUint32(u, v) 227 } 228 229 func (u *unfoldCtx) OnUint64(v uint64) error { 230 return u.unfolder.current.OnUint64(u, v) 231 } 232 233 func (u *unfoldCtx) OnUint(v uint) error { 234 return u.unfolder.current.OnUint(u, v) 235 } 236 237 func (u *unfoldCtx) OnFloat32(f float32) error { 238 return u.unfolder.current.OnFloat32(u, f) 239 } 240 241 func (u *unfoldCtx) OnFloat64(f float64) error { 242 return u.unfolder.current.OnFloat64(u, f) 243 } 244 245 func newTypeUnfoldRegistry() *typeUnfoldRegistry { 246 return &typeUnfoldRegistry{m: map[reflect.Type]reflUnfolder{}} 247 } 248 249 func (r *typeUnfoldRegistry) find(t reflect.Type) reflUnfolder { 250 r.mu.RLock() 251 defer r.mu.RUnlock() 252 return r.m[t] 253 } 254 255 func (r *typeUnfoldRegistry) set(t reflect.Type, f reflUnfolder) { 256 r.mu.Lock() 257 defer r.mu.Unlock() 258 r.m[t] = f 259 }