1*333d2b36SAndroid Build Coastguard Worker// Copyright (C) 2021 The Android Open Source Project 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage sdk 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "reflect" 19*333d2b36SAndroid Build Coastguard Worker 20*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 21*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 22*333d2b36SAndroid Build Coastguard Worker) 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker// Contains information about the sdk properties that list sdk members by trait, e.g. 25*333d2b36SAndroid Build Coastguard Worker// native_bridge. 26*333d2b36SAndroid Build Coastguard Workertype sdkMemberTraitListProperty struct { 27*333d2b36SAndroid Build Coastguard Worker // getter for the list of member names 28*333d2b36SAndroid Build Coastguard Worker getter func(properties interface{}) []string 29*333d2b36SAndroid Build Coastguard Worker 30*333d2b36SAndroid Build Coastguard Worker // the trait of member referenced in the list 31*333d2b36SAndroid Build Coastguard Worker memberTrait android.SdkMemberTrait 32*333d2b36SAndroid Build Coastguard Worker} 33*333d2b36SAndroid Build Coastguard Worker 34*333d2b36SAndroid Build Coastguard Worker// Cache of dynamically generated dynamicSdkMemberTraits objects. The key is the pointer 35*333d2b36SAndroid Build Coastguard Worker// to a slice of SdkMemberTrait instances returned by android.RegisteredSdkMemberTraits(). 36*333d2b36SAndroid Build Coastguard Workervar dynamicSdkMemberTraitsMap android.OncePer 37*333d2b36SAndroid Build Coastguard Worker 38*333d2b36SAndroid Build Coastguard Worker// A dynamically generated set of member list properties and associated structure type. 39*333d2b36SAndroid Build Coastguard Worker// 40*333d2b36SAndroid Build Coastguard Worker// Instances of this are created by createDynamicSdkMemberTraits. 41*333d2b36SAndroid Build Coastguard Workertype dynamicSdkMemberTraits struct { 42*333d2b36SAndroid Build Coastguard Worker // The dynamically generated structure type. 43*333d2b36SAndroid Build Coastguard Worker // 44*333d2b36SAndroid Build Coastguard Worker // Contains one []string exported field for each SdkMemberTrait returned by android.RegisteredSdkMemberTraits(). The name of 45*333d2b36SAndroid Build Coastguard Worker // the field is the exported form of the value returned by SdkMemberTrait.SdkPropertyName(). 46*333d2b36SAndroid Build Coastguard Worker propertiesStructType reflect.Type 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Worker // Information about each of the member trait specific list properties. 49*333d2b36SAndroid Build Coastguard Worker memberTraitListProperties []*sdkMemberTraitListProperty 50*333d2b36SAndroid Build Coastguard Worker} 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Workerfunc (d *dynamicSdkMemberTraits) createMemberTraitListProperties() interface{} { 53*333d2b36SAndroid Build Coastguard Worker return reflect.New(d.propertiesStructType).Interface() 54*333d2b36SAndroid Build Coastguard Worker} 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Workerfunc getDynamicSdkMemberTraits(key android.OnceKey, registeredTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { 57*333d2b36SAndroid Build Coastguard Worker // Get the cached value, creating new instance if necessary. 58*333d2b36SAndroid Build Coastguard Worker return dynamicSdkMemberTraitsMap.Once(key, func() interface{} { 59*333d2b36SAndroid Build Coastguard Worker return createDynamicSdkMemberTraits(registeredTraits) 60*333d2b36SAndroid Build Coastguard Worker }).(*dynamicSdkMemberTraits) 61*333d2b36SAndroid Build Coastguard Worker} 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Worker// Create the dynamicSdkMemberTraits from the list of registered member traits. 64*333d2b36SAndroid Build Coastguard Worker// 65*333d2b36SAndroid Build Coastguard Worker// A struct is created which contains one exported field per member trait corresponding to 66*333d2b36SAndroid Build Coastguard Worker// the SdkMemberTrait.SdkPropertyName() value. 67*333d2b36SAndroid Build Coastguard Worker// 68*333d2b36SAndroid Build Coastguard Worker// A list of sdkMemberTraitListProperty instances is created, one per member trait that provides: 69*333d2b36SAndroid Build Coastguard Worker// * a reference to the member trait. 70*333d2b36SAndroid Build Coastguard Worker// * a getter for the corresponding field in the properties struct. 71*333d2b36SAndroid Build Coastguard Workerfunc createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { 72*333d2b36SAndroid Build Coastguard Worker 73*333d2b36SAndroid Build Coastguard Worker var listProperties []*sdkMemberTraitListProperty 74*333d2b36SAndroid Build Coastguard Worker memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{} 75*333d2b36SAndroid Build Coastguard Worker var fields []reflect.StructField 76*333d2b36SAndroid Build Coastguard Worker 77*333d2b36SAndroid Build Coastguard Worker // Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects. 78*333d2b36SAndroid Build Coastguard Worker nextFieldIndex := 0 79*333d2b36SAndroid Build Coastguard Worker for _, memberTrait := range sdkMemberTraits { 80*333d2b36SAndroid Build Coastguard Worker 81*333d2b36SAndroid Build Coastguard Worker p := memberTrait.SdkPropertyName() 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Worker var getter func(properties interface{}) []string 84*333d2b36SAndroid Build Coastguard Worker 85*333d2b36SAndroid Build Coastguard Worker // Create a dynamic exported field for the member trait's property. 86*333d2b36SAndroid Build Coastguard Worker fields = append(fields, reflect.StructField{ 87*333d2b36SAndroid Build Coastguard Worker Name: proptools.FieldNameForProperty(p), 88*333d2b36SAndroid Build Coastguard Worker Type: reflect.TypeOf([]string{}), 89*333d2b36SAndroid Build Coastguard Worker }) 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Worker // Copy the field index for use in the getter func as using the loop variable directly will 92*333d2b36SAndroid Build Coastguard Worker // cause all funcs to use the last value. 93*333d2b36SAndroid Build Coastguard Worker fieldIndex := nextFieldIndex 94*333d2b36SAndroid Build Coastguard Worker nextFieldIndex += 1 95*333d2b36SAndroid Build Coastguard Worker 96*333d2b36SAndroid Build Coastguard Worker getter = func(properties interface{}) []string { 97*333d2b36SAndroid Build Coastguard Worker // The properties is expected to be of the following form (where 98*333d2b36SAndroid Build Coastguard Worker // <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName(). 99*333d2b36SAndroid Build Coastguard Worker // properties *struct {<Module_traits> []string, ....} 100*333d2b36SAndroid Build Coastguard Worker // 101*333d2b36SAndroid Build Coastguard Worker // Although it accesses the field by index the following reflection code is equivalent to: 102*333d2b36SAndroid Build Coastguard Worker // *properties.<Module_traits> 103*333d2b36SAndroid Build Coastguard Worker // 104*333d2b36SAndroid Build Coastguard Worker list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string) 105*333d2b36SAndroid Build Coastguard Worker return list 106*333d2b36SAndroid Build Coastguard Worker } 107*333d2b36SAndroid Build Coastguard Worker 108*333d2b36SAndroid Build Coastguard Worker // Create an sdkMemberTraitListProperty for the member trait. 109*333d2b36SAndroid Build Coastguard Worker memberListProperty := &sdkMemberTraitListProperty{ 110*333d2b36SAndroid Build Coastguard Worker getter: getter, 111*333d2b36SAndroid Build Coastguard Worker memberTrait: memberTrait, 112*333d2b36SAndroid Build Coastguard Worker } 113*333d2b36SAndroid Build Coastguard Worker 114*333d2b36SAndroid Build Coastguard Worker memberTraitToProperty[memberTrait] = memberListProperty 115*333d2b36SAndroid Build Coastguard Worker listProperties = append(listProperties, memberListProperty) 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker 118*333d2b36SAndroid Build Coastguard Worker // Create a dynamic struct from the collated fields. 119*333d2b36SAndroid Build Coastguard Worker propertiesStructType := reflect.StructOf(fields) 120*333d2b36SAndroid Build Coastguard Worker 121*333d2b36SAndroid Build Coastguard Worker return &dynamicSdkMemberTraits{ 122*333d2b36SAndroid Build Coastguard Worker memberTraitListProperties: listProperties, 123*333d2b36SAndroid Build Coastguard Worker propertiesStructType: propertiesStructType, 124*333d2b36SAndroid Build Coastguard Worker } 125*333d2b36SAndroid Build Coastguard Worker} 126