Go API Documentation

github.com/redis/go-redis/v9/internal/proto

No package summary is available.

Package

Files: 3. Third party imports: 0. Imports from organisation: 0. Tests: 0. Benchmarks: 0.

Constants

const Nil = RedisError("redis: nil")	// nolint:errname
// redis resp protocol data type.
const (
	RespStatus	= '+'	// +<string>\r\n
	RespError	= '-'	// -<string>\r\n
	RespString	= '$'	// $<length>\r\n<bytes>\r\n
	RespInt		= ':'	// :<number>\r\n
	RespNil		= '_'	// _\r\n
	RespFloat	= ','	// ,<floating-point-number>\r\n (golang float)
	RespBool	= '#'	// true: #t\r\n false: #f\r\n
	RespBlobError	= '!'	// !<length>\r\n<bytes>\r\n
	RespVerbatim	= '='	// =<length>\r\nFORMAT:<bytes>\r\n
	RespBigInt	= '('	// (<big number>\r\n
	RespArray	= '*'	// *<len>\r\n... (same as resp2)
	RespMap		= '%'	// %<len>\r\n(key)\r\n(value)\r\n... (golang map)
	RespSet		= '~'	// ~<len>\r\n... (same as Array)
	RespAttr	= '|'	// |<len>\r\n(key)\r\n(value)\r\n... + command reply
	RespPush	= '>'	// ><len>\r\n... (same as Array)
)

Types

Reader

This type doesn't have documentation.

type Reader struct {
	rd *bufio.Reader
}

RedisError

This type doesn't have documentation.

type RedisError string

Writer

This type doesn't have documentation.

type Writer struct {
	writer

	lenBuf	[]byte
	numBuf	[]byte
}

writer

This type doesn't have documentation.

type writer interface {
	io.Writer
	io.ByteWriter
	// WriteString implement io.StringWriter.
	WriteString(s string) (n int, err error)
}

Functions

func IsNilReply

IsNilReply detects redis.Nil of RESP2.

func IsNilReply(line []byte) bool {
	return len(line) == 3 &&
		(line[0] == RespString || line[0] == RespArray) &&
		line[1] == '-' && line[2] == '1'
}

Cognitive complexity: 0, Cyclomatic complexity: 5

func NewReader

