encode.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. package goyaml
  2. // #include "helpers.h"
  3. import "C"
  4. import (
  5. "reflect"
  6. "unsafe"
  7. "strconv"
  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.NewValue(value)
  82. }
  83. switch in := in.(type) {
  84. case *reflect.InterfaceValue:
  85. if in.IsNil() {
  86. e.nilv()
  87. } else {
  88. e.marshal(tag, in.Elem())
  89. }
  90. case *reflect.MapValue:
  91. e.mapv(tag, in)
  92. case *reflect.PtrValue:
  93. if in.IsNil() {
  94. e.nilv()
  95. } else {
  96. e.marshal(tag, in.Elem())
  97. }
  98. case *reflect.StructValue:
  99. e.structv(tag, in)
  100. case *reflect.SliceValue:
  101. e.slicev(tag, in)
  102. case *reflect.StringValue:
  103. e.stringv(tag, in)
  104. case *reflect.IntValue:
  105. e.intv(tag, in)
  106. case *reflect.UintValue:
  107. e.uintv(tag, in)
  108. case *reflect.FloatValue:
  109. e.floatv(tag, in)
  110. case *reflect.BoolValue:
  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.MapValue) {
  117. e.mappingv(tag, func() {
  118. for _, k := range in.Keys() {
  119. e.marshal("", k)
  120. e.marshal("", in.Elem(k))
  121. }
  122. })
  123. }
  124. func (e *encoder) structv(tag string, in *reflect.StructValue) {
  125. fields, err := getStructFields(in.Type().(*reflect.StructType))
  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.Conditional && isZero(value) {
  133. continue
  134. }
  135. e.marshal("", reflect.NewValue(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.SliceValue) {
  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.Elem(i))
  184. }
  185. C.yaml_sequence_end_event_initialize(&e.event)
  186. e.emit()
  187. }
  188. func (e *encoder) stringv(tag string, in *reflect.StringValue) {
  189. var style C.yaml_scalar_style_t
  190. s := in.Get()
  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.BoolValue) {
  199. var s string
  200. if in.Get() {
  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.IntValue) {
  208. s := strconv.Itoa64(in.Get())
  209. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  210. }
  211. func (e *encoder) uintv(tag string, in *reflect.UintValue) {
  212. s := strconv.Uitoa64(in.Get())
  213. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  214. }
  215. func (e *encoder) floatv(tag string, in *reflect.FloatValue) {
  216. // FIXME: Handle 64 bits here.
  217. s := strconv.Ftoa32(float32(in.Get()), 'g', -1)
  218. switch s {
  219. case "+Inf": s = ".inf"
  220. case "-Inf": s = "-.inf"
  221. case "NaN": s = ".nan"
  222. }
  223. e.emitScalar(s, "", tag, C.YAML_PLAIN_SCALAR_STYLE)
  224. }
  225. func (e *encoder) nilv() {
  226. e.emitScalar("null", "", "", C.YAML_PLAIN_SCALAR_STYLE)
  227. }
  228. func (e *encoder) emitScalar(value, anchor, tag string,
  229. style C.yaml_scalar_style_t) {
  230. var canchor, ctag, cvalue *C.yaml_char_t
  231. var cimplicit C.int
  232. var free func()
  233. if anchor != "" {
  234. canchor, free = ystr(anchor)
  235. defer free()
  236. }
  237. if tag != "" {
  238. ctag, free = ystr(tag)
  239. defer free()
  240. cimplicit = 0
  241. style = C.YAML_PLAIN_SCALAR_STYLE
  242. } else {
  243. cimplicit = 1
  244. }
  245. cvalue, free = ystr(value)
  246. defer free()
  247. size := C.int(len(value))
  248. if C.yaml_scalar_event_initialize(&e.event, canchor, ctag, cvalue, size,
  249. cimplicit, cimplicit, style) == 0 {
  250. e.fail("")
  251. }
  252. e.emit()
  253. }
  254. func ystr(s string) (ys *C.yaml_char_t, free func()) {
  255. up := unsafe.Pointer(C.CString(s))
  256. ys = (*C.yaml_char_t)(up)
  257. free = func() { C.free(up) }
  258. return ys, free
  259. }