github.com/dgraph-io/simdjson-go@v0.3.0/parsed_object.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2020 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package simdjson 18 19 import ( 20 "errors" 21 "fmt" 22 ) 23 24 // Object represents a JSON object. 25 type Object struct { 26 // Complete tape 27 tape ParsedJson 28 29 // offset of the next entry to be decoded 30 off int 31 } 32 33 // Map will unmarshal into a map[string]interface{} 34 // See Iter.Interface() for a reference on value types. 35 func (o *Object) Map(dst map[string]interface{}) (map[string]interface{}, error) { 36 if dst == nil { 37 dst = make(map[string]interface{}) 38 } 39 var tmp Iter 40 for { 41 name, t, err := o.NextElement(&tmp) 42 if err != nil { 43 return nil, err 44 } 45 if t == TypeNone { 46 // Done 47 break 48 } 49 dst[name], err = tmp.Interface() 50 if err != nil { 51 return nil, fmt.Errorf("parsing element %q: %w", name, err) 52 } 53 } 54 return dst, nil 55 } 56 57 // Parse will return all elements and iterators. 58 // An optional destination can be given. 59 // The Object will be consumed. 60 func (o *Object) Parse(dst *Elements) (*Elements, error) { 61 if dst == nil { 62 dst = &Elements{ 63 Elements: make([]Element, 0, 5), 64 Index: make(map[string]int, 5), 65 } 66 } else { 67 dst.Elements = dst.Elements[:0] 68 for k := range dst.Index { 69 delete(dst.Index, k) 70 } 71 } 72 var tmp Iter 73 for { 74 name, t, err := o.NextElement(&tmp) 75 if err != nil { 76 return dst, err 77 } 78 if t == TypeNone { 79 // Done 80 break 81 } 82 dst.Index[name] = len(dst.Elements) 83 dst.Elements = append(dst.Elements, Element{ 84 Name: name, 85 Type: t, 86 Iter: tmp, 87 }) 88 } 89 return dst, nil 90 } 91 92 // FindKey will return a single named element. 93 // An optional destination can be given. 94 // The method will return nil if the element cannot be found. 95 // This should only be used to locate a single key where the object is no longer needed. 96 // The object will not be advanced. 97 func (o *Object) FindKey(key string, dst *Element) *Element { 98 tmp := o.tape.Iter() 99 tmp.off = o.off 100 for { 101 typ := tmp.Advance() 102 // We want name and at least one value. 103 if typ != TypeString || tmp.off+1 >= len(tmp.tape.Tape) { 104 return nil 105 } 106 // Advance must be string or end of object 107 offset := tmp.cur 108 length := tmp.tape.Tape[tmp.off] 109 if int(length) != len(key) { 110 // Skip the value. 111 t := tmp.Advance() 112 if t == TypeNone { 113 return nil 114 } 115 continue 116 } 117 // Read name 118 name, err := tmp.tape.stringByteAt(offset, length) 119 if err != nil { 120 return nil 121 } 122 123 if string(name) != key { 124 // Skip the value 125 tmp.Advance() 126 continue 127 } 128 if dst == nil { 129 dst = &Element{} 130 } 131 dst.Name = key 132 dst.Type, err = tmp.AdvanceIter(&dst.Iter) 133 if err != nil { 134 return nil 135 } 136 return dst 137 } 138 } 139 140 // NextElement sets dst to the next element and returns the name. 141 // TypeNone with nil error will be returned if there are no more elements. 142 func (o *Object) NextElement(dst *Iter) (name string, t Type, err error) { 143 n, t, err := o.NextElementBytes(dst) 144 return string(n), t, err 145 } 146 147 // NextElementBytes sets dst to the next element and returns the name. 148 // TypeNone with nil error will be returned if there are no more elements. 149 // Contrary to NextElement this will not cause allocations. 150 func (o *Object) NextElementBytes(dst *Iter) (name []byte, t Type, err error) { 151 if o.off >= len(o.tape.Tape) { 152 return nil, TypeNone, nil 153 } 154 // Advance must be string or end of object 155 v := o.tape.Tape[o.off] 156 switch Tag(v >> 56) { 157 case TagString: 158 // Read name: 159 // We want name and at least one value. 160 if o.off+2 >= len(o.tape.Tape) { 161 return nil, TypeNone, fmt.Errorf("parsing object element name: unexpected end of tape") 162 } 163 length := o.tape.Tape[o.off+1] 164 offset := v & JSONVALUEMASK 165 name, err = o.tape.stringByteAt(offset, length) 166 if err != nil { 167 return nil, TypeNone, fmt.Errorf("parsing object element name: %w", err) 168 } 169 o.off += 2 170 case TagObjectEnd: 171 return nil, TypeNone, nil 172 default: 173 return nil, TypeNone, fmt.Errorf("object: unexpected tag %c", byte(v>>56)) 174 } 175 176 // Read element type 177 v = o.tape.Tape[o.off] 178 // Move to value (if any) 179 o.off++ 180 181 // Set dst 182 dst.cur = v & JSONVALUEMASK 183 dst.t = Tag(v >> 56) 184 dst.off = o.off 185 dst.tape = o.tape 186 dst.calcNext(false) 187 elemSize := dst.addNext 188 dst.calcNext(true) 189 if dst.off+elemSize > len(dst.tape.Tape) { 190 return nil, TypeNone, errors.New("element extends beyond tape") 191 } 192 dst.tape.Tape = dst.tape.Tape[:dst.off+elemSize] 193 194 // Skip to next element 195 o.off += elemSize 196 return name, TagToType[dst.t], nil 197 } 198 199 // Element represents an element in an object. 200 type Element struct { 201 // Name of the element 202 Name string 203 // Type of the element 204 Type Type 205 // Iter containing the element 206 Iter Iter 207 } 208 209 // Elements contains all elements in an object 210 // kept in original order. 211 // And index contains lookup for object keys. 212 type Elements struct { 213 Elements []Element 214 Index map[string]int 215 } 216 217 // Lookup a key in elements and return the element. 218 // Returns nil if key doesn't exist. 219 // Keys are case sensitive. 220 func (e Elements) Lookup(key string) *Element { 221 idx, ok := e.Index[key] 222 if !ok { 223 return nil 224 } 225 return &e.Elements[idx] 226 } 227 228 // MarshalJSON will marshal the entire remaining scope of the iterator. 229 func (e Elements) MarshalJSON() ([]byte, error) { 230 return e.MarshalJSONBuffer(nil) 231 } 232 233 // MarshalJSONBuffer will marshal all elements. 234 // An optional buffer can be provided for fewer allocations. 235 // Output will be appended to the destination. 236 func (e Elements) MarshalJSONBuffer(dst []byte) ([]byte, error) { 237 dst = append(dst, '{') 238 for i, elem := range e.Elements { 239 dst = append(dst, '"') 240 dst = escapeBytes(dst, []byte(elem.Name)) 241 dst = append(dst, '"', ':') 242 var err error 243 dst, err = elem.Iter.MarshalJSONBuffer(dst) 244 if err != nil { 245 return nil, err 246 } 247 if i < len(e.Elements)-1 { 248 dst = append(dst, ',') 249 } 250 } 251 dst = append(dst, '}') 252 return dst, nil 253 }