writeRemainingField writes a non-primitive field (string, slice, map, struct, enum)
(ctx *WriteContext, ptr unsafe.Pointer, field *FieldInfo, value reflect.Value)
| 416 | |
| 417 | // writeRemainingField writes a non-primitive field (string, slice, map, struct, enum) |
| 418 | func (s *structSerializer) writeRemainingField(ctx *WriteContext, ptr unsafe.Pointer, field *FieldInfo, value reflect.Value) { |
| 419 | buf := ctx.Buffer() |
| 420 | if DebugOutputEnabled { |
| 421 | fmt.Printf("[fory-debug] write field %s: fieldInfo=%v typeId=%v serializer=%T, buffer writerIndex=%d\n", |
| 422 | field.Meta.Name, field.Meta.FieldDef, field.Meta.TypeId, field.Serializer, buf.writerIndex) |
| 423 | } |
| 424 | if field.Kind == FieldKindOptional { |
| 425 | if ptr != nil { |
| 426 | if writeOptionFast(ctx, field, unsafe.Add(ptr, field.Offset)) { |
| 427 | return |
| 428 | } |
| 429 | } |
| 430 | fieldValue := value.Field(field.Meta.FieldIndex) |
| 431 | if field.Serializer != nil { |
| 432 | if writeWithCachedTypeInfo(ctx, field, fieldValue) { |
| 433 | return |
| 434 | } |
| 435 | field.Serializer.Write(ctx, field.RefMode, field.Meta.WriteType, field.Meta.HasGenerics, fieldValue) |
| 436 | } else { |
| 437 | ctx.WriteValue(fieldValue, RefModeTracking, true) |
| 438 | } |
| 439 | return |
| 440 | } |
| 441 | // Fast path dispatch using pre-computed DispatchId |
| 442 | // ptr must be valid (addressable value) |
| 443 | if ptr != nil { |
| 444 | fieldPtr := unsafe.Add(ptr, field.Offset) |
| 445 | switch field.DispatchId { |
| 446 | case StringDispatchId: |
| 447 | // Check isPtr first for better branch prediction |
| 448 | if field.Kind != FieldKindPointer { |
| 449 | // Non-pointer string: always non-null, no ref tracking needed in fast path |
| 450 | if field.RefMode == RefModeNone { |
| 451 | ctx.WriteString(*(*string)(fieldPtr)) |
| 452 | } else { |
| 453 | // RefModeNullOnly or RefModeTracking: write NotNull flag then string |
| 454 | buf.WriteInt8(NotNullValueFlag) |
| 455 | ctx.WriteString(*(*string)(fieldPtr)) |
| 456 | } |
| 457 | return |
| 458 | } |
| 459 | // Pointer to string: can be nil, may need ref tracking |
| 460 | if field.RefMode == RefModeTracking { |
| 461 | break // Fall through to slow path for ref tracking |
| 462 | } |
| 463 | strPtr := *(**string)(fieldPtr) |
| 464 | if strPtr == nil { |
| 465 | if field.RefMode == RefModeNullOnly { |
| 466 | buf.WriteInt8(NullFlag) |
| 467 | } else { |
| 468 | // RefModeNone: write empty string for nil pointer |
| 469 | ctx.WriteString("") |
| 470 | } |
| 471 | return |
| 472 | } |
| 473 | // Non-nil pointer |
| 474 | if field.RefMode == RefModeNullOnly { |
| 475 | buf.WriteInt8(NotNullValueFlag) |
no test coverage detected