encode.go 6.2 KB

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