gix_odb/
traits.rs

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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use std::io;

use gix_object::WriteTo;

use crate::find;

/// Describe the capability to write git objects into an object store.
pub trait Write {
    /// Write objects using the intrinsic kind of [`hash`][gix_hash::Kind] into the database,
    /// returning id to reference it in subsequent reads.
    fn write(&self, object: &dyn WriteTo) -> Result<gix_hash::ObjectId, crate::write::Error> {
        let mut buf = Vec::with_capacity(2048);
        object.write_to(&mut buf)?;
        self.write_stream(object.kind(), buf.len() as u64, &mut buf.as_slice())
    }
    /// As [`write`][Write::write], but takes an [`object` kind][gix_object::Kind] along with its encoded bytes.
    fn write_buf(&self, object: gix_object::Kind, mut from: &[u8]) -> Result<gix_hash::ObjectId, crate::write::Error> {
        self.write_stream(object, from.len() as u64, &mut from)
    }
    /// As [`write`][Write::write], but takes an input stream.
    /// This is commonly used for writing blobs directly without reading them to memory first.
    fn write_stream(
        &self,
        kind: gix_object::Kind,
        size: u64,
        from: &mut dyn io::Read,
    ) -> Result<gix_hash::ObjectId, crate::write::Error>;
}

/// A way to obtain object properties without fully decoding it.
pub trait Header {
    /// Try to read the header of the object associated with `id` or return `None` if it could not be found.
    fn try_header(&self, id: &gix_hash::oid) -> Result<Option<find::Header>, gix_object::find::Error>;
}

mod _impls {
    use std::{io::Read, ops::Deref, rc::Rc, sync::Arc};

    use gix_hash::{oid, ObjectId};
    use gix_object::{Kind, WriteTo};

    use crate::find::Header;

    impl<T> crate::Write for &T
    where
        T: crate::Write,
    {
        fn write(&self, object: &dyn WriteTo) -> Result<ObjectId, crate::write::Error> {
            (*self).write(object)
        }

        fn write_buf(&self, object: Kind, from: &[u8]) -> Result<ObjectId, crate::write::Error> {
            (*self).write_buf(object, from)
        }

        fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result<ObjectId, crate::write::Error> {
            (*self).write_stream(kind, size, from)
        }
    }

    impl<T> crate::Write for Arc<T>
    where
        T: crate::Write,
    {
        fn write(&self, object: &dyn WriteTo) -> Result<ObjectId, crate::write::Error> {
            self.deref().write(object)
        }

        fn write_buf(&self, object: Kind, from: &[u8]) -> Result<ObjectId, crate::write::Error> {
            self.deref().write_buf(object, from)
        }

        fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result<ObjectId, crate::write::Error> {
            self.deref().write_stream(kind, size, from)
        }
    }

    impl<T> crate::Write for Rc<T>
    where
        T: crate::Write,
    {
        fn write(&self, object: &dyn WriteTo) -> Result<ObjectId, crate::write::Error> {
            self.deref().write(object)
        }

        fn write_buf(&self, object: Kind, from: &[u8]) -> Result<ObjectId, crate::write::Error> {
            self.deref().write_buf(object, from)
        }

        fn write_stream(&self, kind: Kind, size: u64, from: &mut dyn Read) -> Result<ObjectId, crate::write::Error> {
            self.deref().write_stream(kind, size, from)
        }
    }

    impl<T> crate::Header for &T
    where
        T: crate::Header,
    {
        fn try_header(&self, id: &oid) -> Result<Option<Header>, gix_object::find::Error> {
            (*self).try_header(id)
        }
    }

    impl<T> crate::Header for Rc<T>
    where
        T: crate::Header,
    {
        fn try_header(&self, id: &oid) -> Result<Option<Header>, gix_object::find::Error> {
            self.deref().try_header(id)
        }
    }

    impl<T> crate::Header for Arc<T>
    where
        T: crate::Header,
    {
        fn try_header(&self, id: &oid) -> Result<Option<Header>, gix_object::find::Error> {
            self.deref().try_header(id)
        }
    }
}

mod ext {
    use crate::find;
    /// An extension trait with convenience functions.
    pub trait HeaderExt: super::Header {
        /// Like [`try_header(…)`][super::Header::try_header()], but flattens the `Result<Option<_>>` into a single `Result` making a non-existing object an error.
        fn header(&self, id: impl AsRef<gix_hash::oid>) -> Result<find::Header, gix_object::find::existing::Error> {
            let id = id.as_ref();
            self.try_header(id)
                .map_err(gix_object::find::existing::Error::Find)?
                .ok_or_else(|| gix_object::find::existing::Error::NotFound { oid: id.to_owned() })
        }
    }

    impl<T: super::Header> HeaderExt for T {}
}
pub use ext::HeaderExt;