diff options
Diffstat (limited to 'vendor/github.com/zclconf/go-cty-yaml/yaml.go')
-rw-r--r-- | vendor/github.com/zclconf/go-cty-yaml/yaml.go | 215 |
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. | ||
2 | package yaml | ||
3 | |||
4 | import ( | ||
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. | ||
22 | func 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. | ||
37 | func 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". | ||
49 | func ImpliedType(src []byte) (cty.Type, error) { | ||
50 | return Standard.ImpliedType(src) | ||
51 | } | ||
52 | |||
53 | func 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 | |||
63 | type yamlError struct { | ||
64 | err error | ||
65 | } | ||
66 | |||
67 | func fail(err error) { | ||
68 | panic(yamlError{err}) | ||
69 | } | ||
70 | |||
71 | func 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. | ||
82 | type 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 | |||
91 | type 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 | |||
104 | var structMap = make(map[reflect.Type]*structInfo) | ||
105 | var fieldMapMutex sync.RWMutex | ||
106 | |||
107 | func 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 | } | ||