generateSliceWriteInline generates inline slice serialization code to match reflection behavior exactly
(buf *bytes.Buffer, sliceType *types.Slice, fieldAccess string)
| 398 | |
| 399 | // generateSliceWriteInline generates inline slice serialization code to match reflection behavior exactly |
| 400 | func generateSliceWriteInline(buf *bytes.Buffer, sliceType *types.Slice, fieldAccess string) error { |
| 401 | elemType := sliceType.Elem() |
| 402 | |
| 403 | // Check if element type is referencable (needs ref tracking) |
| 404 | elemIsReferencable := isReferencableType(elemType) |
| 405 | |
| 406 | // In xlang mode, slices are NOT nullable by default (only pointer types are nullable). |
| 407 | // In native Go mode, slices can be nil and need null flags. |
| 408 | // Generate conditional code that respects the mode at runtime. |
| 409 | |
| 410 | // WriteData slice with conditional null flag - use block scope to avoid variable name conflicts |
| 411 | fmt.Fprintf(buf, "\t{\n") |
| 412 | // Check if xlang mode - in xlang mode, slices are not nullable by default |
| 413 | fmt.Fprintf(buf, "\t\tisXlang := ctx.TypeResolver().IsXlang()\n") |
| 414 | fmt.Fprintf(buf, "\t\tif isXlang {\n") |
| 415 | fmt.Fprintf(buf, "\t\t\t// xlang mode: slices are not nullable, write directly without null flag\n") |
| 416 | fmt.Fprintf(buf, "\t\t\tsliceLen := 0\n") |
| 417 | fmt.Fprintf(buf, "\t\t\tif %s != nil {\n", fieldAccess) |
| 418 | fmt.Fprintf(buf, "\t\t\t\tsliceLen = len(%s)\n", fieldAccess) |
| 419 | fmt.Fprintf(buf, "\t\t\t}\n") |
| 420 | fmt.Fprintf(buf, "\t\t\tbuf.WriteVarUint32(uint32(sliceLen))\n") |
| 421 | // Write elements in xlang mode |
| 422 | fmt.Fprintf(buf, "\t\t\tif sliceLen > 0 {\n") |
| 423 | fmt.Fprintf(buf, "\t\t\t\tcollectFlag := 12 // CollectionIsSameType | CollectionIsDeclElementType\n") |
| 424 | if elemIsReferencable { |
| 425 | fmt.Fprintf(buf, "\t\t\t\tif ctx.TrackRef() {\n") |
| 426 | fmt.Fprintf(buf, "\t\t\t\t\tcollectFlag |= 1 // CollectionTrackingRef for referencable element type\n") |
| 427 | fmt.Fprintf(buf, "\t\t\t\t}\n") |
| 428 | } |
| 429 | fmt.Fprintf(buf, "\t\t\t\tbuf.WriteInt8(int8(collectFlag))\n") |
| 430 | fmt.Fprintf(buf, "\t\t\t\tfor _, elem := range %s {\n", fieldAccess) |
| 431 | if elemIsReferencable { |
| 432 | fmt.Fprintf(buf, "\t\t\t\t\tif ctx.TrackRef() {\n") |
| 433 | fmt.Fprintf(buf, "\t\t\t\t\t\tbuf.WriteInt8(-1) // NotNullValueFlag for element\n") |
| 434 | fmt.Fprintf(buf, "\t\t\t\t\t}\n") |
| 435 | } |
| 436 | if err := generateSliceElementWriteInlineIndented(buf, elemType, "elem", "\t\t\t\t\t"); err != nil { |
| 437 | return err |
| 438 | } |
| 439 | fmt.Fprintf(buf, "\t\t\t\t}\n") // end for loop |
| 440 | fmt.Fprintf(buf, "\t\t\t}\n") // end if sliceLen > 0 |
| 441 | fmt.Fprintf(buf, "\t\t} else {\n") |
| 442 | fmt.Fprintf(buf, "\t\t\t// Native Go mode: slices are nullable, write null flag\n") |
| 443 | // Write null flag for slices in native mode |
| 444 | fmt.Fprintf(buf, "\t\t\tif %s == nil {\n", fieldAccess) |
| 445 | fmt.Fprintf(buf, "\t\t\t\tbuf.WriteInt8(-3) // NullFlag\n") |
| 446 | fmt.Fprintf(buf, "\t\t\t} else {\n") |
| 447 | fmt.Fprintf(buf, "\t\t\t\tbuf.WriteInt8(-1) // NotNullValueFlag\n") |
| 448 | fmt.Fprintf(buf, "\t\t\t\tsliceLen := len(%s)\n", fieldAccess) |
| 449 | fmt.Fprintf(buf, "\t\t\t\tbuf.WriteVarUint32(uint32(sliceLen))\n") |
| 450 | |
| 451 | // WriteData collection header and elements for non-empty slice in native mode |
| 452 | fmt.Fprintf(buf, "\t\t\t\tif sliceLen > 0 {\n") |
| 453 | |
| 454 | // For codegen, follow reflection's behavior for struct fields: |
| 455 | // Set both CollectionIsSameType and CollectionIsDeclElementType |
| 456 | // Add CollectionTrackingRef when ref tracking is enabled AND element is referencable |
| 457 | fmt.Fprintf(buf, "\t\t\t\t\tcollectFlag := 12 // CollectionIsSameType | CollectionIsDeclElementType\n") |
no test coverage detected