1/* 2Copyright 2019 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package fieldpath 18 19import ( 20 "bytes" 21 "io" 22 "unsafe" 23 24 jsoniter "github.com/json-iterator/go" 25) 26 27func (s *Set) ToJSON() ([]byte, error) { 28 buf := bytes.Buffer{} 29 err := s.ToJSONStream(&buf) 30 if err != nil { 31 return nil, err 32 } 33 return buf.Bytes(), nil 34} 35 36func (s *Set) ToJSONStream(w io.Writer) error { 37 stream := writePool.BorrowStream(w) 38 defer writePool.ReturnStream(stream) 39 40 var r reusableBuilder 41 42 stream.WriteObjectStart() 43 err := s.emitContentsV1(false, stream, &r) 44 if err != nil { 45 return err 46 } 47 stream.WriteObjectEnd() 48 return stream.Flush() 49} 50 51func manageMemory(stream *jsoniter.Stream) error { 52 // Help jsoniter manage its buffers--without this, it does a bunch of 53 // alloctaions that are not necessary. They were probably optimizing 54 // for folks using the buffer directly. 55 b := stream.Buffer() 56 if len(b) > 4096 || cap(b)-len(b) < 2048 { 57 if err := stream.Flush(); err != nil { 58 return err 59 } 60 stream.SetBuffer(b[:0]) 61 } 62 return nil 63} 64 65type reusableBuilder struct { 66 bytes.Buffer 67} 68 69func (r *reusableBuilder) unsafeString() string { 70 b := r.Bytes() 71 return *(*string)(unsafe.Pointer(&b)) 72} 73 74func (r *reusableBuilder) reset() *bytes.Buffer { 75 r.Reset() 76 return &r.Buffer 77} 78 79func (s *Set) emitContentsV1(includeSelf bool, stream *jsoniter.Stream, r *reusableBuilder) error { 80 mi, ci := 0, 0 81 first := true 82 preWrite := func() { 83 if first { 84 first = false 85 return 86 } 87 stream.WriteMore() 88 } 89 90 if includeSelf && !(len(s.Members.members) == 0 && len(s.Children.members) == 0) { 91 preWrite() 92 stream.WriteObjectField(".") 93 stream.WriteEmptyObject() 94 } 95 96 for mi < len(s.Members.members) && ci < len(s.Children.members) { 97 mpe := s.Members.members[mi] 98 cpe := s.Children.members[ci].pathElement 99 100 if c := mpe.Compare(cpe); c < 0 { 101 preWrite() 102 if err := serializePathElementToWriter(r.reset(), mpe); err != nil { 103 return err 104 } 105 stream.WriteObjectField(r.unsafeString()) 106 stream.WriteEmptyObject() 107 mi++ 108 } else if c > 0 { 109 preWrite() 110 if err := serializePathElementToWriter(r.reset(), cpe); err != nil { 111 return err 112 } 113 stream.WriteObjectField(r.unsafeString()) 114 stream.WriteObjectStart() 115 if err := s.Children.members[ci].set.emitContentsV1(false, stream, r); err != nil { 116 return err 117 } 118 stream.WriteObjectEnd() 119 ci++ 120 } else { 121 preWrite() 122 if err := serializePathElementToWriter(r.reset(), cpe); err != nil { 123 return err 124 } 125 stream.WriteObjectField(r.unsafeString()) 126 stream.WriteObjectStart() 127 if err := s.Children.members[ci].set.emitContentsV1(true, stream, r); err != nil { 128 return err 129 } 130 stream.WriteObjectEnd() 131 mi++ 132 ci++ 133 } 134 } 135 136 for mi < len(s.Members.members) { 137 mpe := s.Members.members[mi] 138 139 preWrite() 140 if err := serializePathElementToWriter(r.reset(), mpe); err != nil { 141 return err 142 } 143 stream.WriteObjectField(r.unsafeString()) 144 stream.WriteEmptyObject() 145 mi++ 146 } 147 148 for ci < len(s.Children.members) { 149 cpe := s.Children.members[ci].pathElement 150 151 preWrite() 152 if err := serializePathElementToWriter(r.reset(), cpe); err != nil { 153 return err 154 } 155 stream.WriteObjectField(r.unsafeString()) 156 stream.WriteObjectStart() 157 if err := s.Children.members[ci].set.emitContentsV1(false, stream, r); err != nil { 158 return err 159 } 160 stream.WriteObjectEnd() 161 ci++ 162 } 163 164 return manageMemory(stream) 165} 166 167// FromJSON clears s and reads a JSON formatted set structure. 168func (s *Set) FromJSON(r io.Reader) error { 169 // The iterator pool is completely useless for memory management, grrr. 170 iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, r, 4096) 171 172 found, _ := readIterV1(iter) 173 if found == nil { 174 *s = Set{} 175 } else { 176 *s = *found 177 } 178 return iter.Error 179} 180 181// returns true if this subtree is also (or only) a member of parent; s is nil 182// if there are no further children. 183func readIterV1(iter *jsoniter.Iterator) (children *Set, isMember bool) { 184 iter.ReadMapCB(func(iter *jsoniter.Iterator, key string) bool { 185 if key == "." { 186 isMember = true 187 iter.Skip() 188 return true 189 } 190 pe, err := DeserializePathElement(key) 191 if err == ErrUnknownPathElementType { 192 // Ignore these-- a future version maybe knows what 193 // they are. We drop these completely rather than try 194 // to preserve things we don't understand. 195 iter.Skip() 196 return true 197 } else if err != nil { 198 iter.ReportError("parsing key as path element", err.Error()) 199 iter.Skip() 200 return true 201 } 202 grandchildren, childIsMember := readIterV1(iter) 203 if childIsMember { 204 if children == nil { 205 children = &Set{} 206 } 207 m := &children.Members.members 208 // Since we expect that most of the time these will have been 209 // serialized in the right order, we just verify that and append. 210 appendOK := len(*m) == 0 || (*m)[len(*m)-1].Less(pe) 211 if appendOK { 212 *m = append(*m, pe) 213 } else { 214 children.Members.Insert(pe) 215 } 216 } 217 if grandchildren != nil { 218 if children == nil { 219 children = &Set{} 220 } 221 // Since we expect that most of the time these will have been 222 // serialized in the right order, we just verify that and append. 223 m := &children.Children.members 224 appendOK := len(*m) == 0 || (*m)[len(*m)-1].pathElement.Less(pe) 225 if appendOK { 226 *m = append(*m, setNode{pe, grandchildren}) 227 } else { 228 *children.Children.Descend(pe) = *grandchildren 229 } 230 } 231 return true 232 }) 233 if children == nil { 234 isMember = true 235 } 236 237 return children, isMember 238} 239