encode.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. package ltsv
  2. import (
  3. "bytes"
  4. "encoding"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. )
  12. // MarshalError is an error type for Marshal()
  13. type MarshalError map[string]error
  14. func (m MarshalError) Error() string {
  15. if len(m) == 0 {
  16. return "(no error)"
  17. }
  18. ee := make([]string, 0, len(m))
  19. for name, err := range m {
  20. ee = append(ee, fmt.Sprintf("field %q: %s", name, err))
  21. }
  22. return strings.Join(ee, "\n")
  23. }
  24. // OfField returns the error correspoinding to a given field
  25. func (m MarshalError) OfField(name string) error {
  26. err := m[name]
  27. if e, ok := err.(*MarshalTypeError); ok {
  28. if e.err != nil {
  29. return e.err
  30. }
  31. }
  32. return m[name]
  33. }
  34. // An MarshalTypeError describes a LTSV value that was
  35. // not appropriate for a value of a specific Go type.
  36. type MarshalTypeError struct {
  37. Value string
  38. Type reflect.Type
  39. key string
  40. err error
  41. }
  42. func (e *MarshalTypeError) Error() string {
  43. if e.err != nil {
  44. return e.err.Error()
  45. }
  46. return fmt.Sprintf("ltsv: failed to marshal type: %s, value: %s", e.Type.String(), e.Value)
  47. }
  48. var keyDelim = []byte{':'}
  49. var valDelim = []byte{'\t'}
  50. type fieldWriter func(w io.Writer, v reflect.Value) error
  51. func makeStructWriter(v reflect.Value) fieldWriter {
  52. t := v.Type()
  53. n := t.NumField()
  54. writers := make([]fieldWriter, n)
  55. for i := 0; i < n; i++ {
  56. ft := t.Field(i)
  57. tag := ft.Tag.Get("ltsv")
  58. tags := strings.Split(tag, ",")
  59. key := tags[0]
  60. if key == "-" {
  61. continue
  62. }
  63. if key == "" {
  64. key = strings.ToLower(ft.Name)
  65. }
  66. kind := ft.Type.Kind()
  67. dereference := false
  68. if kind == reflect.Ptr {
  69. kind = ft.Type.Elem().Kind()
  70. dereference = true
  71. }
  72. var writer fieldWriter
  73. switch kind {
  74. case reflect.String:
  75. writer = makeStringWriter(key)
  76. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  77. writer = makeIntWriter(key)
  78. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  79. writer = makeUintWriter(key)
  80. case reflect.Float32, reflect.Float64:
  81. writer = makeFloatWriter(key)
  82. default:
  83. dereference = false
  84. writer = makeInterfaceWriter(key)
  85. }
  86. if i > 0 {
  87. writer = withDelimWriter(writer)
  88. }
  89. if dereference {
  90. writer = elemWriter(writer)
  91. }
  92. writers[i] = writer
  93. }
  94. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  95. errs := make(MarshalError)
  96. err := writers[0](w, v.Field(0))
  97. if err != nil {
  98. if e, ok := err.(*MarshalTypeError); ok {
  99. errs[e.key] = e
  100. }
  101. }
  102. for i, wr := range writers[1:] {
  103. if wr == nil {
  104. continue
  105. }
  106. err := wr(w, v.Field(i+1))
  107. if err != nil {
  108. if e, ok := err.(*MarshalTypeError); ok {
  109. errs[e.key] = e
  110. }
  111. }
  112. }
  113. if len(errs) > 0 {
  114. return errs
  115. }
  116. return nil
  117. })
  118. }
  119. func withDelimWriter(writer fieldWriter) fieldWriter {
  120. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  121. w.Write(valDelim)
  122. return writer(w, v)
  123. })
  124. }
  125. func elemWriter(writer fieldWriter) fieldWriter {
  126. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  127. if v.IsNil() {
  128. return nil
  129. }
  130. return writer(w, v.Elem())
  131. })
  132. }
  133. func writeField(w io.Writer, key, value string) {
  134. io.WriteString(w, key)
  135. w.Write(keyDelim)
  136. io.WriteString(w, value)
  137. }
  138. func makeStringWriter(key string) fieldWriter {
  139. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  140. writeField(w, key, v.String())
  141. return nil
  142. })
  143. }
  144. func makeIntWriter(key string) fieldWriter {
  145. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  146. writeField(w, key, strconv.FormatInt(v.Int(), 10))
  147. return nil
  148. })
  149. }
  150. func makeUintWriter(key string) fieldWriter {
  151. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  152. writeField(w, key, strconv.FormatUint(v.Uint(), 10))
  153. return nil
  154. })
  155. }
  156. func makeFloatWriter(key string) fieldWriter {
  157. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  158. writeField(w, key, strconv.FormatFloat(v.Float(), 'f', -1, v.Type().Bits()))
  159. return nil
  160. })
  161. }
  162. func makeInterfaceWriter(key string) fieldWriter {
  163. return fieldWriter(func(w io.Writer, v reflect.Value) error {
  164. if !v.CanInterface() {
  165. return &MarshalTypeError{key: key, Type: v.Type(), Value: v.String()}
  166. }
  167. switch u := v.Interface().(type) {
  168. case encoding.TextMarshaler:
  169. b, err := u.MarshalText()
  170. if err != nil {
  171. return &MarshalTypeError{key: key, Type: v.Type(), Value: v.String(), err: err}
  172. }
  173. io.WriteString(w, key)
  174. w.Write(keyDelim)
  175. w.Write(b)
  176. return nil
  177. default:
  178. return &MarshalTypeError{key: key, Type: v.Type(), Value: v.String()}
  179. }
  180. })
  181. }
  182. type writerCache struct {
  183. cache map[reflect.Type]fieldWriter
  184. sync.RWMutex
  185. }
  186. func (c *writerCache) Get(v reflect.Value) fieldWriter {
  187. c.RLock()
  188. t := v.Type()
  189. if v, ok := c.cache[t]; ok {
  190. c.RUnlock()
  191. return v
  192. }
  193. c.RUnlock()
  194. writer := makeStructWriter(v)
  195. c.Lock()
  196. c.cache[t] = writer
  197. c.Unlock()
  198. return writer
  199. }
  200. var cache = &writerCache{
  201. cache: make(map[reflect.Type]fieldWriter),
  202. }
  203. func marshalMapTo(w io.Writer, m map[string]string) error {
  204. first := true
  205. for k, v := range m {
  206. if !first {
  207. w.Write(valDelim)
  208. }
  209. first = false
  210. writeField(w, k, v)
  211. }
  212. return nil
  213. }
  214. func marshalStructTo(w io.Writer, rv reflect.Value) error {
  215. writer := cache.Get(rv)
  216. return writer(w, rv)
  217. }
  218. // MarshalTo writes the LTSV encoding of v into w.
  219. // Be aware that the writing into w is not thread safe.
  220. func MarshalTo(w io.Writer, v interface{}) error {
  221. rv := reflect.ValueOf(v)
  222. if rv.Kind() == reflect.Ptr {
  223. rv = rv.Elem()
  224. }
  225. var err error
  226. switch rv.Kind() {
  227. case reflect.Map:
  228. if m, ok := v.(map[string]string); ok {
  229. err = marshalMapTo(w, m)
  230. break
  231. }
  232. err = fmt.Errorf("not a map[string]string")
  233. case reflect.Struct:
  234. err = marshalStructTo(w, rv)
  235. default:
  236. err = fmt.Errorf("not a struct/map: %v", v)
  237. }
  238. return err
  239. }
  240. // Marshal returns the LTSV encoding of v
  241. func Marshal(v interface{}) ([]byte, error) {
  242. w := bytes.NewBuffer(nil)
  243. err := MarshalTo(w, v)
  244. return w.Bytes(), err
  245. }