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