func NewReader(rd io.Reader) *Reader {
	return &Reader{
		rd: bufio.NewReader(rd),
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

Uses: bufio.NewReader.

func NewWriter

func NewWriter(wr writer) *Writer {
	return &Writer{
		writer:	wr,

		lenBuf:	make([]byte, 64),
		numBuf:	make([]byte, 64),
	}
}

Cognitive complexity: 1, Cyclomatic complexity: 1

func ParseErrorReply

func ParseErrorReply(line []byte) error {
	return RedisError(line[1:])
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func Scan

Scan parses bytes b to v with appropriate type.

func Scan(b []byte, v interface{}) error {
	switch v := v.(type) {
	case nil:
		return fmt.Errorf("redis: Scan(nil)")
	case *string:
		*v = util.BytesToString(b)
		return nil
	case *[]byte:
		*v = b
		return nil
	case *int:
		var err error
		*v, err = util.Atoi(b)
		return err
	case *int8:
		n, err := util.ParseInt(b, 10, 8)
		if err != nil {
			return err
		}
		*v = int8(n)
		return nil
	case *int16:
		n, err := util.ParseInt(b, 10, 16)
		if err != nil {
			return err
		}
		*v = int16(n)
		return nil
	case *int32:
		n, err := util.ParseInt(b, 10, 32)
		if err != nil {
			return err
		}
		*v = int32(n)
		return nil
	case *int64:
		n, err := util.ParseInt(b, 10, 64)
		if err != nil {
			return err
		}
		*v = n
		return nil
	case *uint:
		n, err := util.ParseUint(b, 10, 64)
		if err != nil {
			return err
		}
		*v = uint(n)
		return nil
	case *uint8:
		n, err := util.ParseUint(b, 10, 8)
		if err != nil {
			return err
		}
		*v = uint8(n)
		return nil
	case *uint16:
		n, err := util.ParseUint(b, 10, 16)
		if err != nil {
			return err
		}
		*v = uint16(n)
		return nil
	case *uint32:
		n, err := util.ParseUint(b, 10, 32)
		if err != nil {
			return err
		}
		*v = uint32(n)
		return nil
	case *uint64:
		n, err := util.ParseUint(b, 10, 64)
		if err != nil {
			return err
		}
		*v = n
		return nil
	case *float32:
		n, err := util.ParseFloat(b, 32)
		if err != nil {
			return err
		}
		*v = float32(n)
		return err
	case *float64:
		var err error
		*v, err = util.ParseFloat(b, 64)
		return err
	case *bool:
		*v = len(b) == 1 && b[0] == '1'
		return nil
	case *time.Time:
		var err error
		*v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
		return err
	case *time.Duration:
		n, err := util.ParseInt(b, 10, 64)
		if err != nil {
			return err
		}
		*v = time.Duration(n)
		return nil
	case encoding.BinaryUnmarshaler:
		return v.UnmarshalBinary(b)
	case *net.IP:
		*v = b
		return nil
	default:
		return fmt.Errorf(
			"redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
	}
}

Cognitive complexity: 45, Cyclomatic complexity: 34

Uses: encoding.BinaryUnmarshaler, fmt.Errorf, net.IP, time.Duration, time.Parse, time.RFC3339Nano, time.Time, util.Atoi, util.BytesToString, util.ParseFloat, util.ParseInt, util.ParseUint.

func ScanSlice

func ScanSlice(data []string, slice interface{}) error {
	v := reflect.ValueOf(slice)
	if !v.IsValid() {
		return fmt.Errorf("redis: ScanSlice(nil)")
	}
	if v.Kind() != reflect.Ptr {
		return fmt.Errorf("redis: ScanSlice(non-pointer %T)", slice)
	}
	v = v.Elem()
	if v.Kind() != reflect.Slice {
		return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
	}

	next := makeSliceNextElemFunc(v)
	for i, s := range data {
		elem := next()
		if err := Scan([]byte(s), elem.Addr().Interface()); err != nil {
			err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %w", i, s, err)
			return err
		}
	}

	return nil
}

Cognitive complexity: 12, Cyclomatic complexity: 6

Uses: fmt.Errorf, reflect.Ptr, reflect.Slice, reflect.ValueOf.

func (*Reader) Buffered

func (r *Reader) Buffered() int {
	return r.rd.Buffered()
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Reader) Discard

Discard the data represented by line.

func (r *Reader) Discard(line []byte) (err error) {
	if len(line) == 0 {
		return errors.New("redis: invalid line")
	}
	switch line[0] {
	case RespStatus, RespError, RespInt, RespNil, RespFloat, RespBool, RespBigInt:
		return nil
	}

	n, err := replyLen(line)
	if err != nil && err != Nil {
		return err
	}

	switch line[0] {
	case RespBlobError, RespString, RespVerbatim:
		// +\r\n
		_, err = r.rd.Discard(n + 2)
		return err
	case RespArray, RespSet, RespPush:
		for i := 0; i < n; i++ {
			if err = r.DiscardNext(); err != nil {
				return err
			}
		}
		return nil
	case RespMap, RespAttr:
		// Read key & value.
		for i := 0; i < n*2; i++ {
			if err = r.DiscardNext(); err != nil {
				return err
			}
		}
		return nil
	}

	return fmt.Errorf("redis: can't parse %.100q", line)
}

Cognitive complexity: 20, Cyclomatic complexity: 14

Uses: errors.New, fmt.Errorf.

func (*Reader) DiscardNext

DiscardNext read and discard the data represented by the next line.

func (r *Reader) DiscardNext() error {
	line, err := r.readLine()
	if err != nil {
		return err
	}
	return r.Discard(line)
}

Cognitive complexity: 2, Cyclomatic complexity: 2

func (*Reader) Peek

func (r *Reader) Peek(n int) ([]byte, error) {
	return r.rd.Peek(n)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Reader) PeekReplyType

PeekReplyType returns the data type of the next response without advancing the Reader, and discard the attribute type.

func (r *Reader) PeekReplyType() (byte, error) {
	b, err := r.rd.Peek(1)
	if err != nil {
		return 0, err
	}
	if b[0] == RespAttr {
		if err = r.DiscardNext(); err != nil {
			return 0, err
		}
		return r.PeekReplyType()
	}
	return b[0], nil
}

Cognitive complexity: 6, Cyclomatic complexity: 4

func (*Reader) ReadArrayLen

ReadArrayLen Read and return the length of the array.

func (r *Reader) ReadArrayLen() (int, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespArray, RespSet, RespPush:
		return replyLen(line)
	default:
		return 0, fmt.Errorf("redis: can't parse array/set/push reply: %.100q", line)
	}
}

Cognitive complexity: 5, Cyclomatic complexity: 4

Uses: fmt.Errorf.

func (*Reader) ReadBool

func (r *Reader) ReadBool() (bool, error) {
	s, err := r.ReadString()
	if err != nil {
		return false, err
	}
	return s == "OK" || s == "1" || s == "true", nil
}

Cognitive complexity: 2, Cyclomatic complexity: 4

func (*Reader) ReadFixedArrayLen

ReadFixedArrayLen read fixed array length.

func (r *Reader) ReadFixedArrayLen(fixedLen int) error {
	n, err := r.ReadArrayLen()
	if err != nil {
		return err
	}
	if n != fixedLen {
		return fmt.Errorf("redis: got %d elements in the array, wanted %d", n, fixedLen)
	}
	return nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: fmt.Errorf.

func (*Reader) ReadFixedMapLen

ReadFixedMapLen reads fixed map length.

func (r *Reader) ReadFixedMapLen(fixedLen int) error {
	n, err := r.ReadMapLen()
	if err != nil {
		return err
	}
	if n != fixedLen {
		return fmt.Errorf("redis: got %d elements in the map, wanted %d", n, fixedLen)
	}
	return nil
}

Cognitive complexity: 4, Cyclomatic complexity: 3

Uses: fmt.Errorf.

func (*Reader) ReadFloat

func (r *Reader) ReadFloat() (float64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespFloat:
		return r.readFloat(line)
	case RespStatus:
		return strconv.ParseFloat(string(line[1:]), 64)
	case RespString:
		s, err := r.readStringReply(line)
		if err != nil {
			return 0, err
		}
		return strconv.ParseFloat(s, 64)
	}
	return 0, fmt.Errorf("redis: can't parse float reply: %.100q", line)
}

Cognitive complexity: 9, Cyclomatic complexity: 7

Uses: fmt.Errorf, strconv.ParseFloat.

func (*Reader) ReadInt

func (r *Reader) ReadInt() (int64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespInt, RespStatus:
		return util.ParseInt(line[1:], 10, 64)
	case RespString:
		s, err := r.readStringReply(line)
		if err != nil {
			return 0, err
		}
		return util.ParseInt([]byte(s), 10, 64)
	case RespBigInt:
		b, err := r.readBigInt(line)
		if err != nil {
			return 0, err
		}
		if !b.IsInt64() {
			return 0, fmt.Errorf("bigInt(%s) value out of range", b.String())
		}
		return b.Int64(), nil
	}
	return 0, fmt.Errorf("redis: can't parse int reply: %.100q", line)
}

Cognitive complexity: 13, Cyclomatic complexity: 9

Uses: fmt.Errorf, util.ParseInt.

func (*Reader) ReadLine

ReadLine Return a valid reply, it will check the protocol or redis error, and discard the attribute type.

func (r *Reader) ReadLine() ([]byte, error) {
	line, err := r.readLine()
	if err != nil {
		return nil, err
	}
	switch line[0] {
	case RespError:
		return nil, ParseErrorReply(line)
	case RespNil:
		return nil, Nil
	case RespBlobError:
		var blobErr string
		blobErr, err = r.readStringReply(line)
		if err == nil {
			err = RedisError(blobErr)
		}
		return nil, err
	case RespAttr:
		if err = r.Discard(line); err != nil {
			return nil, err
		}
		return r.ReadLine()
	}

	// Compatible with RESP2
	if IsNilReply(line) {
		return nil, Nil
	}

	return line, nil
}

Cognitive complexity: 14, Cyclomatic complexity: 10

func (*Reader) ReadMapLen

ReadMapLen reads the length of the map type. If responding to the array type (RespArray/RespSet/RespPush), it must be a multiple of 2 and return n/2. Other types will return an error.

func (r *Reader) ReadMapLen() (int, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespMap:
		return replyLen(line)
	case RespArray, RespSet, RespPush:
		// Some commands and RESP2 protocol may respond to array types.
		n, err := replyLen(line)
		if err != nil {
			return 0, err
		}
		if n%2 != 0 {
			return 0, fmt.Errorf("redis: the length of the array must be a multiple of 2, got: %d", n)
		}
		return n / 2, nil
	default:
		return 0, fmt.Errorf("redis: can't parse map reply: %.100q", line)
	}
}

Cognitive complexity: 10, Cyclomatic complexity: 7

Uses: fmt.Errorf.

func (*Reader) ReadReply

func (r *Reader) ReadReply() (interface{}, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}

	switch line[0] {
	case RespStatus:
		return string(line[1:]), nil
	case RespInt:
		return util.ParseInt(line[1:], 10, 64)
	case RespFloat:
		return r.readFloat(line)
	case RespBool:
		return r.readBool(line)
	case RespBigInt:
		return r.readBigInt(line)

	case RespString:
		return r.readStringReply(line)
	case RespVerbatim:
		return r.readVerb(line)

	case RespArray, RespSet, RespPush:
		return r.readSlice(line)
	case RespMap:
		return r.readMap(line)
	}
	return nil, fmt.Errorf("redis: can't parse %.100q", line)
}

