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