github.com/solo-io/cue@v0.4.7/internal/third_party/yaml/yaml.go (about)

     1  // Package yaml implements YAML support for the Go language.
     2  //
     3  // Source code and other details for the project are available at GitHub:
     4  //
     5  //   https://github.com/go-yaml/yaml
     6  //
     7  package yaml // import "github.com/solo-io/cue/internal/third_party/yaml"
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"reflect"
    14  	"strconv"
    15  	"strings"
    16  	"sync"
    17  
    18  	"github.com/solo-io/cue/cue/ast"
    19  )
    20  
    21  // MapSlice encodes and decodes as a YAML map.
    22  // The order of keys is preserved when encoding and decoding.
    23  type MapSlice []MapItem
    24  
    25  // MapItem is an item in a MapSlice.
    26  type MapItem struct {
    27  	Key, Value interface{}
    28  }
    29  
    30  // The Unmarshaler interface may be implemented by types to customize their
    31  // behavior when being unmarshaled from a YAML document. The UnmarshalYAML
    32  // method receives a function that may be called to unmarshal the original
    33  // YAML value into a field or variable. It is safe to call the unmarshal
    34  // function parameter more than once if necessary.
    35  type Unmarshaler interface {
    36  	UnmarshalYAML(unmarshal func(interface{}) error) error
    37  }
    38  
    39  // The Marshaler interface may be implemented by types to customize their
    40  // behavior when being marshaled into a YAML document. The returned value
    41  // is marshaled in place of the original value implementing Marshaler.
    42  //
    43  // If an error is returned by MarshalYAML, the marshaling procedure stops
    44  // and returns with the provided error.
    45  type Marshaler interface {
    46  	MarshalYAML() (interface{}, error)
    47  }
    48  
    49  // Unmarshal decodes the first document found within the in byte slice
    50  // and assigns decoded values into the out value.
    51  //
    52  // Maps and pointers (to a struct, string, int, etc) are accepted as out
    53  // values. If an internal pointer within a struct is not initialized,
    54  // the yaml package will initialize it if necessary for unmarshalling
    55  // the provided data. The out parameter must not be nil.
    56  //
    57  // The type of the decoded values should be compatible with the respective
    58  // values in out. If one or more values cannot be decoded due to a type
    59  // mismatches, decoding continues partially until the end of the YAML
    60  // content, and a *yaml.TypeError is returned with details for all
    61  // missed values.
    62  //
    63  // Struct fields are only unmarshalled if they are exported (have an
    64  // upper case first letter), and are unmarshalled using the field name
    65  // lowercased as the default key. Custom keys may be defined via the
    66  // "yaml" name in the field tag: the content preceding the first comma
    67  // is used as the key, and the following comma-separated options are
    68  // used to tweak the marshalling process (see Marshal).
    69  // Conflicting names result in a runtime error.
    70  //
    71  // For example:
    72  //
    73  //     type T struct {
    74  //         F int `yaml:"a,omitempty"`
    75  //         B int
    76  //     }
    77  //     var t T
    78  //     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
    79  //
    80  // See the documentation of Marshal for the format of tags and a list of
    81  // supported tag options.
    82  //
    83  func Unmarshal(filename string, in []byte) (expr ast.Expr, err error) {
    84  	return unmarshal(filename, in)
    85  }
    86  
    87  // A Decorder reads and decodes YAML values from an input stream.
    88  type Decoder struct {
    89  	strict    bool
    90  	firstDone bool
    91  	parser    *parser
    92  }
    93  
    94  // NewDecoder returns a new decoder that reads from r.
    95  //
    96  // The decoder introduces its own buffering and may read
    97  // data from r beyond the YAML values requested.
    98  func NewDecoder(filename string, src interface{}) (*Decoder, error) {
    99  	d, err := newParser(filename, src)
   100  	if err != nil {
   101  		return nil, err
   102  	}
   103  	return &Decoder{parser: d}, nil
   104  }
   105  
   106  // Decode reads the next YAML-encoded value from its input and stores it in the
   107  // value pointed to by v. It returns io.EOF if there are no more value in the
   108  // stream.
   109  //
   110  // See the documentation for Unmarshal for details about the conversion of YAML
   111  // into a Go value.
   112  func (dec *Decoder) Decode() (expr ast.Expr, err error) {
   113  	d := newDecoder(dec.parser)
   114  	defer handleErr(&err)
   115  	node := dec.parser.parse()
   116  	if node == nil {
   117  		if !dec.firstDone {
   118  			expr = ast.NewNull()
   119  		}
   120  		return expr, io.EOF
   121  	}
   122  	dec.firstDone = true
   123  	expr = d.unmarshal(node)
   124  	if len(d.terrors) > 0 {
   125  		return nil, &TypeError{d.terrors}
   126  	}
   127  	return expr, nil
   128  }
   129  
   130  func unmarshal(filename string, in []byte) (expr ast.Expr, err error) {
   131  	defer handleErr(&err)
   132  	p, err := newParser(filename, in)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  	defer p.destroy()
   137  	node := p.parse()
   138  	d := newDecoder(p)
   139  	if node != nil {
   140  		expr = d.unmarshal(node)
   141  	}
   142  	if len(d.terrors) > 0 {
   143  		return nil, &TypeError{d.terrors}
   144  	}
   145  	return expr, nil
   146  }
   147  
   148  func handleErr(err *error) {
   149  	if v := recover(); v != nil {
   150  		if e, ok := v.(yamlError); ok {
   151  			*err = e.err
   152  		} else {
   153  			panic(v)
   154  		}
   155  	}
   156  }
   157  
   158  type yamlError struct {
   159  	err error
   160  }
   161  
   162  func (p *parser) failf(line int, format string, args ...interface{}) {
   163  	where := p.parser.filename + ":"
   164  	line++
   165  	where += strconv.Itoa(line) + ": "
   166  	panic(yamlError{fmt.Errorf(where+format, args...)})
   167  }
   168  
   169  // A TypeError is returned by Unmarshal when one or more fields in
   170  // the YAML document cannot be properly decoded into the requested
   171  // types. When this error is returned, the value is still
   172  // unmarshaled partially.
   173  type TypeError struct {
   174  	Errors []string
   175  }
   176  
   177  func (e *TypeError) Error() string {
   178  	return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))
   179  }
   180  
   181  // --------------------------------------------------------------------------
   182  // Maintain a mapping of keys to structure field indexes
   183  
   184  // The code in this section was copied from mgo/bson.
   185  
   186  // structInfo holds details for the serialization of fields of
   187  // a given struct.
   188  type structInfo struct {
   189  	FieldsMap  map[string]fieldInfo
   190  	FieldsList []fieldInfo
   191  
   192  	// InlineMap is the number of the field in the struct that
   193  	// contains an ,inline map, or -1 if there's none.
   194  	InlineMap int
   195  }
   196  
   197  type fieldInfo struct {
   198  	Key       string
   199  	Num       int
   200  	OmitEmpty bool
   201  	Flow      bool
   202  	// Id holds the unique field identifier, so we can cheaply
   203  	// check for field duplicates without maintaining an extra map.
   204  	Id int
   205  
   206  	// Inline holds the field index if the field is part of an inlined struct.
   207  	Inline []int
   208  }
   209  
   210  var structMap = make(map[reflect.Type]*structInfo)
   211  var fieldMapMutex sync.RWMutex
   212  
   213  func getStructInfo(st reflect.Type) (*structInfo, error) {
   214  	fieldMapMutex.RLock()
   215  	sinfo, found := structMap[st]
   216  	fieldMapMutex.RUnlock()
   217  	if found {
   218  		return sinfo, nil
   219  	}
   220  
   221  	n := st.NumField()
   222  	fieldsMap := make(map[string]fieldInfo)
   223  	fieldsList := make([]fieldInfo, 0, n)
   224  	inlineMap := -1
   225  	for i := 0; i != n; i++ {
   226  		field := st.Field(i)
   227  		if field.PkgPath != "" && !field.Anonymous {
   228  			continue // Private field
   229  		}
   230  
   231  		info := fieldInfo{Num: i}
   232  
   233  		tag := field.Tag.Get("yaml")
   234  		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
   235  			tag = string(field.Tag)
   236  		}
   237  		if tag == "-" {
   238  			continue
   239  		}
   240  
   241  		inline := false
   242  		fields := strings.Split(tag, ",")
   243  		if len(fields) > 1 {
   244  			for _, flag := range fields[1:] {
   245  				switch flag {
   246  				case "omitempty":
   247  					info.OmitEmpty = true
   248  				case "flow":
   249  					info.Flow = true
   250  				case "inline":
   251  					inline = true
   252  				default:
   253  					return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
   254  				}
   255  			}
   256  			tag = fields[0]
   257  		}
   258  
   259  		if inline {
   260  			switch field.Type.Kind() {
   261  			case reflect.Map:
   262  				if inlineMap >= 0 {
   263  					return nil, errors.New("Multiple ,inline maps in struct " + st.String())
   264  				}
   265  				if field.Type.Key() != reflect.TypeOf("") {
   266  					return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
   267  				}
   268  				inlineMap = info.Num
   269  			case reflect.Struct:
   270  				sinfo, err := getStructInfo(field.Type)
   271  				if err != nil {
   272  					return nil, err
   273  				}
   274  				for _, finfo := range sinfo.FieldsList {
   275  					if _, found := fieldsMap[finfo.Key]; found {
   276  						msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
   277  						return nil, errors.New(msg)
   278  					}
   279  					if finfo.Inline == nil {
   280  						finfo.Inline = []int{i, finfo.Num}
   281  					} else {
   282  						finfo.Inline = append([]int{i}, finfo.Inline...)
   283  					}
   284  					finfo.Id = len(fieldsList)
   285  					fieldsMap[finfo.Key] = finfo
   286  					fieldsList = append(fieldsList, finfo)
   287  				}
   288  			default:
   289  				//return nil, errors.New("Option ,inline needs a struct value or map field")
   290  				return nil, errors.New("Option ,inline needs a struct value field")
   291  			}
   292  			continue
   293  		}
   294  
   295  		if tag != "" {
   296  			info.Key = tag
   297  		} else {
   298  			info.Key = strings.ToLower(field.Name)
   299  		}
   300  
   301  		if _, found = fieldsMap[info.Key]; found {
   302  			msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
   303  			return nil, errors.New(msg)
   304  		}
   305  
   306  		info.Id = len(fieldsList)
   307  		fieldsList = append(fieldsList, info)
   308  		fieldsMap[info.Key] = info
   309  	}
   310  
   311  	sinfo = &structInfo{
   312  		FieldsMap:  fieldsMap,
   313  		FieldsList: fieldsList,
   314  		InlineMap:  inlineMap,
   315  	}
   316  
   317  	fieldMapMutex.Lock()
   318  	structMap[st] = sinfo
   319  	fieldMapMutex.Unlock()
   320  	return sinfo, nil
   321  }
   322  
   323  // IsZeroer is used to check whether an object is zero to
   324  // determine whether it should be omitted when marshaling
   325  // with the omitempty flag. One notable implementation
   326  // is time.Time.
   327  type IsZeroer interface {
   328  	IsZero() bool
   329  }
   330  
   331  func isZero(v reflect.Value) bool {
   332  	kind := v.Kind()
   333  	if z, ok := v.Interface().(IsZeroer); ok {
   334  		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
   335  			return true
   336  		}
   337  		return z.IsZero()
   338  	}
   339  	switch kind {
   340  	case reflect.String:
   341  		return len(v.String()) == 0
   342  	case reflect.Interface, reflect.Ptr:
   343  		return v.IsNil()
   344  	case reflect.Slice:
   345  		return v.Len() == 0
   346  	case reflect.Map:
   347  		return v.Len() == 0
   348  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   349  		return v.Int() == 0
   350  	case reflect.Float32, reflect.Float64:
   351  		return v.Float() == 0
   352  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   353  		return v.Uint() == 0
   354  	case reflect.Bool:
   355  		return !v.Bool()
   356  	case reflect.Struct:
   357  		vt := v.Type()
   358  		for i := v.NumField() - 1; i >= 0; i-- {
   359  			if vt.Field(i).PkgPath != "" {
   360  				continue // Private field
   361  			}
   362  			if !isZero(v.Field(i)) {
   363  				return false
   364  			}
   365  		}
   366  		return true
   367  	}
   368  	return false
   369  }