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:?}");
+        }
+    }
 }