@@ -322,13 +322,39 @@ func assignValueToField(desc *Descriptor, src interface{}, fieldValue reflect.Va
322322 // Handle pointer fields - allocate if needed
323323 if fieldValue .Kind () == reflect .Ptr {
324324 if fieldValue .IsNil () {
325+ // Skip allocating for empty non-leaf sources to avoid clobbering existing data
326+ if isEmptyNonLeaf (desc , src ) {
327+ return nil
328+ }
329+
325330 fieldValue .Set (reflect .New (fieldValue .Type ().Elem ()))
326331 }
327332 return assignValue (desc , src , fieldValue .Elem (), opt , stack )
328333 }
329334 return assignValue (desc , src , fieldValue , opt , stack )
330335}
331336
337+ // isEmptyNonLeaf returns true if src is an empty composite value for the given descriptor.
338+ // Used to avoid allocating new nested structs or slices when there is nothing to assign.
339+ func isEmptyNonLeaf (desc * Descriptor , src interface {}) bool {
340+ if desc == nil || src == nil {
341+ return false
342+ }
343+
344+ switch desc .Kind {
345+ case TypeKind_Struct , TypeKind_StrMap :
346+ if m , ok := src .(map [string ]interface {}); ok {
347+ return len (m ) == 0
348+ }
349+ case TypeKind_List :
350+ if s , ok := src .([]interface {}); ok {
351+ return len (s ) == 0
352+ }
353+ }
354+
355+ return false
356+ }
357+
332358// assignStrMap handles TypeKind_StrMap assignment
333359func assignStrMap (desc * Descriptor , src interface {}, destValue reflect.Value , opt * AssignOptions , stack * pathStack ) error {
334360 srcMap , ok := src .(map [string ]interface {})
@@ -355,24 +381,55 @@ func assignStrMap(desc *Descriptor, src interface{}, destValue reflect.Value, op
355381 elemType := destValue .Type ().Elem ()
356382
357383 for key , value := range srcMap {
358- // Create a new element
384+ keyValue := reflect .ValueOf (key )
385+ existing := destValue .MapIndex (keyValue )
359386 elemValue := reflect .New (elemType ).Elem ()
387+ if existing .IsValid () {
388+ elemValue .Set (existing )
389+ }
390+
391+ // Find the appropriate descriptor for this entry
392+ var childDesc * Descriptor
393+ if wildcardDesc != nil {
394+ childDesc = wildcardDesc
395+ } else if child , ok := keyDescMap [key ]; ok {
396+ childDesc = child .Desc
397+ }
398+
399+ // Skip assigning empty non-leaf nodes to avoid overwriting existing values
400+ if childDesc != nil && isEmptyNonLeaf (childDesc , value ) {
401+ if ! existing .IsValid () {
402+ continue
403+ }
404+ // keep existing value untouched
405+ continue
406+ }
360407
361408 if value == nil {
362- // Set nil value in map (zero value for the element type, e.g., nil pointer)
363- destValue .SetMapIndex (reflect .ValueOf (key ), elemValue )
409+ // Preserve existing entry if present; otherwise set zero value
410+ if existing .IsValid () {
411+ destValue .SetMapIndex (keyValue , existing )
412+ }
364413 continue
365414 }
366415
367416 // Push map key onto stack
368417 stack .push (TypeKind_StrMap , key , 0 )
369418
370- // Find the appropriate descriptor
371419 var err error
372- if wildcardDesc != nil {
373- err = assignValueToField (wildcardDesc , value , elemValue , opt , stack )
374- } else if child , ok := keyDescMap [key ]; ok && child .Desc != nil {
375- err = assignValueToField (child .Desc , value , elemValue , opt , stack )
420+ if childDesc != nil {
421+ if elemType .Kind () == reflect .Ptr {
422+ ptrValue := elemValue
423+ if elemValue .IsNil () {
424+ ptrValue = reflect .New (elemType .Elem ())
425+ }
426+ err = assignValue (childDesc , value , ptrValue .Elem (), opt , stack )
427+ if err == nil {
428+ elemValue = ptrValue
429+ }
430+ } else {
431+ err = assignValue (childDesc , value , elemValue , opt , stack )
432+ }
376433 } else {
377434 err = assignLeaf (reflect .ValueOf (value ), elemValue )
378435 }
@@ -384,7 +441,7 @@ func assignStrMap(desc *Descriptor, src interface{}, destValue reflect.Value, op
384441 return err
385442 }
386443
387- destValue .SetMapIndex (reflect . ValueOf ( key ) , elemValue )
444+ destValue .SetMapIndex (keyValue , elemValue )
388445 }
389446
390447 return nil
@@ -440,14 +497,27 @@ func assignList(desc *Descriptor, src interface{}, destValue reflect.Value, opt
440497 return nil
441498 }
442499
443- // Handle slice (dynamic size)
500+ // Handle slice (dynamic size). Reuse existing slice when possible; only allocate when growing.
444501 elemType := destValue .Type ().Elem ()
445- newSlice := reflect .MakeSlice (destValue .Type (), srcLen , srcLen )
502+ destLen := destValue .Len ()
503+ useSlice := destValue
504+ if destLen < srcLen {
505+ useSlice = reflect .MakeSlice (destValue .Type (), srcLen , srcLen )
506+ if destLen > 0 {
507+ reflect .Copy (useSlice , destValue )
508+ }
509+ }
446510
447511 for i := 0 ; i < srcLen ; i ++ {
448- elemValue := newSlice .Index (i )
512+ elemValue := useSlice .Index (i )
513+
514+ // Skip empty non-leaf sources to avoid overwriting existing elements
515+ if wildcardDesc != nil && isEmptyNonLeaf (wildcardDesc , srcSlice [i ]) {
516+ continue
517+ }
518+
449519 if srcSlice [i ] == nil {
450- // Keep as zero value
520+ // Preserve existing value
451521 continue
452522 }
453523
@@ -456,12 +526,15 @@ func assignList(desc *Descriptor, src interface{}, destValue reflect.Value, opt
456526
457527 var err error
458528 if wildcardDesc != nil {
459- // Handle pointer element type
529+ // Handle pointer element type without dropping existing value
460530 if elemType .Kind () == reflect .Ptr {
461- newElem := reflect .New (elemType .Elem ())
462- err = assignValue (wildcardDesc , srcSlice [i ], newElem .Elem (), opt , stack )
531+ targetPtr := elemValue
532+ if elemValue .IsNil () {
533+ targetPtr = reflect .New (elemType .Elem ())
534+ }
535+ err = assignValue (wildcardDesc , srcSlice [i ], targetPtr .Elem (), opt , stack )
463536 if err == nil {
464- elemValue .Set (newElem )
537+ elemValue .Set (targetPtr )
465538 }
466539 } else {
467540 err = assignValue (wildcardDesc , srcSlice [i ], elemValue , opt , stack )
@@ -478,7 +551,9 @@ func assignList(desc *Descriptor, src interface{}, destValue reflect.Value, opt
478551 }
479552 }
480553
481- destValue .Set (newSlice )
554+ if useSlice .Pointer () != destValue .Pointer () || destLen != useSlice .Len () {
555+ destValue .Set (useSlice )
556+ }
482557 return nil
483558 }
484559
0 commit comments