From 8d00139051e8365485dd095b3d4d9ce1d7fe2b41 Mon Sep 17 00:00:00 2001 From: Chyroc Date: Mon, 27 Aug 2018 12:22:58 +0800 Subject: [PATCH] add resp3 protocol part 2(double and big number) --- internal/protcl/errors.go | 19 +++++++++++++++++++ internal/protcl/resp3.go | 27 +++++++++++++++++++++++++++ internal/protcl/resp3_test.go | 13 +++++++++++++ 3 files changed, 59 insertions(+) diff --git a/internal/protcl/errors.go b/internal/protcl/errors.go index ab575b0..d0cf091 100644 --- a/internal/protcl/errors.go +++ b/internal/protcl/errors.go @@ -129,3 +129,22 @@ func (e *ErrUnexpectString) Recoverable() bool { func (e *ErrUnexpectString) Error() string { return fmt.Sprintf("unexpect string: %s", e.Str) } + +// ErrConvertType is for convert value to another type fail +type ErrConvertType struct { + Type string + Err error + Value interface{} +} + +// Recoverable whether error is recoverable or not +func (e *ErrConvertType) Recoverable() bool { + return true +} + +func (e *ErrConvertType) Error() string { + if e.Err == nil { + return fmt.Sprintf("convert %v to %s fail", e.Value, e.Type) + } + return fmt.Sprintf("convert %v to %s fail, because of %s", e.Value, e.Type, e.Err) +} diff --git a/internal/protcl/resp3.go b/internal/protcl/resp3.go index 9384ca5..4d08a1c 100644 --- a/internal/protcl/resp3.go +++ b/internal/protcl/resp3.go @@ -3,6 +3,7 @@ package protcl import ( "bufio" "fmt" + "math/big" "strconv" ) @@ -32,6 +33,8 @@ type Resp3 struct { Str string Integer int Boolean bool + Double float64 + BigInt *big.Int } func (r *Resp3) String() string { @@ -42,6 +45,10 @@ func (r *Resp3) String() string { return "(error) " + r.Str case Resp3Number: return "(integer) " + strconv.Itoa(r.Integer) + case Resp3Double: + return "(double) " + strconv.FormatFloat(r.Double, 'f', -1, 64) + case Resp3BigNumber: + return "(big number) " + r.BigInt.String() case Resp3Null: return "(null)" case Resp3Boolean: @@ -96,6 +103,26 @@ func (r *Resp3Parser) Parse() (*Resp3, error) { return nil, err } return &Resp3{Type: b, Integer: integer}, nil + case Resp3Double: + str, err := r.stringBeforeLF() + if err != nil { + return nil, err + } + f, err := strconv.ParseFloat(str, 64) + if err != nil { + return nil, &ErrConvertType{Type: "double", Value: str, Err: err} + } + return &Resp3{Type: b, Double: f}, nil + case Resp3BigNumber: + str, err := r.stringBeforeLF() + if err != nil { + return nil, err + } + bigInt, ok := big.NewInt(0).SetString(str, 10) + if !ok { + return nil, &ErrConvertType{Type: "Big Number", Value: str} + } + return &Resp3{Type: b, BigInt: bigInt}, nil case Resp3Null: if _, err := r.readLengthBytesWithLF(0); err != nil { return nil, err diff --git a/internal/protcl/resp3_test.go b/internal/protcl/resp3_test.go index 71c3816..b8fd7d9 100644 --- a/internal/protcl/resp3_test.go +++ b/internal/protcl/resp3_test.go @@ -51,6 +51,19 @@ func TestResp3Parser(t *testing.T) { testResp3Parser(t, ":0\n", `(integer) 0`) testResp3Parser(t, ":100\n", `(integer) 100`) + // double + testResp3Parser(t, ",-1\n", `(double) -1`) + testResp3Parser(t, ",0\n", `(double) 0`) + testResp3Parser(t, ",10\n", `(double) 10`) + testResp3Parser(t, ",.1\n", `(double) 0.1`) + testResp3Parser(t, ",1.23\n", `(double) 1.23`) + testResp3Parser(t, ",1.\n", `(double) 1`) + testResp3Error(t, ",invalid\n", `convert invalid to double fail, because of strconv.ParseFloat: parsing "invalid": invalid syntax`) + + // big number + testResp3Parser(t, "(3492890328409238509324850943850943825024385\n", `(big number) 3492890328409238509324850943850943825024385`) + testResp3Error(t, "(invalid string\n", `convert invalid string to Big Number fail`) + // null testResp3Parser(t, "_\n", "(null)")