summaryrefslogtreecommitdiff
path: root/rust-bindings/src/object_name.rs
blob: d6071780e08aed90689af1560b26e6da4528cad5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::ObjectType;
use crate::{object_name_deserialize, object_name_serialize, object_to_string};
use glib::GString;
use std::fmt::Display;
use std::fmt::Error;
use std::fmt::Formatter;
use std::hash::Hash;
use std::hash::Hasher;

fn hash_object_name(v: &glib::Variant) -> u32 {
    unsafe { ffi::ostree_hash_object_name(v.as_ptr() as glib::ffi::gconstpointer) }
}

/// A reference to an object in an OSTree repo. It contains both a checksum and an
/// [ObjectType](enum.ObjectType.html) which together identify an object in a repository.
#[derive(Eq, Debug)]
pub struct ObjectName {
    variant: glib::Variant,
    checksum: GString,
    object_type: ObjectType,
}

impl ObjectName {
    /// Create a new `ObjectName` from a serialized representation.
    pub fn new_from_variant(variant: glib::Variant) -> ObjectName {
        let deserialize = object_name_deserialize(&variant);
        ObjectName {
            variant,
            checksum: deserialize.0,
            object_type: deserialize.1,
        }
    }

    /// Create a new `ObjectName` with the given checksum and `ObjectType`.
    pub fn new<S: Into<GString>>(checksum: S, object_type: ObjectType) -> ObjectName {
        let checksum = checksum.into();
        let variant = object_name_serialize(checksum.as_str(), object_type)
            .expect("type checks should make this safe");
        ObjectName {
            variant,
            checksum,
            object_type,
        }
    }

    /// Return a reference to this `ObjectName`'s checksum string.
    pub fn checksum(&self) -> &str {
        self.checksum.as_str()
    }

    /// Return this `ObjectName`'s `ObjectType`.
    pub fn object_type(&self) -> ObjectType {
        self.object_type
    }

    /// Format this `ObjectName` as a string.
    fn to_string(&self) -> GString {
        object_to_string(self.checksum(), self.object_type())
            .expect("type checks should make this safe")
    }
}

impl Display for ObjectName {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "{}", self.to_string())
    }
}

impl Hash for ObjectName {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u32(hash_object_name(&self.variant));
    }
}

impl PartialEq for ObjectName {
    fn eq(&self, other: &ObjectName) -> bool {
        self.checksum == other.checksum && self.object_type == other.object_type
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn should_stringify_object_name() {
        let object_name = ObjectName::new("abcdef123456", ObjectType::DirTree);
        let stringified = format!("{object_name}");
        assert_eq!(stringified, "abcdef123456.dirtree");
    }

    #[test]
    fn same_values_should_be_equal() {
        let a = ObjectName::new("abc123", ObjectType::File);
        let b = ObjectName::new("abc123", ObjectType::File);
        assert_eq!(a, b);
    }

    #[test]
    fn different_values_should_not_be_equal() {
        let a = ObjectName::new("abc123", ObjectType::Commit);
        let b = ObjectName::new("abc123", ObjectType::File);
        assert_ne!(a, b);
    }

    #[test]
    fn should_create_object_name_from_variant() {
        let object_name = ObjectName::new("123456", ObjectType::CommitMeta);
        let from_variant = ObjectName::new_from_variant(object_name.variant.clone());
        assert_eq!(object_name, from_variant);
        assert_eq!("123456", from_variant.checksum());
        assert_eq!(ObjectType::CommitMeta, from_variant.object_type());
    }
}