Added AppendAny

This commit is contained in:
tidwall 2020-03-03 14:16:44 -07:00
parent 72acf6b980
commit a389b6ca04
2 changed files with 108 additions and 0 deletions

100
append.go
View File

@ -1,6 +1,9 @@
package redcon
import (
"fmt"
"reflect"
"sort"
"strconv"
"strings"
)
@ -348,3 +351,100 @@ func AppendBulkUint(b []byte, x uint64) []byte {
b = b[:mark1+(mark3-mark2)]
return b
}
// AppendAny appends any type to valid Redis type
func AppendAny(b []byte, v interface{}) []byte {
switch v := v.(type) {
case nil:
b = AppendNull(b)
case error:
b = AppendError(b, "ERR "+v.Error())
case string:
b = AppendBulkString(b, v)
case []byte:
b = AppendBulk(b, v)
case bool:
if v {
b = AppendInt(b, 1)
} else {
b = AppendInt(b, 0)
}
case int:
b = AppendInt(b, int64(v))
case int8:
b = AppendInt(b, int64(v))
case int16:
b = AppendInt(b, int64(v))
case int32:
b = AppendInt(b, int64(v))
case int64:
b = AppendInt(b, int64(v))
case uint:
b = AppendUint(b, uint64(v))
case uint8:
b = AppendUint(b, uint64(v))
case uint16:
b = AppendUint(b, uint64(v))
case uint32:
b = AppendUint(b, uint64(v))
case uint64:
b = AppendUint(b, uint64(v))
case float32:
b = AppendBulkFloat(b, float64(v))
case float64:
b = AppendBulkFloat(b, float64(v))
default:
vv := reflect.ValueOf(v)
switch vv.Kind() {
case reflect.Slice:
n := vv.Len()
b = AppendArray(b, n)
for i := 0; i < n; i++ {
b = AppendAny(b, vv.Index(i).Interface())
}
case reflect.Map:
n := vv.Len()
b = AppendArray(b, n*2)
var i int
var strKey bool
var strsKeyItems []strKeyItem
iter := vv.MapRange()
for iter.Next() {
key := iter.Key().Interface()
if i == 0 {
if _, ok := key.(string); ok {
strKey = true
strsKeyItems = make([]strKeyItem, n)
}
}
if strKey {
strsKeyItems[i] = strKeyItem{
key.(string), iter.Value().Interface(),
}
} else {
b = AppendAny(b, key)
b = AppendAny(b, iter.Value().Interface())
}
i++
}
if strKey {
sort.Slice(strsKeyItems, func(i, j int) bool {
return strsKeyItems[i].key < strsKeyItems[j].key
})
for _, item := range strsKeyItems {
b = AppendBulkString(b, item.key)
b = AppendAny(b, item.value)
}
}
default:
b = AppendBulkString(b, fmt.Sprint(v))
}
}
return b
}
type strKeyItem struct {
key string
value interface{}
}

View File

@ -60,6 +60,8 @@ type Conn interface {
WriteNull()
// WriteRaw writes raw data to the client.
WriteRaw(data []byte)
// WriteAny writes any type to the client.
WriteAny(any interface{})
// Context returns a user-defined context
Context() interface{}
// SetContext sets a user-defined context
@ -442,6 +444,7 @@ func (c *conn) WriteError(msg string) { c.wr.WriteError(msg) }
func (c *conn) WriteArray(count int) { c.wr.WriteArray(count) }
func (c *conn) WriteNull() { c.wr.WriteNull() }
func (c *conn) WriteRaw(data []byte) { c.wr.WriteRaw(data) }
func (c *conn) WriteAny(v interface{}) { c.wr.WriteAny(v) }
func (c *conn) RemoteAddr() string { return c.addr }
func (c *conn) ReadPipeline() []Command {
cmds := c.cmds
@ -633,6 +636,11 @@ func (w *Writer) WriteRaw(data []byte) {
w.b = append(w.b, data...)
}
// WriteAny writes any type to client.
func (w *Writer) WriteAny(v interface{}) {
w.b = AppendAny(w.b, v)
}
// Reader represent a reader for RESP or telnet commands.
type Reader struct {
rd *bufio.Reader