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 }