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. 71func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { 72 73 var listProperties []*sdkMemberTraitListProperty 74 memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{} 75 var fields []reflect.StructField 76 77 // Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects. 78 nextFieldIndex := 0 79 for _, memberTrait := range sdkMemberTraits { 80 81 p := memberTrait.SdkPropertyName() 82 83 var getter func(properties interface{}) []string 84 85 // Create a dynamic exported field for the member trait's property. 86 fields = append(fields, reflect.StructField{ 87 Name: proptools.FieldNameForProperty(p), 88 Type: reflect.TypeOf([]string{}), 89 }) 90 91 // Copy the field index for use in the getter func as using the loop variable directly will 92 // cause all funcs to use the last value. 93 fieldIndex := nextFieldIndex 94 nextFieldIndex += 1 95 96 getter = func(properties interface{}) []string { 97 // The properties is expected to be of the following form (where 98 // <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName(). 99 // properties *struct {<Module_traits> []string, ....} 100 // 101 // Although it accesses the field by index the following reflection code is equivalent to: 102 // *properties.<Module_traits> 103 // 104 list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string) 105 return list 106 } 107 108 // Create an sdkMemberTraitListProperty for the member trait. 109 memberListProperty := &sdkMemberTraitListProperty{ 110 getter: getter, 111 memberTrait: memberTrait, 112 } 113 114 memberTraitToProperty[memberTrait] = memberListProperty 115 listProperties = append(listProperties, memberListProperty) 116 } 117 118 // Create a dynamic struct from the collated fields. 119 propertiesStructType := reflect.StructOf(fields) 120 121 return &dynamicSdkMemberTraits{ 122 memberTraitListProperties: listProperties, 123 propertiesStructType: propertiesStructType, 124 } 125} 126