Handle colon-less and relative bazel labels in `ir.rs`.
This has been bugging me for a while now -- not because I'd predict it to be a real issue, but just because it feels weird to rely on a specific formatting of bazel labels. This has bitten me in the past with e.g. unknown commit.
I restrained myself until now, but it's still kind of bothering me that we crash on `//foo` syntax. I took the most expedient option of fixing it the simplest way I know how.
The alternative would have been to make the field private, and validate the input at parsing time (e.g. defining `TryFrom` instead of `From`, and validating that the label meets basic validity checks. I chose not to because it's a lot more work than to accept invalid labels without crashing.
This probably won't actually affect anything, but if we ever find ourselves forwarding bazel labels along using non-canonicalized form of `//foo:bar`, we will DTRT. Hopefully that doesn't hide any problems.
PiperOrigin-RevId: 516897644
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index c16a444..e7f0e94 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -250,16 +250,21 @@
}
}
+/// A Bazel label, e.g. `//foo:bar`.
#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
#[serde(transparent)]
pub struct BazelLabel(pub Rc<str>);
impl BazelLabel {
+ /// Returns the target name. E.g. `bar` for `//foo:bar`.
pub fn target_name(&self) -> &str {
- match self.0.split_once(':') {
- Some((_package, target_name)) => target_name,
- None => panic!("Unsupported label format {:?}", self.0),
+ if let Some((_package, target_name)) = self.0.split_once(':') {
+ return target_name;
}
+ if let Some((_, last_package_component)) = self.0.rsplit_once('/') {
+ return last_package_component;
+ }
+ &self.0
}
}
@@ -1103,4 +1108,32 @@
let ir = deserialize_ir(input.as_bytes()).unwrap();
assert_eq!(ir.crate_root_path().as_deref(), Some("__cc_template_instantiations_rs_api"));
}
+
+ #[test]
+ fn test_bazel_label_target() {
+ let label: BazelLabel = "//foo:bar".into();
+ assert_eq!(label.target_name(), "bar");
+ }
+
+ #[test]
+ fn test_bazel_label_target_dotless() {
+ let label: BazelLabel = "//foo".into();
+ assert_eq!(label.target_name(), "foo");
+ }
+
+ #[test]
+ fn test_bazel_label_dotless_slashless() {
+ let label: BazelLabel = "foo".into();
+ assert_eq!(label.target_name(), "foo");
+ }
+
+ /// These are not labels, but there is an unambiguous interpretation of
+ /// what their target should be that lets us keep going.
+ #[test]
+ fn test_bazel_label_empty_target() {
+ for s in ["foo:", "foo/", ""] {
+ let label: BazelLabel = s.into();
+ assert_eq!(label.target_name(), "", "label={s:?}");
+ }
+ }
}