1package codegen
2
3import (
4	"fmt"
5	"strconv"
6
7	"android/soong/android"
8	"android/soong/rust"
9
10	"github.com/google/blueprint"
11	"github.com/google/blueprint/proptools"
12)
13
14type rustDeclarationsTagType struct {
15	blueprint.BaseDependencyTag
16}
17
18var rustDeclarationsTag = rustDeclarationsTagType{}
19
20type RustAconfigLibraryProperties struct {
21	// name of the aconfig_declarations module to generate a library for
22	Aconfig_declarations string
23
24	// default mode is "production", the other accepted modes are:
25	// "test": to generate test mode version of the library
26	// "exported": to generate exported mode version of the library
27	// "force-read-only": to generate force-read-only mode version of the library
28	// an error will be thrown if the mode is not supported
29	Mode *string
30}
31
32type aconfigDecorator struct {
33	*rust.BaseSourceProvider
34
35	Properties RustAconfigLibraryProperties
36}
37
38func NewRustAconfigLibrary(hod android.HostOrDeviceSupported) (*rust.Module, *aconfigDecorator) {
39	aconfig := &aconfigDecorator{
40		BaseSourceProvider: rust.NewSourceProvider(),
41		Properties:         RustAconfigLibraryProperties{},
42	}
43
44	module := rust.NewSourceProviderModule(android.HostAndDeviceSupported, aconfig, false, false)
45	return module, aconfig
46}
47
48// rust_aconfig_library generates aconfig rust code from the provided aconfig declaration. This module type will
49// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
50// properties of other modules.
51func RustAconfigLibraryFactory() android.Module {
52	module, _ := NewRustAconfigLibrary(android.HostAndDeviceSupported)
53	return module.Init()
54}
55
56func (a *aconfigDecorator) SourceProviderProps() []interface{} {
57	return append(a.BaseSourceProvider.SourceProviderProps(), &a.Properties)
58}
59
60func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
61	generatedDir := android.PathForModuleGen(ctx)
62	generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs")
63
64	declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag)
65
66	if len(declarationsModules) != 1 {
67		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
68	}
69	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
70
71	mode := proptools.StringDefault(a.Properties.Mode, "production")
72	if !isModeSupported(mode) {
73		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
74	}
75
76	ctx.Build(pctx, android.BuildParams{
77		Rule:  rustRule,
78		Input: declarations.IntermediateCacheOutputPath,
79		Outputs: []android.WritablePath{
80			generatedSource,
81		},
82		Description: "rust_aconfig_library",
83		Args: map[string]string{
84			"gendir": generatedDir.String(),
85			"mode":   mode,
86			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()),
87		},
88	})
89	a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
90
91	android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
92		ModeInfos: map[string]android.ModeInfo{
93			ctx.ModuleName(): {
94				Container: declarations.Container,
95				Mode:      mode,
96			}},
97	})
98
99	return generatedSource
100}
101
102func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps {
103	deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps)
104	deps.Rustlibs = append(deps.Rustlibs, "libaconfig_storage_read_api")
105	deps.Rustlibs = append(deps.Rustlibs, "libflags_rust")
106	deps.Rustlibs = append(deps.Rustlibs, "liblazy_static")
107	deps.Rustlibs = append(deps.Rustlibs, "liblogger")
108	deps.Rustlibs = append(deps.Rustlibs, "liblog_rust")
109	ctx.AddDependency(ctx.Module(), rustDeclarationsTag, a.Properties.Aconfig_declarations)
110	return deps
111}
112