github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/dump/slice.go (about)

     1  package dump
     2  
     3  import (
     4  	"context"
     5  	"unsafe"
     6  	"github.com/v2pro/plz/msgfmt/jsonfmt"
     7  	"encoding/json"
     8  )
     9  
    10  type sliceHeader struct {
    11  	data unsafe.Pointer
    12  	len  int
    13  	cap  int
    14  }
    15  
    16  type sliceEncoder struct {
    17  	elemEncoder jsonfmt.Encoder
    18  	elemSize    uintptr
    19  }
    20  
    21  func (encoder *sliceEncoder) Encode(ctx context.Context, space []byte, ptr unsafe.Pointer) []byte {
    22  	header := (*sliceHeader)(ptr)
    23  	space = append(space, `{"data":{"__ptr__":"`...)
    24  	ptrStr := ptrToStr(uintptr(header.data))
    25  	space = append(space, ptrStr...)
    26  	space = append(space, `"},"len":`...)
    27  	space = jsonfmt.WriteInt64(space, int64(header.len))
    28  	space = append(space, `,"cap":`...)
    29  	space = jsonfmt.WriteInt64(space, int64(header.cap))
    30  	space = append(space, `}`...)
    31  	data := encoder.encodeData(ctx, nil, ptr)
    32  	if uintptr(header.data) != 0 {
    33  		addrMap := ctx.Value(addrMapKey).(map[string]json.RawMessage)
    34  		addrMap[ptrStr] = json.RawMessage(data)
    35  	}
    36  	return space
    37  }
    38  
    39  func (encoder *sliceEncoder) encodeData(ctx context.Context, space []byte, ptr unsafe.Pointer) []byte {
    40  	slice := (*sliceHeader)(ptr)
    41  	space = append(space, '[')
    42  	offset := uintptr(slice.data)
    43  	for i := 0; i < slice.len; i++ {
    44  		if i != 0 {
    45  			space = append(space, ',')
    46  		}
    47  		space = encoder.elemEncoder.Encode(ctx, space, unsafe.Pointer(offset))
    48  		offset += encoder.elemSize
    49  	}
    50  	space = append(space, ']')
    51  	return space
    52  }