| // 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 | 
 | 			// <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName(). | 
 | 			//     properties *struct {<Module_traits> []string, ....} | 
 | 			// | 
 | 			// Although it accesses the field by index the following reflection code is equivalent to: | 
 | 			//    *properties.<Module_traits> | 
 | 			// | 
 | 			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, | 
 | 	} | 
 | } |