member_trait.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // Copyright (C) 2021 The Android Open Source Project
  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 sdk
  15. import (
  16. "reflect"
  17. "android/soong/android"
  18. "github.com/google/blueprint/proptools"
  19. )
  20. // Contains information about the sdk properties that list sdk members by trait, e.g.
  21. // native_bridge.
  22. type sdkMemberTraitListProperty struct {
  23. // getter for the list of member names
  24. getter func(properties interface{}) []string
  25. // the trait of member referenced in the list
  26. memberTrait android.SdkMemberTrait
  27. }
  28. // Cache of dynamically generated dynamicSdkMemberTraits objects. The key is the pointer
  29. // to a slice of SdkMemberTrait instances returned by android.RegisteredSdkMemberTraits().
  30. var dynamicSdkMemberTraitsMap android.OncePer
  31. // A dynamically generated set of member list properties and associated structure type.
  32. //
  33. // Instances of this are created by createDynamicSdkMemberTraits.
  34. type dynamicSdkMemberTraits struct {
  35. // The dynamically generated structure type.
  36. //
  37. // Contains one []string exported field for each SdkMemberTrait returned by android.RegisteredSdkMemberTraits(). The name of
  38. // the field is the exported form of the value returned by SdkMemberTrait.SdkPropertyName().
  39. propertiesStructType reflect.Type
  40. // Information about each of the member trait specific list properties.
  41. memberTraitListProperties []*sdkMemberTraitListProperty
  42. }
  43. func (d *dynamicSdkMemberTraits) createMemberTraitListProperties() interface{} {
  44. return reflect.New(d.propertiesStructType).Interface()
  45. }
  46. func getDynamicSdkMemberTraits(key android.OnceKey, registeredTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits {
  47. // Get the cached value, creating new instance if necessary.
  48. return dynamicSdkMemberTraitsMap.Once(key, func() interface{} {
  49. return createDynamicSdkMemberTraits(registeredTraits)
  50. }).(*dynamicSdkMemberTraits)
  51. }
  52. // Create the dynamicSdkMemberTraits from the list of registered member traits.
  53. //
  54. // A struct is created which contains one exported field per member trait corresponding to
  55. // the SdkMemberTrait.SdkPropertyName() value.
  56. //
  57. // A list of sdkMemberTraitListProperty instances is created, one per member trait that provides:
  58. // * a reference to the member trait.
  59. // * a getter for the corresponding field in the properties struct.
  60. func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits {
  61. var listProperties []*sdkMemberTraitListProperty
  62. memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{}
  63. var fields []reflect.StructField
  64. // Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects.
  65. nextFieldIndex := 0
  66. for _, memberTrait := range sdkMemberTraits {
  67. p := memberTrait.SdkPropertyName()
  68. var getter func(properties interface{}) []string
  69. // Create a dynamic exported field for the member trait's property.
  70. fields = append(fields, reflect.StructField{
  71. Name: proptools.FieldNameForProperty(p),
  72. Type: reflect.TypeOf([]string{}),
  73. })
  74. // Copy the field index for use in the getter func as using the loop variable directly will
  75. // cause all funcs to use the last value.
  76. fieldIndex := nextFieldIndex
  77. nextFieldIndex += 1
  78. getter = func(properties interface{}) []string {
  79. // The properties is expected to be of the following form (where
  80. // <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName().
  81. // properties *struct {<Module_traits> []string, ....}
  82. //
  83. // Although it accesses the field by index the following reflection code is equivalent to:
  84. // *properties.<Module_traits>
  85. //
  86. list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
  87. return list
  88. }
  89. // Create an sdkMemberTraitListProperty for the member trait.
  90. memberListProperty := &sdkMemberTraitListProperty{
  91. getter: getter,
  92. memberTrait: memberTrait,
  93. }
  94. memberTraitToProperty[memberTrait] = memberListProperty
  95. listProperties = append(listProperties, memberListProperty)
  96. }
  97. // Create a dynamic struct from the collated fields.
  98. propertiesStructType := reflect.StructOf(fields)
  99. return &dynamicSdkMemberTraits{
  100. memberTraitListProperties: listProperties,
  101. propertiesStructType: propertiesStructType,
  102. }
  103. }