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  }