encoder.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. type zero interface {
  51. IsZero() bool
  52. }
  53. if v.Type().Implements(reflect.TypeOf((*zero)(nil)).Elem()) {
  54. iz := v.MethodByName("IsZero").Call([]reflect.Value{})[0]
  55. return iz.Interface().(bool)
  56. }
  57. z := true
  58. for i := 0; i < v.NumField(); i++ {
  59. z = z && isZero(v.Field(i))
  60. }
  61. return z
  62. }
  63. // Compare other types directly:
  64. z := reflect.Zero(v.Type())
  65. return v.Interface() == z.Interface()
  66. }
  67. func (e *Encoder) encode(v reflect.Value, dst map[string][]string) error {
  68. if v.Kind() == reflect.Ptr {
  69. v = v.Elem()
  70. }
  71. if v.Kind() != reflect.Struct {
  72. return errors.New("schema: interface must be a struct")
  73. }
  74. t := v.Type()
  75. errors := MultiError{}
  76. for i := 0; i < v.NumField(); i++ {
  77. name, opts := fieldAlias(t.Field(i), e.cache.tag)
  78. if name == "-" {
  79. continue
  80. }
  81. // Encode struct pointer types if the field is a valid pointer and a struct.
  82. if isValidStructPointer(v.Field(i)) {
  83. _ = e.encode(v.Field(i).Elem(), dst)
  84. continue
  85. }
  86. encFunc := typeEncoder(v.Field(i).Type(), e.regenc)
  87. // Encode non-slice types and custom implementations immediately.
  88. if encFunc != nil {
  89. value := encFunc(v.Field(i))
  90. if opts.Contains("omitempty") && isZero(v.Field(i)) {
  91. continue
  92. }
  93. dst[name] = append(dst[name], value)
  94. continue
  95. }
  96. if v.Field(i).Type().Kind() == reflect.Struct {
  97. _ = e.encode(v.Field(i), dst)
  98. continue
  99. }
  100. if v.Field(i).Type().Kind() == reflect.Slice {
  101. encFunc = typeEncoder(v.Field(i).Type().Elem(), e.regenc)
  102. }
  103. if encFunc == nil {
  104. errors[v.Field(i).Type().String()] = fmt.Errorf("schema: encoder not found for %v", v.Field(i))
  105. continue
  106. }
  107. // Encode a slice.
  108. if v.Field(i).Len() == 0 && opts.Contains("omitempty") {
  109. continue
  110. }
  111. dst[name] = []string{}
  112. for j := 0; j < v.Field(i).Len(); j++ {
  113. dst[name] = append(dst[name], encFunc(v.Field(i).Index(j)))
  114. }
  115. }
  116. if len(errors) > 0 {
  117. return errors
  118. }
  119. return nil
  120. }
  121. func typeEncoder(t reflect.Type, reg map[reflect.Type]encoderFunc) encoderFunc {
  122. if f, ok := reg[t]; ok {
  123. return f
  124. }
  125. switch t.Kind() {
  126. case reflect.Bool:
  127. return encodeBool
  128. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  129. return encodeInt
  130. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  131. return encodeUint
  132. case reflect.Float32:
  133. return encodeFloat32
  134. case reflect.Float64:
  135. return encodeFloat64
  136. case reflect.Ptr:
  137. f := typeEncoder(t.Elem(), reg)
  138. return func(v reflect.Value) string {
  139. if v.IsNil() {
  140. return "null"
  141. }
  142. return f(v.Elem())
  143. }
  144. case reflect.String:
  145. return encodeString
  146. default:
  147. return nil
  148. }
  149. }
  150. func encodeBool(v reflect.Value) string {
  151. return strconv.FormatBool(v.Bool())
  152. }
  153. func encodeInt(v reflect.Value) string {
  154. return strconv.FormatInt(int64(v.Int()), 10)
  155. }
  156. func encodeUint(v reflect.Value) string {
  157. return strconv.FormatUint(uint64(v.Uint()), 10)
  158. }
  159. func encodeFloat(v reflect.Value, bits int) string {
  160. return strconv.FormatFloat(v.Float(), 'f', 6, bits)
  161. }
  162. func encodeFloat32(v reflect.Value) string {
  163. return encodeFloat(v, 32)
  164. }
  165. func encodeFloat64(v reflect.Value) string {
  166. return encodeFloat(v, 64)
  167. }
  168. func encodeString(v reflect.Value) string {
  169. return v.String()
  170. }