You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
4.0 KiB

  1. package gen
  2. import (
  3. "fmt"
  4. "io"
  5. "github.com/tinylib/msgp/msgp"
  6. )
  7. func marshal(w io.Writer) *marshalGen {
  8. return &marshalGen{
  9. p: printer{w: w},
  10. }
  11. }
  12. type marshalGen struct {
  13. passes
  14. p printer
  15. fuse []byte
  16. }
  17. func (m *marshalGen) Method() Method { return Marshal }
  18. func (m *marshalGen) Apply(dirs []string) error {
  19. return nil
  20. }
  21. func (m *marshalGen) Execute(p Elem) error {
  22. if !m.p.ok() {
  23. return m.p.err
  24. }
  25. p = m.applyall(p)
  26. if p == nil {
  27. return nil
  28. }
  29. if !IsPrintable(p) {
  30. return nil
  31. }
  32. m.p.comment("MarshalMsg implements msgp.Marshaler")
  33. // save the vname before
  34. // calling methodReceiver so
  35. // that z.Msgsize() is printed correctly
  36. c := p.Varname()
  37. m.p.printf("\nfunc (%s %s) MarshalMsg(b []byte) (o []byte, err error) {", p.Varname(), imutMethodReceiver(p))
  38. m.p.printf("\no = msgp.Require(b, %s.Msgsize())", c)
  39. next(m, p)
  40. m.p.nakedReturn()
  41. return m.p.err
  42. }
  43. func (m *marshalGen) rawAppend(typ string, argfmt string, arg interface{}) {
  44. m.p.printf("\no = msgp.Append%s(o, %s)", typ, fmt.Sprintf(argfmt, arg))
  45. }
  46. func (m *marshalGen) fuseHook() {
  47. if len(m.fuse) > 0 {
  48. m.rawbytes(m.fuse)
  49. m.fuse = m.fuse[:0]
  50. }
  51. }
  52. func (m *marshalGen) Fuse(b []byte) {
  53. if len(m.fuse) == 0 {
  54. m.fuse = b
  55. } else {
  56. m.fuse = append(m.fuse, b...)
  57. }
  58. }
  59. func (m *marshalGen) gStruct(s *Struct) {
  60. if !m.p.ok() {
  61. return
  62. }
  63. if s.AsTuple {
  64. m.tuple(s)
  65. } else {
  66. m.mapstruct(s)
  67. }
  68. return
  69. }
  70. func (m *marshalGen) tuple(s *Struct) {
  71. data := make([]byte, 0, 5)
  72. data = msgp.AppendArrayHeader(data, uint32(len(s.Fields)))
  73. m.p.printf("\n// array header, size %d", len(s.Fields))
  74. m.Fuse(data)
  75. if len(s.Fields) == 0 {
  76. m.fuseHook()
  77. }
  78. for i := range s.Fields {
  79. if !m.p.ok() {
  80. return
  81. }
  82. next(m, s.Fields[i].FieldElem)
  83. }
  84. }
  85. func (m *marshalGen) mapstruct(s *Struct) {
  86. data := make([]byte, 0, 64)
  87. data = msgp.AppendMapHeader(data, uint32(len(s.Fields)))
  88. m.p.printf("\n// map header, size %d", len(s.Fields))
  89. m.Fuse(data)
  90. if len(s.Fields) == 0 {
  91. m.fuseHook()
  92. }
  93. for i := range s.Fields {
  94. if !m.p.ok() {
  95. return
  96. }
  97. data = msgp.AppendString(nil, s.Fields[i].FieldTag)
  98. m.p.printf("\n// string %q", s.Fields[i].FieldTag)
  99. m.Fuse(data)
  100. next(m, s.Fields[i].FieldElem)
  101. }
  102. }
  103. // append raw data
  104. func (m *marshalGen) rawbytes(bts []byte) {
  105. m.p.print("\no = append(o, ")
  106. for _, b := range bts {
  107. m.p.printf("0x%x,", b)
  108. }
  109. m.p.print(")")
  110. }
  111. func (m *marshalGen) gMap(s *Map) {
  112. if !m.p.ok() {
  113. return
  114. }
  115. m.fuseHook()
  116. vname := s.Varname()
  117. m.rawAppend(mapHeader, lenAsUint32, vname)
  118. m.p.printf("\nfor %s, %s := range %s {", s.Keyidx, s.Validx, vname)
  119. m.rawAppend(stringTyp, literalFmt, s.Keyidx)
  120. next(m, s.Value)
  121. m.p.closeblock()
  122. }
  123. func (m *marshalGen) gSlice(s *Slice) {
  124. if !m.p.ok() {
  125. return
  126. }
  127. m.fuseHook()
  128. vname := s.Varname()
  129. m.rawAppend(arrayHeader, lenAsUint32, vname)
  130. m.p.rangeBlock(s.Index, vname, m, s.Els)
  131. }
  132. func (m *marshalGen) gArray(a *Array) {
  133. if !m.p.ok() {
  134. return
  135. }
  136. m.fuseHook()
  137. if be, ok := a.Els.(*BaseElem); ok && be.Value == Byte {
  138. m.rawAppend("Bytes", "(%s)[:]", a.Varname())
  139. return
  140. }
  141. m.rawAppend(arrayHeader, literalFmt, coerceArraySize(a.Size))
  142. m.p.rangeBlock(a.Index, a.Varname(), m, a.Els)
  143. }
  144. func (m *marshalGen) gPtr(p *Ptr) {
  145. if !m.p.ok() {
  146. return
  147. }
  148. m.fuseHook()
  149. m.p.printf("\nif %s == nil {\no = msgp.AppendNil(o)\n} else {", p.Varname())
  150. next(m, p.Value)
  151. m.p.closeblock()
  152. }
  153. func (m *marshalGen) gBase(b *BaseElem) {
  154. if !m.p.ok() {
  155. return
  156. }
  157. m.fuseHook()
  158. vname := b.Varname()
  159. if b.Convert {
  160. if b.ShimMode == Cast {
  161. vname = tobaseConvert(b)
  162. } else {
  163. vname = randIdent()
  164. m.p.printf("\nvar %s %s", vname, b.BaseType())
  165. m.p.printf("\n%s, err = %s", vname, tobaseConvert(b))
  166. m.p.printf(errcheck)
  167. }
  168. }
  169. var echeck bool
  170. switch b.Value {
  171. case IDENT:
  172. echeck = true
  173. m.p.printf("\no, err = %s.MarshalMsg(o)", vname)
  174. case Intf, Ext:
  175. echeck = true
  176. m.p.printf("\no, err = msgp.Append%s(o, %s)", b.BaseName(), vname)
  177. default:
  178. m.rawAppend(b.BaseName(), literalFmt, vname)
  179. }
  180. if echeck {
  181. m.p.print(errcheck)
  182. }
  183. }