| Paul Duffin | d19f894 | 2021-07-14 12:08:37 +0100 | [diff] [blame] | 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 |  | 
|  | 15 | package sdk | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 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. | 
|  | 26 | type 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 | 
| Paul Duffin | 30c830b | 2021-09-22 11:49:47 +0100 | [diff] [blame] | 35 | // to a slice of SdkMemberTrait instances returned by android.RegisteredSdkMemberTraits(). | 
| Paul Duffin | d19f894 | 2021-07-14 12:08:37 +0100 | [diff] [blame] | 36 | var 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. | 
|  | 41 | type dynamicSdkMemberTraits struct { | 
|  | 42 | // The dynamically generated structure type. | 
|  | 43 | // | 
| Paul Duffin | 30c830b | 2021-09-22 11:49:47 +0100 | [diff] [blame] | 44 | // Contains one []string exported field for each SdkMemberTrait returned by android.RegisteredSdkMemberTraits(). The name of | 
| Paul Duffin | d19f894 | 2021-07-14 12:08:37 +0100 | [diff] [blame] | 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 |  | 
|  | 52 | func (d *dynamicSdkMemberTraits) createMemberTraitListProperties() interface{} { | 
|  | 53 | return reflect.New(d.propertiesStructType).Interface() | 
|  | 54 | } | 
|  | 55 |  | 
| Paul Duffin | 30c830b | 2021-09-22 11:49:47 +0100 | [diff] [blame] | 56 | func getDynamicSdkMemberTraits(key android.OnceKey, registeredTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits { | 
| Paul Duffin | d19f894 | 2021-07-14 12:08:37 +0100 | [diff] [blame] | 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. | 
| Paul Duffin | d19f894 | 2021-07-14 12:08:37 +0100 | [diff] [blame] | 71 | func 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 | } |