// Copyright (C) 2021 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package sdk import ( "reflect" "android/soong/android" "github.com/google/blueprint/proptools" ) // Contains information about the sdk properties that list sdk members by trait, e.g. // native_bridge. type sdkMemberTraitListProperty struct { // getter for the list of member names getter func(properties interface{}) []string // the trait of member referenced in the list memberTrait android.SdkMemberTrait } // Cache of dynamically generated dynamicSdkMemberTraits objects. The key is the pointer // to a slice of SdkMemberTrait instances returned by android.RegisteredSdkMemberTraits(). var dynamicSdkMemberTraitsMap android.OncePer // A dynamically generated set of member list properties and associated structure type. // // Instances of this are created by createDynamicSdkMemberTraits. type dynamicSdkMemberTraits struct { // The dynamically generated structure type. // // Contains one []string exported field for each SdkMemberTrait returned by android.RegisteredSdkMemberTraits(). The name of // the field is the exported form of the value returned by SdkMemberTrait.SdkPropertyName(). propertiesStructType reflect.Type // Information about each of the member trait specific list properties. memberTraitListProperties []*sdkMemberTraitListProperty } func (d *dynamicSdkMemberTraits) createMemberTraitListProperties() interface{} { return reflect.New(d.propertiesStructType).Interface() } func getDynamicSdkMemberTraits(key android.OnceKey, registeredTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { // Get the cached value, creating new instance if necessary. return dynamicSdkMemberTraitsMap.Once(key, func() interface{} { return createDynamicSdkMemberTraits(registeredTraits) }).(*dynamicSdkMemberTraits) } // Create the dynamicSdkMemberTraits from the list of registered member traits. // // A struct is created which contains one exported field per member trait corresponding to // the SdkMemberTrait.SdkPropertyName() value. // // A list of sdkMemberTraitListProperty instances is created, one per member trait that provides: // * a reference to the member trait. // * a getter for the corresponding field in the properties struct. func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { var listProperties []*sdkMemberTraitListProperty memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{} var fields []reflect.StructField // Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects. nextFieldIndex := 0 for _, memberTrait := range sdkMemberTraits { p := memberTrait.SdkPropertyName() var getter func(properties interface{}) []string // Create a dynamic exported field for the member trait's property. fields = append(fields, reflect.StructField{ Name: proptools.FieldNameForProperty(p), Type: reflect.TypeOf([]string{}), }) // Copy the field index for use in the getter func as using the loop variable directly will // cause all funcs to use the last value. fieldIndex := nextFieldIndex nextFieldIndex += 1 getter = func(properties interface{}) []string { // The properties is expected to be of the following form (where // is the name of an SdkMemberTrait.SdkPropertyName(). // properties *struct { []string, ....} // // Although it accesses the field by index the following reflection code is equivalent to: // *properties. // list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string) return list } // Create an sdkMemberTraitListProperty for the member trait. memberListProperty := &sdkMemberTraitListProperty{ getter: getter, memberTrait: memberTrait, } memberTraitToProperty[memberTrait] = memberListProperty listProperties = append(listProperties, memberListProperty) } // Create a dynamic struct from the collated fields. propertiesStructType := reflect.StructOf(fields) return &dynamicSdkMemberTraits{ memberTraitListProperties: listProperties, propertiesStructType: propertiesStructType, } }