@@ -17,103 +17,70 @@ limitations under the License.
1717package fieldpath
1818
1919import (
20+ "bytes"
2021 "errors"
2122 "fmt"
22- "io"
2323 "strconv"
2424 "strings"
2525
26- jsoniter "github.com/json-iterator/go "
26+ "github.com/go- json-experiment/json "
2727 "sigs.k8s.io/structured-merge-diff/v6/value"
2828)
2929
3030var ErrUnknownPathElementType = errors .New ("unknown path element type" )
3131
3232const (
3333 // Field indicates that the content of this path element is a field's name
34- peField = "f"
34+ peField = 'f'
3535
3636 // Value indicates that the content of this path element is a field's value
37- peValue = "v"
37+ peValue = 'v'
3838
3939 // Index indicates that the content of this path element is an index in an array
40- peIndex = "i"
40+ peIndex = 'i'
4141
4242 // Key indicates that the content of this path element is a key value map
43- peKey = "k"
43+ peKey = 'k'
4444
4545 // Separator separates the type of a path element from the contents
46- peSeparator = ":"
46+ peSeparator = ':'
4747)
4848
4949var (
50- peFieldSepBytes = []byte (peField + peSeparator )
51- peValueSepBytes = []byte (peValue + peSeparator )
52- peIndexSepBytes = []byte (peIndex + peSeparator )
53- peKeySepBytes = []byte (peKey + peSeparator )
54- peSepBytes = []byte (peSeparator )
50+ peFieldSepBytes = []byte {peField , peSeparator }
51+ peValueSepBytes = []byte {peValue , peSeparator }
52+ peIndexSepBytes = []byte {peIndex , peSeparator }
53+ peKeySepBytes = []byte {peKey , peSeparator }
5554)
5655
57- // readJSONIter reads a Value from a JSON iterator.
58- // DO NOT EXPORT
59- // TODO: eliminate this https://github.com/kubernetes-sigs/structured-merge-diff/issues/202
60- func readJSONIter (iter * jsoniter.Iterator ) (value.Value , error ) {
61- v := iter .Read ()
62- if iter .Error != nil && iter .Error != io .EOF {
63- return nil , iter .Error
64- }
65- return value .NewValueInterface (v ), nil
66- }
67-
68- // writeJSONStream writes a value into a JSON stream.
69- // DO NOT EXPORT
70- // TODO: eliminate this https://github.com/kubernetes-sigs/structured-merge-diff/issues/202
71- func writeJSONStream (v value.Value , stream * jsoniter.Stream ) {
72- stream .WriteVal (v .Unstructured ())
73- }
74-
7556// DeserializePathElement parses a serialized path element
7657func DeserializePathElement (s string ) (PathElement , error ) {
77- b := []byte (s )
78- if len (b ) < 2 {
79- return PathElement {}, errors .New ("key must be 2 characters long:" )
58+ if len (s ) < 2 {
59+ return PathElement {}, errors .New ("key must be 2 characters long" )
8060 }
81- typeSep , b := b [: 2 ], b [ 2 : ]
82- if typeSep [ 1 ] != peSepBytes [ 0 ] {
61+ typeSep0 , typeSep1 := s [ 0 ], s [ 1 ]
62+ if typeSep1 != peSeparator {
8363 return PathElement {}, fmt .Errorf ("missing colon: %v" , s )
8464 }
85- switch typeSep [ 0 ] {
65+ switch typeSep0 {
8666 case peFieldSepBytes [0 ]:
87- // Slice s rather than convert b, to save on
88- // allocations.
8967 str := s [2 :]
9068 return PathElement {
9169 FieldName : & str ,
9270 }, nil
9371 case peValueSepBytes [0 ]:
94- iter := readPool .BorrowIterator (b )
95- defer readPool .ReturnIterator (iter )
96- v , err := readJSONIter (iter )
97- if err != nil {
72+ var v any
73+ if err := json .UnmarshalRead (strings .NewReader (s [2 :]), & v ); err != nil {
9874 return PathElement {}, err
9975 }
100- return PathElement {Value : & v }, nil
76+ interfaceValue := value .NewValueInterface (v )
77+ return PathElement {Value : & interfaceValue }, nil
10178 case peKeySepBytes [0 ]:
102- iter := readPool .BorrowIterator (b )
103- defer readPool .ReturnIterator (iter )
104- fields := value.FieldList {}
105-
106- iter .ReadObjectCB (func (iter * jsoniter.Iterator , key string ) bool {
107- v , err := readJSONIter (iter )
108- if err != nil {
109- iter .Error = err
110- return false
111- }
112- fields = append (fields , value.Field {Name : key , Value : v })
113- return true
114- })
115- fields .Sort ()
116- return PathElement {Key : & fields }, iter .Error
79+ var fields value.FieldList
80+ if err := json .UnmarshalRead (strings .NewReader (s [2 :]), & fields ); err != nil {
81+ return PathElement {}, err
82+ }
83+ return PathElement {Key : & fields }, nil
11784 case peIndexSepBytes [0 ]:
11885 i , err := strconv .Atoi (s [2 :])
11986 if err != nil {
@@ -127,60 +94,58 @@ func DeserializePathElement(s string) (PathElement, error) {
12794 }
12895}
12996
130- var (
131- readPool = jsoniter .NewIterator (jsoniter .ConfigCompatibleWithStandardLibrary ).Pool ()
132- writePool = jsoniter .NewStream (jsoniter .ConfigCompatibleWithStandardLibrary , nil , 1024 ).Pool ()
133- )
134-
13597// SerializePathElement serializes a path element
13698func SerializePathElement (pe PathElement ) (string , error ) {
137- buf := strings.Builder {}
138- err := serializePathElementToWriter (& buf , pe )
139- return buf .String (), err
99+ serializer := pathElementSerializer {}
100+ if err := serializer .serialize (pe ); err != nil {
101+ return "" , err
102+ }
103+ return serializer .builder .String (), nil
140104}
141105
142- func serializePathElementToWriter (w io.Writer , pe PathElement ) error {
143- stream := writePool .BorrowStream (w )
144- defer writePool .ReturnStream (stream )
106+ type pathElementSerializer struct {
107+ builder bytes.Buffer
108+ fastValue value.FastMarshalValue
109+ }
110+
111+ func (pes * pathElementSerializer ) reset () {
112+ pes .builder .Reset ()
113+ pes .fastValue .Value = nil
114+ }
115+
116+ func (pes * pathElementSerializer ) serialize (pe PathElement ) error {
145117 switch {
146118 case pe .FieldName != nil :
147- if _ , err := stream .Write (peFieldSepBytes ); err != nil {
119+ if _ , err := pes .builder .Write (peFieldSepBytes ); err != nil {
120+ return err
121+ }
122+ if _ , err := pes .builder .WriteString (* pe .FieldName ); err != nil {
148123 return err
149124 }
150- stream .WriteRaw (* pe .FieldName )
151125 case pe .Key != nil :
152- if _ , err := stream .Write (peKeySepBytes ); err != nil {
126+ if _ , err := pes . builder .Write (peKeySepBytes ); err != nil {
153127 return err
154128 }
155- stream .WriteObjectStart ()
156-
157- for i , field := range * pe .Key {
158- if i > 0 {
159- stream .WriteMore ()
160- }
161- stream .WriteObjectField (field .Name )
162- writeJSONStream (field .Value , stream )
129+ if err := json .MarshalWrite (& pes .builder , pe .Key , json .Deterministic (true )); err != nil {
130+ return err
163131 }
164- stream .WriteObjectEnd ()
165132 case pe .Value != nil :
166- if _ , err := stream .Write (peValueSepBytes ); err != nil {
133+ if _ , err := pes .builder .Write (peValueSepBytes ); err != nil {
134+ return err
135+ }
136+ pes .fastValue .Value = pe .Value
137+ if err := json .MarshalWrite (& pes .builder , & pes .fastValue , json .Deterministic (true )); err != nil {
167138 return err
168139 }
169- writeJSONStream (* pe .Value , stream )
170140 case pe .Index != nil :
171- if _ , err := stream .Write (peIndexSepBytes ); err != nil {
141+ if _ , err := pes .builder .Write (peIndexSepBytes ); err != nil {
142+ return err
143+ }
144+ if _ , err := pes .builder .WriteString (strconv .Itoa (* pe .Index )); err != nil {
172145 return err
173146 }
174- stream .WriteInt (* pe .Index )
175147 default :
176148 return errors .New ("invalid PathElement" )
177149 }
178- b := stream .Buffer ()
179- err := stream .Flush ()
180- // Help jsoniter manage its buffers--without this, the next
181- // use of the stream is likely to require an allocation. Look
182- // at the jsoniter stream code to understand why. They were probably
183- // optimizing for folks using the buffer directly.
184- stream .SetBuffer (b [:0 ])
185- return err
150+ return nil
186151}
0 commit comments