encode.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. package goyaml
  2. // #include "helpers.h"
  3. import "C"
  4. import (
  5. "reflect"
  6. "sort"
  7. "strconv"
  8. "unsafe"
  9. )
  10. type encoder struct {
  11. emitter C.yaml_emitter_t
  12. event C.yaml_event_t
  13. out []byte
  14. tmp []byte
  15. tmph *reflect.SliceHeader
  16. flow bool
  17. }
  18. //export outputHandler
  19. func outputHandler(data unsafe.Pointer, buffer *C.uchar, size C.size_t) C.int {
  20. e := (*encoder)(data)
  21. e.tmph.Data = uintptr(unsafe.Pointer(buffer))
  22. e.tmph.Len = int(size)
  23. e.tmph.Cap = int(size)
  24. e.out = append(e.out, e.tmp...)
  25. return 1
  26. }
  27. func newEncoder() (e *encoder) {
  28. e = &encoder{}
  29. e.tmph = (*reflect.SliceHeader)(unsafe.Pointer(&e.tmp))
  30. if C.yaml_emitter_initialize(&e.emitter) == 0 {
  31. panic("Failed to initialize YAML emitter")
  32. }
  33. C.set_output_handler(&e.emitter)
  34. C.yaml_stream_start_event_initialize(&e.event, C.YAML_UTF8_ENCODING)
  35. e.emit()
  36. C.yaml_document_start_event_initialize(&e.event, nil, nil, nil, 1)
  37. e.emit()
  38. return e
  39. }
  40. func (e *encoder) finish() {
  41. C.yaml_document_end_event_initialize(&e.event, 1)
  42. e.emit()
  43. e.emitter.open_ended = 0
  44. C.yaml_stream_end_event_initialize(&e.event)
  45. e.emit()
  46. }
  47. func (e *encoder) destroy() {
  48. C.yaml_emitter_delete(&e.emitter)
  49. }
  50. func (e *encoder) emit() {
  51. // This will internally delete the e.event value.
  52. if C.yaml_emitter_emit(&e.emitter, &e.event) == 0 &&
  53. e.event._type != C.YAML_DOCUMENT_END_EVENT &&
  54. e.event._type != C.YAML_STREAM_END_EVENT {
  55. if e.emitter.error == C.YAML_EMITTER_ERROR {
  56. // XXX TESTME
  57. panic("YAML emitter error: " + C.GoString(e.emitter.problem))
  58. } else {
  59. // XXX TESTME
  60. panic("Unknown YAML emitter error")
  61. }
  62. }
  63. }
  64. func (e *encoder) fail(msg string) {
  65. if msg == "" {
  66. if e.emitter.problem != nil {
  67. msg = C.GoString(e.emitter.problem)
  68. } else {
  69. msg = "Unknown problem generating YAML content"
  70. }
  71. }
  72. panic(msg)
  73. }
  74. func (e *encoder) marshal(tag string, in reflect.Value) {
  75. var value interface{}
  76. if getter, ok := in.Interface().(Getter); ok {
  77. tag, value = getter.GetYAML()
  78. if value == nil {
  79. e.nilv()
  80. return
  81. }
  82. in = reflect.ValueOf(value)
  83. }
  84. switch in.Kind() {
  85. case reflect.Interface:
  86. if in.IsNil() {
  87. e.nilv()
  88. } else {
  89. e.marshal(tag, in.Elem())
  90. }
  91. case reflect.Map:
  92. e.mapv(tag, in)
  93. case reflect.Ptr:
  94. if in.IsNil() {
  95. e.nilv()
  96. } else {
  97. e.marshal(tag, in.Elem())
  98. }
  99. case reflect.Struct:
  100. e.structv(tag, in)
  101. case reflect.Slice:
  102. e.slicev(tag, in)
  103. case reflect.String:
  104. e.stringv(tag, in)
  105. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  106. e.intv(tag, in)
  107. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  108. e.uintv(tag, in)
  109. case reflect.Float32, reflect.Float64:
  110. e.floatv(tag, in)
  111. case reflect.Bool:
  112. e.boolv(tag, in)
  113. default:
  114. panic("Can't marshal type yet: " + in.Type().String())
  115. }
  116. }
  117. func (e *encoder) mapv(tag string, in reflect.Value) {
  118. e.mappingv(tag, func() {
  119. keys := keyList(in.MapKeys())
  120. sort.Sort(keys)
  121. for _, k := range keys {
  122. e.marshal("", k)
  123. e.marshal("", in.MapIndex(k))
  124. }
  125. })
  126. }
  127. func (e *encoder) structv(tag string, in reflect.Value) {
  128. fields, err := getStructFields(in.Type())
  129. if err != nil {
  130. panic(err)
  131. }
  132. e.mappingv(tag, func() {
  133. for i, info := range fields.List {
  134. value := in.Field(i)
  135. if info.OmitEmpty && isZero(value) {
  136. continue
  137. }
  138. e.marshal("", reflect.ValueOf(info.Key))
  139. e.flow = info.Flow
  140. e.marshal("", value)
  141. }
  142. })
  143. }
  144. func (e *encoder) mappingv(tag string, f func()) {
  145. var ctag *C.yaml_char_t
  146. var free func()
  147. cimplicit := C.int(1)
  148. if tag != "" {
  149. ctag, free = ystr(tag)
  150. defer free()
  151. cimplicit = 0
  152. }
  153. cstyle := C.yaml_mapping_style_t(C.YAML_BLOCK_MAPPING_STYLE)
  154. if e.flow {
  155. e.flow = false
  156. cstyle = C.YAML_FLOW_MAPPING_STYLE
  157. }
  158. C.yaml_mapping_start_event_initialize(&e.event, nil, ctag, cimplicit,
  159. cstyle)
  160. e.emit()
  161. f()
  162. C.yaml_mapping_end_event_initialize(&e.event)
  163. e.emit()
  164. }
  165. func (e *encoder) slicev(tag string, in reflect.Value) {
  166. var ctag *C.yaml_char_t
  167. var free func()
  168. var cimplicit C.int
  169. if tag != "" {
  170. ctag, free = ystr(tag)
  171. defer free()
  172. cimplicit = 0
  173. } else {
  174. cimplicit = 1
  175. }
  176. cstyle := C.yaml_sequence_style_t(C.YAML_BLOCK_SEQUENCE_STYLE)
  177. if e.flow {
  178. e.flow = false
  179. cstyle = C.YAML_FLOW_SEQUENCE_STYLE
  180. }
  181. C.yaml_sequence_start_event_initialize(&e.event, nil, ctag, cimplicit,
  182. cstyle)
  183. e.emit()
  184. n := in.Len()
  185. for i := 0; i < n; i++ {
  186. e.marshal("", in.Index(i))
  187. }
  188. C.yaml_sequence_end_event_initialize(&e.event)
  189. e.emit()
  190. }
  191. func (e *encoder) stringv(tag string, in reflect.Value) {
  192. var style C.yaml_scalar_style_t
  193. s := in.String()
  194. if rtag, _ := resolve("", s); rtag != "!!str" {
  195. style = C.YAML_DOUBLE_QUOTED_SCALAR_STYLE
  196. } else {
  197. style = C.YAML_PLAIN_SCALAR_STYLE
  198. }
  199. e.emitScalar(s, "", tag, style)
  200. }
  201. func (e *encoder) boolv(tag string, in reflect.Value) {
  202. var s string
  203. if in.Bool() {
  204. s = "true"
  205. } else {
  206. s = "false"
  207. }
  208. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  209. }
  210. func (e *encoder) intv(tag string, in reflect.Value) {
  211. s := strconv.FormatInt(in.Int(), 10)
  212. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  213. }
  214. func (e *encoder) uintv(tag string, in reflect.Value) {
  215. s := strconv.FormatUint(in.Uint(), 10)
  216. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  217. }
  218. func (e *encoder) floatv(tag string, in reflect.Value) {
  219. // FIXME: Handle 64 bits here.
  220. s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32)
  221. switch s {
  222. case "+Inf":
  223. s = ".inf"
  224. case "-Inf":
  225. s = "-.inf"
  226. case "NaN":
  227. s = ".nan"
  228. }
  229. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  230. }
  231. func (e *encoder) nilv() {
  232. e.emitScalar("null", "", "", C.YAML_PLAIN_SCALAR_STYLE)
  233. }
  234. func (e *encoder) emitScalar(value, anchor, tag string, style C.yaml_scalar_style_t) {
  235. var canchor, ctag, cvalue *C.yaml_char_t
  236. var cimplicit C.int
  237. var free func()
  238. if anchor != "" {
  239. canchor, free = ystr(anchor)
  240. defer free()
  241. }
  242. if tag != "" {
  243. ctag, free = ystr(tag)
  244. defer free()
  245. cimplicit = 0
  246. style = C.YAML_PLAIN_SCALAR_STYLE
  247. } else {
  248. cimplicit = 1
  249. }
  250. cvalue, free = ystr(value)
  251. defer free()
  252. size := C.int(len(value))
  253. if C.yaml_scalar_event_initialize(&e.event, canchor, ctag, cvalue, size,
  254. cimplicit, cimplicit, style) == 0 {
  255. e.fail("")
  256. }
  257. e.emit()
  258. }
  259. func ystr(s string) (ys *C.yaml_char_t, free func()) {
  260. up := unsafe.Pointer(C.CString(s))
  261. ys = (*C.yaml_char_t)(up)
  262. free = func() { C.free(up) }
  263. return ys, free
  264. }