unmarshal.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. // Copyright 2023 Google Inc. All rights reserved.
  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 starlark_import
  15. import (
  16. "fmt"
  17. "math"
  18. "reflect"
  19. "unsafe"
  20. "go.starlark.net/starlark"
  21. "go.starlark.net/starlarkstruct"
  22. )
  23. func Unmarshal[T any](value starlark.Value) (T, error) {
  24. var zero T
  25. x, err := UnmarshalReflect(value, reflect.TypeOf(zero))
  26. return x.Interface().(T), err
  27. }
  28. func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
  29. zero := reflect.Zero(ty)
  30. var result reflect.Value
  31. if ty.Kind() == reflect.Interface {
  32. var err error
  33. ty, err = typeOfStarlarkValue(value)
  34. if err != nil {
  35. return zero, err
  36. }
  37. }
  38. if ty.Kind() == reflect.Map {
  39. result = reflect.MakeMap(ty)
  40. } else {
  41. result = reflect.Indirect(reflect.New(ty))
  42. }
  43. switch v := value.(type) {
  44. case starlark.String:
  45. if result.Type().Kind() != reflect.String {
  46. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  47. }
  48. result.SetString(v.GoString())
  49. case starlark.Int:
  50. signedValue, signedOk := v.Int64()
  51. unsignedValue, unsignedOk := v.Uint64()
  52. switch result.Type().Kind() {
  53. case reflect.Int64:
  54. if !signedOk {
  55. return zero, fmt.Errorf("starlark int didn't fit in go int64")
  56. }
  57. result.SetInt(signedValue)
  58. case reflect.Int32:
  59. if !signedOk || signedValue > math.MaxInt32 || signedValue < math.MinInt32 {
  60. return zero, fmt.Errorf("starlark int didn't fit in go int32")
  61. }
  62. result.SetInt(signedValue)
  63. case reflect.Int16:
  64. if !signedOk || signedValue > math.MaxInt16 || signedValue < math.MinInt16 {
  65. return zero, fmt.Errorf("starlark int didn't fit in go int16")
  66. }
  67. result.SetInt(signedValue)
  68. case reflect.Int8:
  69. if !signedOk || signedValue > math.MaxInt8 || signedValue < math.MinInt8 {
  70. return zero, fmt.Errorf("starlark int didn't fit in go int8")
  71. }
  72. result.SetInt(signedValue)
  73. case reflect.Int:
  74. if !signedOk || signedValue > math.MaxInt || signedValue < math.MinInt {
  75. return zero, fmt.Errorf("starlark int didn't fit in go int")
  76. }
  77. result.SetInt(signedValue)
  78. case reflect.Uint64:
  79. if !unsignedOk {
  80. return zero, fmt.Errorf("starlark int didn't fit in go uint64")
  81. }
  82. result.SetUint(unsignedValue)
  83. case reflect.Uint32:
  84. if !unsignedOk || unsignedValue > math.MaxUint32 {
  85. return zero, fmt.Errorf("starlark int didn't fit in go uint32")
  86. }
  87. result.SetUint(unsignedValue)
  88. case reflect.Uint16:
  89. if !unsignedOk || unsignedValue > math.MaxUint16 {
  90. return zero, fmt.Errorf("starlark int didn't fit in go uint16")
  91. }
  92. result.SetUint(unsignedValue)
  93. case reflect.Uint8:
  94. if !unsignedOk || unsignedValue > math.MaxUint8 {
  95. return zero, fmt.Errorf("starlark int didn't fit in go uint8")
  96. }
  97. result.SetUint(unsignedValue)
  98. case reflect.Uint:
  99. if !unsignedOk || unsignedValue > math.MaxUint {
  100. return zero, fmt.Errorf("starlark int didn't fit in go uint")
  101. }
  102. result.SetUint(unsignedValue)
  103. default:
  104. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  105. }
  106. case starlark.Float:
  107. f := float64(v)
  108. switch result.Type().Kind() {
  109. case reflect.Float64:
  110. result.SetFloat(f)
  111. case reflect.Float32:
  112. if f > math.MaxFloat32 || f < -math.MaxFloat32 {
  113. return zero, fmt.Errorf("starlark float didn't fit in go float32")
  114. }
  115. result.SetFloat(f)
  116. default:
  117. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  118. }
  119. case starlark.Bool:
  120. if result.Type().Kind() != reflect.Bool {
  121. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  122. }
  123. result.SetBool(bool(v))
  124. case starlark.Tuple:
  125. if result.Type().Kind() != reflect.Slice {
  126. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  127. }
  128. elemType := result.Type().Elem()
  129. // TODO: Add this grow call when we're on go 1.20
  130. //result.Grow(v.Len())
  131. for i := 0; i < v.Len(); i++ {
  132. elem, err := UnmarshalReflect(v.Index(i), elemType)
  133. if err != nil {
  134. return zero, err
  135. }
  136. result = reflect.Append(result, elem)
  137. }
  138. case *starlark.List:
  139. if result.Type().Kind() != reflect.Slice {
  140. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  141. }
  142. elemType := result.Type().Elem()
  143. // TODO: Add this grow call when we're on go 1.20
  144. //result.Grow(v.Len())
  145. for i := 0; i < v.Len(); i++ {
  146. elem, err := UnmarshalReflect(v.Index(i), elemType)
  147. if err != nil {
  148. return zero, err
  149. }
  150. result = reflect.Append(result, elem)
  151. }
  152. case *starlark.Dict:
  153. if result.Type().Kind() != reflect.Map {
  154. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  155. }
  156. keyType := result.Type().Key()
  157. valueType := result.Type().Elem()
  158. for _, pair := range v.Items() {
  159. key := pair.Index(0)
  160. value := pair.Index(1)
  161. unmarshalledKey, err := UnmarshalReflect(key, keyType)
  162. if err != nil {
  163. return zero, err
  164. }
  165. unmarshalledValue, err := UnmarshalReflect(value, valueType)
  166. if err != nil {
  167. return zero, err
  168. }
  169. result.SetMapIndex(unmarshalledKey, unmarshalledValue)
  170. }
  171. case *starlarkstruct.Struct:
  172. if result.Type().Kind() != reflect.Struct {
  173. return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
  174. }
  175. if result.NumField() != len(v.AttrNames()) {
  176. return zero, fmt.Errorf("starlark struct and go struct have different number of fields (%d and %d)", len(v.AttrNames()), result.NumField())
  177. }
  178. for _, attrName := range v.AttrNames() {
  179. attr, err := v.Attr(attrName)
  180. if err != nil {
  181. return zero, err
  182. }
  183. // TODO(b/279787235): this should probably support tags to rename the field
  184. resultField := result.FieldByName(attrName)
  185. if resultField == (reflect.Value{}) {
  186. return zero, fmt.Errorf("starlark struct had field %s, but requested struct type did not", attrName)
  187. }
  188. // This hack allows us to change unexported fields
  189. resultField = reflect.NewAt(resultField.Type(), unsafe.Pointer(resultField.UnsafeAddr())).Elem()
  190. x, err := UnmarshalReflect(attr, resultField.Type())
  191. if err != nil {
  192. return zero, err
  193. }
  194. resultField.Set(x)
  195. }
  196. default:
  197. return zero, fmt.Errorf("unimplemented starlark type: %s", value.Type())
  198. }
  199. return result, nil
  200. }
  201. func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) {
  202. var err error
  203. switch v := value.(type) {
  204. case starlark.String:
  205. return reflect.TypeOf(""), nil
  206. case *starlark.List:
  207. innerType := reflect.TypeOf("")
  208. if v.Len() > 0 {
  209. innerType, err = typeOfStarlarkValue(v.Index(0))
  210. if err != nil {
  211. return nil, err
  212. }
  213. }
  214. for i := 1; i < v.Len(); i++ {
  215. innerTypeI, err := typeOfStarlarkValue(v.Index(i))
  216. if err != nil {
  217. return nil, err
  218. }
  219. if innerType != innerTypeI {
  220. return nil, fmt.Errorf("List must contain elements of entirely the same type, found %v and %v", innerType, innerTypeI)
  221. }
  222. }
  223. return reflect.SliceOf(innerType), nil
  224. case *starlark.Dict:
  225. keyType := reflect.TypeOf("")
  226. valueType := reflect.TypeOf("")
  227. keys := v.Keys()
  228. if v.Len() > 0 {
  229. firstKey := keys[0]
  230. keyType, err = typeOfStarlarkValue(firstKey)
  231. if err != nil {
  232. return nil, err
  233. }
  234. firstValue, found, err := v.Get(firstKey)
  235. if !found {
  236. err = fmt.Errorf("value not found")
  237. }
  238. if err != nil {
  239. return nil, err
  240. }
  241. valueType, err = typeOfStarlarkValue(firstValue)
  242. if err != nil {
  243. return nil, err
  244. }
  245. }
  246. for _, key := range keys {
  247. keyTypeI, err := typeOfStarlarkValue(key)
  248. if err != nil {
  249. return nil, err
  250. }
  251. if keyType != keyTypeI {
  252. return nil, fmt.Errorf("dict must contain elements of entirely the same type, found %v and %v", keyType, keyTypeI)
  253. }
  254. value, found, err := v.Get(key)
  255. if !found {
  256. err = fmt.Errorf("value not found")
  257. }
  258. if err != nil {
  259. return nil, err
  260. }
  261. valueTypeI, err := typeOfStarlarkValue(value)
  262. if valueType.Kind() != reflect.Interface && valueTypeI != valueType {
  263. // If we see conflicting value types, change the result value type to an empty interface
  264. valueType = reflect.TypeOf([]interface{}{}).Elem()
  265. }
  266. }
  267. return reflect.MapOf(keyType, valueType), nil
  268. case starlark.Int:
  269. return reflect.TypeOf(0), nil
  270. case starlark.Float:
  271. return reflect.TypeOf(0.0), nil
  272. case starlark.Bool:
  273. return reflect.TypeOf(true), nil
  274. default:
  275. return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
  276. }
  277. }