github.com/marinho/drone@v0.2.1-0.20140504195434-d3ba962e89a7/Godeps/_workspace/src/launchpad.net/goyaml/encode.go (about) 1 package goyaml 2 3 import ( 4 "reflect" 5 "sort" 6 "strconv" 7 ) 8 9 type encoder struct { 10 emitter yaml_emitter_t 11 event yaml_event_t 12 out []byte 13 flow bool 14 } 15 16 func newEncoder() (e *encoder) { 17 e = &encoder{} 18 e.must(yaml_emitter_initialize(&e.emitter)) 19 yaml_emitter_set_output_string(&e.emitter, &e.out) 20 e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)) 21 e.emit() 22 e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true)) 23 e.emit() 24 return e 25 } 26 27 func (e *encoder) finish() { 28 e.must(yaml_document_end_event_initialize(&e.event, true)) 29 e.emit() 30 e.emitter.open_ended = false 31 e.must(yaml_stream_end_event_initialize(&e.event)) 32 e.emit() 33 } 34 35 func (e *encoder) destroy() { 36 yaml_emitter_delete(&e.emitter) 37 } 38 39 func (e *encoder) emit() { 40 // This will internally delete the e.event value. 41 if !yaml_emitter_emit(&e.emitter, &e.event) && e.event.typ != yaml_DOCUMENT_END_EVENT && e.event.typ != yaml_STREAM_END_EVENT { 42 e.must(false) 43 } 44 } 45 46 func (e *encoder) must(ok bool) { 47 if !ok { 48 msg := e.emitter.problem 49 if msg == "" { 50 msg = "Unknown problem generating YAML content" 51 } 52 panic(msg) 53 } 54 } 55 56 func (e *encoder) marshal(tag string, in reflect.Value) { 57 var value interface{} 58 if getter, ok := in.Interface().(Getter); ok { 59 tag, value = getter.GetYAML() 60 if value == nil { 61 e.nilv() 62 return 63 } 64 in = reflect.ValueOf(value) 65 } 66 switch in.Kind() { 67 case reflect.Interface: 68 if in.IsNil() { 69 e.nilv() 70 } else { 71 e.marshal(tag, in.Elem()) 72 } 73 case reflect.Map: 74 e.mapv(tag, in) 75 case reflect.Ptr: 76 if in.IsNil() { 77 e.nilv() 78 } else { 79 e.marshal(tag, in.Elem()) 80 } 81 case reflect.Struct: 82 e.structv(tag, in) 83 case reflect.Slice: 84 e.slicev(tag, in) 85 case reflect.String: 86 e.stringv(tag, in) 87 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 88 e.intv(tag, in) 89 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 90 e.uintv(tag, in) 91 case reflect.Float32, reflect.Float64: 92 e.floatv(tag, in) 93 case reflect.Bool: 94 e.boolv(tag, in) 95 default: 96 panic("Can't marshal type yet: " + in.Type().String()) 97 } 98 } 99 100 func (e *encoder) mapv(tag string, in reflect.Value) { 101 e.mappingv(tag, func() { 102 keys := keyList(in.MapKeys()) 103 sort.Sort(keys) 104 for _, k := range keys { 105 e.marshal("", k) 106 e.marshal("", in.MapIndex(k)) 107 } 108 }) 109 } 110 111 func (e *encoder) structv(tag string, in reflect.Value) { 112 sinfo, err := getStructInfo(in.Type()) 113 if err != nil { 114 panic(err) 115 } 116 e.mappingv(tag, func() { 117 for _, info := range sinfo.FieldsList { 118 var value reflect.Value 119 if info.Inline == nil { 120 value = in.Field(info.Num) 121 } else { 122 value = in.FieldByIndex(info.Inline) 123 } 124 if info.OmitEmpty && isZero(value) { 125 continue 126 } 127 e.marshal("", reflect.ValueOf(info.Key)) 128 e.flow = info.Flow 129 e.marshal("", value) 130 } 131 }) 132 } 133 134 func (e *encoder) mappingv(tag string, f func()) { 135 implicit := tag == "" 136 style := yaml_BLOCK_MAPPING_STYLE 137 if e.flow { 138 e.flow = false 139 style = yaml_FLOW_MAPPING_STYLE 140 } 141 e.must(yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) 142 e.emit() 143 f() 144 e.must(yaml_mapping_end_event_initialize(&e.event)) 145 e.emit() 146 } 147 148 func (e *encoder) slicev(tag string, in reflect.Value) { 149 implicit := tag == "" 150 style := yaml_BLOCK_SEQUENCE_STYLE 151 if e.flow { 152 e.flow = false 153 style = yaml_FLOW_SEQUENCE_STYLE 154 } 155 e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) 156 e.emit() 157 n := in.Len() 158 for i := 0; i < n; i++ { 159 e.marshal("", in.Index(i)) 160 } 161 e.must(yaml_sequence_end_event_initialize(&e.event)) 162 e.emit() 163 } 164 165 func (e *encoder) stringv(tag string, in reflect.Value) { 166 var style yaml_scalar_style_t 167 s := in.String() 168 if rtag, _ := resolve("", s); rtag != "!!str" { 169 style = yaml_DOUBLE_QUOTED_SCALAR_STYLE 170 } else { 171 style = yaml_PLAIN_SCALAR_STYLE 172 } 173 e.emitScalar(s, "", tag, style) 174 } 175 176 func (e *encoder) boolv(tag string, in reflect.Value) { 177 var s string 178 if in.Bool() { 179 s = "true" 180 } else { 181 s = "false" 182 } 183 e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 184 } 185 186 func (e *encoder) intv(tag string, in reflect.Value) { 187 s := strconv.FormatInt(in.Int(), 10) 188 e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 189 } 190 191 func (e *encoder) uintv(tag string, in reflect.Value) { 192 s := strconv.FormatUint(in.Uint(), 10) 193 e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 194 } 195 196 func (e *encoder) floatv(tag string, in reflect.Value) { 197 // FIXME: Handle 64 bits here. 198 s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32) 199 switch s { 200 case "+Inf": 201 s = ".inf" 202 case "-Inf": 203 s = "-.inf" 204 case "NaN": 205 s = ".nan" 206 } 207 e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 208 } 209 210 func (e *encoder) nilv() { 211 e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) 212 } 213 214 func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { 215 implicit := tag == "" 216 if !implicit { 217 style = yaml_PLAIN_SCALAR_STYLE 218 } 219 e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) 220 e.emit() 221 }