src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

decoder_util.go (3310B)


      1 package json
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/json"
      6 	"fmt"
      7 	"io"
      8 )
      9 
     10 // DiscardUnknownField discards unknown fields from a decoder body.
     11 // This function is useful while deserializing a JSON body with additional
     12 // unknown information that should be discarded.
     13 func DiscardUnknownField(decoder *json.Decoder) error {
     14 	// This deliberately does not share logic with CollectUnknownField, even
     15 	// though it could, because if we were to delegate to that then we'd incur
     16 	// extra allocations and general memory usage.
     17 	v, err := decoder.Token()
     18 	if err == io.EOF {
     19 		return nil
     20 	}
     21 	if err != nil {
     22 		return err
     23 	}
     24 
     25 	if _, ok := v.(json.Delim); ok {
     26 		for decoder.More() {
     27 			err = DiscardUnknownField(decoder)
     28 		}
     29 		endToken, err := decoder.Token()
     30 		if err != nil {
     31 			return err
     32 		}
     33 		if _, ok := endToken.(json.Delim); !ok {
     34 			return fmt.Errorf("invalid JSON : expected json delimiter, found %T %v",
     35 				endToken, endToken)
     36 		}
     37 	}
     38 
     39 	return nil
     40 }
     41 
     42 // CollectUnknownField grabs the contents of unknown fields from the decoder body
     43 // and returns them as a byte slice. This is useful for skipping unknown fields without
     44 // completely discarding them.
     45 func CollectUnknownField(decoder *json.Decoder) ([]byte, error) {
     46 	result, err := collectUnknownField(decoder)
     47 	if err != nil {
     48 		return nil, err
     49 	}
     50 
     51 	buff := bytes.NewBuffer(nil)
     52 	encoder := json.NewEncoder(buff)
     53 
     54 	if err := encoder.Encode(result); err != nil {
     55 		return nil, err
     56 	}
     57 
     58 	return buff.Bytes(), nil
     59 }
     60 
     61 func collectUnknownField(decoder *json.Decoder) (interface{}, error) {
     62 	// Grab the initial value. This could either be a concrete value like a string or a a
     63 	// delimiter.
     64 	token, err := decoder.Token()
     65 	if err == io.EOF {
     66 		return nil, nil
     67 	}
     68 	if err != nil {
     69 		return nil, err
     70 	}
     71 
     72 	// If it's an array or object, we'll need to recurse.
     73 	delim, ok := token.(json.Delim)
     74 	if ok {
     75 		var result interface{}
     76 		if delim == '{' {
     77 			result, err = collectUnknownObject(decoder)
     78 			if err != nil {
     79 				return nil, err
     80 			}
     81 		} else {
     82 			result, err = collectUnknownArray(decoder)
     83 			if err != nil {
     84 				return nil, err
     85 			}
     86 		}
     87 
     88 		// Discard the closing token. decoder.Token handles checking for matching delimiters
     89 		if _, err := decoder.Token(); err != nil {
     90 			return nil, err
     91 		}
     92 		return result, nil
     93 	}
     94 
     95 	return token, nil
     96 }
     97 
     98 func collectUnknownArray(decoder *json.Decoder) ([]interface{}, error) {
     99 	// We need to create an empty array here instead of a nil array, since by getting
    100 	// into this function at all we necessarily have seen a non-nil list.
    101 	array := []interface{}{}
    102 
    103 	for decoder.More() {
    104 		value, err := collectUnknownField(decoder)
    105 		if err != nil {
    106 			return nil, err
    107 		}
    108 		array = append(array, value)
    109 	}
    110 
    111 	return array, nil
    112 }
    113 
    114 func collectUnknownObject(decoder *json.Decoder) (map[string]interface{}, error) {
    115 	object := make(map[string]interface{})
    116 
    117 	for decoder.More() {
    118 		key, err := collectUnknownField(decoder)
    119 		if err != nil {
    120 			return nil, err
    121 		}
    122 
    123 		// Keys have to be strings, which is particularly important as the encoder
    124 		// won't except a map with interface{} keys
    125 		stringKey, ok := key.(string)
    126 		if !ok {
    127 			return nil, fmt.Errorf("expected string key, found %T", key)
    128 		}
    129 
    130 		value, err := collectUnknownField(decoder)
    131 		if err != nil {
    132 			return nil, err
    133 		}
    134 
    135 		object[stringKey] = value
    136 	}
    137 
    138 	return object, nil
    139 }