2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

feat:(ast) Add more strict casting API (#249)

* feat:(ast) Add more strict API

* test: add cast test
This commit is contained in:
Yi Duan 2022-06-28 13:27:07 +08:00 committed by GitHub
parent f8fb04a184
commit 2e751bf5db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 128 additions and 8 deletions

View file

@ -85,7 +85,7 @@ func TestEncodeValue(t *testing.T) {
{NewBool(false), "false", false},
{NewNumber("0.0"), "0.0", false},
{NewString(""), `""`, false},
{NewString("\"\""), `"\"\""`, false},
{NewString(`\"\"`), `"\\\"\\\""`, false},
{NewString(_TwitterJson), string(quote), false},
{NewArray([]Node{}), "[]", false},
{NewArray([]Node{NewBool(true), NewString("true"), NewString("\t")}), `[true,"true","\t"]`, false},

View file

@ -165,7 +165,7 @@ func (self *Node) checkRaw() error {
return nil
}
// Bool_E returns bool value represented by this node
// Bool returns bool value represented by this node
//
// If node type is not types.V_TRUE or types.V_FALSE,
// V_RAW (must be a bool json value), or V_ANY (must be a bool type)
@ -187,7 +187,7 @@ func (self *Node) Bool() (bool, error) {
}
}
// Int64 as above.
// Int64 casts the node to int64 value, including V_NUMBER, V_TRUE, V_FALSE, V_ANY
func (self *Node) Int64() (int64, error) {
if err := self.checkRaw(); err != nil {
return 0, err
@ -215,7 +215,33 @@ func (self *Node) Int64() (int64, error) {
}
}
// Number as above.
// StrictInt64 exports underlying int64 value, including V_NUMBER, V_ANY
func (self *Node) StrictInt64() (int64, error) {
if err := self.checkRaw(); err != nil {
return 0, err
}
switch self.t {
case _V_NUMBER : return numberToInt64(self)
case _V_ANY :
any := self.packAny()
switch v := any.(type) {
case int : return int64(v), nil
case int8 : return int64(v), nil
case int16 : return int64(v), nil
case int32 : return int64(v), nil
case int64 : return int64(v), nil
case uint : return int64(v), nil
case uint8 : return int64(v), nil
case uint16: return int64(v), nil
case uint32: return int64(v), nil
case uint64: return int64(v), nil
default: return 0, ErrUnsupportType
}
default : return 0, ErrUnsupportType
}
}
// Number casts node to float64, including V_NUMBER, V_TRUE, V_FALSE, V_ANY of json.Number
func (self *Node) Number() (json.Number, error) {
if err := self.checkRaw(); err != nil {
return json.Number(""), err
@ -234,6 +260,23 @@ func (self *Node) Number() (json.Number, error) {
}
}
// Number exports underlying float64 value, including V_NUMBER, V_ANY of json.Number
func (self *Node) StrictNumber() (json.Number, error) {
if err := self.checkRaw(); err != nil {
return json.Number(""), err
}
switch self.t {
case _V_NUMBER : return toNumber(self) , nil
case _V_ANY :
if v, ok := self.packAny().(json.Number); ok {
return v, nil
} else {
return json.Number(""), ErrUnsupportType
}
default : return json.Number(""), ErrUnsupportType
}
}
// String returns raw string value if node type is V_STRING.
// Or return the string representation of other types:
// V_NULL => "null",
@ -261,7 +304,26 @@ func (self *Node) String() (string, error) {
}
}
// Float64 as above.
// StrictString returns string value (unescaped), includeing V_STRING, V_ANY of string.
// In other cases, it will return empty string.
func (self *Node) StrictString() (string, error) {
if err := self.checkRaw(); err != nil {
return "", err
}
switch self.t {
case types.V_NULL : return "", nil
case types.V_STRING : return addr2str(self.p, self.v), nil
case _V_ANY :
if v, ok := self.packAny().(string); ok {
return v, nil
} else {
return "", ErrUnsupportType
}
default : return "", ErrUnsupportType
}
}
// Float64 casts node to float64, includeing V_NUMBER, V_TRUE, V_FALSE, V_ANY
func (self *Node) Float64() (float64, error) {
if err := self.checkRaw(); err != nil {
return 0.0, err
@ -281,6 +343,24 @@ func (self *Node) Float64() (float64, error) {
}
}
// Float64 exports underlying float64 value, includeing V_NUMBER, V_ANY
func (self *Node) StrictFloat64() (float64, error) {
if err := self.checkRaw(); err != nil {
return 0.0, err
}
switch self.t {
case _V_NUMBER : return numberToFloat64(self)
case _V_ANY :
any := self.packAny()
switch v := any.(type) {
case float32 : return float64(v), nil
case float64 : return float64(v), nil
default : return 0, ErrUnsupportType
}
default : return 0.0, ErrUnsupportType
}
}
/** Sequencial Value Methods **/
// Len returns children count of a array|object|string node
@ -1410,7 +1490,10 @@ func newBytes(v []byte) Node {
}
}
// NewString creates a node of type string
// NewString creates a node of type V_STRING.
// v is considered to be a valid UTF-8 string,
// which means it won't be validated and unescaped.
// when the node is encoded to json, v will be escaped.
func NewString(v string) Node {
return Node{
t: types.V_STRING,

View file

@ -280,6 +280,8 @@ func TestTypeCast(t *testing.T) {
{"Bool", NewAny(false), false, nil},
{"Bool", NewRaw("true"), true, nil},
{"Bool", NewRaw("false"), false, nil},
{"Int64", NewRaw("true"), int64(1), nil},
{"Int64", NewRaw("false"), int64(0), nil},
{"Int64", NewAny(int(0)), int64(0), nil},
{"Int64", NewAny(int8(0)), int64(0), nil},
{"Int64", NewAny(int16(0)), int64(0), nil},
@ -291,22 +293,57 @@ func TestTypeCast(t *testing.T) {
{"Int64", NewAny(uint64(0)), int64(0), nil},
{"Int64", Node{}, int64(0), ErrUnsupportType},
{"Int64", NewRaw("0"), int64(0), nil},
{"StrictInt64", NewRaw("true"), int64(0), ErrUnsupportType},
{"StrictInt64", NewRaw("false"), int64(0), ErrUnsupportType},
{"StrictInt64", NewAny(int(0)), int64(0), nil},
{"StrictInt64", NewAny(int8(0)), int64(0), nil},
{"StrictInt64", NewAny(int16(0)), int64(0), nil},
{"StrictInt64", NewAny(int32(0)), int64(0), nil},
{"StrictInt64", NewAny(int64(0)), int64(0), nil},
{"StrictInt64", NewAny(uint(0)), int64(0), nil},
{"StrictInt64", NewAny(uint8(0)), int64(0), nil},
{"StrictInt64", NewAny(uint32(0)), int64(0), nil},
{"StrictInt64", NewAny(uint64(0)), int64(0), nil},
{"StrictInt64", Node{}, int64(0), ErrUnsupportType},
{"StrictInt64", NewRaw("0"), int64(0), nil},
{"Float64", NewRaw("true"), float64(1), nil},
{"Float64", NewRaw("false"), float64(0), nil},
{"Float64", Node{}, float64(0), ErrUnsupportType},
{"Float64", NewAny(float32(0)), float64(0), nil},
{"Float64", NewAny(float64(0)), float64(0), nil},
{"Float64", NewRaw("0.0"), float64(0.0), nil},
{"StrictFloat64", NewRaw("true"), float64(0), ErrUnsupportType},
{"StrictFloat64", NewRaw("false"), float64(0), ErrUnsupportType},
{"StrictFloat64", Node{}, float64(0), ErrUnsupportType},
{"StrictFloat64", NewAny(float32(0)), float64(0), nil},
{"StrictFloat64", NewAny(float64(0)), float64(0), nil},
{"StrictFloat64", NewRaw("0.0"), float64(0.0), nil},
{"Number", Node{}, json.Number(""), ErrUnsupportType},
{"Number", NewAny(json.Number("0")), json.Number("0"), nil},
{"Number", NewRaw("0.0"), json.Number("0.0"), nil},
{"Number", NewRaw("true"), json.Number("1"), nil},
{"Number", NewRaw("false"), json.Number("0"), nil},
{"StrictNumber", NewRaw("true"), json.Number(""), ErrUnsupportType},
{"StrictNumber", NewRaw("false"), json.Number(""), ErrUnsupportType},
{"StrictNumber", Node{}, json.Number(""), ErrUnsupportType},
{"StrictNumber", NewAny(json.Number("0")), json.Number("0"), nil},
{"StrictNumber", NewRaw("0.0"), json.Number("0.0"), nil},
{"String", Node{}, "", ErrUnsupportType},
{"String", NewAny(""), "", nil},
{"String", NewRaw(`""`), ``, nil},
{"String", NewAny(`\u263a`), `\u263a`, nil},
{"String", NewRaw(`"\u263a"`), ``, nil},
{"String", NewString(`\u263a`), `\u263a`, nil},
{"String", NewRaw(`0.0`), "0.0", nil},
{"String", NewRaw(`null`), "null", nil},
{"String", NewRaw(`true`), "true", nil},
{"String", NewRaw(`false`), "false", nil},
{"StrictString", Node{}, "", ErrUnsupportType},
{"StrictString", NewAny(`\u263a`), `\u263a`, nil},
{"StrictString", NewRaw(`"\u263a"`), ``, nil},
{"StrictString", NewString(`\u263a`), `\u263a`, nil},
{"StrictString", NewRaw(`0.0`), "", ErrUnsupportType},
{"StrictString", NewRaw(`null`), "", nil},
{"StrictString", NewRaw(`true`), "", ErrUnsupportType},
{"StrictString", NewRaw(`false`), "", ErrUnsupportType},
{"Len", Node{}, 0, nil},
{"Len", NewAny(0), 0, ErrUnsupportType},
{"Len", NewNull(), 0, nil},