github.com/dgraph-io/simdjson-go@v0.3.0/parsed_array.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  	"math"
    23  )
    24  
    25  // Array represents a JSON array.
    26  // There are methods that allows to get full arrays if the value type is the same.
    27  // Otherwise an iterator can be retrieved.
    28  type Array struct {
    29  	tape ParsedJson
    30  	off  int
    31  }
    32  
    33  // Iter returns the array as an iterator.
    34  // This can be used for parsing mixed content arrays.
    35  // The first value is ready with a call to Advance.
    36  // Calling after last element should have TypeNone.
    37  func (a *Array) Iter() Iter {
    38  	i := Iter{
    39  		tape: a.tape,
    40  		off:  a.off,
    41  	}
    42  	return i
    43  }
    44  
    45  // FirstType will return the type of the first element.
    46  // If there are no elements, TypeNone is returned.
    47  func (a *Array) FirstType() Type {
    48  	iter := a.Iter()
    49  	return iter.PeekNext()
    50  }
    51  
    52  // MarshalJSON will marshal the entire remaining scope of the iterator.
    53  func (a *Array) MarshalJSON() ([]byte, error) {
    54  	return a.MarshalJSONBuffer(nil)
    55  }
    56  
    57  // MarshalJSONBuffer will marshal all elements.
    58  // An optional buffer can be provided for fewer allocations.
    59  // Output will be appended to the destination.
    60  func (a *Array) MarshalJSONBuffer(dst []byte) ([]byte, error) {
    61  	dst = append(dst, '[')
    62  	i := a.Iter()
    63  	var elem Iter
    64  	for {
    65  		t, err := i.AdvanceIter(&elem)
    66  		if err != nil {
    67  			return nil, err
    68  		}
    69  		if t == TypeNone {
    70  			break
    71  		}
    72  		dst, err = elem.MarshalJSONBuffer(dst)
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  		if i.PeekNextTag() == TagArrayEnd {
    77  			break
    78  		}
    79  		dst = append(dst, ',')
    80  	}
    81  	if i.PeekNextTag() != TagArrayEnd {
    82  		return nil, errors.New("expected TagArrayEnd as final tag in array")
    83  	}
    84  	dst = append(dst, ']')
    85  	return dst, nil
    86  }
    87  
    88  // Interface returns the array as a slice of interfaces.
    89  // See Iter.Interface() for a reference on value types.
    90  func (a *Array) Interface() ([]interface{}, error) {
    91  	// Estimate length. Assume one value per element.
    92  	lenEst := (len(a.tape.Tape) - a.off - 1) / 2
    93  	if lenEst < 0 {
    94  		lenEst = 0
    95  	}
    96  	dst := make([]interface{}, 0, lenEst)
    97  	i := a.Iter()
    98  	for i.Advance() != TypeNone {
    99  		elem, err := i.Interface()
   100  		if err != nil {
   101  			return nil, err
   102  		}
   103  		dst = append(dst, elem)
   104  	}
   105  	return dst, nil
   106  }
   107  
   108  // AsFloat returns the array values as float.
   109  // Integers are automatically converted to float.
   110  func (a *Array) AsFloat() ([]float64, error) {
   111  	// Estimate length
   112  	lenEst := (len(a.tape.Tape) - a.off - 1) / 2
   113  	if lenEst < 0 {
   114  		lenEst = 0
   115  	}
   116  	dst := make([]float64, 0, lenEst)
   117  
   118  readArray:
   119  	for {
   120  		tag := Tag(a.tape.Tape[a.off] >> 56)
   121  		a.off++
   122  		switch tag {
   123  		case TagFloat:
   124  			if len(a.tape.Tape) <= a.off {
   125  				return nil, errors.New("corrupt input: expected float, but no more values")
   126  			}
   127  			dst = append(dst, math.Float64frombits(a.tape.Tape[a.off]))
   128  		case TagInteger:
   129  			if len(a.tape.Tape) <= a.off {
   130  				return nil, errors.New("corrupt input: expected integer, but no more values")
   131  			}
   132  			dst = append(dst, float64(int64(a.tape.Tape[a.off])))
   133  		case TagUint:
   134  			if len(a.tape.Tape) <= a.off {
   135  				return nil, errors.New("corrupt input: expected integer, but no more values")
   136  			}
   137  			dst = append(dst, float64(a.tape.Tape[a.off]))
   138  		case TagArrayEnd:
   139  			break readArray
   140  		default:
   141  			return nil, fmt.Errorf("unable to convert type %v to float", tag)
   142  		}
   143  		a.off++
   144  	}
   145  	return dst, nil
   146  }
   147  
   148  // AsInteger returns the array values as int64 values.
   149  // Uints/Floats are automatically converted to int64 if they fit within the range.
   150  func (a *Array) AsInteger() ([]int64, error) {
   151  	// Estimate length
   152  	lenEst := (len(a.tape.Tape) - a.off - 1) / 2
   153  	if lenEst < 0 {
   154  		lenEst = 0
   155  	}
   156  	dst := make([]int64, 0, lenEst)
   157  readArray:
   158  	for {
   159  		tag := Tag(a.tape.Tape[a.off] >> 56)
   160  		a.off++
   161  		switch tag {
   162  		case TagFloat:
   163  			if len(a.tape.Tape) <= a.off {
   164  				return nil, errors.New("corrupt input: expected float, but no more values")
   165  			}
   166  			val := math.Float64frombits(a.tape.Tape[a.off])
   167  			if val > math.MaxInt64 {
   168  				return nil, errors.New("float value overflows int64")
   169  			}
   170  			if val < math.MinInt64 {
   171  				return nil, errors.New("float value underflows int64")
   172  			}
   173  			dst = append(dst, int64(val))
   174  		case TagInteger:
   175  			if len(a.tape.Tape) <= a.off {
   176  				return nil, errors.New("corrupt input: expected integer, but no more values")
   177  			}
   178  			dst = append(dst, int64(a.tape.Tape[a.off]))
   179  		case TagUint:
   180  			if len(a.tape.Tape) <= a.off {
   181  				return nil, errors.New("corrupt input: expected integer, but no more values")
   182  			}
   183  
   184  			val := a.tape.Tape[a.off]
   185  			if val > math.MaxInt64 {
   186  				return nil, errors.New("unsigned integer value overflows int64")
   187  			}
   188  
   189  			dst = append(dst)
   190  		case TagArrayEnd:
   191  			break readArray
   192  		default:
   193  			return nil, fmt.Errorf("unable to convert type %v to integer", tag)
   194  		}
   195  		a.off++
   196  	}
   197  	return dst, nil
   198  }
   199  
   200  // AsUint64 returns the array values as float.
   201  // Uints/Floats are automatically converted to uint64 if they fit within the range.
   202  func (a *Array) AsUint64() ([]uint64, error) {
   203  	// Estimate length
   204  	lenEst := (len(a.tape.Tape) - a.off - 1) / 2
   205  	if lenEst < 0 {
   206  		lenEst = 0
   207  	}
   208  	dst := make([]uint64, 0, lenEst)
   209  readArray:
   210  	for {
   211  		tag := Tag(a.tape.Tape[a.off] >> 56)
   212  		a.off++
   213  		switch tag {
   214  		case TagFloat:
   215  			if len(a.tape.Tape) <= a.off {
   216  				return nil, errors.New("corrupt input: expected float, but no more values")
   217  			}
   218  			val := math.Float64frombits(a.tape.Tape[a.off])
   219  			if val > math.MaxInt64 {
   220  				return nil, errors.New("float value overflows uint64")
   221  			}
   222  			if val < 0 {
   223  				return nil, errors.New("float value is negative")
   224  			}
   225  			dst = append(dst, uint64(val))
   226  		case TagInteger:
   227  			if len(a.tape.Tape) <= a.off {
   228  				return nil, errors.New("corrupt input: expected integer, but no more values")
   229  			}
   230  			val := int64(a.tape.Tape[a.off])
   231  			if val < 0 {
   232  				return nil, errors.New("int64 value is negative")
   233  			}
   234  			dst = append(dst, uint64(val))
   235  		case TagUint:
   236  			if len(a.tape.Tape) <= a.off {
   237  				return nil, errors.New("corrupt input: expected integer, but no more values")
   238  			}
   239  
   240  			dst = append(dst, a.tape.Tape[a.off])
   241  		case TagArrayEnd:
   242  			break readArray
   243  		default:
   244  			return nil, fmt.Errorf("unable to convert type %v to integer", tag)
   245  		}
   246  		a.off++
   247  	}
   248  	return dst, nil
   249  }
   250  
   251  // AsString returns the array values as a slice of strings.
   252  // No conversion is done.
   253  func (a *Array) AsString() ([]string, error) {
   254  	// Estimate length
   255  	lenEst := len(a.tape.Tape) - a.off - 1
   256  	if lenEst < 0 {
   257  		lenEst = 0
   258  	}
   259  	dst := make([]string, 0, lenEst)
   260  	i := a.Iter()
   261  	var elem Iter
   262  	for {
   263  		t, err := i.AdvanceIter(&elem)
   264  		if err != nil {
   265  			return nil, err
   266  		}
   267  		switch t {
   268  		case TypeNone:
   269  			return dst, nil
   270  		case TypeString:
   271  			s, err := elem.String()
   272  			if err != nil {
   273  				return nil, err
   274  			}
   275  			dst = append(dst, s)
   276  		default:
   277  			return nil, fmt.Errorf("element in array is not string, but %v", t)
   278  		}
   279  	}
   280  }
   281  
   282  // AsStringCvt returns the array values as a slice of strings.
   283  // Scalar types are converted.
   284  // Root, Object and Arrays are not supported an will return an error if found.
   285  func (a *Array) AsStringCvt() ([]string, error) {
   286  	// Estimate length
   287  	lenEst := len(a.tape.Tape) - a.off - 1
   288  	if lenEst < 0 {
   289  		lenEst = 0
   290  	}
   291  	dst := make([]string, 0, lenEst)
   292  	i := a.Iter()
   293  	var elem Iter
   294  	for {
   295  		t, err := i.AdvanceIter(&elem)
   296  		if err != nil {
   297  			return nil, err
   298  		}
   299  		switch t {
   300  		case TypeNone:
   301  			return dst, nil
   302  		default:
   303  			s, err := elem.StringCvt()
   304  			if err != nil {
   305  				return nil, err
   306  			}
   307  			dst = append(dst, s)
   308  		}
   309  	}
   310  }