Cognitive complexity: 14, Cyclomatic complexity: 12

Uses: fmt.Errorf, util.ParseInt.

func (*Reader) ReadSlice

func (r *Reader) ReadSlice() ([]interface{}, error) {
	line, err := r.ReadLine()
	if err != nil {
		return nil, err
	}
	return r.readSlice(line)
}

Cognitive complexity: 3, Cyclomatic complexity: 2

func (*Reader) ReadString

func (r *Reader) ReadString() (string, error) {
	line, err := r.ReadLine()
	if err != nil {
		return "", err
	}

	switch line[0] {
	case RespStatus, RespInt, RespFloat:
		return string(line[1:]), nil
	case RespString:
		return r.readStringReply(line)
	case RespBool:
		b, err := r.readBool(line)
		return strconv.FormatBool(b), err
	case RespVerbatim:
		return r.readVerb(line)
	case RespBigInt:
		b, err := r.readBigInt(line)
		if err != nil {
			return "", err
		}
		return b.String(), nil
	}
	return "", fmt.Errorf("redis: can't parse reply=%.100q reading string", line)
}

Cognitive complexity: 11, Cyclomatic complexity: 9

Uses: fmt.Errorf, strconv.FormatBool.

func (*Reader) ReadUint

func (r *Reader) ReadUint() (uint64, error) {
	line, err := r.ReadLine()
	if err != nil {
		return 0, err
	}
	switch line[0] {
	case RespInt, RespStatus:
		return util.ParseUint(line[1:], 10, 64)
	case RespString:
		s, err := r.readStringReply(line)
		if err != nil {
			return 0, err
		}
		return util.ParseUint([]byte(s), 10, 64)
	case RespBigInt:
		b, err := r.readBigInt(line)
		if err != nil {
			return 0, err
		}
		if !b.IsUint64() {
			return 0, fmt.Errorf("bigInt(%s) value out of range", b.String())
		}
		return b.Uint64(), nil
	}
	return 0, fmt.Errorf("redis: can't parse uint reply: %.100q", line)
}

