aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/zclconf/go-cty-yaml/yaml.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zclconf/go-cty-yaml/yaml.go')
-rw-r--r--vendor/github.com/zclconf/go-cty-yaml/yaml.go215
1 files changed, 215 insertions, 0 deletions
diff --git a/vendor/github.com/zclconf/go-cty-yaml/yaml.go b/vendor/github.com/zclconf/go-cty-yaml/yaml.go
new file mode 100644
index 0000000..2c314cc
--- /dev/null
+++ b/vendor/github.com/zclconf/go-cty-yaml/yaml.go
@@ -0,0 +1,215 @@
1// Package yaml can marshal and unmarshal cty values in YAML format.
2package yaml
3
4import (
5 "errors"
6 "fmt"
7 "reflect"
8 "strings"
9 "sync"
10
11 "github.com/zclconf/go-cty/cty"
12)
13
14// Unmarshal reads the document found within the given source buffer
15// and attempts to convert it into a value conforming to the given type
16// constraint.
17//
18// This is an alias for Unmarshal on the predefined Converter in "Standard".
19//
20// An error is returned if the given source contains any YAML document
21// delimiters.
22func Unmarshal(src []byte, ty cty.Type) (cty.Value, error) {
23 return Standard.Unmarshal(src, ty)
24}
25
26// Marshal serializes the given value into a YAML document, using a fixed
27// mapping from cty types to YAML constructs.
28//
29// This is an alias for Marshal on the predefined Converter in "Standard".
30//
31// Note that unlike the function of the same name in the cty JSON package,
32// this does not take a type constraint and therefore the YAML serialization
33// cannot preserve late-bound type information in the serialization to be
34// recovered from Unmarshal. Instead, any cty.DynamicPseudoType in the type
35// constraint given to Unmarshal will be decoded as if the corresponding portion
36// of the input were processed with ImpliedType to find a target type.
37func Marshal(v cty.Value) ([]byte, error) {
38 return Standard.Marshal(v)
39}
40
41// ImpliedType analyzes the given source code and returns a suitable type that
42// it could be decoded into.
43//
44// For a converter that is using standard YAML rather than cty-specific custom
45// tags, only a subset of cty types can be produced: strings, numbers, bools,
46// tuple types, and object types.
47//
48// This is an alias for ImpliedType on the predefined Converter in "Standard".
49func ImpliedType(src []byte) (cty.Type, error) {
50 return Standard.ImpliedType(src)
51}
52
53func handleErr(err *error) {
54 if v := recover(); v != nil {
55 if e, ok := v.(yamlError); ok {
56 *err = e.err
57 } else {
58 panic(v)
59 }
60 }
61}
62
63type yamlError struct {
64 err error
65}
66
67func fail(err error) {
68 panic(yamlError{err})
69}
70
71func failf(format string, args ...interface{}) {
72 panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
73}
74
75// --------------------------------------------------------------------------
76// Maintain a mapping of keys to structure field indexes
77
78// The code in this section was copied from mgo/bson.
79
80// structInfo holds details for the serialization of fields of
81// a given struct.
82type structInfo struct {
83 FieldsMap map[string]fieldInfo
84 FieldsList []fieldInfo
85
86 // InlineMap is the number of the field in the struct that
87 // contains an ,inline map, or -1 if there's none.
88 InlineMap int
89}
90
91type fieldInfo struct {
92 Key string
93 Num int
94 OmitEmpty bool
95 Flow bool
96 // Id holds the unique field identifier, so we can cheaply
97 // check for field duplicates without maintaining an extra map.
98 Id int
99
100 // Inline holds the field index if the field is part of an inlined struct.
101 Inline []int
102}
103
104var structMap = make(map[reflect.Type]*structInfo)
105var fieldMapMutex sync.RWMutex
106
107func getStructInfo(st reflect.Type) (*structInfo, error) {
108 fieldMapMutex.RLock()
109 sinfo, found := structMap[st]
110 fieldMapMutex.RUnlock()
111 if found {
112 return sinfo, nil
113 }
114
115 n := st.NumField()
116 fieldsMap := make(map[string]fieldInfo)
117 fieldsList := make([]fieldInfo, 0, n)
118 inlineMap := -1
119 for i := 0; i != n; i++ {
120 field := st.Field(i)
121 if field.PkgPath != "" && !field.Anonymous {
122 continue // Private field
123 }
124
125 info := fieldInfo{Num: i}
126
127 tag := field.Tag.Get("yaml")
128 if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
129 tag = string(field.Tag)
130 }
131 if tag == "-" {
132 continue
133 }
134
135 inline := false
136 fields := strings.Split(tag, ",")
137 if len(fields) > 1 {
138 for _, flag := range fields[1:] {
139 switch flag {
140 case "omitempty":
141 info.OmitEmpty = true
142 case "flow":
143 info.Flow = true
144 case "inline":
145 inline = true
146 default:
147 return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
148 }
149 }
150 tag = fields[0]
151 }
152
153 if inline {
154 switch field.Type.Kind() {
155 case reflect.Map:
156 if inlineMap >= 0 {
157 return nil, errors.New("Multiple ,inline maps in struct " + st.String())
158 }
159 if field.Type.Key() != reflect.TypeOf("") {
160 return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
161 }
162 inlineMap = info.Num
163 case reflect.Struct:
164 sinfo, err := getStructInfo(field.Type)
165 if err != nil {
166 return nil, err
167 }
168 for _, finfo := range sinfo.FieldsList {
169 if _, found := fieldsMap[finfo.Key]; found {
170 msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
171 return nil, errors.New(msg)
172 }
173 if finfo.Inline == nil {
174 finfo.Inline = []int{i, finfo.Num}
175 } else {
176 finfo.Inline = append([]int{i}, finfo.Inline...)
177 }
178 finfo.Id = len(fieldsList)
179 fieldsMap[finfo.Key] = finfo
180 fieldsList = append(fieldsList, finfo)
181 }
182 default:
183 //return nil, errors.New("Option ,inline needs a struct value or map field")
184 return nil, errors.New("Option ,inline needs a struct value field")
185 }
186 continue
187 }
188
189 if tag != "" {
190 info.Key = tag
191 } else {
192 info.Key = strings.ToLower(field.Name)
193 }
194
195 if _, found = fieldsMap[info.Key]; found {
196 msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
197 return nil, errors.New(msg)
198 }
199
200 info.Id = len(fieldsList)
201 fieldsList = append(fieldsList, info)
202 fieldsMap[info.Key] = info
203 }
204
205 sinfo = &structInfo{
206 FieldsMap: fieldsMap,
207 FieldsList: fieldsList,
208 InlineMap: inlineMap,
209 }
210
211 fieldMapMutex.Lock()
212 structMap[st] = sinfo
213 fieldMapMutex.Unlock()
214 return sinfo, nil
215}