github.com/moreal/bencodex-go@v0.0.0-20231021172012-18277a477d15/internal/encoder/encoder.go (about)

     1  package encoder
     2  
     3  import (
     4  	"fmt"
     5  	"unsafe"
     6  
     7  	"github.com/moreal/bencodex-go/internal"
     8  )
     9  
    10  //go:linkname memmove runtime.memmove
    11  //go:noescape
    12  func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
    13  
    14  type sliceHeader struct {
    15  	data unsafe.Pointer
    16  	len  int
    17  	cap  int
    18  }
    19  
    20  type Encoder struct {
    21  	buffer []byte
    22  	length int
    23  	offset int
    24  }
    25  
    26  //go:nosplit
    27  func (e *Encoder) grow(neededLength int) {
    28  	availableLength := e.length - e.offset
    29  	if availableLength >= neededLength {
    30  		return
    31  	}
    32  	if e.length == 0 {
    33  		if neededLength < 16 {
    34  			neededLength = 16
    35  		}
    36  		e.length = neededLength
    37  		availableLength = neededLength
    38  	} else {
    39  		for availableLength < neededLength {
    40  			e.length += e.length
    41  			availableLength = e.length - e.offset
    42  		}
    43  	}
    44  	buffer := make([]byte, e.length)
    45  	memmove(
    46  		unsafe.Pointer(uintptr((*sliceHeader)(unsafe.Pointer(&buffer)).data)),
    47  		(*sliceHeader)(unsafe.Pointer(&e.buffer)).data,
    48  		uintptr(e.offset),
    49  	)
    50  	e.buffer = buffer
    51  }
    52  
    53  //go:nosplit
    54  func (e *Encoder) write(data []byte) {
    55  	length := len(data)
    56  	memmove(
    57  		unsafe.Pointer(uintptr((*sliceHeader)(unsafe.Pointer(&e.buffer)).data)+uintptr(e.offset)),
    58  		(*sliceHeader)(unsafe.Pointer(&data)).data,
    59  		uintptr(length),
    60  	)
    61  	e.offset += length
    62  }
    63  
    64  //go:nosplit
    65  func (e *Encoder) writeByte(data byte) {
    66  	*(*byte)(unsafe.Pointer(uintptr((*sliceHeader)(unsafe.Pointer(&e.buffer)).data) + uintptr(e.offset))) = data
    67  	e.offset++
    68  }
    69  
    70  func (e *Encoder) EncodeTo(dst []byte, data interface{}) ([]byte, error) {
    71  	if cap(dst) > len(dst) {
    72  		dst = dst[:cap(dst)]
    73  	} else if len(dst) == 0 {
    74  		dst = make([]byte, 512)
    75  	}
    76  	e.buffer = dst
    77  	e.length = cap(dst)
    78  	err := e.encode(data)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	return e.buffer[:e.offset], nil
    83  }
    84  
    85  func (e *Encoder) encode(data interface{}) error {
    86  	switch value := data.(type) {
    87  	case int64:
    88  		e.encodeInt(value)
    89  	case int32:
    90  		e.encodeInt(int64(value))
    91  	case int16:
    92  		e.encodeInt(int64(value))
    93  	case int8:
    94  		e.encodeInt(int64(value))
    95  	case int:
    96  		e.encodeInt(int64(value))
    97  	case uint64:
    98  		e.encodeInt(int64(value))
    99  	case uint32:
   100  		e.encodeInt(int64(value))
   101  	case uint16:
   102  		e.encodeInt(int64(value))
   103  	case uint8:
   104  		e.encodeInt(int64(value))
   105  	case uint:
   106  		e.encodeInt(int64(value))
   107  	case []byte:
   108  		e.encodeBytesLike(internal.NewBytes(value))
   109  	case string:
   110  		e.encodeBytesLike(internal.NewString(value))
   111  	case internal.BencodexBytesLike:
   112  		e.encodeBytesLike(value)
   113  	case []interface{}:
   114  		return e.encodeList(value)
   115  	case map[internal.BencodexBytesLike]interface{}:
   116  		return e.encodeDictionary(value)
   117  	default:
   118  		return fmt.Errorf("bencode: unsupported type: %T", value)
   119  	}
   120  	return nil
   121  }