readRemainingField reads a non-primitive field (string, slice, map, struct, enum)
(ctx *ReadContext, ptr unsafe.Pointer, field *FieldInfo, value reflect.Value)
| 1613 | |
| 1614 | // readRemainingField reads a non-primitive field (string, slice, map, struct, enum) |
| 1615 | func (s *structSerializer) readRemainingField(ctx *ReadContext, ptr unsafe.Pointer, field *FieldInfo, value reflect.Value) { |
| 1616 | buf := ctx.Buffer() |
| 1617 | if DebugOutputEnabled { |
| 1618 | fmt.Printf("[fory-debug] read remaining field %s: fieldInfo=%v typeId=%v, buffer readerIndex=%d\n", |
| 1619 | field.Meta.Name, field.Meta.FieldDef, field.Meta.TypeId, buf.readerIndex) |
| 1620 | } |
| 1621 | ctxErr := ctx.Err() |
| 1622 | if field.Kind == FieldKindOptional { |
| 1623 | if ptr != nil { |
| 1624 | if readOptionFast(ctx, field, unsafe.Add(ptr, field.Offset)) { |
| 1625 | return |
| 1626 | } |
| 1627 | } |
| 1628 | fieldValue := value.Field(field.Meta.FieldIndex) |
| 1629 | if field.Serializer != nil { |
| 1630 | field.Serializer.Read(ctx, field.RefMode, field.Meta.WriteType, field.Meta.HasGenerics, fieldValue) |
| 1631 | } else { |
| 1632 | ctx.ReadValue(fieldValue, RefModeTracking, true) |
| 1633 | } |
| 1634 | return |
| 1635 | } |
| 1636 | // Fast path dispatch using pre-computed DispatchId |
| 1637 | // ptr must be valid (addressable value) |
| 1638 | if ptr != nil { |
| 1639 | fieldPtr := unsafe.Add(ptr, field.Offset) |
| 1640 | switch field.DispatchId { |
| 1641 | case StringDispatchId: |
| 1642 | // Check isPtr first for better branch prediction |
| 1643 | if field.Kind != FieldKindPointer { |
| 1644 | // Non-pointer string: no ref tracking needed in fast path |
| 1645 | if field.RefMode == RefModeNone { |
| 1646 | *(*string)(fieldPtr) = ctx.ReadString() |
| 1647 | } else { |
| 1648 | // RefModeNullOnly or RefModeTracking: read NotNull flag then string |
| 1649 | refFlag := buf.ReadInt8(ctxErr) |
| 1650 | if refFlag == NullFlag { |
| 1651 | *(*string)(fieldPtr) = "" |
| 1652 | } else { |
| 1653 | *(*string)(fieldPtr) = ctx.ReadString() |
| 1654 | } |
| 1655 | } |
| 1656 | return |
| 1657 | } |
| 1658 | // Pointer to string: can be nil, may need ref tracking |
| 1659 | if field.RefMode == RefModeTracking { |
| 1660 | break // Fall through to slow path for ref tracking |
| 1661 | } |
| 1662 | if field.RefMode == RefModeNullOnly { |
| 1663 | refFlag := buf.ReadInt8(ctxErr) |
| 1664 | if refFlag == NullFlag { |
| 1665 | // Leave as nil |
| 1666 | return |
| 1667 | } |
| 1668 | } |
| 1669 | // Allocate new string and store pointer |
| 1670 | str := ctx.ReadString() |
| 1671 | sp := new(string) |
| 1672 | *sp = str |
no test coverage detected