239 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
| /*
 | |
| Copyright 2019 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package fieldpath
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"io"
 | |
| 	"unsafe"
 | |
| 
 | |
| 	jsoniter "github.com/json-iterator/go"
 | |
| )
 | |
| 
 | |
| func (s *Set) ToJSON() ([]byte, error) {
 | |
| 	buf := bytes.Buffer{}
 | |
| 	err := s.ToJSONStream(&buf)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return buf.Bytes(), nil
 | |
| }
 | |
| 
 | |
| func (s *Set) ToJSONStream(w io.Writer) error {
 | |
| 	stream := writePool.BorrowStream(w)
 | |
| 	defer writePool.ReturnStream(stream)
 | |
| 
 | |
| 	var r reusableBuilder
 | |
| 
 | |
| 	stream.WriteObjectStart()
 | |
| 	err := s.emitContentsV1(false, stream, &r)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	stream.WriteObjectEnd()
 | |
| 	return stream.Flush()
 | |
| }
 | |
| 
 | |
| func manageMemory(stream *jsoniter.Stream) error {
 | |
| 	// Help jsoniter manage its buffers--without this, it does a bunch of
 | |
| 	// alloctaions that are not necessary. They were probably optimizing
 | |
| 	// for folks using the buffer directly.
 | |
| 	b := stream.Buffer()
 | |
| 	if len(b) > 4096 || cap(b)-len(b) < 2048 {
 | |
| 		if err := stream.Flush(); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		stream.SetBuffer(b[:0])
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| type reusableBuilder struct {
 | |
| 	bytes.Buffer
 | |
| }
 | |
| 
 | |
| func (r *reusableBuilder) unsafeString() string {
 | |
| 	b := r.Bytes()
 | |
| 	return *(*string)(unsafe.Pointer(&b))
 | |
| }
 | |
| 
 | |
| func (r *reusableBuilder) reset() *bytes.Buffer {
 | |
| 	r.Reset()
 | |
| 	return &r.Buffer
 | |
| }
 | |
| 
 | |
| func (s *Set) emitContentsV1(includeSelf bool, stream *jsoniter.Stream, r *reusableBuilder) error {
 | |
| 	mi, ci := 0, 0
 | |
| 	first := true
 | |
| 	preWrite := func() {
 | |
| 		if first {
 | |
| 			first = false
 | |
| 			return
 | |
| 		}
 | |
| 		stream.WriteMore()
 | |
| 	}
 | |
| 
 | |
| 	if includeSelf && !(len(s.Members.members) == 0 && len(s.Children.members) == 0) {
 | |
| 		preWrite()
 | |
| 		stream.WriteObjectField(".")
 | |
| 		stream.WriteEmptyObject()
 | |
| 	}
 | |
| 
 | |
| 	for mi < len(s.Members.members) && ci < len(s.Children.members) {
 | |
| 		mpe := s.Members.members[mi]
 | |
| 		cpe := s.Children.members[ci].pathElement
 | |
| 
 | |
| 		if c := mpe.Compare(cpe); c < 0 {
 | |
| 			preWrite()
 | |
| 			if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			stream.WriteObjectField(r.unsafeString())
 | |
| 			stream.WriteEmptyObject()
 | |
| 			mi++
 | |
| 		} else if c > 0 {
 | |
| 			preWrite()
 | |
| 			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			stream.WriteObjectField(r.unsafeString())
 | |
| 			stream.WriteObjectStart()
 | |
| 			if err := s.Children.members[ci].set.emitContentsV1(false, stream, r); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			stream.WriteObjectEnd()
 | |
| 			ci++
 | |
| 		} else {
 | |
| 			preWrite()
 | |
| 			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			stream.WriteObjectField(r.unsafeString())
 | |
| 			stream.WriteObjectStart()
 | |
| 			if err := s.Children.members[ci].set.emitContentsV1(true, stream, r); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			stream.WriteObjectEnd()
 | |
| 			mi++
 | |
| 			ci++
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for mi < len(s.Members.members) {
 | |
| 		mpe := s.Members.members[mi]
 | |
| 
 | |
| 		preWrite()
 | |
| 		if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		stream.WriteObjectField(r.unsafeString())
 | |
| 		stream.WriteEmptyObject()
 | |
| 		mi++
 | |
| 	}
 | |
| 
 | |
| 	for ci < len(s.Children.members) {
 | |
| 		cpe := s.Children.members[ci].pathElement
 | |
| 
 | |
| 		preWrite()
 | |
| 		if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		stream.WriteObjectField(r.unsafeString())
 | |
| 		stream.WriteObjectStart()
 | |
| 		if err := s.Children.members[ci].set.emitContentsV1(false, stream, r); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		stream.WriteObjectEnd()
 | |
| 		ci++
 | |
| 	}
 | |
| 
 | |
| 	return manageMemory(stream)
 | |
| }
 | |
| 
 | |
| // FromJSON clears s and reads a JSON formatted set structure.
 | |
| func (s *Set) FromJSON(r io.Reader) error {
 | |
| 	// The iterator pool is completely useless for memory management, grrr.
 | |
| 	iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, r, 4096)
 | |
| 
 | |
| 	found, _ := readIterV1(iter)
 | |
| 	if found == nil {
 | |
| 		*s = Set{}
 | |
| 	} else {
 | |
| 		*s = *found
 | |
| 	}
 | |
| 	return iter.Error
 | |
| }
 | |
| 
 | |
| // returns true if this subtree is also (or only) a member of parent; s is nil
 | |
| // if there are no further children.
 | |
| func readIterV1(iter *jsoniter.Iterator) (children *Set, isMember bool) {
 | |
| 	iter.ReadMapCB(func(iter *jsoniter.Iterator, key string) bool {
 | |
| 		if key == "." {
 | |
| 			isMember = true
 | |
| 			iter.Skip()
 | |
| 			return true
 | |
| 		}
 | |
| 		pe, err := DeserializePathElement(key)
 | |
| 		if err == ErrUnknownPathElementType {
 | |
| 			// Ignore these-- a future version maybe knows what
 | |
| 			// they are. We drop these completely rather than try
 | |
| 			// to preserve things we don't understand.
 | |
| 			iter.Skip()
 | |
| 			return true
 | |
| 		} else if err != nil {
 | |
| 			iter.ReportError("parsing key as path element", err.Error())
 | |
| 			iter.Skip()
 | |
| 			return true
 | |
| 		}
 | |
| 		grandchildren, childIsMember := readIterV1(iter)
 | |
| 		if childIsMember {
 | |
| 			if children == nil {
 | |
| 				children = &Set{}
 | |
| 			}
 | |
| 			m := &children.Members.members
 | |
| 			// Since we expect that most of the time these will have been
 | |
| 			// serialized in the right order, we just verify that and append.
 | |
| 			appendOK := len(*m) == 0 || (*m)[len(*m)-1].Less(pe)
 | |
| 			if appendOK {
 | |
| 				*m = append(*m, pe)
 | |
| 			} else {
 | |
| 				children.Members.Insert(pe)
 | |
| 			}
 | |
| 		}
 | |
| 		if grandchildren != nil {
 | |
| 			if children == nil {
 | |
| 				children = &Set{}
 | |
| 			}
 | |
| 			// Since we expect that most of the time these will have been
 | |
| 			// serialized in the right order, we just verify that and append.
 | |
| 			m := &children.Children.members
 | |
| 			appendOK := len(*m) == 0 || (*m)[len(*m)-1].pathElement.Less(pe)
 | |
| 			if appendOK {
 | |
| 				*m = append(*m, setNode{pe, grandchildren})
 | |
| 			} else {
 | |
| 				*children.Children.Descend(pe) = *grandchildren
 | |
| 			}
 | |
| 		}
 | |
| 		return true
 | |
| 	})
 | |
| 	if children == nil {
 | |
| 		isMember = true
 | |
| 	}
 | |
| 
 | |
| 	return children, isMember
 | |
| }
 |