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 }