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]) -> 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(kind, body)?)
204 }
205
206 pub fn from_bytes(kind: Kind, data: &'a [u8]) -> Result<ObjectRef<'a>, crate::decode::Error> {
208 Ok(match kind {
209 Kind::Tree => ObjectRef::Tree(TreeRef::from_bytes(data)?),
210 Kind::Blob => ObjectRef::Blob(BlobRef { data }),
211 Kind::Commit => ObjectRef::Commit(CommitRef::from_bytes(data)?),
212 Kind::Tag => ObjectRef::Tag(TagRef::from_bytes(data)?),
213 })
214 }
215
216 pub fn into_owned(self) -> Object {
220 self.into()
221 }
222
223 pub fn to_owned(&self) -> Object {
227 self.clone().into()
228 }
229}
230
231impl<'a> ObjectRef<'a> {
233 pub fn as_blob(&self) -> Option<&BlobRef<'a>> {
235 match self {
236 ObjectRef::Blob(v) => Some(v),
237 _ => None,
238 }
239 }
240 pub fn into_blob(self) -> Option<BlobRef<'a>> {
242 match self {
243 ObjectRef::Blob(v) => Some(v),
244 _ => None,
245 }
246 }
247 pub fn as_commit(&self) -> Option<&CommitRef<'a>> {
249 match self {
250 ObjectRef::Commit(v) => Some(v),
251 _ => None,
252 }
253 }
254 pub fn into_commit(self) -> Option<CommitRef<'a>> {
256 match self {
257 ObjectRef::Commit(v) => Some(v),
258 _ => None,
259 }
260 }
261 pub fn as_tree(&self) -> Option<&TreeRef<'a>> {
263 match self {
264 ObjectRef::Tree(v) => Some(v),
265 _ => None,
266 }
267 }
268 pub fn into_tree(self) -> Option<TreeRef<'a>> {
270 match self {
271 ObjectRef::Tree(v) => Some(v),
272 _ => None,
273 }
274 }
275 pub fn as_tag(&self) -> Option<&TagRef<'a>> {
277 match self {
278 ObjectRef::Tag(v) => Some(v),
279 _ => None,
280 }
281 }
282 pub fn into_tag(self) -> Option<TagRef<'a>> {
284 match self {
285 ObjectRef::Tag(v) => Some(v),
286 _ => None,
287 }
288 }
289 pub fn kind(&self) -> Kind {
291 match self {
292 ObjectRef::Tree(_) => Kind::Tree,
293 ObjectRef::Blob(_) => Kind::Blob,
294 ObjectRef::Commit(_) => Kind::Commit,
295 ObjectRef::Tag(_) => Kind::Tag,
296 }
297 }
298}