1use crate::{Blob, Commit, Object, Tag, Tree};
2
3mod convert;
4
5mod write {
6 use std::io;
7
8 use crate::{Kind, Object, ObjectRef, WriteTo};
9
10 impl WriteTo for ObjectRef<'_> {
12 fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
14 use crate::ObjectRef::*;
15 match self {
16 Tree(v) => v.write_to(out),
17 Blob(v) => v.write_to(out),
18 Commit(v) => v.write_to(out),
19 Tag(v) => v.write_to(out),
20 }
21 }
22
23 fn kind(&self) -> Kind {
24 self.kind()
25 }
26
27 fn size(&self) -> u64 {
28 use crate::ObjectRef::*;
29 match self {
30 Tree(v) => v.size(),
31 Blob(v) => v.size(),
32 Commit(v) => v.size(),
33 Tag(v) => v.size(),
34 }
35 }
36 }
37
38 impl WriteTo for Object {
40 fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
42 use crate::Object::*;
43 match self {
44 Tree(v) => v.write_to(out),
45 Blob(v) => v.write_to(out),
46 Commit(v) => v.write_to(out),
47 Tag(v) => v.write_to(out),
48 }
49 }
50
51 fn kind(&self) -> Kind {
52 self.kind()
53 }
54
55 fn size(&self) -> u64 {
56 use crate::Object::*;
57 match self {
58 Tree(v) => v.size(),
59 Blob(v) => v.size(),
60 Commit(v) => v.size(),
61 Tag(v) => v.size(),
62 }
63 }
64 }
65}
66
67impl Object {
69 pub fn into_blob(self) -> Blob {
71 match self {
72 Object::Blob(v) => v,
73 _ => panic!("BUG: not a blob"),
74 }
75 }
76 pub fn into_commit(self) -> Commit {
78 match self {
79 Object::Commit(v) => v,
80 _ => panic!("BUG: not a commit"),
81 }
82 }
83 pub fn into_tree(self) -> Tree {
85 match self {
86 Object::Tree(v) => v,
87 _ => panic!("BUG: not a tree"),
88 }
89 }
90 pub fn into_tag(self) -> Tag {
92 match self {
93 Object::Tag(v) => v,
94 _ => panic!("BUG: not a tag"),
95 }
96 }
97 #[allow(clippy::result_large_err)]
99 pub fn try_into_blob(self) -> Result<Blob, Self> {
100 match self {
101 Object::Blob(v) => Ok(v),
102 _ => Err(self),
103 }
104 }
105 pub fn try_into_blob_ref(&self) -> Option<BlobRef<'_>> {
107 match self {
108 Object::Blob(v) => Some(v.to_ref()),
109 _ => None,
110 }
111 }
112 #[allow(clippy::result_large_err)]
114 pub fn try_into_commit(self) -> Result<Commit, Self> {
115 match self {
116 Object::Commit(v) => Ok(v),
117 _ => Err(self),
118 }
119 }
120 #[allow(clippy::result_large_err)]
122 pub fn try_into_tree(self) -> Result<Tree, Self> {
123 match self {
124 Object::Tree(v) => Ok(v),
125 _ => Err(self),
126 }
127 }
128 #[allow(clippy::result_large_err)]
130 pub fn try_into_tag(self) -> Result<Tag, Self> {
131 match self {
132 Object::Tag(v) => Ok(v),
133 _ => Err(self),
134 }
135 }
136
137 pub fn as_blob(&self) -> Option<&Blob> {
139 match self {
140 Object::Blob(v) => Some(v),
141 _ => None,
142 }
143 }
144 pub fn as_commit(&self) -> Option<&Commit> {
146 match self {
147 Object::Commit(v) => Some(v),
148 _ => None,
149 }
150 }
151 pub fn as_tree(&self) -> Option<&Tree> {
153 match self {
154 Object::Tree(v) => Some(v),
155 _ => None,
156 }
157 }
158 pub fn as_tag(&self) -> Option<&Tag> {
160 match self {
161 Object::Tag(v) => Some(v),
162 _ => None,
163 }
164 }
165 pub fn kind(&self) -> crate::Kind {
167 match self {
168 Object::Tree(_) => crate::Kind::Tree,
169 Object::Blob(_) => crate::Kind::Blob,
170 Object::Commit(_) => crate::Kind::Commit,
171 Object::Tag(_) => crate::Kind::Tag,
172 }
173 }
174}
175
176use crate::{
177 decode::{loose_header, Error as DecodeError, LooseHeaderDecodeError},
178 BlobRef, CommitRef, Kind, ObjectRef, TagRef, TreeRef,
179};
180
181#[derive(Debug, thiserror::Error)]
182#[allow(missing_docs)]
183pub enum LooseDecodeError {
184 #[error(transparent)]
185 InvalidHeader(#[from] LooseHeaderDecodeError),
186 #[error(transparent)]
187 InvalidContent(#[from] DecodeError),
188 #[error("Object sized {size} does not fit into memory - this can happen on 32 bit systems")]
189 OutOfMemory { size: u64 },
190}
191
192impl<'a> ObjectRef<'a> {
193 pub fn from_loose(data: &'a [u8], hash_kind: gix_hash::Kind) -> Result<ObjectRef<'a>, LooseDecodeError> {
195 let (kind, size, offset) = loose_header(data)?;
196
197 let body = &data[offset..]
198 .get(..size.try_into().map_err(|_| LooseDecodeError::OutOfMemory { size })?)
199 .ok_or(LooseHeaderDecodeError::InvalidHeader {
200 message: "object data was shorter than its size declared in the header",
201 })?;
202
203 Ok(Self::from_bytes(body, kind, hash_kind)?)
204 }
205
206 pub fn from_bytes(
208 data: &'a [u8],
209 kind: Kind,
210 hash_kind: gix_hash::Kind,
211 ) -> Result<ObjectRef<'a>, crate::decode::Error> {
212 Ok(match kind {
213 Kind::Tree => ObjectRef::Tree(TreeRef::from_bytes(data, hash_kind)?),
214 Kind::Blob => ObjectRef::Blob(BlobRef { data }),
215 Kind::Commit => ObjectRef::Commit(CommitRef::from_bytes(data)?),
216 Kind::Tag => ObjectRef::Tag(TagRef::from_bytes(data)?),
217 })
218 }
219
220 pub fn into_owned(self) -> Result<Object, crate::decode::Error> {
224 self.try_into()
225 }
226
227 pub fn to_owned(&self) -> Result<Object, crate::decode::Error> {
231 self.clone().try_into()
232 }
233}
234
235impl<'a> ObjectRef<'a> {
237 pub fn as_blob(&self) -> Option<&BlobRef<'a>> {
239 match self {
240 ObjectRef::Blob(v) => Some(v),
241 _ => None,
242 }
243 }
244 pub fn into_blob(self) -> Option<BlobRef<'a>> {
246 match self {
247 ObjectRef::Blob(v) => Some(v),
248 _ => None,
249 }
250 }
251 pub fn as_commit(&self) -> Option<&CommitRef<'a>> {
253 match self {
254 ObjectRef::Commit(v) => Some(v),
255 _ => None,
256 }
257 }
258 pub fn into_commit(self) -> Option<CommitRef<'a>> {
260 match self {
261 ObjectRef::Commit(v) => Some(v),
262 _ => None,
263 }
264 }
265 pub fn as_tree(&self) -> Option<&TreeRef<'a>> {
267 match self {
268 ObjectRef::Tree(v) => Some(v),
269 _ => None,
270 }
271 }
272 pub fn into_tree(self) -> Option<TreeRef<'a>> {
274 match self {
275 ObjectRef::Tree(v) => Some(v),
276 _ => None,
277 }
278 }
279 pub fn as_tag(&self) -> Option<&TagRef<'a>> {
281 match self {
282 ObjectRef::Tag(v) => Some(v),
283 _ => None,
284 }
285 }
286 pub fn into_tag(self) -> Option<TagRef<'a>> {
288 match self {
289 ObjectRef::Tag(v) => Some(v),
290 _ => None,
291 }
292 }
293 pub fn kind(&self) -> Kind {
295 match self {
296 ObjectRef::Tree(_) => Kind::Tree,
297 ObjectRef::Blob(_) => Kind::Blob,
298 ObjectRef::Commit(_) => Kind::Commit,
299 ObjectRef::Tag(_) => Kind::Tag,
300 }
301 }
302}