github.com/ndau/noms@v1.0.5/go/util/json/from_json.go (about)

     1  // Copyright 2016 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  package json
     6  
     7  import (
     8  	"encoding/json"
     9  	"io"
    10  	"reflect"
    11  
    12  	"github.com/ndau/noms/go/d"
    13  	"github.com/ndau/noms/go/types"
    14  )
    15  
    16  func nomsValueFromDecodedJSONBase(vrw types.ValueReadWriter, o interface{}, useStruct bool) types.Value {
    17  	switch o := o.(type) {
    18  	case string:
    19  		return types.String(o)
    20  	case bool:
    21  		return types.Bool(o)
    22  	case float64:
    23  		return types.Number(o)
    24  	case nil:
    25  		return nil
    26  	case []interface{}:
    27  		items := make([]types.Value, 0, len(o))
    28  		for _, v := range o {
    29  			nv := nomsValueFromDecodedJSONBase(vrw, v, useStruct)
    30  			if nv != nil {
    31  				items = append(items, nv)
    32  			}
    33  		}
    34  		return types.NewList(vrw, items...)
    35  	case map[string]interface{}:
    36  		var v types.Value
    37  		if useStruct {
    38  			structName := ""
    39  			fields := make(types.StructData, len(o))
    40  			for k, v := range o {
    41  				nv := nomsValueFromDecodedJSONBase(vrw, v, useStruct)
    42  				if nv != nil {
    43  					k := types.EscapeStructField(k)
    44  					fields[k] = nv
    45  				}
    46  			}
    47  			v = types.NewStruct(structName, fields)
    48  		} else {
    49  			kv := make([]types.Value, 0, len(o)*2)
    50  			for k, v := range o {
    51  				nv := nomsValueFromDecodedJSONBase(vrw, v, useStruct)
    52  				if nv != nil {
    53  					kv = append(kv, types.String(k), nv)
    54  				}
    55  			}
    56  			v = types.NewMap(vrw, kv...)
    57  		}
    58  		return v
    59  
    60  	default:
    61  		d.Chk.Fail("Nomsification failed.", "I don't understand %+v, which is of type %s!\n", o, reflect.TypeOf(o).String())
    62  	}
    63  	return nil
    64  }
    65  
    66  // NomsValueFromDecodedJSON takes a generic Go interface{} and recursively
    67  // tries to resolve the types within so that it can build up and return
    68  // a Noms Value with the same structure.
    69  //
    70  // Currently, the only types supported are the Go versions of legal JSON types:
    71  // Primitives:
    72  //  - float64
    73  //  - bool
    74  //  - string
    75  //  - nil
    76  //
    77  // Composites:
    78  //  - []interface{}
    79  //  - map[string]interface{}
    80  func NomsValueFromDecodedJSON(vrw types.ValueReadWriter, o interface{}, useStruct bool) types.Value {
    81  	return nomsValueFromDecodedJSONBase(vrw, o, useStruct)
    82  }
    83  
    84  func FromJSON(r io.Reader, vrw types.ValueReadWriter, opts FromOptions) (types.Value, error) {
    85  	dec := json.NewDecoder(r)
    86  	// TODO: This is pretty inefficient. It would be better to parse the JSON directly into Noms values,
    87  	// rather than going through a pile of Go interfaces.
    88  	var pile interface{}
    89  	err := dec.Decode(&pile)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	return NomsValueFromDecodedJSON(vrw, pile, opts.Structs), nil
    94  }
    95  
    96  // FromOptions controls how FromJSON works.
    97  type FromOptions struct {
    98  	// If true, JSON objects are decoded into Noms Structs. Otherwise, they are decoded into Maps.
    99  	Structs bool
   100  }