github.com/minio/simdjson-go@v0.4.6-0.20231116094823-04d21cddf993/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 // ForEach will call back fn for each key. 141 // A key filter can be provided for optional filtering. 142 func (o *Object) ForEach(fn func(key []byte, i Iter), onlyKeys map[string]struct{}) error { 143 tmp := o.tape.Iter() 144 tmp.off = o.off 145 n := 0 146 for { 147 typ := tmp.Advance() 148 149 // We want name and at least one value. 150 if typ != TypeString || tmp.off+1 >= len(tmp.tape.Tape) { 151 if typ == TypeNone { 152 return nil 153 } 154 return fmt.Errorf("object: unexpected name tag %v", tmp.t) 155 } 156 // Advance must be string or end of object 157 offset := tmp.cur 158 length := tmp.tape.Tape[tmp.off] 159 // Read name 160 name, err := tmp.tape.stringByteAt(offset, length) 161 if err != nil { 162 return fmt.Errorf("getting object name: %w", err) 163 } 164 165 if len(onlyKeys) > 0 { 166 if _, ok := onlyKeys[string(name)]; !ok { 167 // Skip the value 168 t := tmp.Advance() 169 if t == TypeNone { 170 return nil 171 } 172 } 173 } 174 175 t := tmp.Advance() 176 if t == TypeNone { 177 return nil 178 } 179 fn(name, tmp) 180 n++ 181 if n == len(onlyKeys) { 182 return nil 183 } 184 } 185 } 186 187 // DeleteElems will call back fn for each key. 188 // If true is returned, the key+value is deleted. 189 // A key filter can be provided for optional filtering. 190 // If fn is nil all elements in onlyKeys will be deleted. 191 // If both are nil all elements are deleted. 192 func (o *Object) DeleteElems(fn func(key []byte, i Iter) bool, onlyKeys map[string]struct{}) error { 193 tmp := o.tape.Iter() 194 tmp.off = o.off 195 n := 0 196 for { 197 typ := tmp.Advance() 198 // We want name and at least one value. 199 if typ != TypeString || tmp.off+1 >= len(tmp.tape.Tape) { 200 if typ == TypeNone { 201 return nil 202 } 203 return fmt.Errorf("object: unexpected name tag %v", tmp.t) 204 } 205 startO := tmp.off - 1 206 // Advance must be string or end of object 207 offset := tmp.cur 208 length := tmp.tape.Tape[tmp.off] 209 // Read name 210 name, err := tmp.tape.stringByteAt(offset, length) 211 if err != nil { 212 return fmt.Errorf("getting object name: %w", err) 213 } 214 215 if len(onlyKeys) > 0 { 216 if _, ok := onlyKeys[string(name)]; !ok { 217 // Skip the value 218 t := tmp.Advance() 219 if t == TypeNone { 220 return nil 221 } 222 continue 223 } 224 } 225 226 t := tmp.Advance() 227 if t == TypeNone { 228 return nil 229 } 230 if fn == nil || fn(name, tmp) { 231 end := tmp.off + tmp.addNext 232 skip := uint64(end - startO) 233 for i := startO; i < end; i++ { 234 tmp.tape.Tape[i] = (uint64(TagNop) << JSONTAGOFFSET) | skip 235 skip-- 236 } 237 } 238 n++ 239 if n == len(onlyKeys) { 240 return nil 241 } 242 } 243 } 244 245 // ErrPathNotFound is returned 246 var ErrPathNotFound = errors.New("path not found") 247 248 // FindPath allows searching for fields and objects by path. 249 // Separate each object name by /. 250 // For example `Image/Url` will search the current object for an "Image" 251 // object and return the value of the "Url" element. 252 // ErrPathNotFound is returned if any part of the path cannot be found. 253 // If the tape contains an error it will be returned. 254 // The object will not be advanced. 255 func (o *Object) FindPath(dst *Element, path ...string) (*Element, error) { 256 if len(path) == 0 { 257 return dst, ErrPathNotFound 258 } 259 tmp := o.tape.Iter() 260 tmp.off = o.off 261 key := path[0] 262 path = path[1:] 263 for { 264 typ := tmp.Advance() 265 // We want name and at least one value. 266 if typ != TypeString || tmp.off+1 >= len(tmp.tape.Tape) { 267 return dst, ErrPathNotFound 268 } 269 // Advance must be string or end of object 270 offset := tmp.cur 271 length := tmp.tape.Tape[tmp.off] 272 if int(length) != len(key) { 273 // Skip the value. 274 t := tmp.Advance() 275 if t == TypeNone { 276 // Not found... 277 return dst, ErrPathNotFound 278 } 279 continue 280 } 281 // Read name 282 name, err := tmp.tape.stringByteAt(offset, length) 283 if err != nil { 284 return dst, err 285 } 286 287 if string(name) != key { 288 // Skip the value 289 tmp.Advance() 290 continue 291 } 292 // Done... 293 if len(path) == 0 { 294 if dst == nil { 295 dst = &Element{} 296 } 297 dst.Name = key 298 dst.Type, err = tmp.AdvanceIter(&dst.Iter) 299 if err != nil { 300 return dst, err 301 } 302 return dst, nil 303 } 304 305 t, err := tmp.AdvanceIter(&tmp) 306 if err != nil { 307 return dst, err 308 } 309 if t != TypeObject { 310 return dst, fmt.Errorf("value of key %v is not an object", key) 311 } 312 key = path[0] 313 path = path[1:] 314 } 315 } 316 317 // NextElement sets dst to the next element and returns the name. 318 // TypeNone with nil error will be returned if there are no more elements. 319 func (o *Object) NextElement(dst *Iter) (name string, t Type, err error) { 320 n, t, err := o.NextElementBytes(dst) 321 return string(n), t, err 322 } 323 324 // NextElementBytes sets dst to the next element and returns the name. 325 // TypeNone with nil error will be returned if there are no more elements. 326 // Contrary to NextElement this will not cause allocations. 327 func (o *Object) NextElementBytes(dst *Iter) (name []byte, t Type, err error) { 328 if o.off >= len(o.tape.Tape) { 329 return nil, TypeNone, nil 330 } 331 // Advance must be string or end of object 332 v := o.tape.Tape[o.off] 333 switch Tag(v >> 56) { 334 case TagString: 335 // Read name: 336 // We want name and at least one value. 337 if o.off+2 >= len(o.tape.Tape) { 338 return nil, TypeNone, fmt.Errorf("parsing object element name: unexpected end of tape") 339 } 340 length := o.tape.Tape[o.off+1] 341 offset := v & JSONVALUEMASK 342 name, err = o.tape.stringByteAt(offset, length) 343 if err != nil { 344 return nil, TypeNone, fmt.Errorf("parsing object element name: %w", err) 345 } 346 o.off += 2 347 case TagObjectEnd: 348 return nil, TypeNone, nil 349 case TagNop: 350 o.off += int(v & JSONVALUEMASK) 351 return o.NextElementBytes(dst) 352 default: 353 return nil, TypeNone, fmt.Errorf("object: unexpected tag %c", byte(v>>56)) 354 } 355 356 // Read element type 357 v = o.tape.Tape[o.off] 358 // Move to value (if any) 359 o.off++ 360 361 // Set dst 362 dst.cur = v & JSONVALUEMASK 363 dst.t = Tag(v >> 56) 364 dst.off = o.off 365 dst.tape = o.tape 366 dst.calcNext(false) 367 elemSize := dst.addNext 368 dst.calcNext(true) 369 if dst.off+elemSize > len(dst.tape.Tape) { 370 return nil, TypeNone, errors.New("element extends beyond tape") 371 } 372 dst.tape.Tape = dst.tape.Tape[:dst.off+elemSize] 373 374 // Skip to next element 375 o.off += elemSize 376 return name, TagToType[dst.t], nil 377 } 378 379 // Element represents an element in an object. 380 type Element struct { 381 // Name of the element 382 Name string 383 // Type of the element 384 Type Type 385 // Iter containing the element 386 Iter Iter 387 } 388 389 // Elements contains all elements in an object 390 // kept in original order. 391 // And index contains lookup for object keys. 392 type Elements struct { 393 Elements []Element 394 Index map[string]int 395 } 396 397 // Lookup a key in elements and return the element. 398 // Returns nil if key doesn't exist. 399 // Keys are case sensitive. 400 func (e Elements) Lookup(key string) *Element { 401 idx, ok := e.Index[key] 402 if !ok { 403 return nil 404 } 405 return &e.Elements[idx] 406 } 407 408 // MarshalJSON will marshal the entire remaining scope of the iterator. 409 func (e Elements) MarshalJSON() ([]byte, error) { 410 return e.MarshalJSONBuffer(nil) 411 } 412 413 // MarshalJSONBuffer will marshal all elements. 414 // An optional buffer can be provided for fewer allocations. 415 // Output will be appended to the destination. 416 func (e Elements) MarshalJSONBuffer(dst []byte) ([]byte, error) { 417 dst = append(dst, '{') 418 for i, elem := range e.Elements { 419 dst = append(dst, '"') 420 dst = escapeBytes(dst, []byte(elem.Name)) 421 dst = append(dst, '"', ':') 422 var err error 423 dst, err = elem.Iter.MarshalJSONBuffer(dst) 424 if err != nil { 425 return nil, err 426 } 427 if i < len(e.Elements)-1 { 428 dst = append(dst, ',') 429 } 430 } 431 dst = append(dst, '}') 432 return dst, nil 433 }