openvcs_core/
backend_id.rs

1use serde::{Deserialize, Deserializer};
2use std::borrow::Cow;
3use std::fmt;
4
5/// Backend identifiers are stable, kebab-case strings registered by each backend crate.
6#[derive(Debug, Clone)]
7pub struct BackendId(pub Cow<'static, str>);
8
9impl BackendId {
10    pub fn as_str(&self) -> &str {
11        self.0.as_ref()
12    }
13}
14
15impl From<String> for BackendId {
16    fn from(s: String) -> Self {
17        BackendId(Cow::Owned(s))
18    }
19}
20
21impl<'de> Deserialize<'de> for BackendId {
22    fn deserialize<D>(de: D) -> Result<Self, D::Error>
23    where
24        D: Deserializer<'de>,
25    {
26        let deserialised_string = String::deserialize(de)?;
27        Ok(BackendId(Cow::Owned(deserialised_string)))
28    }
29}
30
31impl From<&str> for BackendId {
32    fn from(s: &str) -> Self {
33        BackendId(Cow::Owned(s.to_owned()))
34    }
35}
36
37impl AsRef<str> for BackendId {
38    fn as_ref(&self) -> &str {
39        self.as_str()
40    }
41}
42
43impl fmt::Display for BackendId {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        f.write_str(self.as_str())
46    }
47}
48
49impl PartialEq<&str> for BackendId {
50    fn eq(&self, other: &&str) -> bool {
51        self.as_str() == *other
52    }
53}
54
55#[macro_export]
56macro_rules! backend_id {
57    ($lit:literal) => {
58        $crate::BackendId(::std::borrow::Cow::Borrowed($lit))
59    };
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use serde_json::json;
66
67    #[test]
68    fn from_string_and_str_produce_expected_values() {
69        let owned = BackendId::from(String::from("git"));
70        let borrowed = BackendId::from("git");
71
72        assert_eq!(owned.as_str(), "git");
73        assert_eq!(borrowed.as_str(), "git");
74        assert!(borrowed == "git");
75    }
76
77    #[test]
78    fn displays_inner_string() {
79        let id = BackendId::from("libgit2");
80        assert_eq!(id.to_string(), "libgit2");
81    }
82
83    #[test]
84    fn serde_deserialises_from_json_string() {
85        let id: BackendId = serde_json::from_value(json!("git")).expect("deserialise backend id");
86        assert_eq!(id.as_str(), "git");
87    }
88
89    #[test]
90    fn macro_creates_borrowed_backend_id() {
91        let id = backend_id!("memory");
92        match id.0 {
93            Cow::Borrowed(value) => assert_eq!(value, "memory"),
94            Cow::Owned(_) => panic!("backend_id! should borrow literals"),
95        }
96    }
97}