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<'a> WriteTo for ObjectRef<'a> {
12 fn write_to(&self, out: impl 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 size(&self) -> usize {
24 use crate::ObjectRef::*;
25 match self {
26 Tree(v) => v.size(),
27 Blob(v) => v.size(),
28 Commit(v) => v.size(),
29 Tag(v) => v.size(),
30 }
31 }
32
33 fn kind(&self) -> Kind {
34 self.kind()
35 }
36 }
37
38 impl WriteTo for Object {
40 fn write_to(&self, out: impl 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 size(&self) -> usize {
52 use crate::Object::*;
53 match self {
54 Tree(v) => v.size(),
55 Blob(v) => v.size(),
56 Commit(v) => v.size(),
57 Tag(v) => v.size(),
58 }
59 }
60
61 fn kind(&self) -> Kind {
62 self.kind()
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}
189
190impl<'a> ObjectRef<'a> {
191 pub fn from_loose(data: &'a [u8]) -> Result<ObjectRef<'a>, LooseDecodeError> {
193 let (kind, size, offset) = loose_header(data)?;
194
195 let body = &data[offset..]
196 .get(..size)
197 .ok_or(LooseHeaderDecodeError::InvalidHeader {
198 message: "object data was shorter than its size declared in the header",
199 })?;
200
201 Ok(Self::from_bytes(kind, body)?)
202 }
203
204 pub fn from_bytes(kind: Kind, data: &'a [u8]) -> Result<ObjectRef<'a>, crate::decode::Error> {
206 Ok(match kind {
207 Kind::Tree => ObjectRef::Tree(TreeRef::from_bytes(data)?),
208 Kind::Blob => ObjectRef::Blob(BlobRef { data }),
209 Kind::Commit => ObjectRef::Commit(CommitRef::from_bytes(data)?),
210 Kind::Tag => ObjectRef::Tag(TagRef::from_bytes(data)?),
211 })
212 }
213
214 pub fn into_owned(self) -> Object {
218 self.into()
219 }
220
221 pub fn to_owned(&self) -> Object {
225 self.clone().into()
226 }
227}
228
229impl<'a> ObjectRef<'a> {
231 pub fn as_blob(&self) -> Option<&BlobRef<'a>> {
233 match self {
234 ObjectRef::Blob(v) => Some(v),
235 _ => None,
236 }
237 }
238 pub fn into_blob(self) -> Option<BlobRef<'a>> {
240 match self {
241 ObjectRef::Blob(v) => Some(v),
242 _ => None,
243 }
244 }
245 pub fn as_commit(&self) -> Option<&CommitRef<'a>> {
247 match self {
248 ObjectRef::Commit(v) => Some(v),
249 _ => None,
250 }
251 }
252 pub fn into_commit(self) -> Option<CommitRef<'a>> {
254 match self {
255 ObjectRef::Commit(v) => Some(v),
256 _ => None,
257 }
258 }
259 pub fn as_tree(&self) -> Option<&TreeRef<'a>> {
261 match self {
262 ObjectRef::Tree(v) => Some(v),
263 _ => None,
264 }
265 }
266 pub fn into_tree(self) -> Option<TreeRef<'a>> {
268 match self {
269 ObjectRef::Tree(v) => Some(v),
270 _ => None,
271 }
272 }
273 pub fn as_tag(&self) -> Option<&TagRef<'a>> {
275 match self {
276 ObjectRef::Tag(v) => Some(v),
277 _ => None,
278 }
279 }
280 pub fn into_tag(self) -> Option<TagRef<'a>> {
282 match self {
283 ObjectRef::Tag(v) => Some(v),
284 _ => None,
285 }
286 }
287 pub fn kind(&self) -> Kind {
289 match self {
290 ObjectRef::Tree(_) => Kind::Tree,
291 ObjectRef::Blob(_) => Kind::Blob,
292 ObjectRef::Commit(_) => Kind::Commit,
293 ObjectRef::Tag(_) => Kind::Tag,
294 }
295 }
296}