Remove BPA from Makefile
[icn.git] / cmd / bpa-operator / vendor / gopkg.in / yaml.v2 / encode.go
1 package yaml
2
3 import (
4         "encoding"
5         "fmt"
6         "io"
7         "reflect"
8         "regexp"
9         "sort"
10         "strconv"
11         "strings"
12         "time"
13         "unicode/utf8"
14 )
15
16 // jsonNumber is the interface of the encoding/json.Number datatype.
17 // Repeating the interface here avoids a dependency on encoding/json, and also
18 // supports other libraries like jsoniter, which use a similar datatype with
19 // the same interface. Detecting this interface is useful when dealing with
20 // structures containing json.Number, which is a string under the hood. The
21 // encoder should prefer the use of Int64(), Float64() and string(), in that
22 // order, when encoding this type.
23 type jsonNumber interface {
24         Float64() (float64, error)
25         Int64() (int64, error)
26         String() string
27 }
28
29 type encoder struct {
30         emitter yaml_emitter_t
31         event   yaml_event_t
32         out     []byte
33         flow    bool
34         // doneInit holds whether the initial stream_start_event has been
35         // emitted.
36         doneInit bool
37 }
38
39 func newEncoder() *encoder {
40         e := &encoder{}
41         yaml_emitter_initialize(&e.emitter)
42         yaml_emitter_set_output_string(&e.emitter, &e.out)
43         yaml_emitter_set_unicode(&e.emitter, true)
44         return e
45 }
46
47 func newEncoderWithWriter(w io.Writer) *encoder {
48         e := &encoder{}
49         yaml_emitter_initialize(&e.emitter)
50         yaml_emitter_set_output_writer(&e.emitter, w)
51         yaml_emitter_set_unicode(&e.emitter, true)
52         return e
53 }
54
55 func (e *encoder) init() {
56         if e.doneInit {
57                 return
58         }
59         yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)
60         e.emit()
61         e.doneInit = true
62 }
63
64 func (e *encoder) finish() {
65         e.emitter.open_ended = false
66         yaml_stream_end_event_initialize(&e.event)
67         e.emit()
68 }
69
70 func (e *encoder) destroy() {
71         yaml_emitter_delete(&e.emitter)
72 }
73
74 func (e *encoder) emit() {
75         // This will internally delete the e.event value.
76         e.must(yaml_emitter_emit(&e.emitter, &e.event))
77 }
78
79 func (e *encoder) must(ok bool) {
80         if !ok {
81                 msg := e.emitter.problem
82                 if msg == "" {
83                         msg = "unknown problem generating YAML content"
84                 }
85                 failf("%s", msg)
86         }
87 }
88
89 func (e *encoder) marshalDoc(tag string, in reflect.Value) {
90         e.init()
91         yaml_document_start_event_initialize(&e.event, nil, nil, true)
92         e.emit()
93         e.marshal(tag, in)
94         yaml_document_end_event_initialize(&e.event, true)
95         e.emit()
96 }
97
98 func (e *encoder) marshal(tag string, in reflect.Value) {
99         if !in.IsValid() || in.Kind() == reflect.Ptr && in.IsNil() {
100                 e.nilv()
101                 return
102         }
103         iface := in.Interface()
104         switch m := iface.(type) {
105         case jsonNumber:
106                 integer, err := m.Int64()
107                 if err == nil {
108                         // In this case the json.Number is a valid int64
109                         in = reflect.ValueOf(integer)
110                         break
111                 }
112                 float, err := m.Float64()
113                 if err == nil {
114                         // In this case the json.Number is a valid float64
115                         in = reflect.ValueOf(float)
116                         break
117                 }
118                 // fallback case - no number could be obtained
119                 in = reflect.ValueOf(m.String())
120         case time.Time, *time.Time:
121                 // Although time.Time implements TextMarshaler,
122                 // we don't want to treat it as a string for YAML
123                 // purposes because YAML has special support for
124                 // timestamps.
125         case Marshaler:
126                 v, err := m.MarshalYAML()
127                 if err != nil {
128                         fail(err)
129                 }
130                 if v == nil {
131                         e.nilv()
132                         return
133                 }
134                 in = reflect.ValueOf(v)
135         case encoding.TextMarshaler:
136                 text, err := m.MarshalText()
137                 if err != nil {
138                         fail(err)
139                 }
140                 in = reflect.ValueOf(string(text))
141         case nil:
142                 e.nilv()
143                 return
144         }
145         switch in.Kind() {
146         case reflect.Interface:
147                 e.marshal(tag, in.Elem())
148         case reflect.Map:
149                 e.mapv(tag, in)
150         case reflect.Ptr:
151                 if in.Type() == ptrTimeType {
152                         e.timev(tag, in.Elem())
153                 } else {
154                         e.marshal(tag, in.Elem())
155                 }
156         case reflect.Struct:
157                 if in.Type() == timeType {
158                         e.timev(tag, in)
159                 } else {
160                         e.structv(tag, in)
161                 }
162         case reflect.Slice, reflect.Array:
163                 if in.Type().Elem() == mapItemType {
164                         e.itemsv(tag, in)
165                 } else {
166                         e.slicev(tag, in)
167                 }
168         case reflect.String:
169                 e.stringv(tag, in)
170         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
171                 if in.Type() == durationType {
172                         e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String()))
173                 } else {
174                         e.intv(tag, in)
175                 }
176         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
177                 e.uintv(tag, in)
178         case reflect.Float32, reflect.Float64:
179                 e.floatv(tag, in)
180         case reflect.Bool:
181                 e.boolv(tag, in)
182         default:
183                 panic("cannot marshal type: " + in.Type().String())
184         }
185 }
186
187 func (e *encoder) mapv(tag string, in reflect.Value) {
188         e.mappingv(tag, func() {
189                 keys := keyList(in.MapKeys())
190                 sort.Sort(keys)
191                 for _, k := range keys {
192                         e.marshal("", k)
193                         e.marshal("", in.MapIndex(k))
194                 }
195         })
196 }
197
198 func (e *encoder) itemsv(tag string, in reflect.Value) {
199         e.mappingv(tag, func() {
200                 slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem)
201                 for _, item := range slice {
202                         e.marshal("", reflect.ValueOf(item.Key))
203                         e.marshal("", reflect.ValueOf(item.Value))
204                 }
205         })
206 }
207
208 func (e *encoder) structv(tag string, in reflect.Value) {
209         sinfo, err := getStructInfo(in.Type())
210         if err != nil {
211                 panic(err)
212         }
213         e.mappingv(tag, func() {
214                 for _, info := range sinfo.FieldsList {
215                         var value reflect.Value
216                         if info.Inline == nil {
217                                 value = in.Field(info.Num)
218                         } else {
219                                 value = in.FieldByIndex(info.Inline)
220                         }
221                         if info.OmitEmpty && isZero(value) {
222                                 continue
223                         }
224                         e.marshal("", reflect.ValueOf(info.Key))
225                         e.flow = info.Flow
226                         e.marshal("", value)
227                 }
228                 if sinfo.InlineMap >= 0 {
229                         m := in.Field(sinfo.InlineMap)
230                         if m.Len() > 0 {
231                                 e.flow = false
232                                 keys := keyList(m.MapKeys())
233                                 sort.Sort(keys)
234                                 for _, k := range keys {
235                                         if _, found := sinfo.FieldsMap[k.String()]; found {
236                                                 panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String()))
237                                         }
238                                         e.marshal("", k)
239                                         e.flow = false
240                                         e.marshal("", m.MapIndex(k))
241                                 }
242                         }
243                 }
244         })
245 }
246
247 func (e *encoder) mappingv(tag string, f func()) {
248         implicit := tag == ""
249         style := yaml_BLOCK_MAPPING_STYLE
250         if e.flow {
251                 e.flow = false
252                 style = yaml_FLOW_MAPPING_STYLE
253         }
254         yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)
255         e.emit()
256         f()
257         yaml_mapping_end_event_initialize(&e.event)
258         e.emit()
259 }
260
261 func (e *encoder) slicev(tag string, in reflect.Value) {
262         implicit := tag == ""
263         style := yaml_BLOCK_SEQUENCE_STYLE
264         if e.flow {
265                 e.flow = false
266                 style = yaml_FLOW_SEQUENCE_STYLE
267         }
268         e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style))
269         e.emit()
270         n := in.Len()
271         for i := 0; i < n; i++ {
272                 e.marshal("", in.Index(i))
273         }
274         e.must(yaml_sequence_end_event_initialize(&e.event))
275         e.emit()
276 }
277
278 // isBase60 returns whether s is in base 60 notation as defined in YAML 1.1.
279 //
280 // The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported
281 // in YAML 1.2 and by this package, but these should be marshalled quoted for
282 // the time being for compatibility with other parsers.
283 func isBase60Float(s string) (result bool) {
284         // Fast path.
285         if s == "" {
286                 return false
287         }
288         c := s[0]
289         if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 {
290                 return false
291         }
292         // Do the full match.
293         return base60float.MatchString(s)
294 }
295
296 // From http://yaml.org/type/float.html, except the regular expression there
297 // is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix.
298 var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`)
299
300 func (e *encoder) stringv(tag string, in reflect.Value) {
301         var style yaml_scalar_style_t
302         s := in.String()
303         canUsePlain := true
304         switch {
305         case !utf8.ValidString(s):
306                 if tag == yaml_BINARY_TAG {
307                         failf("explicitly tagged !!binary data must be base64-encoded")
308                 }
309                 if tag != "" {
310                         failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag))
311                 }
312                 // It can't be encoded directly as YAML so use a binary tag
313                 // and encode it as base64.
314                 tag = yaml_BINARY_TAG
315                 s = encodeBase64(s)
316         case tag == "":
317                 // Check to see if it would resolve to a specific
318                 // tag when encoded unquoted. If it doesn't,
319                 // there's no need to quote it.
320                 rtag, _ := resolve("", s)
321                 canUsePlain = rtag == yaml_STR_TAG && !isBase60Float(s)
322         }
323         // Note: it's possible for user code to emit invalid YAML
324         // if they explicitly specify a tag and a string containing
325         // text that's incompatible with that tag.
326         switch {
327         case strings.Contains(s, "\n"):
328                 style = yaml_LITERAL_SCALAR_STYLE
329         case canUsePlain:
330                 style = yaml_PLAIN_SCALAR_STYLE
331         default:
332                 style = yaml_DOUBLE_QUOTED_SCALAR_STYLE
333         }
334         e.emitScalar(s, "", tag, style)
335 }
336
337 func (e *encoder) boolv(tag string, in reflect.Value) {
338         var s string
339         if in.Bool() {
340                 s = "true"
341         } else {
342                 s = "false"
343         }
344         e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
345 }
346
347 func (e *encoder) intv(tag string, in reflect.Value) {
348         s := strconv.FormatInt(in.Int(), 10)
349         e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
350 }
351
352 func (e *encoder) uintv(tag string, in reflect.Value) {
353         s := strconv.FormatUint(in.Uint(), 10)
354         e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
355 }
356
357 func (e *encoder) timev(tag string, in reflect.Value) {
358         t := in.Interface().(time.Time)
359         s := t.Format(time.RFC3339Nano)
360         e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
361 }
362
363 func (e *encoder) floatv(tag string, in reflect.Value) {
364         // Issue #352: When formatting, use the precision of the underlying value
365         precision := 64
366         if in.Kind() == reflect.Float32 {
367                 precision = 32
368         }
369
370         s := strconv.FormatFloat(in.Float(), 'g', -1, precision)
371         switch s {
372         case "+Inf":
373                 s = ".inf"
374         case "-Inf":
375                 s = "-.inf"
376         case "NaN":
377                 s = ".nan"
378         }
379         e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE)
380 }
381
382 func (e *encoder) nilv() {
383         e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE)
384 }
385
386 func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) {
387         implicit := tag == ""
388         e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style))
389         e.emit()
390 }