diff --git a/ast/encode.go b/ast/encode.go index c5ef602..147709d 100644 --- a/ast/encode.go +++ b/ast/encode.go @@ -17,38 +17,45 @@ package ast import ( - `sync` + `sync` + + `github.com/bytedance/sonic/encoder` ) const ( - _MaxBuffer = 4 * 1024 // 4KB buffer size + _MaxBuffer = 4 * 1024 // 4KB buffer size ) const ( - bytesNull = "null" - bytesTrue = "true" - bytesFalse = "false" - bytesObject = "{}" - bytesArray = "[]" + bytesNull = "null" + bytesTrue = "true" + bytesFalse = "false" + bytesObject = "{}" + bytesArray = "[]" ) var bytesPool = sync.Pool{} func (self *Node) MarshalJSON() ([]byte, error) { - buf := newBuffer() - err := self.encode(buf) - ret := make([]byte, len(*buf)) - copy(ret, *buf) - freeBuffer(buf) - return ret, err + buf := newBuffer() + err := self.encode(buf) + if err != nil { + freeBuffer(buf) + return nil, err + } + + ret := make([]byte, len(*buf)) + copy(ret, *buf) + freeBuffer(buf) + return ret, err } func newBuffer() *[]byte { if ret := bytesPool.Get(); ret != nil { return ret.(*[]byte) } else { - buf := make([]byte, 0, _MaxBuffer) - return &buf + buf := make([]byte, 0, _MaxBuffer) + return &buf } } @@ -58,130 +65,135 @@ func freeBuffer(buf *[]byte) { } func (self *Node) encode(buf *[]byte) error { - if self.IsRaw() { - return self.encodeRaw(buf) - } - switch self.Type() { - case V_NONE : return ErrNotExist - case V_ERROR : return self.Check() - case V_NULL : return self.encodeNull(buf) - case V_TRUE : return self.encodeTrue(buf) - case V_FALSE : return self.encodeFalse(buf) - case V_ARRAY : return self.encodeArray(buf) - case V_OBJECT: return self.encodeObject(buf) - case V_STRING: return self.encodeString(buf) - case V_NUMBER: return self.encodeNumber(buf) - default : return ErrUnsupportType - } + if self.IsRaw() { + return self.encodeRaw(buf) + } + switch self.Type() { + case V_NONE : return ErrNotExist + case V_ERROR : return self.Check() + case V_NULL : return self.encodeNull(buf) + case V_TRUE : return self.encodeTrue(buf) + case V_FALSE : return self.encodeFalse(buf) + case V_ARRAY : return self.encodeArray(buf) + case V_OBJECT: return self.encodeObject(buf) + case V_STRING: return self.encodeString(buf) + case V_NUMBER: return self.encodeNumber(buf) + case V_ANY : return self.encodeInterface(buf) + default : return ErrUnsupportType + } } func (self *Node) encodeRaw(buf *[]byte) error { - raw, err := self.Raw() - if err != nil { - return err - } - *buf = append(*buf, raw...) - return nil + raw, err := self.Raw() + if err != nil { + return err + } + *buf = append(*buf, raw...) + return nil } func (self *Node) encodeNull(buf *[]byte) error { - *buf = append(*buf, bytesNull...) - return nil + *buf = append(*buf, bytesNull...) + return nil } func (self *Node) encodeTrue(buf *[]byte) error { - *buf = append(*buf, bytesTrue...) - return nil + *buf = append(*buf, bytesTrue...) + return nil } func (self *Node) encodeFalse(buf *[]byte) error { - *buf = append(*buf, bytesFalse...) - return nil + *buf = append(*buf, bytesFalse...) + return nil } func (self *Node) encodeNumber(buf *[]byte) error { - str := addr2str(self.p, self.v) - *buf = append(*buf, str...) - return nil + str := addr2str(self.p, self.v) + *buf = append(*buf, str...) + return nil } func (self *Node) encodeString(buf *[]byte) error { - str := addr2str(self.p, self.v) - *buf = append(*buf, '"') - *buf = append(*buf, str...) - *buf = append(*buf, '"') - return nil + str := addr2str(self.p, self.v) + *buf = append(*buf, '"') + *buf = append(*buf, str...) + *buf = append(*buf, '"') + return nil } func (self *Node) encodeArray(buf *[]byte) error { - if self.isLazy() { - if err := self.skipAllIndex(); err != nil { - return err - } - } + if self.isLazy() { + if err := self.skipAllIndex(); err != nil { + return err + } + } - nb := self.len() - if nb == 0 { - *buf = append(*buf, bytesArray...) - return nil - } - - *buf = append(*buf, '[') + nb := self.len() + if nb == 0 { + *buf = append(*buf, bytesArray...) + return nil + } + + *buf = append(*buf, '[') var p = (*Node)(self.p) - err := p.encode(buf) - if err != nil { - return err - } + err := p.encode(buf) + if err != nil { + return err + } for i := 1; i < nb; i++ { - *buf = append(*buf, ',') + *buf = append(*buf, ',') p = p.unsafe_next() err := p.encode(buf) - if err != nil { - return err - } - } + if err != nil { + return err + } + } - *buf = append(*buf, ']') + *buf = append(*buf, ']') return nil } func (self *Pair) encode(buf *[]byte) error { - *buf = append(*buf, '"') - *buf = append(*buf, self.Key...) - *buf = append(*buf, '"', ':') - return self.Value.encode(buf) + *buf = append(*buf, '"') + *buf = append(*buf, self.Key...) + *buf = append(*buf, '"', ':') + return self.Value.encode(buf) } func (self *Node) encodeObject(buf *[]byte) error { - if self.isLazy() { - if err := self.skipAllKey(); err != nil { - return err - } - } - - nb := self.len() - if nb == 0 { - *buf = append(*buf, bytesObject...) - return nil - } - - *buf = append(*buf, '{') + if self.isLazy() { + if err := self.skipAllKey(); err != nil { + return err + } + } + + nb := self.len() + if nb == 0 { + *buf = append(*buf, bytesObject...) + return nil + } + + *buf = append(*buf, '{') var p = (*Pair)(self.p) - err := p.encode(buf) - if err != nil { - return err - } + err := p.encode(buf) + if err != nil { + return err + } for i := 1; i < nb; i++ { - *buf = append(*buf, ',') + *buf = append(*buf, ',') p = p.unsafe_next() err := p.encode(buf) - if err != nil { - return err - } - } + if err != nil { + return err + } + } - *buf = append(*buf, '}') + *buf = append(*buf, '}') return nil +} + +func (self *Node) encodeInterface(buf *[]byte) error { + return encoder.EncodeInto(buf, self.packAny(), 0) } \ No newline at end of file diff --git a/ast/encode_test.go b/ast/encode_test.go index 3c9302d..39e4a7b 100644 --- a/ast/encode_test.go +++ b/ast/encode_test.go @@ -17,17 +17,19 @@ package ast import ( - `encoding/json` - `testing` `runtime` `runtime/debug` `sync` + `testing` + `github.com/bytedance/sonic/decoder` + `github.com/bytedance/sonic/encoder` `github.com/bytedance/sonic/internal/native/types` + `github.com/stretchr/testify/assert` ) func TestGC_Encode(t *testing.T) { - if debugSyncGC { + if debugSyncGC { return } root, err := NewSearcher(_TwitterJson).GetByPath() @@ -44,12 +46,12 @@ func TestGC_Encode(t *testing.T) { for i:=0; i= int64(mi.Len()) { @@ -85,111 +88,120 @@ func TestRawIterator(t *testing.T) { } i++ } + if i != int64(loop) { + t.Fatal(i) + } } func TestIterator(t *testing.T) { - str, loop := getTestIteratorSample() - fmt.Println(str) + str, loop := getTestIteratorSample() + fmt.Println(str) - root, err := NewParser(str).Parse() - if err != 0 { - t.Fatal(err) - } - ai, _ := root.Get("array").Values() - i := int64(0) - for ai.HasNext() { - v := &Node{} - if !ai.Next(v) { - t.Fatalf("no next") - } - x, _ := v.Int64() - if i < int64(loop) && x != i { - t.Fatalf("exp:%v, got:%v", i, v) - } - if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) { - t.Fatal(i) - } - i++ - } + root, err := NewParser(str).Parse() + if err != 0 { + t.Fatal(err) + } + ai, _ := root.Get("array").Values() + i := int64(0) + for ai.HasNext() { + v := &Node{} + if !ai.Next(v) { + t.Fatalf("no next") + } + x, _ := v.Int64() + if i < int64(loop) && x != i { + t.Fatalf("exp:%v, got:%v", i, v) + } + if i != int64(ai.Pos())-1 || i >= int64(ai.Len()) { + t.Fatal(i) + } + i++ + } + if i != int64(loop) { + t.Fatal(i) + } - root, err = NewParser(str).Parse() - if err != 0 { - t.Fatal(err) - } - mi, _ := root.Get("object").Properties() - i = int64(0) - for mi.HasNext() { - v := &Pair{} - if !mi.Next(v) { - t.Fatalf("no next") - } - x, _ := v.Value.Int64() - if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) { - vv, _ := v.Value.Interface() - t.Fatalf("exp:%v, got:%v", i, vv) - } - if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) { - t.Fatal(i) - } - i++ - } + root, err = NewParser(str).Parse() + if err != 0 { + t.Fatal(err) + } + mi, _ := root.Get("object").Properties() + i = int64(0) + for mi.HasNext() { + v := &Pair{} + if !mi.Next(v) { + t.Fatalf("no next") + } + x, _ := v.Value.Int64() + if i < int64(loop) &&( x != i ||v.Key != fmt.Sprintf("k%d", i)) { + vv, _ := v.Value.Interface() + t.Fatalf("exp:%v, got:%v", i, vv) + } + if i != int64(mi.Pos())-1 || i >= int64(mi.Len()) { + t.Fatal(i) + } + i++ + } + if i != int64(loop) { + t.Fatal(i) + } } func BenchmarkArrays(b *testing.B) { - for i:=0;i= V_NULL && it <= V_STRING || it == V_NUMBER + return self.t != V_ERROR } -// Check check if the node itself is valid, and return: -// - ErrNotFound If the node does not exist +// Check checks if the node itself is valid, and return: +// - ErrNotFound If the node is nil // - Its underlying error If the node is V_ERROR func (self *Node) Check() error { - if self == nil || self.t == V_NONE { + if self == nil { return ErrNotExist } else if self.t != V_ERROR { return nil @@ -114,9 +125,7 @@ func (self *Node) Check() error { // Error returns error message if the node is invalid func (self Node) Error() string { - if self.t == V_NONE { - return "unsupported type" - } else if self.t != V_ERROR { + if self.t != V_ERROR { return "" } else { return *(*string)(self.p) @@ -128,17 +137,21 @@ func (self Node) IsRaw() bool { return self.t&_V_RAW != 0 } -func (self Node) isLazy() bool { - return self.t&_V_LAZY != 0 +func (self *Node) isLazy() bool { + return self != nil && self.t&_V_LAZY != 0 +} + +func (self *Node) isAny() bool { + return self != nil && self.t == _V_ANY } /** Simple Value Methods **/ -// Raw returns underlying json string of an raw node, -// which usually created by Search() api +// Raw returns json representation of the node, func (self *Node) Raw() (string, error) { if !self.IsRaw() { - return "", ErrUnsupportType + buf, err := self.MarshalJSON() + return rt.Mem2Str(buf), err } return addr2str(self.p, self.v), nil } @@ -155,7 +168,8 @@ func (self *Node) checkRaw() error { // Bool_E returns bool value represented by this node // -// If node type is not types.V_TRUE or types.V_FALSE, or V_RAW (must be a bool json value), +// 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) // it will return error func (self *Node) Bool() (bool, error) { if err := self.checkRaw(); err != nil { @@ -164,6 +178,12 @@ func (self *Node) Bool() (bool, error) { switch self.t { case types.V_TRUE : return true , nil case types.V_FALSE : return false, nil + case _V_ANY : + if v, ok := self.packAny().(bool); ok { + return v, nil + } else { + return false, ErrUnsupportType + } default : return false, ErrUnsupportType } } @@ -177,6 +197,21 @@ func (self *Node) Int64() (int64, error) { case _V_NUMBER : return numberToInt64(self) case types.V_TRUE : return 1, nil case types.V_FALSE : return 0, nil + 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 } } @@ -190,6 +225,12 @@ func (self *Node) Number() (json.Number, error) { case _V_NUMBER : return toNumber(self) , nil case types.V_TRUE : return json.Number("1"), nil case types.V_FALSE : return json.Number("0"), 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 } } @@ -200,6 +241,7 @@ func (self *Node) Number() (json.Number, error) { // V_TRUE => "true", // V_FALSE => "false", // V_NUMBER => "[0-9\.]*" +// V_ANY => interface{}.(string) func (self *Node) String() (string, error) { if err := self.checkRaw(); err != nil { return "", err @@ -210,6 +252,12 @@ func (self *Node) String() (string, error) { case types.V_TRUE : return "true" , nil case types.V_FALSE : return "false", 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 } } @@ -223,6 +271,13 @@ func (self *Node) Float64() (float64, error) { case _V_NUMBER : return numberToFloat64(self) case types.V_TRUE : return 1.0, nil case types.V_FALSE : return 0.0, nil + 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 } } @@ -239,6 +294,8 @@ func (self *Node) Len() (int, error) { return int(self.v & _LEN_MASK), nil } else if self.t == types.V_STRING { return int(self.v), nil + } else if self.t == _V_NONE || self.t == types.V_NULL { + return 0, nil } else { return 0, ErrUnsupportType } @@ -255,6 +312,8 @@ func (self *Node) Cap() (int, error) { } if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { return int(self.v >> _CAP_BITS), nil + } else if self.t == _V_NONE || self.t == types.V_NULL { + return 0, nil } else { return 0, ErrUnsupportType } @@ -264,9 +323,15 @@ func (self Node) cap() int { return int(self.v >> _CAP_BITS) } -// Set sets the node of given key under object parent -// If the key doesn't exist, it will be append to the last +// Set sets the node of given key under self, and reports if the key has existed. +// +// If self is V_NONE or V_NULL, it becomes V_OBJECT and sets the node at the key. func (self *Node) Set(key string, node Node) (bool, error) { + if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) { + *self = NewObject([]Pair{{key, node}}) + return false, nil + } + if err := node.Check(); err != nil { return false, err } @@ -296,7 +361,12 @@ func (self *Node) Set(key string, node Node) (bool, error) { return true, nil } -// Unset remove the node of given key under object parent +// SetAny wraps val with V_ANY node, and Set() the node. +func (self *Node) SetAny(key string, val interface{}) (bool, error) { + return self.Set(key, NewAny(val)) +} + +// Unset remove the node of given key under object parent, and reports if the key has existed. func (self *Node) Unset(key string) (bool, error) { self.must(types.V_OBJECT, "an object") p, i := self.skipKey(key) @@ -310,9 +380,9 @@ func (self *Node) Unset(key string) (bool, error) { return true, nil } -// SetByIndex sets the node of given index +// SetByIndex sets the node of given index, and reports if the key has existed. // -// The index must within parent array's children +// The index must be within self's children. func (self *Node) SetByIndex(index int, node Node) (bool, error) { if err := node.Check(); err != nil { return false, err @@ -329,6 +399,11 @@ func (self *Node) SetByIndex(index int, node Node) (bool, error) { return true, nil } +// SetAny wraps val with V_ANY node, and SetByIndex() the node. +func (self *Node) SetAnyByIndex(index int, val interface{}) (bool, error) { + return self.SetByIndex(index, NewAny(val)) +} + // UnsetByIndex remove the node of given index func (self *Node) UnsetByIndex(index int) (bool, error) { var p *Node @@ -341,7 +416,7 @@ func (self *Node) UnsetByIndex(index int) (bool, error) { return false, ErrNotExist } p = &pr.Value - }else{ + } else { return false, ErrUnsupportType } @@ -357,8 +432,15 @@ func (self *Node) UnsetByIndex(index int) (bool, error) { return true, nil } -// Add appends the given node under array node +// Add appends the given node under self. +// +// If self is V_NONE or V_NULL, it becomes V_ARRAY and sets the node at index 0. func (self *Node) Add(node Node) error { + if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) { + *self = NewArray([]Node{node}) + return nil + } + if err := self.should(types.V_ARRAY, "an array"); err != nil { return err } @@ -379,6 +461,11 @@ func (self *Node) Add(node Node) error { return nil } +// SetAny wraps val with V_ANY node, and Add() the node. +func (self *Node) AddAny(val interface{}) error { + return self.Add(NewAny(val)) +} + // GetByPath load given path on demands, // which only ensure nodes before this path got parsed func (self *Node) GetByPath(path ...interface{}) *Node { @@ -428,12 +515,12 @@ func (self *Node) Index(idx int) *Node { }else if it == types.V_OBJECT { pr := self.skipIndexPair(idx) if pr == nil { - return nodeNotExist + return newError(_ERR_NOT_FOUND, "value not exists") } return &pr.Value - }else{ - return nodeUnsupportType + } else { + return newError(_ERR_UNSUPPORT_TYPE, fmt.Sprintf("unsupported type: %v", self.itype())) } } @@ -461,32 +548,18 @@ func (self *Node) IndexOrGet(idx int, key string) *Node { return n } -// Values returns iterator for array's children traversal -func (self *Node) Values() (ListIterator, error) { - if err := self.should(types.V_ARRAY, "an array"); err != nil { - return ListIterator{}, err - } - if err := self.skipAllIndex(); err != nil { - return ListIterator{}, err - } - return ListIterator{Iterator{p: self}}, nil -} - -// Properties returns iterator for object's children traversal -func (self *Node) Properties() (ObjectIterator, error) { - if err := self.should(types.V_OBJECT, "an object"); err != nil { - return ObjectIterator{}, err - } - if err := self.skipAllKey(); err != nil { - return ObjectIterator{}, err - } - return ObjectIterator{Iterator{p: self}}, nil -} - /** Generic Value Converters **/ // Map loads all keys of an object node func (self *Node) Map() (map[string]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.(map[string]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } if err := self.should(types.V_OBJECT, "an object"); err != nil { return nil, err } @@ -498,6 +571,14 @@ func (self *Node) Map() (map[string]interface{}, error) { // MapUseNumber loads all keys of an object node, with numeric nodes casted to json.Number func (self *Node) MapUseNumber() (map[string]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.(map[string]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } if err := self.should(types.V_OBJECT, "an object"); err != nil { return nil, err } @@ -510,6 +591,14 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) { // MapUseNode scans both parsed and non-parsed chidren nodes, // and map them by their keys func (self *Node) MapUseNode() (map[string]Node, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.(map[string]Node); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } if err := self.should(types.V_OBJECT, "an object"); err != nil { return nil, err } @@ -534,6 +623,14 @@ func (self *Node) UnsafeMap() ([]Pair, error) { // Array loads all indexes of an array node func (self *Node) Array() ([]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.([]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } if err := self.should(types.V_ARRAY, "an array"); err != nil { return nil, err } @@ -545,6 +642,14 @@ func (self *Node) Array() ([]interface{}, error) { // ArrayUseNumber loads all indexes of an array node, with numeric nodes casted to json.Number func (self *Node) ArrayUseNumber() ([]interface{}, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.([]interface{}); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } if err := self.should(types.V_ARRAY, "an array"); err != nil { return nil, err } @@ -557,6 +662,14 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) { // ArrayUseNode copys both parsed and non-parsed chidren nodes, // and indexes them by original order func (self *Node) ArrayUseNode() ([]Node, error) { + if self.isAny() { + any := self.packAny() + if v, ok := any.([]Node); ok { + return v, nil + } else { + return nil, ErrUnsupportType + } + } if err := self.should(types.V_ARRAY, "an array"); err != nil { return nil, err } @@ -610,10 +723,20 @@ func (self *Node) Interface() (interface{}, error) { return nil, err } return self.toGenericObject() + case _V_ANY: + switch v := self.packAny().(type) { + case Node : return v.Interface() + case *Node: return v.Interface() + default : return v, nil + } default : return nil, ErrUnsupportType } } +func (self *Node) packAny() interface{} { + return *(*interface{})(self.p) +} + // InterfaceUseNumber works same with Interface() // except numberic nodes are casted to json.Number func (self *Node) InterfaceUseNumber() (interface{}, error) { @@ -639,6 +762,7 @@ func (self *Node) InterfaceUseNumber() (interface{}, error) { return nil, err } return self.toGenericObjectUseNumber() + case _V_ANY : return self.packAny(), nil default : return nil, ErrUnsupportType } } @@ -662,66 +786,66 @@ func (self *Node) InterfaceUseNode() (interface{}, error) { return nil, err } return self.toGenericObjectUseNode() - default : return *self, nil + default : return *self, self.Check() } } // LoadAll loads all the node's children and children's children as parsed. // After calling it, the node can be safely used on concurrency func (self *Node) LoadAll() error { - if self.IsRaw() { - self.parseRaw(true) - return self.Check() - } + if self.IsRaw() { + self.parseRaw(true) + return self.Check() + } - switch self.itype() { - case types.V_ARRAY: - e := self.len() - if err := self.loadAllIndex(); err != nil { - return err - } - for i := 0; i < e; i++ { - n := self.nodeAt(i) - n.parseRaw(true) - if err := n.Check(); err != nil { - return err - } - } - return nil - case types.V_OBJECT: - e := self.len() - if err := self.loadAllKey(); err != nil { - return err - } - for i := 0; i < e; i++ { - n := self.pairAt(i) - n.Value.parseRaw(true) - if err := n.Value.Check(); err != nil { - return err - } - } - return nil - default: - return self.Check() - } + switch self.itype() { + case types.V_ARRAY: + e := self.len() + if err := self.loadAllIndex(); err != nil { + return err + } + for i := 0; i < e; i++ { + n := self.nodeAt(i) + n.parseRaw(true) + if err := n.Check(); err != nil { + return err + } + } + return nil + case types.V_OBJECT: + e := self.len() + if err := self.loadAllKey(); err != nil { + return err + } + for i := 0; i < e; i++ { + n := self.pairAt(i) + n.Value.parseRaw(true) + if err := n.Value.Check(); err != nil { + return err + } + } + return nil + default: + return self.Check() + } } // Load loads the node's children as parsed. // After calling it, only the node itself can be used on concurrency (not include its children) func (self *Node) Load() error { - if self.IsRaw() { - self.parseRaw(false) - return self.Load() - } + if self.IsRaw() { + self.parseRaw(false) + return self.Load() + } - switch self.t { - case _V_ARRAY_LAZY: - return self.skipAllIndex() - case _V_OBJECT_LAZY: - return self.skipAllKey() - default: - return self.Check() - } + switch self.t { + case _V_ARRAY_LAZY: + return self.skipAllIndex() + case _V_OBJECT_LAZY: + return self.skipAllKey() + default: + return self.Check() + } } /**---------------------------------- Internal Helper Methods ----------------------------------**/ @@ -859,7 +983,7 @@ func (self *Node) skipNextNode() *Node { /* skip the value */ if start, err := parser.skip(); err != 0 { return newSyntaxError(parser.syntaxError(err)) - }else{ + } else { t := switchRawType(parser.s[start]) if t == _V_NONE { return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) @@ -942,7 +1066,7 @@ func (self *Node) skipNextPair() (*Pair) { /* skip the value */ if start, err := parser.skip(); err != 0 { return &Pair{key, *newSyntaxError(parser.syntaxError(err))} - }else{ + } else { t := switchRawType(parser.s[start]) if t == _V_NONE { return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} @@ -1299,6 +1423,41 @@ var ( emptyObjectNode = Node{t: types.V_OBJECT} ) +// NewRaw creates a node of raw json, and decides its type by first char. +func NewRaw(json string) Node { + if json == "" { + panic("empty json string") + } + it := switchRawType(json[0]) + return newRawNode(json, it) +} + +// NewAny creates a node of type V_ANY if any's type isn't Node or *Node, +// which stores interface{} and can be only used for `.Interface()`\`.MarshalJSON()`. +func NewAny(any interface{}) Node { + switch n := any.(type) { + case Node: + return n + case *Node: + return *n + default: + return Node{ + t: _V_ANY, + v: 0, + p: unsafe.Pointer(&any), + } + } +} + +// NewBytes encodes given src with Base64 (RFC 4648), and creates a node of type V_STRING. +func NewBytes(src []byte) Node { + if len(src) == 0 { + panic("empty src bytes") + } + out := base64x.StdEncoding.EncodeToString(src) + return NewString(out) +} + // NewNull creates a node of type V_NULL func NewNull() Node { return Node{ @@ -1520,7 +1679,7 @@ func unwrapError(err error) *Node { return se }else if sse, ok := err.(Node); ok { return &sse - }else{ + } else { msg := err.Error() return &Node{ t: V_ERROR, diff --git a/ast/node_test.go b/ast/node_test.go index 2d7aeb6..2ddcede 100644 --- a/ast/node_test.go +++ b/ast/node_test.go @@ -20,21 +20,47 @@ import ( `encoding/json` `fmt` `reflect` + `runtime` + `runtime/debug` `strconv` `testing` `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` `github.com/stretchr/testify/assert` ) +//go:noinline +func stackObj() interface{} { + var a int = 1 + return rt.UnpackEface(a).Pack() +} + +func TestStackAny(t *testing.T) { + var obj = stackObj() + any := NewAny(obj) + fmt.Printf("any: %#v\n", any) + runtime.GC() + debug.FreeOSMemory() + println("finish GC") + buf, err := any.MarshalJSON() + println("finish marshal") + if err != nil { + t.Fatal(err) + } + if string(buf) != `1` { + t.Fatal(string(buf)) + } +} + func TestLoadAll(t *testing.T) { e := Node{} err := e.Load() - if err != ErrNotExist { + if err != nil { t.Fatal(err) } err = e.LoadAll() - if err != ErrNotExist { + if err != nil { t.Fatal(err) } @@ -151,39 +177,96 @@ func TestTypeCast(t *testing.T) { exp interface{} err error } + a1 := NewAny(1) lazyArray, _ := NewParser("[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]").Parse() lazyObject, _ := NewParser(`{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8,"9":9,"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16}`).Parse() var cases = []tcase{ - {"Raw", Node{}, "", ErrUnsupportType}, - {"Raw", newRawNode("[ ]", types.V_ARRAY), "[ ]", nil}, - {"Bool", Node{}, false, ErrNotExist}, - {"Bool", newRawNode("true", types.V_TRUE), true, nil}, - {"Bool", newRawNode("false", types.V_FALSE), false, nil}, - {"Int64", Node{}, int64(0), ErrNotExist}, - {"Int64", newRawNode("0", _V_NUMBER), int64(0), nil}, - {"Float64", Node{}, float64(0), ErrNotExist}, - {"Float64", newRawNode("0.0", _V_NUMBER), float64(0.0), nil}, - {"Number", Node{}, json.Number(""), ErrNotExist}, - {"Number", newRawNode("0.0", _V_NUMBER), json.Number("0.0"), nil}, - {"Number", newRawNode("true", types.V_TRUE), json.Number("1"), nil}, - {"Number", newRawNode("false", types.V_FALSE), json.Number("0"), nil}, - {"String", Node{}, "", ErrNotExist}, - {"String", newRawNode(`""`, types.V_STRING), ``, nil}, - {"String", newRawNode(`0.0`, _V_NUMBER), "0.0", nil}, - {"String", newRawNode(`null`, types.V_NULL), "null", nil}, - {"String", newRawNode(`true`, types.V_TRUE), "true", nil}, - {"String", newRawNode(`false`, types.V_FALSE), "false", nil}, - {"Len", NewNull(), 0, ErrUnsupportType}, - {"Len", newRawNode(`"1"`, types.V_STRING), 1, nil}, - {"Len", newRawNode(`[1]`, types.V_ARRAY), 0, nil}, + {"Interface", Node{}, interface{}(nil), ErrUnsupportType}, + {"Interface", NewAny(NewNumber("1")), float64(1), nil}, + {"Interface", NewAny(int64(1)), int64(1), nil}, + {"Interface", NewNumber("1"), float64(1), nil}, + {"InterfaceUseNode", Node{}, Node{}, nil}, + {"InterfaceUseNode", a1, a1, nil}, + {"InterfaceUseNode", NewNumber("1"), NewNumber("1"), nil}, + {"InterfaceUseNumber", Node{}, interface{}(nil), ErrUnsupportType}, + {"InterfaceUseNumber", NewAny(1), 1, nil}, + {"InterfaceUseNumber", NewNumber("1"), json.Number("1"), nil}, + {"Map", Node{}, map[string]interface{}(nil), ErrUnsupportType}, + {"Map", NewAny(map[string]Node{"a":NewNumber("1")}), map[string]interface{}(nil), ErrUnsupportType}, + {"Map", NewAny(map[string]interface{}{"a":1}), map[string]interface{}{"a":1}, nil}, + {"Map", NewObject([]Pair{{"a",NewNumber("1")}}), map[string]interface{}{"a":float64(1.0)}, nil}, + {"MapUseNode", Node{}, map[string]Node(nil), ErrUnsupportType}, + {"MapUseNode", NewAny(map[string]interface{}{"a":1}), map[string]Node(nil), ErrUnsupportType}, + {"MapUseNode", NewAny(map[string]Node{"a":NewNumber("1")}), map[string]Node{"a":NewNumber("1")}, nil}, + {"MapUseNode", NewObject([]Pair{{"a",NewNumber("1")}}), map[string]Node{"a":NewNumber("1")}, nil}, + {"MapUseNumber", Node{}, map[string]interface{}(nil), ErrUnsupportType}, + {"MapUseNumber", NewAny(map[string]interface{}{"a":1}), map[string]interface{}{"a":1}, nil}, + {"MapUseNumber", NewObject([]Pair{{"a",NewNumber("1")}}), map[string]interface{}{"a":json.Number("1")}, nil}, + {"Array", Node{}, []interface{}(nil), ErrUnsupportType}, + {"Array", NewAny([]interface{}{1}), []interface{}{1}, nil}, + {"Array", NewArray([]Node{NewNumber("1")}), []interface{}{float64(1.0)}, nil}, + {"ArrayUseNode", Node{}, []Node(nil), ErrUnsupportType}, + {"ArrayUseNode", NewAny([]interface{}{1}), []Node(nil), ErrUnsupportType}, + {"ArrayUseNode", NewAny([]Node{NewNumber("1")}), []Node{NewNumber("1")}, nil}, + {"ArrayUseNode", NewArray([]Node{NewNumber("1")}), []Node{NewNumber("1")}, nil}, + {"ArrayUseNumber", Node{}, []interface{}(nil), ErrUnsupportType}, + {"ArrayUseNumber", NewAny([]interface{}{1}), []interface{}{1}, nil}, + {"ArrayUseNumber", NewAny([]Node{NewNumber("1")}), []interface{}(nil), ErrUnsupportType}, + {"ArrayUseNumber", NewArray([]Node{NewNumber("1")}), []interface{}{json.Number("1")}, nil}, + {"Raw", Node{}, "", ErrNotExist}, + {"Raw", NewAny(""), `""`, nil}, + {"Raw", NewRaw("[ ]"), "[ ]", nil}, + {"Raw", NewBool(true), "true", nil}, + {"Raw", NewNumber("-0.0"), "-0.0", nil}, + {"Raw", NewString(""), `""`, nil}, + {"Raw", NewBytes([]byte("hello, world")), `"aGVsbG8sIHdvcmxk"`, nil}, + {"Bool", Node{}, false, ErrUnsupportType}, + {"Bool", NewAny(true), true, nil}, + {"Bool", NewAny(false), false, nil}, + {"Bool", NewRaw("true"), true, nil}, + {"Bool", NewRaw("false"), false, nil}, + {"Int64", NewAny(int(0)), int64(0), nil}, + {"Int64", NewAny(int8(0)), int64(0), nil}, + {"Int64", NewAny(int16(0)), int64(0), nil}, + {"Int64", NewAny(int32(0)), int64(0), nil}, + {"Int64", NewAny(int64(0)), int64(0), nil}, + {"Int64", NewAny(uint(0)), int64(0), nil}, + {"Int64", NewAny(uint8(0)), int64(0), nil}, + {"Int64", NewAny(uint32(0)), int64(0), nil}, + {"Int64", NewAny(uint64(0)), int64(0), nil}, + {"Int64", Node{}, int64(0), ErrUnsupportType}, + {"Int64", NewRaw("0"), int64(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}, + {"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}, + {"String", Node{}, "", ErrUnsupportType}, + {"String", NewAny(""), "", nil}, + {"String", NewRaw(`""`), ``, nil}, + {"String", NewRaw(`0.0`), "0.0", nil}, + {"String", NewRaw(`null`), "null", nil}, + {"String", NewRaw(`true`), "true", nil}, + {"String", NewRaw(`false`), "false", nil}, + {"Len", Node{}, 0, nil}, + {"Len", NewAny(0), 0, ErrUnsupportType}, + {"Len", NewNull(), 0, nil}, + {"Len", NewRaw(`"1"`), 1, nil}, + {"Len", NewRaw(`[1]`), 0, nil}, {"Len", NewArray([]Node{NewNull()}), 1, nil}, {"Len", lazyArray, 0, nil}, - {"Len", newRawNode(`{"a":1}`, types.V_OBJECT), 0, nil}, + {"Len", NewRaw(`{"a":1}`), 0, nil}, {"Len", lazyObject, 0, nil}, - {"Cap", NewNull(), 0, ErrUnsupportType}, - {"Cap", newRawNode(`[1]`, types.V_ARRAY), _DEFAULT_NODE_CAP, nil}, + {"Cap", Node{}, 0, nil}, + {"Cap", NewAny(0), 0, ErrUnsupportType}, + {"Cap", NewNull(), 0, nil}, + {"Cap", NewRaw(`[1]`), _DEFAULT_NODE_CAP, nil}, {"Cap", NewObject([]Pair{{"",NewNull()}}), 1, nil}, - {"Cap", newRawNode(`{"a":1}`, types.V_OBJECT), _DEFAULT_NODE_CAP, nil}, + {"Cap", NewRaw(`{"a":1}`), _DEFAULT_NODE_CAP, nil}, } lazyArray.skipAllIndex() lazyObject.skipAllKey() @@ -195,15 +278,15 @@ func TestTypeCast(t *testing.T) { ) for i, c := range cases { - fmt.Println(c) + fmt.Println(i, c) rt := reflect.ValueOf(&c.node) m := rt.MethodByName(c.method) rets := m.Call([]reflect.Value{}) if len(rets) != 2 { t.Fatal(i, rets) } - if rets[0].Interface() != c.exp { - t.Fatal(i, rets[0].Interface()) + if !reflect.DeepEqual(rets[0].Interface(), c.exp) { + t.Fatal(i, rets[0].Interface(), c.exp) } if rets[1].Interface() != c.err { t.Fatal(i, rets[1].Interface()) @@ -212,6 +295,11 @@ func TestTypeCast(t *testing.T) { } func TestCheckError(t *testing.T) { + empty := Node{} + if !empty.Valid() || empty.Check() != nil || empty.Error() != "" { + t.Fatal() + } + n := newRawNode("[hello]", types.V_ARRAY) n.parseRaw(false) if n.Check() != nil { @@ -680,6 +768,56 @@ func TestNodeGetByPath(t *testing.T) { } func TestNodeSet(t *testing.T) { + empty := Node{} + err := empty.Add(Node{}) + if err != nil { + t.Fatal(err) + } + empty2 := empty.Index(0) + if empty2.Check() != nil { + t.Fatal(err) + } + exist, err := empty2.SetByIndex(1, Node{}) + if exist || err == nil { + t.Fatal(exist, err) + } + empty3 := empty.Index(0) + if empty3.Check() != nil { + t.Fatal(err) + } + exist, err = empty3.Set("a", NewNumber("-1")) + if exist || err != nil { + t.Fatal(exist, err) + } + if n, e := empty.Index(0).Get("a").Int64(); e != nil || n != -1 { + t.Fatal(n, e) + } + + empty = NewNull() + err = empty.Add(NewNull()) + if err != nil { + t.Fatal(err) + } + empty2 = empty.Index(0) + if empty2.Check() != nil { + t.Fatal(err) + } + exist, err = empty2.SetByIndex(1, NewNull()) + if exist || err == nil { + t.Fatal(exist, err) + } + empty3 = empty.Index(0) + if empty3.Check() != nil { + t.Fatal(err) + } + exist, err = empty3.Set("a", NewNumber("-1")) + if exist || err != nil { + t.Fatal(exist, err) + } + if n, e := empty.Index(0).Get("a").Int64(); e != nil || n != -1 { + t.Fatal(n, e) + } + root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { t.Fatalf("decode failed: %v", derr.Error()) @@ -709,6 +847,43 @@ func TestNodeSet(t *testing.T) { } } +func TestNodeAny(t *testing.T) { + empty := Node{} + _,err := empty.SetAny("any", map[string]interface{}{"a": []int{0}}) + if err != nil { + t.Fatal(err) + } + if m, err := empty.Get("any").Interface(); err != nil { + t.Fatal(err) + } else if v, ok := m.(map[string]interface{}); !ok { + t.Fatal(v) + } + if buf, err := empty.MarshalJSON(); err != nil { + t.Fatal(err) + } else if string(buf) != `{"any":{"a":[0]}}` { + t.Fatal(string(buf)) + } + if _, err := empty.Set("any2", Node{}); err != nil { + t.Fatal(err) + } + if err := empty.Get("any2").AddAny(nil); err != nil { + t.Fatal(err) + } + if buf, err := empty.MarshalJSON(); err != nil { + t.Fatal(err) + } else if string(buf) != `{"any":{"a":[0]},"any2":[null]}` { + t.Fatal(string(buf)) + } + if _, err := empty.Get("any2").SetAnyByIndex(0, NewNumber("-0.0")); err != nil { + t.Fatal(err) + } + if buf, err := empty.MarshalJSON(); err != nil { + t.Fatal(err) + } else if string(buf) != `{"any":{"a":[0]},"any2":[-0.0]}` { + t.Fatal(string(buf)) + } +} + func TestNodeSetByIndex(t *testing.T) { root, derr := NewParser(_TwitterJson).Parse() if derr != 0 { diff --git a/ast/parser.go b/ast/parser.go index b01715a..f83936e 100644 --- a/ast/parser.go +++ b/ast/parser.go @@ -17,15 +17,15 @@ package ast import ( - `fmt` - `sync` + `fmt` + `sync` `unsafe` - `github.com/bytedance/sonic/decoder` - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - `github.com/bytedance/sonic/unquote` + `github.com/bytedance/sonic/decoder` + `github.com/bytedance/sonic/internal/native` + `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` + `github.com/bytedance/sonic/unquote` ) const _DEFAULT_NODE_CAP int = 16 @@ -36,11 +36,8 @@ const ( ) var ( - nodeNotExist = newError(_ERR_NOT_FOUND, "value not exists") - nodeUnsupportType = newError(_ERR_UNSUPPORT_TYPE, "unsupported type") - - ErrNotExist error = nodeNotExist - ErrUnsupportType error = nodeUnsupportType + ErrNotExist error = newError(_ERR_NOT_FOUND, "value not exists") + ErrUnsupportType error = newError(_ERR_UNSUPPORT_TYPE, "unsupported type") ) type Parser struct { diff --git a/ast/search_test.go b/ast/search_test.go index a2f8b2d..959de9c 100644 --- a/ast/search_test.go +++ b/ast/search_test.go @@ -22,7 +22,7 @@ import ( `runtime/debug` `sync` `fmt` - `math` + `math` `strconv` `github.com/tidwall/sjson` @@ -277,83 +277,83 @@ func BenchmarkGetOne_Parallel_Sonic(b *testing.B) { } func BenchmarkSetOne_Sonic(b *testing.B) { - node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) - if err != nil { - b.Fatal(err) - } - n := NewNumber(strconv.Itoa(math.MaxInt32)) - _, err = node.Set("id", n) - if err != nil { - b.Fatal(err) - } - b.SetBytes(int64(len(_TwitterJson))) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) - _, _ = node.Set("id", n) - } + node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + if err != nil { + b.Fatal(err) + } + n := NewNumber(strconv.Itoa(math.MaxInt32)) + _, err = node.Set("id", n) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + _, _ = node.Set("id", n) + } } func BenchmarkSetOne_Sjson(b *testing.B) { - path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") - _, err := sjson.Set(_TwitterJson, path, math.MaxInt32) - if err != nil { - b.Fatal(err) - } - b.SetBytes(int64(len(_TwitterJson))) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - sjson.Set(_TwitterJson, path, math.MaxInt32) - } + path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") + _, err := sjson.Set(_TwitterJson, path, math.MaxInt32) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + sjson.Set(_TwitterJson, path, math.MaxInt32) + } } func BenchmarkSetOne_Jsoniter(b *testing.B) { data := []byte(_TwitterJson) - node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) - if !ok { - b.Fatal(node) - } + node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + if !ok { + b.Fatal(node) + } - b.SetBytes(int64(len(data))) - b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { - node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) - node["id"] = math.MaxInt32 - } + b.SetBytes(int64(len(data))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + node, _ := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + node["id"] = math.MaxInt32 + } } func BenchmarkSetOne_Parallel_Sonic(b *testing.B) { - node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) - if err != nil { - b.Fatal(err) - } - n := NewNumber(strconv.Itoa(math.MaxInt32)) - _, err = node.Set("id", n) - if err != nil { - b.Fatal(err) - } - b.SetBytes(int64(len(_TwitterJson))) - b.ReportAllocs() + node, err := NewSearcher(_TwitterJson).GetByPath("statuses", 3) + if err != nil { + b.Fatal(err) + } + n := NewNumber(strconv.Itoa(math.MaxInt32)) + _, err = node.Set("id", n) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { node, _ := NewSearcher(_TwitterJson).GetByPath("statuses", 3) - _, _ = node.Set("id", n) + _, _ = node.Set("id", n) } }) } func BenchmarkSetOne_Parallel_Sjson(b *testing.B) { - path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") - _, err := sjson.Set(_TwitterJson, path, math.MaxInt32) - if err != nil { - b.Fatal(err) - } - b.SetBytes(int64(len(_TwitterJson))) - b.ReportAllocs() + path := fmt.Sprintf("%s.%d.%s", "statuses", 3, "id") + _, err := sjson.Set(_TwitterJson, path, math.MaxInt32) + if err != nil { + b.Fatal(err) + } + b.SetBytes(int64(len(_TwitterJson))) + b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { @@ -364,13 +364,13 @@ func BenchmarkSetOne_Parallel_Sjson(b *testing.B) { func BenchmarkSetOne_Parallel_Jsoniter(b *testing.B) { data := []byte(_TwitterJson) - node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) - if !ok { - b.Fatal(node) - } + node, ok := jsoniter.Get(data, "statuses", 3).GetInterface().(map[string]interface{}) + if !ok { + b.Fatal(node) + } - b.SetBytes(int64(len(data))) - b.ReportAllocs() + b.SetBytes(int64(len(data))) + b.ReportAllocs() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { diff --git a/ast/utils.go b/ast/utils.go index 4c9ffe5..0f99a77 100644 --- a/ast/utils.go +++ b/ast/utils.go @@ -30,9 +30,9 @@ func mem2ptr(s []byte) unsafe.Pointer { //go:nosplit func ptr2slice(s unsafe.Pointer, l int, c int) unsafe.Pointer { slice := &rt.GoSlice{ - Ptr: s, - Len: l, - Cap: c, + Ptr: s, + Len: l, + Cap: c, } return unsafe.Pointer(slice) }