1
0
mirror of https://github.com/astaxie/beego.git synced 2024-12-24 13:10:50 +00:00
Beego/vendor/github.com/cupcake/rdb/encoder.go

131 lines
2.8 KiB
Go
Raw Normal View History

2018-11-09 04:37:28 +00:00
package rdb
import (
"encoding/binary"
"fmt"
"hash"
"io"
"math"
"strconv"
"github.com/cupcake/rdb/crc64"
)
const Version = 6
type Encoder struct {
w io.Writer
crc hash.Hash
}
func NewEncoder(w io.Writer) *Encoder {
e := &Encoder{crc: crc64.New()}
e.w = io.MultiWriter(w, e.crc)
return e
}
func (e *Encoder) EncodeHeader() error {
_, err := fmt.Fprintf(e.w, "REDIS%04d", Version)
return err
}
func (e *Encoder) EncodeFooter() error {
e.w.Write([]byte{rdbFlagEOF})
_, err := e.w.Write(e.crc.Sum(nil))
return err
}
func (e *Encoder) EncodeDumpFooter() error {
binary.Write(e.w, binary.LittleEndian, uint16(Version))
_, err := e.w.Write(e.crc.Sum(nil))
return err
}
func (e *Encoder) EncodeDatabase(n int) error {
e.w.Write([]byte{rdbFlagSelectDB})
return e.EncodeLength(uint32(n))
}
func (e *Encoder) EncodeExpiry(expiry uint64) error {
b := make([]byte, 9)
b[0] = rdbFlagExpiryMS
binary.LittleEndian.PutUint64(b[1:], expiry)
_, err := e.w.Write(b)
return err
}
func (e *Encoder) EncodeType(v ValueType) error {
_, err := e.w.Write([]byte{byte(v)})
return err
}
func (e *Encoder) EncodeString(s []byte) error {
written, err := e.encodeIntString(s)
if written {
return err
}
e.EncodeLength(uint32(len(s)))
_, err = e.w.Write(s)
return err
}
func (e *Encoder) EncodeLength(l uint32) (err error) {
switch {
case l < 1<<6:
_, err = e.w.Write([]byte{byte(l)})
case l < 1<<14:
_, err = e.w.Write([]byte{byte(l>>8) | rdb14bitLen<<6, byte(l)})
default:
b := make([]byte, 5)
b[0] = rdb32bitLen << 6
binary.BigEndian.PutUint32(b[1:], l)
_, err = e.w.Write(b)
}
return
}
func (e *Encoder) EncodeFloat(f float64) (err error) {
switch {
case math.IsNaN(f):
_, err = e.w.Write([]byte{253})
case math.IsInf(f, 1):
_, err = e.w.Write([]byte{254})
case math.IsInf(f, -1):
_, err = e.w.Write([]byte{255})
default:
b := []byte(strconv.FormatFloat(f, 'g', 17, 64))
e.w.Write([]byte{byte(len(b))})
_, err = e.w.Write(b)
}
return
}
func (e *Encoder) encodeIntString(b []byte) (written bool, err error) {
s := string(b)
i, err := strconv.ParseInt(s, 10, 32)
if err != nil {
return
}
// if the stringified parsed int isn't exactly the same, we can't encode it as an int
if s != strconv.FormatInt(i, 10) {
return
}
switch {
case i >= math.MinInt8 && i <= math.MaxInt8:
_, err = e.w.Write([]byte{rdbEncVal << 6, byte(int8(i))})
case i >= math.MinInt16 && i <= math.MaxInt16:
b := make([]byte, 3)
b[0] = rdbEncVal<<6 | rdbEncInt16
binary.LittleEndian.PutUint16(b[1:], uint16(int16(i)))
_, err = e.w.Write(b)
case i >= math.MinInt32 && i <= math.MaxInt32:
b := make([]byte, 5)
b[0] = rdbEncVal<<6 | rdbEncInt32
binary.LittleEndian.PutUint32(b[1:], uint32(int32(i)))
_, err = e.w.Write(b)
default:
return
}
return true, err
}