github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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 = "host", 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  
    97      if ctx.attr.anon:
    98          args.append("-anon")
    99  
   100      ctx.actions.run(
   101          inputs = [info.template],
   102          outputs = [output],
   103          mnemonic = "GoGenericsInstance",
   104          progress_message = "Building Go template instance %s" % ctx.label,
   105          arguments = args,
   106          executable = ctx.executable._tool,
   107      )
   108  
   109      return [DefaultInfo(
   110          files = depset([output]),
   111      )]
   112  
   113  go_template_instance = rule(
   114      implementation = _go_template_instance_impl,
   115      attrs = {
   116          "template": attr.label(doc = "the label of the template to be instantiated", mandatory = True),
   117          "prefix": attr.string(doc = "a prefix to be added to globals in the template"),
   118          "suffix": attr.string(doc = "a suffix to be added to globals in the template"),
   119          "types": attr.string_dict(doc = "the map from generic type names to concrete ones"),
   120          "consts": attr.string_dict(doc = "the map from constant names to their values"),
   121          "imports": attr.string_dict(doc = "the map from imports used in types/consts to their import paths"),
   122          "anon": attr.bool(doc = "whether anoymous fields should be processed", mandatory = False, default = False),
   123          "package": attr.string(doc = "the package for the generated source file", mandatory = False),
   124          "out": attr.output(doc = "output file", mandatory = True),
   125          "_tool": attr.label(executable = True, cfg = "host", default = Label("//tools/go_generics")),
   126      },
   127  )