Cognitive complexity: 13, Cyclomatic complexity: 9

Uses: fmt.Errorf, util.ParseUint.

func (*Reader) Reset

func (r *Reader) Reset(rd io.Reader) {
	r.rd.Reset(rd)
}

Cognitive complexity: 0, Cyclomatic complexity: 1

func (*Writer) WriteArg

func (w *Writer) WriteArg(v interface{}) error {
	switch v := v.(type) {
	case nil:
		return w.string("")
	case string:
		return w.string(v)
	case *string:
		return w.string(*v)
	case []byte:
		return w.bytes(v)
	case int:
		return w.int(int64(v))
	case *int:
		return w.int(int64(*v))
	case int8:
		return w.int(int64(v))
	case *int8:
		return w.int(int64(*v))
	case int16:
		return w.int(int64(v))
	case *int16:
		return w.int(int64(*v))
	case int32:
		return w.int(int64(v))
	case *int32:
		return w.int(int64(*v))
	case int64:
		return w.int(v)
	case *int64:
		return w.int(*v)
	case uint:
		return w.uint(uint64(v))
	case *uint:
		return w.uint(uint64(*v))
	case uint8:
		return w.uint(uint64(v))
	case *uint8:
		return w.uint(uint64(*v))
	case uint16:
		return w.uint(uint64(v))
	case *uint16:
		return w.uint(uint64(*v))
	case uint32:
		return w.uint(uint64(v))
	case *uint32:
		return w.uint(uint64(*v))
	case uint64:
		return w.uint(v)
	case *uint64:
		return w.uint(*v)
	case float32:
		return w.float(float64(v))
	case *float32:
		return w.float(float64(*v))
	case float64:
		return w.float(v)
	case *float64:
		return w.float(*v)
	case bool:
		if v {
			return w.int(1)
		}
		return w.int(0)
	case *bool:
		if *v {
			return w.int(1)
		}
		return w.int(0)
	case time.Time:
		w.numBuf = v.AppendFormat(w.numBuf[:0], time.RFC3339Nano)
		return w.bytes(w.numBuf)
	case time.Duration:
		return w.int(v.Nanoseconds())
	case encoding.BinaryMarshaler:
		b, err := v.MarshalBinary()
		if err != nil {
			return err
		}
		return w.bytes(b)
	case net.IP:
		return w.bytes(v)
	default:
		return fmt.Errorf(
			"redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
	}
}

Cognitive complexity: 43, Cyclomatic complexity: 39

Uses: encoding.BinaryMarshaler, fmt.Errorf, net.IP, time.Duration, time.RFC3339Nano, time.Time.

func (*Writer) WriteArgs

func (w *Writer) WriteArgs(args []interface{}) error {
	if err := w.WriteByte(RespArray); err != nil {
		return err
	}

	if err := w.writeLen(len(args)); err != nil {
		return err
	}

	for _, arg := range args {
		if err := w.WriteArg(arg); err != nil {
			return err
		}
	}

	return nil
}

Cognitive complexity: 10, Cyclomatic complexity: 5

func (RedisError) Error

func (e RedisError) Error() string	{ return string(e) }

Cognitive complexity: 0, Cyclomatic complexity: 1

func (RedisError) RedisError

func (RedisError) RedisError()	{}

Cognitive complexity: 0, Cyclomatic complexity: 1

Private functions

func makeSliceNextElemFunc

makeSliceNextElemFunc (v reflect.Value) func() reflect.Value
References: reflect.Append, reflect.New, reflect.Ptr, reflect.Value, reflect.Zero.

func replyLen

replyLen (line []byte) (int, error)
References: fmt.Errorf, util.Atoi.

func readBigInt

readBigInt (line []byte) (*big.Int, error)
References: big.Int, fmt.Errorf.

func readBool

readBool (line []byte) (bool, error)
References: fmt.Errorf.

func readFloat

readFloat (line []byte) (float64, error)
References: math.Inf, math.NaN, strconv.ParseFloat.

func readLine

readLine returns an error if:

  • there is a pending read error;
  • or line does not end with \r\n.

readLine () ([]byte, error)
References: bufio.ErrBufferFull, fmt.Errorf.

func readMap

readMap (line []byte) (map[interface{}]interface{}, error)

func readSlice

readSlice (line []byte) ([]interface{}, error)

func readStringReply

readStringReply (line []byte) (string, error)
References: io.ReadFull, util.BytesToString.

func readVerb

readVerb (line []byte) (string, error)
References: fmt.Errorf.

func bytes

bytes (b []byte) error

func crlf

crlf () error

func float

float (f float64) error
References: strconv.AppendFloat.

func int

int (n int64) error
References: strconv.AppendInt.

func string

string (s string) error
References: util.StringToBytes.

func uint

uint (n uint64) error
References: strconv.AppendUint.

func writeLen

writeLen (n int) error
References: strconv.AppendUint.


Tests

Files: 4. Third party imports: 2. Imports from organisation: 0. Tests: 2. Benchmarks: 16.

Vars

var _ = Describe("ScanSlice", func() {
	data := []string{
		`{"ID":-1,"Name":"Back Yu"}`,
		`{"ID":1,"Name":"szyhf"}`,
	}

	It("[]testScanSliceStruct", func() {
		var slice []testScanSliceStruct
		err := proto.ScanSlice(data, &slice)
		Expect(err).NotTo(HaveOccurred())
		Expect(slice).To(Equal([]testScanSliceStruct{
			{-1, "Back Yu"},
			{1, "szyhf"},
		}))
	})

	It("var testContainer []*testScanSliceStruct", func() {
		var slice []*testScanSliceStruct
		err := proto.ScanSlice(data, &slice)
		Expect(err).NotTo(HaveOccurred())
		Expect(slice).To(Equal([]*testScanSliceStruct{
			{-1, "Back Yu"},
			{1, "szyhf"},
		}))
	})
})
var buf *bytes.Buffer
var slice []testScanSliceStruct
var wr *proto.Writer

Types

MyType

This type doesn't have documentation.

type MyType struct{}

discard

This type doesn't have documentation.

type discard struct{}

testScanSliceStruct

This type doesn't have documentation.

type testScanSliceStruct struct {
	ID	int
	Name	string
}

Test functions

TestGinkgoSuite

TestReader_ReadLine

References: bytes.Equal, bytes.NewReader, bytes.Repeat, io.EOF, proto.NewReader.

Benchmark functions

BenchmarkReader_ParseReply_Attr

BenchmarkReader_ParseReply_BigInt

BenchmarkReader_ParseReply_BlobError

BenchmarkReader_ParseReply_Bool

BenchmarkReader_ParseReply_Error

BenchmarkReader_ParseReply_Float

BenchmarkReader_ParseReply_Int

BenchmarkReader_ParseReply_Map

BenchmarkReader_ParseReply_Nil

BenchmarkReader_ParseReply_Push

BenchmarkReader_ParseReply_Set

BenchmarkReader_ParseReply_Slice

BenchmarkReader_ParseReply_Status

BenchmarkReader_ParseReply_String

BenchmarkReader_ParseReply_Verb

BenchmarkWriteBuffer_Append

References: proto.NewWriter.