blob: 85b3e1379f5e4f9310383b33be48b1fb98bf4e23 [file] [log] [blame]
Paul Duffind19f8942021-07-14 12:08:37 +01001// 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 held in 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 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(registry *android.SdkMemberTraitsRegistry) *dynamicSdkMemberTraits {
57
58 // Get a key that uniquely identifies the registry contents.
59 key := registry.UniqueOnceKey()
60
61 // Get the registered traits.
62 registeredTraits := registry.RegisteredTraits()
63
64 // Get the cached value, creating new instance if necessary.
65 return dynamicSdkMemberTraitsMap.Once(key, func() interface{} {
66 return createDynamicSdkMemberTraits(registeredTraits)
67 }).(*dynamicSdkMemberTraits)
68}
69
70// Create the dynamicSdkMemberTraits from the list of registered member traits.
71//
72// A struct is created which contains one exported field per member trait corresponding to
73// the SdkMemberTrait.SdkPropertyName() value.
74//
75// A list of sdkMemberTraitListProperty instances is created, one per member trait that provides:
76// * a reference to the member trait.
77// * a getter for the corresponding field in the properties struct.
78//
79func createDynamicSdkMemberTraits(sdkMemberTraits []android.SdkMemberTrait) *dynamicSdkMemberTraits {
80
81 var listProperties []*sdkMemberTraitListProperty
82 memberTraitToProperty := map[android.SdkMemberTrait]*sdkMemberTraitListProperty{}
83 var fields []reflect.StructField
84
85 // Iterate over the member traits creating StructField and sdkMemberTraitListProperty objects.
86 nextFieldIndex := 0
87 for _, memberTrait := range sdkMemberTraits {
88
89 p := memberTrait.SdkPropertyName()
90
91 var getter func(properties interface{}) []string
92
93 // Create a dynamic exported field for the member trait's property.
94 fields = append(fields, reflect.StructField{
95 Name: proptools.FieldNameForProperty(p),
96 Type: reflect.TypeOf([]string{}),
97 })
98
99 // Copy the field index for use in the getter func as using the loop variable directly will
100 // cause all funcs to use the last value.
101 fieldIndex := nextFieldIndex
102 nextFieldIndex += 1
103
104 getter = func(properties interface{}) []string {
105 // The properties is expected to be of the following form (where
106 // <Module_traits> is the name of an SdkMemberTrait.SdkPropertyName().
107 // properties *struct {<Module_traits> []string, ....}
108 //
109 // Although it accesses the field by index the following reflection code is equivalent to:
110 // *properties.<Module_traits>
111 //
112 list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
113 return list
114 }
115
116 // Create an sdkMemberTraitListProperty for the member trait.
117 memberListProperty := &sdkMemberTraitListProperty{
118 getter: getter,
119 memberTrait: memberTrait,
120 }
121
122 memberTraitToProperty[memberTrait] = memberListProperty
123 listProperties = append(listProperties, memberListProperty)
124 }
125
126 // Create a dynamic struct from the collated fields.
127 propertiesStructType := reflect.StructOf(fields)
128
129 return &dynamicSdkMemberTraits{
130 memberTraitListProperties: listProperties,
131 propertiesStructType: propertiesStructType,
132 }
133}