gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/tools/go_generics/defs.bzl (about) 1 """Generics support via go_generics. 2 3 A Go template is similar to a go library, except that it has certain types that 4 can be replaced before usage. For example, one could define a templatized List 5 struct, whose elements are of type T, then instantiate that template for 6 T=segment, where "segment" is the concrete type. 7 """ 8 9 TemplateInfo = provider( 10 "Information about a go_generics template.", 11 fields = { 12 "unsafe": "whether the template requires unsafe code", 13 "types": "required types", 14 "opt_types": "optional types", 15 "consts": "required consts", 16 "opt_consts": "optional consts", 17 "deps": "package dependencies", 18 "template": "merged template source file", 19 }, 20 ) 21 22 def _go_template_impl(ctx): 23 srcs = ctx.files.srcs 24 template = ctx.actions.declare_file(ctx.label.name + "_template.go") 25 args = ["-o=%s" % template.path] + [f.path for f in srcs] 26 27 ctx.actions.run( 28 inputs = srcs, 29 outputs = [template], 30 mnemonic = "GoGenericsTemplate", 31 progress_message = "Building Go template %s" % ctx.label, 32 arguments = args, 33 executable = ctx.executable._tool, 34 ) 35 36 return [TemplateInfo( 37 types = ctx.attr.types, 38 opt_types = ctx.attr.opt_types, 39 consts = ctx.attr.consts, 40 opt_consts = ctx.attr.opt_consts, 41 deps = ctx.attr.deps, 42 template = template, 43 )] 44 45 go_template = rule( 46 implementation = _go_template_impl, 47 attrs = { 48 "srcs": attr.label_list(doc = "the list of source files that comprise the template", mandatory = True, allow_files = True), 49 "deps": attr.label_list(doc = "the standard dependency list", allow_files = True, cfg = "target"), 50 "types": attr.string_list(doc = "the list of generic types in the template that are required to be specified"), 51 "opt_types": attr.string_list(doc = "the list of generic types in the template that can but aren't required to be specified"), 52 "consts": attr.string_list(doc = "the list of constants in the template that are required to be specified"), 53 "opt_consts": attr.string_list(doc = "the list of constants in the template that can but aren't required to be specified"), 54 "_tool": attr.label(executable = True, cfg = "exec", default = Label("//tools/go_generics/go_merge")), 55 }, 56 ) 57 58 def _go_template_instance_impl(ctx): 59 info = ctx.attr.template[TemplateInfo] 60 output = ctx.outputs.out 61 62 # Check that all required types are defined. 63 for t in info.types: 64 if t not in ctx.attr.types: 65 fail("Missing value for type %s in %s" % (t, ctx.attr.template.label)) 66 67 # Check that all defined types are expected by the template. 68 for t in ctx.attr.types: 69 if (t not in info.types) and (t not in info.opt_types): 70 fail("Type %s is not a parameter to %s" % (t, ctx.attr.template.label)) 71 72 # Check that all required consts are defined. 73 for t in info.consts: 74 if t not in ctx.attr.consts: 75 fail("Missing value for constant %s in %s" % (t, ctx.attr.template.label)) 76 77 # Check that all defined consts are expected by the template. 78 for t in ctx.attr.consts: 79 if (t not in info.consts) and (t not in info.opt_consts): 80 fail("Const %s is not a parameter to %s" % (t, ctx.attr.template.label)) 81 82 # Build the argument list. 83 args = ["-i=%s" % info.template.path, "-o=%s" % output.path] 84 if ctx.attr.package: 85 args.append("-p=%s" % ctx.attr.package) 86 87 if len(ctx.attr.prefix) > 0: 88 args.append("-prefix=%s" % ctx.attr.prefix) 89 90 if len(ctx.attr.suffix) > 0: 91 args.append("-suffix=%s" % ctx.attr.suffix) 92 93 args += [("-t=%s=%s" % (p[0], p[1])) for p in ctx.attr.types.items()] 94 args += [("-c=%s=%s" % (p[0], p[1])) for p in ctx.attr.consts.items()] 95 args += [("-import=%s=%s" % (p[0], p[1])) for p in ctx.attr.imports.items()] 96 args += [("-in-substr=%s=%s" % (p[0], p[1])) for p in ctx.attr.input_substrs.items()] 97 args += [("-out-substr=%s=%s" % (p[0], p[1])) for p in ctx.attr.substrs.items()] 98 99 if ctx.attr.anon: 100 args.append("-anon") 101 102 ctx.actions.run( 103 inputs = [info.template], 104 outputs = [output], 105 mnemonic = "GoGenericsInstance", 106 progress_message = "Building Go template instance %s" % ctx.label, 107 arguments = args, 108 executable = ctx.executable._tool, 109 ) 110 111 return [DefaultInfo( 112 files = depset([output]), 113 )] 114 115 go_template_instance = rule( 116 implementation = _go_template_instance_impl, 117 attrs = { 118 "template": attr.label(doc = "the label of the template to be instantiated", mandatory = True), 119 "prefix": attr.string(doc = "a prefix to be added to globals in the template"), 120 "suffix": attr.string(doc = "a suffix to be added to globals in the template"), 121 "types": attr.string_dict(doc = "the map from generic type names to concrete ones"), 122 "consts": attr.string_dict(doc = "the map from constant names to their values"), 123 "imports": attr.string_dict(doc = "the map from imports used in types/consts to their import paths"), 124 "input_substrs": attr.string_dict(doc = "the map from sub-strings to their replacements, applied just after reading the template code"), 125 "substrs": attr.string_dict(doc = "the map from sub-strings to their replacements, applied just before writing the template instance code"), 126 "anon": attr.bool(doc = "whether anoymous fields should be processed", mandatory = False, default = False), 127 "package": attr.string(doc = "the package for the generated source file", mandatory = False), 128 "out": attr.output(doc = "output file", mandatory = True), 129 "_tool": attr.label(executable = True, cfg = "exec", default = Label("//tools/go_generics")), 130 }, 131 )