encoder.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. package schema
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. )
  8. type encoderFunc func(reflect.Value) string
  9. // Encoder encodes values from a struct into url.Values.
  10. type Encoder struct {
  11. cache *cache
  12. regenc map[reflect.Type]encoderFunc
  13. }
  14. // NewEncoder returns a new Encoder with defaults.
  15. func NewEncoder() *Encoder {
  16. return &Encoder{cache: newCache(), regenc: make(map[reflect.Type]encoderFunc)}
  17. }
  18. // Encode encodes a struct into map[string][]string.
  19. //
  20. // Intended for use with url.Values.
  21. func (e *Encoder) Encode(src interface{}, dst map[string][]string) error {
  22. v := reflect.ValueOf(src)
  23. return e.encode(v, dst)
  24. }
  25. // RegisterEncoder registers a converter for encoding a custom type.
  26. func (e *Encoder) RegisterEncoder(value interface{}, encoder func(reflect.Value) string) {
  27. e.regenc[reflect.TypeOf(value)] = encoder
  28. }
  29. // SetAliasTag changes the tag used to locate custom field aliases.
  30. // The default tag is "schema".
  31. func (e *Encoder) SetAliasTag(tag string) {
  32. e.cache.tag = tag
  33. }
  34. // isValidStructPointer test if input value is a valid struct pointer.
  35. func isValidStructPointer(v reflect.Value) bool {
  36. return v.Type().Kind() == reflect.Ptr && v.Elem().IsValid() && v.Elem().Type().Kind() == reflect.Struct
  37. }
  38. func isZero(v reflect.Value) bool {
  39. switch v.Kind() {
  40. case reflect.Func:
  41. case reflect.Map, reflect.Slice:
  42. return v.IsNil() || v.Len() == 0
  43. case reflect.Array:
  44. z := true
  45. for i := 0; i < v.Len(); i++ {
  46. z = z && isZero(v.Index(i))
  47. }
  48. return z
  49. case reflect.Struct:
  50. z := true
  51. for i := 0; i < v.NumField(); i++ {
  52. z = z && isZero(v.Field(i))
  53. }
  54. return z
  55. }
  56. // Compare other types directly:
  57. z := reflect.Zero(v.Type())
  58. return v.Interface() == z.Interface()
  59. }
  60. func (e *Encoder) encode(v reflect.Value, dst map[string][]string) error {
  61. if v.Kind() == reflect.Ptr {
  62. v = v.Elem()
  63. }
  64. if v.Kind() != reflect.Struct {
  65. return errors.New("schema: interface must be a struct")
  66. }
  67. t := v.Type()
  68. errors := MultiError{}
  69. for i := 0; i < v.NumField(); i++ {
  70. name, opts := fieldAlias(t.Field(i), e.cache.tag)
  71. if name == "-" {
  72. continue
  73. }
  74. // Encode struct pointer types if the field is a valid pointer and a struct.
  75. if isValidStructPointer(v.Field(i)) {
  76. e.encode(v.Field(i).Elem(), dst)
  77. continue
  78. }
  79. encFunc := typeEncoder(v.Field(i).Type(), e.regenc)
  80. // Encode non-slice types and custom implementations immediately.
  81. if encFunc != nil {
  82. value := encFunc(v.Field(i))
  83. if opts.Contains("omitempty") && isZero(v.Field(i)) {
  84. continue
  85. }
  86. dst[name] = append(dst[name], value)
  87. continue
  88. }
  89. if v.Field(i).Type().Kind() == reflect.Struct {
  90. e.encode(v.Field(i), dst)
  91. continue
  92. }
  93. if v.Field(i).Type().Kind() == reflect.Slice {
  94. encFunc = typeEncoder(v.Field(i).Type().Elem(), e.regenc)
  95. }
  96. if encFunc == nil {
  97. errors[v.Field(i).Type().String()] = fmt.Errorf("schema: encoder not found for %v", v.Field(i))
  98. continue
  99. }
  100. // Encode a slice.
  101. if v.Field(i).Len() == 0 && opts.Contains("omitempty") {
  102. continue
  103. }
  104. dst[name] = []string{}
  105. for j := 0; j < v.Field(i).Len(); j++ {
  106. dst[name] = append(dst[name], encFunc(v.Field(i).Index(j)))
  107. }
  108. }
  109. if len(errors) > 0 {
  110. return errors
  111. }
  112. return nil
  113. }
  114. func typeEncoder(t reflect.Type, reg map[reflect.Type]encoderFunc) encoderFunc {
  115. if f, ok := reg[t]; ok {
  116. return f
  117. }
  118. switch t.Kind() {
  119. case reflect.Bool:
  120. return encodeBool
  121. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  122. return encodeInt
  123. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  124. return encodeUint
  125. case reflect.Float32:
  126. return encodeFloat32
  127. case reflect.Float64:
  128. return encodeFloat64
  129. case reflect.Ptr:
  130. f := typeEncoder(t.Elem(), reg)
  131. return func(v reflect.Value) string {
  132. if v.IsNil() {
  133. return "null"
  134. }
  135. return f(v.Elem())
  136. }
  137. case reflect.String:
  138. return encodeString
  139. default:
  140. return nil
  141. }
  142. }
  143. func encodeBool(v reflect.Value) string {
  144. return strconv.FormatBool(v.Bool())
  145. }
  146. func encodeInt(v reflect.Value) string {
  147. return strconv.FormatInt(int64(v.Int()), 10)
  148. }
  149. func encodeUint(v reflect.Value) string {
  150. return strconv.FormatUint(uint64(v.Uint()), 10)
  151. }
  152. func encodeFloat(v reflect.Value, bits int) string {
  153. return strconv.FormatFloat(v.Float(), 'f', 6, bits)
  154. }
  155. func encodeFloat32(v reflect.Value) string {
  156. return encodeFloat(v, 32)
  157. }
  158. func encodeFloat64(v reflect.Value) string {
  159. return encodeFloat(v, 64)
  160. }
  161. func encodeString(v reflect.Value) string {
  162. return v.String()
  163. }