1"""This file implements rust_proto_library.""" 2 3load("@rules_rust//rust:defs.bzl", "rust_common") 4load("//bazel/common:proto_common.bzl", "proto_common") 5load("//bazel/common:proto_info.bzl", "ProtoInfo") 6load( 7 "//rust:aspects.bzl", 8 "RustProtoInfo", 9 "label_to_crate_name", 10 "proto_rust_toolchain_label", 11 "rust_cc_proto_library_aspect", 12 "rust_upb_proto_library_aspect", 13) 14 15def rust_proto_library(name, deps, **args): 16 """Declares all the boilerplate needed to use Rust protobufs conveniently. 17 18 Hopefully no user will ever need to read this code. 19 20 Args: 21 name: name of the Rust protobuf target. 22 deps: proto_library target for which to generate Rust gencode. 23 **args: other args passed to the rust_<kernel>_proto_library targets. 24 """ 25 if not name.endswith("_rust_proto"): 26 fail( 27 "Name rust_proto_library target should end with `_rust_proto`, but was '{}'" 28 .format(name), 29 ) 30 name = name.removesuffix("_rust_proto") 31 alias_args = {} 32 if "visibility" in args: 33 alias_args["visibility"] = args.pop("visibility") 34 native.alias( 35 name = name + "_rust_proto", 36 actual = select({ 37 "//rust:use_upb_kernel": name + "_upb_rust_proto", 38 "//conditions:default": name + "_cpp_rust_proto", 39 }), 40 **alias_args 41 ) 42 43 rust_upb_proto_library( 44 name = name + "_upb_rust_proto", 45 deps = deps, 46 visibility = ["//visibility:private"], 47 **args 48 ) 49 50 rust_cc_proto_library( 51 name = name + "_cpp_rust_proto", 52 deps = deps, 53 visibility = ["//visibility:private"], 54 **args 55 ) 56 57def _user_visible_label(ctx): 58 label = str(ctx.label) 59 label = label.removesuffix("_cpp_rust_proto") 60 label = label.removesuffix("_upb_rust_proto") 61 return label + "_rust_proto" 62 63def _rust_proto_library_impl(ctx): 64 if not ctx.label.name.endswith("_rust_proto"): 65 fail( 66 "{}: Name of rust_proto_library target should end with `_rust_proto`." 67 .format(_user_visible_label(ctx)), 68 ) 69 deps = ctx.attr.deps 70 if not deps: 71 fail( 72 "{}: Exactly 1 dependency in `deps` attribute expected, none were provided." 73 .format(_user_visible_label(ctx)), 74 ) 75 if len(deps) > 1: 76 fail( 77 "{}: Exactly 1 dependency in `deps` attribute expected, too many were provided." 78 .format(_user_visible_label(ctx)), 79 ) 80 81 dep = deps[0] 82 rust_proto_info = dep[RustProtoInfo] 83 84 dep_variant_info = rust_proto_info.dep_variant_info 85 crate_info = dep_variant_info.crate_info 86 87 # Change the crate name from the hame of the proto_library to the name of the rust_proto_library. 88 # 89 # When the aspect visits proto_libraries, it doesn't know and cannot deduce the name of the 90 # rust_proto_library (although the name of rust_proto_libraries is consistently ending with 91 # _rust_proto, we can't rely on all proto_libraries to have a name consistently ending with 92 # _proto), therefore we have to modify it after the fact here. 93 # 94 # Since Starlark providers are frozen once they leave the _impl function that defines them, 95 # we have to create a shallow copy. 96 toolchain = ctx.toolchains["@rules_rust//rust:toolchain_type"] 97 fields = {field: getattr(crate_info, field) for field in dir(crate_info)} 98 pkg, name = _user_visible_label(ctx).rsplit(":") 99 label = struct(**{"name": name, "pkg": pkg}) 100 fields["name"] = label_to_crate_name(ctx, label, toolchain) 101 102 # These two fields present on the dir(crate_info) but break on some versions of Bazel when 103 # passed back in to crate_info. Strip them for now. 104 fields.pop("to_json") 105 fields.pop("to_proto") 106 107 crate_info_with_rust_proto_name = rust_common.crate_info(**fields) 108 109 return [ 110 crate_info_with_rust_proto_name, 111 dep_variant_info.dep_info, 112 dep_variant_info.cc_info, 113 DefaultInfo(files = dep_variant_info.crate_info.srcs), 114 ] 115 116def _make_rust_proto_library(is_upb): 117 return rule( 118 implementation = _rust_proto_library_impl, 119 attrs = { 120 "deps": attr.label_list( 121 mandatory = True, 122 providers = [ProtoInfo], 123 aspects = [rust_upb_proto_library_aspect if is_upb else rust_cc_proto_library_aspect], 124 ), 125 "_proto_lang_toolchain": attr.label( 126 default = Label(proto_rust_toolchain_label(is_upb)), 127 ), 128 }, 129 toolchains = [ 130 "@rules_rust//rust:toolchain_type", 131 ], 132 ) 133 134rust_upb_proto_library = _make_rust_proto_library(is_upb = True) 135rust_cc_proto_library = _make_rust_proto_library(is_upb = False) 136