bindstring.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright 2019 DeepMap, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package runtime
  15. import (
  16. "encoding"
  17. "errors"
  18. "fmt"
  19. "reflect"
  20. "strconv"
  21. "time"
  22. "github.com/deepmap/oapi-codegen/pkg/types"
  23. )
  24. // BindStringToObject takes a string, and attempts to assign it to the destination
  25. // interface via whatever type conversion is necessary. We have to do this
  26. // via reflection instead of a much simpler type switch so that we can handle
  27. // type aliases. This function was the easy way out, the better way, since we
  28. // know the destination type each place that we use this, is to generate code
  29. // to read each specific type.
  30. func BindStringToObject(src string, dst interface{}) error {
  31. var err error
  32. v := reflect.ValueOf(dst)
  33. t := reflect.TypeOf(dst)
  34. // We need to dereference pointers
  35. if t.Kind() == reflect.Ptr {
  36. v = reflect.Indirect(v)
  37. t = v.Type()
  38. }
  39. // For some optioinal args
  40. if t.Kind() == reflect.Ptr {
  41. if v.IsNil() {
  42. v.Set(reflect.New(t.Elem()))
  43. }
  44. v = reflect.Indirect(v)
  45. t = v.Type()
  46. }
  47. // The resulting type must be settable. reflect will catch issues like
  48. // passing the destination by value.
  49. if !v.CanSet() {
  50. return errors.New("destination is not settable")
  51. }
  52. switch t.Kind() {
  53. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  54. var val int64
  55. val, err = strconv.ParseInt(src, 10, 64)
  56. if err == nil {
  57. if v.OverflowInt(val) {
  58. err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
  59. }
  60. if err == nil {
  61. v.SetInt(val)
  62. }
  63. }
  64. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  65. var val uint64
  66. val, err = strconv.ParseUint(src, 10, 64)
  67. if err == nil {
  68. if v.OverflowUint(val) {
  69. err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
  70. }
  71. v.SetUint(val)
  72. }
  73. case reflect.String:
  74. v.SetString(src)
  75. err = nil
  76. case reflect.Float64, reflect.Float32:
  77. var val float64
  78. val, err = strconv.ParseFloat(src, 64)
  79. if err == nil {
  80. if v.OverflowFloat(val) {
  81. err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
  82. }
  83. v.SetFloat(val)
  84. }
  85. case reflect.Bool:
  86. var val bool
  87. val, err = strconv.ParseBool(src)
  88. if err == nil {
  89. v.SetBool(val)
  90. }
  91. case reflect.Array:
  92. if tu, ok := dst.(encoding.TextUnmarshaler); ok {
  93. if err := tu.UnmarshalText([]byte(src)); err != nil {
  94. return fmt.Errorf("error unmarshalling '%s' text as %T: %s", src, dst, err)
  95. }
  96. return nil
  97. }
  98. fallthrough
  99. case reflect.Struct:
  100. // if this is not of type Time or of type Date look to see if this is of type Binder.
  101. if dstType, ok := dst.(Binder); ok {
  102. return dstType.Bind(src)
  103. }
  104. if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
  105. // Don't fail on empty string.
  106. if src == "" {
  107. return nil
  108. }
  109. // Time is a special case of a struct that we handle
  110. parsedTime, err := time.Parse(time.RFC3339Nano, src)
  111. if err != nil {
  112. parsedTime, err = time.Parse(types.DateFormat, src)
  113. if err != nil {
  114. return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", src, err)
  115. }
  116. }
  117. // So, assigning this gets a little fun. We have a value to the
  118. // dereference destination. We can't do a conversion to
  119. // time.Time because the result isn't assignable, so we need to
  120. // convert pointers.
  121. if t != reflect.TypeOf(time.Time{}) {
  122. vPtr := v.Addr()
  123. vtPtr := vPtr.Convert(reflect.TypeOf(&time.Time{}))
  124. v = reflect.Indirect(vtPtr)
  125. }
  126. v.Set(reflect.ValueOf(parsedTime))
  127. return nil
  128. }
  129. if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
  130. // Don't fail on empty string.
  131. if src == "" {
  132. return nil
  133. }
  134. parsedTime, err := time.Parse(types.DateFormat, src)
  135. if err != nil {
  136. return fmt.Errorf("error parsing '%s' as date: %s", src, err)
  137. }
  138. parsedDate := types.Date{Time: parsedTime}
  139. // We have to do the same dance here to assign, just like with times
  140. // above.
  141. if t != reflect.TypeOf(types.Date{}) {
  142. vPtr := v.Addr()
  143. vtPtr := vPtr.Convert(reflect.TypeOf(&types.Date{}))
  144. v = reflect.Indirect(vtPtr)
  145. }
  146. v.Set(reflect.ValueOf(parsedDate))
  147. return nil
  148. }
  149. // We fall through to the error case below if we haven't handled the
  150. // destination type above.
  151. fallthrough
  152. default:
  153. // We've got a bunch of types unimplemented, don't fail silently.
  154. err = fmt.Errorf("can not bind to destination of type: %s", t.Kind())
  155. }
  156. if err != nil {
  157. return fmt.Errorf("error binding string parameter: %s", err)
  158. }
  159. return nil
  160. }