github.com/hedzr/evendeep@v0.4.8/params.go (about) 1 package evendeep 2 3 import ( 4 "github.com/hedzr/log" 5 6 "github.com/hedzr/evendeep/dbglog" 7 "github.com/hedzr/evendeep/flags" 8 "github.com/hedzr/evendeep/flags/cms" 9 "github.com/hedzr/evendeep/internal/cl" 10 "github.com/hedzr/evendeep/internal/tool" 11 12 "reflect" 13 "unsafe" 14 ) 15 16 // Params is params package. 17 type Params struct { 18 srcOwner *reflect.Value // srcOwner of source slice or struct, or any others 19 dstOwner *reflect.Value // dstOwner of destination slice or struct, or any others 20 srcDecoded *reflect.Value // 21 dstDecoded *reflect.Value // 22 srcType reflect.Type // = field(i+parent.srcOffset).type, or srcOwner.type for non-struct 23 dstType reflect.Type // = field(i+parent.dstOffset).type, or dstOwner.type for non-struct 24 25 // index int // struct field or slice index, 26 // srcOffset int // -1, or an offset of the embedded struct fields 27 // dstOffset int // -1, or an offset of the embedded struct fields 28 29 // srcFieldType *reflect.StructField // 30 // dstFieldType *reflect.StructField // 31 // srcAnonymous bool // 32 // dstAnonymous bool // 33 // mergingMode bool // base state 34 35 visited map[visit]visiteddestination 36 visiting visit 37 resultForNewSlice *reflect.Value 38 39 targetIterator structIterable // 40 accessor accessor // 41 // srcIndex int // 42 // field *reflect.StructField // source field type 43 // fieldTags *fieldTags // tag of source field 44 45 flags flags.Flags 46 47 children map[string]*Params // children of struct fields 48 childrenAnonymous []*Params // or children without name (non-struct) 49 owner *Params // 50 controller *cpController // 51 } 52 53 type visit struct { 54 addr1, addr2 unsafe.Pointer 55 typ reflect.Type 56 } 57 58 type visiteddestination struct { 59 dst reflect.Value 60 } 61 62 type paramsOpt func(p *Params) 63 64 func newParams(opts ...paramsOpt) *Params { 65 p := &Params{} 66 for _, opt := range opts { 67 opt(p) 68 } 69 return p 70 } 71 72 func withFlags(flagsList ...cms.CopyMergeStrategy) paramsOpt { //nolint:unused //future code 73 return func(p *Params) { 74 p.flags = flags.New(flagsList...) 75 } 76 } 77 78 func withOwnersSimple(c *cpController, ownerParams *Params) paramsOpt { //nolint:unused //future code 79 return func(p *Params) { 80 p.controller = c 81 ownerParams.addChildParams(p) 82 } 83 } 84 85 func withOwners(c *cpController, ownerParams *Params, ownerSource, ownerTarget, osDecoded, otDecoded *reflect.Value) paramsOpt { //nolint:lll,gocognit //future 86 return func(p *Params) { 87 p.srcOwner = ownerSource 88 p.dstOwner = ownerTarget 89 p.srcDecoded = osDecoded 90 p.dstDecoded = otDecoded 91 92 var st, tt reflect.Type 93 94 if p.srcDecoded == nil && p.srcOwner != nil { 95 d, _ := tool.Rdecode(*p.srcOwner) 96 p.srcDecoded = &d 97 if p.srcOwner.IsValid() { 98 p.srcType = p.srcOwner.Type() 99 } 100 } 101 102 if p.srcDecoded != nil && p.srcDecoded.IsValid() { 103 st = p.srcDecoded.Type() 104 p.parseSourceStruct(ownerParams, st) 105 p.dstType = p.dstOwner.Type() 106 } else if p.srcOwner != nil { 107 st = p.srcOwner.Type() 108 st = tool.RindirectType(st) 109 p.parseSourceStruct(ownerParams, st) 110 p.dstType = st 111 } 112 113 if p.dstDecoded == nil && p.dstOwner != nil { 114 d, _ := tool.Rdecode(*p.dstOwner) 115 p.dstDecoded = &d 116 } 117 118 if p.dstDecoded != nil && p.dstDecoded.IsValid() { 119 tt = p.dstDecoded.Type() 120 p.parseTargetStruct(ownerParams, tt) 121 } else if p.dstOwner != nil { 122 tt = p.dstOwner.Type() 123 tt = tool.RindirectType(tt) 124 p.parseTargetStruct(ownerParams, tt) 125 } 126 127 // 128 129 // p.mergingMode = c.flags.isAnyFlagsOK(SliceMerge, MapMerge) || ownerParams.isAnyFlagsOK(SliceMerge, MapMerge) 130 131 if p.dstDecoded != nil { 132 t := *p.dstDecoded 133 p.targetIterator = newStructIterator(t, 134 withStructPtrAutoExpand(c.autoExpandStruct), 135 withStructFieldPtrAutoNew(c.autoNewStruct), 136 withStructSource(p.srcDecoded, c.autoExpandStruct), 137 ) 138 } 139 140 // 141 142 p.controller = c 143 ownerParams.addChildParams(p) 144 } 145 } 146 147 // func (params *Params) withIteratorIndex(srcIndex int) (sourcefield tableRecT) { 148 // params.srcIndex = srcIndex 149 // 150 // //if i < params.srcType.NumField() { 151 // // t := params.srcType.Field(i) 152 // // params.fieldType = &t 153 // // params.fieldTags = parseFieldTags(t.Tag) 154 // //} 155 // 156 // if srcIndex < len(params.sourcefields.tableRecordsT) { 157 // sourcefield = params.sourcefields.tableRecordsT[srcIndex] 158 // params.field = sourcefield.StructField() 159 // params.fieldTags = parseFieldTags(params.field.Tag) 160 // } 161 // return 162 // } 163 164 func (params *Params) sourceFieldShouldBeIgnored() (yes bool) { 165 if params.targetIterator != nil { 166 yes = params.targetIterator.SourceFieldShouldBeIgnored(params.controller.ignoreNames) 167 } 168 return 169 } 170 171 func (params *Params) shouldBeIgnored(name string) (yes bool) { 172 if name == "" { 173 return true 174 } 175 if params.targetIterator != nil { 176 yes = params.targetIterator.ShouldBeIgnored(name, params.controller.ignoreNames) 177 } 178 return 179 } 180 181 func (params *Params) nextTargetField() (sourceField *tableRecT, ok bool) { 182 if params.targetIterator != nil { 183 byName := params.isGroupedFlagOKDeeply(cms.ByName) 184 params.accessor, ok = params.targetIterator.Next(params, byName) 185 if ok { 186 sourceField = params.accessor.SourceField() 187 _, isIgnored := params.parseFieldTags(sourceField.structField.Tag) 188 ok = !isIgnored 189 } 190 } 191 return 192 } 193 194 func (params *Params) nextTargetFieldLite() (ok bool) { 195 if params.targetIterator != nil { 196 byName := params.isGroupedFlagOKDeeply(cms.ByName) 197 params.accessor, ok = params.targetIterator.Next(params, byName) 198 } 199 return 200 } 201 202 func (params *Params) inMergeMode() bool { 203 return params.controller.flags.IsAnyFlagsOK(cms.SliceMerge, cms.MapMerge) || 204 params.owner.isAnyFlagsOK(cms.SliceMerge, cms.MapMerge) || 205 params.flags.IsAnyFlagsOK(cms.SliceMerge, cms.MapMerge) 206 } 207 208 func (params *Params) dstFieldIsExportedR() (copyUnexportedFields, isExported bool) { 209 k := reflect.Invalid 210 if params != nil && params.dstDecoded != nil { 211 k = params.dstDecoded.Kind() 212 } 213 if k != reflect.Struct || params.accessor == nil { 214 return false, true // non-struct-field target, treat it as exported 215 } 216 217 isExported, copyUnexportedFields = tool.IsExported(params.accessor.StructField()), params.controller.copyUnexportedFields 218 if isExported && params.owner != nil { 219 copyUnexportedFields, isExported = params.owner.dstFieldIsExportedR() 220 } 221 return 222 } 223 224 // processUnexportedField try to set newval into target if it's an unexported field. 225 func (params *Params) processUnexportedField(target, newval reflect.Value) (processed bool) { 226 if params == nil || params.controller == nil || params.accessor == nil { 227 return 228 } 229 if !params.controller.copyUnexportedFields { 230 return 231 } 232 if fld := params.accessor.StructField(); fld != nil { 233 // in a struct 234 if !tool.IsExported(fld) { 235 dbglog.Log(" unexported field %q (typ: %v): old(%v) -> new(%v)", 236 fld.Name, tool.Typfmt(fld.Type), tool.Valfmt(&target), tool.Valfmt(&newval)) 237 cl.SetUnexportedField(target, newval) 238 processed = true 239 } 240 } 241 return 242 } 243 244 // func (params *Params) parseSourceFieldTag(i int) { 245 // params.index = i 246 // } 247 248 func (params *Params) parseSourceStruct(ownerParams *Params, st reflect.Type) { 249 params.srcType = st 250 // if kind := st.Kind(); kind == reflect.Struct { 251 // // idx := index 252 // // if ownerParams != nil { 253 // // idx += ownerParams.srcOffset 254 // // } 255 // // params.withIteratorIndex(idx) 256 // // //if idx < st.NumField() { 257 // // // t := st.Field(idx) 258 // // // p.srcFieldType = &t 259 // // // p.fieldTags = parseFieldTags(t.Tag) 260 // // // p.srcType = t.Type 261 // // //} 262 // // //if ownerParams != nil { 263 // // // if oft := ownerParams.srcFieldType; oft != nil && oft.Anonymous && oft.Type.Kind() == reflect.Struct { 264 // // // p.srcAnonymous = true 265 // // // p.srcOffset = p.index 266 // // // } 267 // // //} 268 // } 269 } 270 271 func (params *Params) parseTargetStruct(ownerParams *Params, tt reflect.Type) { 272 params.dstType = tt 273 // if kind := tt.Kind(); kind == reflect.Struct { 274 // // idx := index 275 // // if ownerParams != nil { 276 // // idx += ownerParams.dstOffset 277 // // } 278 // // //if idx < tt.NumField() { 279 // // // t := tt.Field(idx) 280 // // // p.dstFieldType = &t 281 // // // p.dstType = t.Type 282 // // //} 283 // // //if ownerParams != nil { 284 // // // if oft := ownerParams.dstFieldType; oft != nil && oft.Anonymous && oft.Type.Kind() == reflect.Struct { 285 // // // p.dstAnonymous = true 286 // // // p.dstOffset = p.index 287 // // // } 288 // // //} 289 // // //} else if ownerParams != nil && ownerParams.dstFieldType != nil { 290 // } 291 } 292 293 // addChildParams does link this params into parent params. 294 func (params *Params) addChildParams(ppChild *Params) { 295 if params == nil || ppChild == nil { 296 return 297 } 298 299 // if struct 300 if ppChild.accessor != nil && ppChild.accessor.StructField() != nil { 301 fieldName := ppChild.accessor.StructFieldName() 302 303 if ppChild.children == nil { 304 ppChild.children = make(map[string]*Params) 305 } 306 if params.children == nil { 307 params.children = make(map[string]*Params) 308 } 309 if _, ok := ppChild.children[fieldName]; ok { 310 log.Panicf("field %q exists, cannot iterate another field on the same name", fieldName) 311 } 312 // if ppChild == nil { 313 // log.Panicf("setting nil Params for field %q, r u kidding me?", fieldName) 314 // } 315 316 params.children[fieldName] = ppChild 317 } else { 318 params.childrenAnonymous = append(params.childrenAnonymous, ppChild) 319 } 320 321 ppChild.owner = params 322 } 323 324 // revoke does revoke itself from parent params if necessary. 325 func (params *Params) revoke() { 326 if pp := params.owner; pp != nil { 327 if pp.accessor != nil && pp.accessor.StructField() != nil { 328 fieldName := pp.accessor.StructFieldName() 329 delete(pp.children, fieldName) 330 } else { 331 for i := 0; i < len(pp.childrenAnonymous); i++ { 332 if child := pp.childrenAnonymous[i]; child == params { 333 pp.childrenAnonymous = append(pp.childrenAnonymous[0:i], pp.childrenAnonymous[i+1:]...) 334 break 335 } 336 } 337 } 338 } 339 } 340 341 // // ValueOfSource _ 342 // func (params *Params) ValueOfSource() reflect.Value { 343 // if params.srcFieldType != nil { 344 // return params.srcDecoded.Field(params.index + params.srcOffset) 345 // } 346 // return *params.srcOwner 347 // } 348 // 349 // // ValueOfDestination _ 350 // func (params *Params) ValueOfDestination() reflect.Value { 351 // if params.dstFieldType != nil { 352 // return params.dstDecoded.Field(params.index + params.dstOffset) 353 // } 354 // return *params.dstOwner 355 // } 356 357 func (params *Params) isStruct() bool { //nolint:unused //future 358 return params != nil && params.accessor != nil && params.accessor.IsStruct() && params.dstOwner != nil 359 } 360 361 func (params *Params) parseFieldTags(tag reflect.StructTag) (flagsInTag *fieldTags, isIgnored bool) { 362 var tagName string 363 if params.controller != nil { 364 tagName = params.controller.tagKeyName 365 } 366 flagsInTag = parseFieldTags(tag, tagName) 367 isIgnored = flagsInTag.isFlagIgnored() 368 return 369 } 370 371 func (params *Params) isFlagExists(ftf cms.CopyMergeStrategy) (ret bool) { 372 if params == nil { 373 return 374 } 375 if params.controller != nil { 376 ret = params.controller.flags.IsFlagOK(ftf) 377 } 378 if !ret && params.flags != nil { 379 ret = params.flags.IsFlagOK(ftf) 380 } 381 if !ret && params.accessor != nil { 382 ret = params.accessor.IsFlagOK(ftf) 383 } 384 return 385 } 386 387 // isGroupedFlagOK tests if the given flag is exists or valid. 388 // 389 // Different with isGroupedFlagOKDeeply is, isGroupedFlagOK will return 390 // false simply while Params.fieldTags is empty or unset. 391 // 392 // When Params.fieldTags is valid, the actual testing will be forwarded 393 // to Params.fieldTags.flags.isGroupedFlagOK(). 394 func (params *Params) isGroupedFlagOK(ftf ...cms.CopyMergeStrategy) (ret bool) { //nolint:unused //future 395 if params == nil { 396 return flags.New().IsGroupedFlagOK(ftf...) 397 } 398 if params.controller != nil { 399 ret = params.controller.flags.IsGroupedFlagOK(ftf...) 400 } 401 if !ret && params.flags != nil { 402 ret = params.flags.IsGroupedFlagOK(ftf...) 403 } 404 if !ret && params.accessor != nil { 405 ret = params.accessor.IsGroupedFlagOK(ftf...) 406 } 407 return 408 } 409 410 // isGroupedFlagOKDeeply tests if the given flag is exists or valid. 411 // 412 // Different with isGroupedFlagOK is, isGroupedFlagOKDeeply will check 413 // whether the given flag is a leader (i.e. default choice) in a group 414 // or not, even if Params.fieldTags is empty or unset. And too, we run 415 // the same logical on these sources: 416 // 417 // 1. params.controller.flags 418 // 2. params.flags 419 // 3. params.accessor.fieldTags.flags if present 420 // 421 // When Params.fieldTags is valid, the actual testing will be forwarded 422 // to Params.fieldTags.flags.isGroupedFlagOK(). 423 func (params *Params) isGroupedFlagOKDeeply(ftf ...cms.CopyMergeStrategy) (ret bool) { 424 if params == nil { 425 return flags.New().IsGroupedFlagOK(ftf...) 426 } 427 if params.controller != nil { 428 ret = params.controller.flags.IsGroupedFlagOK(ftf...) 429 } 430 if !ret && params.flags != nil { 431 ret = params.flags.IsGroupedFlagOK(ftf...) 432 } 433 if !ret && params.accessor != nil { 434 ret = params.accessor.IsGroupedFlagOK(ftf...) 435 } 436 return 437 } 438 439 func (params *Params) isAnyFlagsOK(ftf ...cms.CopyMergeStrategy) (ret bool) { 440 if params == nil { 441 return 442 } 443 if params.controller != nil { 444 ret = params.controller.flags.IsAnyFlagsOK(ftf...) 445 } 446 if !ret && params.flags != nil { 447 ret = params.flags.IsAnyFlagsOK(ftf...) 448 } 449 if !ret && params.accessor != nil { 450 ret = params.accessor.IsAnyFlagsOK(ftf...) 451 } 452 return 453 } 454 455 func (params *Params) isAllFlagsOK(ftf ...cms.CopyMergeStrategy) (ret bool) { //nolint:unused //future 456 if params == nil { 457 return 458 } 459 if params.controller != nil { 460 ret = params.controller.flags.IsAllFlagsOK(ftf...) 461 } 462 if !ret && params.flags != nil { 463 ret = params.flags.IsAllFlagsOK(ftf...) 464 } 465 if !ret && params.accessor != nil { 466 ret = params.accessor.IsAllFlagsOK(ftf...) 467 } 468 return 469 } 470 471 func (params *Params) depth() (depth int) { 472 p := params 473 for p != nil { 474 depth++ 475 p = p.owner 476 } 477 return 478 }