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 }