1use crate::{Blob, Commit, Object, Tag, Tree};
2use gix_error::Result;
3
4mod convert;
5
6mod write {
7 use std::io;
8
9 use crate::{Kind, Object, ObjectRef, WriteTo};
10
11 impl WriteTo for ObjectRef<'_> {
13 fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
15 use crate::ObjectRef::*;
16 match self {
17 Tree(v) => v.write_to(out),
18 Blob(v) => v.write_to(out),
19 Commit(v) => v.write_to(out),
20 Tag(v) => v.write_to(out),
21 }
22 }
23
24 fn kind(&self) -> Kind {
25 self.kind()
26 }
27
28 fn size(&self) -> u64 {
29 use crate::ObjectRef::*;
30 match self {
31 Tree(v) => v.size(),
32 Blob(v) => v.size(),
33 Commit(v) => v.size(),
34 Tag(v) => v.size(),
35 }
36 }
37 }
38
39 impl WriteTo for Object {
41 fn write_to(&self, out: &mut dyn io::Write) -> io::Result<()> {
43 use crate::Object::*;
44 match self {
45 Tree(v) => v.write_to(out),
46 Blob(v) => v.write_to(out),
47 Commit(v) => v.write_to(out),
48 Tag(v) => v.write_to(out),
49 }
50 }
51
52 fn kind(&self) -> Kind {
53 self.kind()
54 }
55
56 fn size(&self) -> u64 {
57 use crate::Object::*;
58 match self {
59 Tree(v) => v.size(),
60 Blob(v) => v.size(),
61 Commit(v) => v.size(),
62 Tag(v) => v.size(),
63 }
64 }
65 }
66}
67
68impl Object {
70 pub fn into_blob(self) -> Blob {
72 match self {
73 Object::Blob(v) => v,
74 _ => panic!("BUG: not a blob"),
75 }
76 }
77 pub fn into_commit(self) -> Commit {
79 match self {
80 Object::Commit(v) => v,
81 _ => panic!("BUG: not a commit"),
82 }
83 }
84 pub fn into_tree(self) -> Tree {
86 match self {
87 Object::Tree(v) => v,
88 _ => panic!("BUG: not a tree"),
89 }
90 }
91 pub fn into_tag(self) -> Tag {
93 match self {
94 Object::Tag(v) => v,
95 _ => panic!("BUG: not a tag"),
96 }
97 }
98 #[expect(
100 clippy::result_large_err,
101 reason = "will be removed once `gix-error` is used consistently"
102 )]
103 pub fn try_into_blob(self) -> std::result::Result<Blob, Self> {
104 match self {
105 Object::Blob(v) => Ok(v),
106 _ => Err(self),
107 }
108 }
109 pub fn try_into_blob_ref(&self) -> Option<BlobRef<'_>> {
111 match self {
112 Object::Blob(v) => Some(v.to_ref()),
113 _ => None,
114 }
115 }
116 #[expect(
118 clippy::result_large_err,
119 reason = "will be removed once `gix-error` is used consistently"
120 )]
121 pub fn try_into_commit(self) -> std::result::Result<Commit, Self> {
122 match self {
123 Object::Commit(v) => Ok(v),
124 _ => Err(self),
125 }
126 }
127 #[expect(
129 clippy::result_large_err,
130 reason = "will be removed once `gix-error` is used consistently"
131 )]
132 pub fn try_into_tree(self) -> std::result::Result<Tree, Self> {
133 match self {
134 Object::Tree(v) => Ok(v),
135 _ => Err(self),
136 }
137 }
138 #[expect(
140 clippy::result_large_err,
141 reason = "will be removed once `gix-error` is used consistently"
142 )]
143 pub fn try_into_tag(self) -> std::result::Result<Tag, Self> {
144 match self {
145 Object::Tag(v) => Ok(v),
146 _ => Err(self),
147 }
148 }
149
150 pub fn as_blob(&self) -> Option<&Blob> {
152 match self {
153 Object::Blob(v) => Some(v),
154 _ => None,
155 }
156 }
157 pub fn as_commit(&self) -> Option<&Commit> {
159 match self {
160 Object::Commit(v) => Some(v),
161 _ => None,
162 }
163 }
164 pub fn as_tree(&self) -> Option<&Tree> {
166 match self {
167 Object::Tree(v) => Some(v),
168 _ => None,
169 }
170 }
171 pub fn as_tag(&self) -> Option<&Tag> {
173 match self {
174 Object::Tag(v) => Some(v),
175 _ => None,
176 }
177 }
178 pub fn kind(&self) -> crate::Kind {
180 match self {
181 Object::Tree(_) => crate::Kind::Tree,
182 Object::Blob(_) => crate::Kind::Blob,
183 Object::Commit(_) => crate::Kind::Commit,
184 Object::Tag(_) => crate::Kind::Tag,
185 }
186 }
187}
188
189use crate::{BlobRef, CommitRef, Kind, ObjectRef, TagRef, TreeRef, decode::loose_header};
190use gix_error::{OptionExt, ResultExt, message, validation};
191
192impl<'a> ObjectRef<'a> {
193 pub fn from_loose(data: &'a [u8], hash_kind: gix_hash::Kind) -> Result<ObjectRef<'a>> {
195 let (kind, size, offset) = loose_header(data)?;
196
197 let size = usize::try_from(size).or_raise(|| {
198 message!("Object sized {size} does not fit into memory - this can happen on 32 bit systems").validation()
199 })?;
200 let body = &data[offset..]
201 .get(..size)
202 .ok_or_raise(|| validation("object data was shorter than its size declared in the header"))?;
203
204 Self::from_bytes(body, kind, hash_kind)
205 }
206
207 pub fn from_bytes(data: &'a [u8], kind: Kind, hash_kind: gix_hash::Kind) -> Result<ObjectRef<'a>> {
209 Ok(match kind {
210 Kind::Tree => ObjectRef::Tree(TreeRef::from_bytes(data, hash_kind)?),
211 Kind::Blob => ObjectRef::Blob(BlobRef { data }),
212 Kind::Commit => ObjectRef::Commit(CommitRef::from_bytes(data, hash_kind)?),
213 Kind::Tag => ObjectRef::Tag(TagRef::from_bytes(data, hash_kind)?),
214 })
215 }
216
217 pub fn into_owned(self) -> Result<Object> {
221 self.try_into()
222 }
223
224 pub fn to_owned(&self) -> Result<Object> {
228 self.clone().try_into()
229 }
230}
231
232impl<'a> ObjectRef<'a> {
234 pub fn as_blob(&self) -> Option<&BlobRef<'a>> {
236 match self {
237 ObjectRef::Blob(v) => Some(v),
238 _ => None,
239 }
240 }
241 pub fn into_blob(self) -> Option<BlobRef<'a>> {
243 match self {
244 ObjectRef::Blob(v) => Some(v),
245 _ => None,
246 }
247 }
248 pub fn as_commit(&self) -> Option<&CommitRef<'a>> {
250 match self {
251 ObjectRef::Commit(v) => Some(v),
252 _ => None,
253 }
254 }
255 pub fn into_commit(self) -> Option<CommitRef<'a>> {
257 match self {
258 ObjectRef::Commit(v) => Some(v),
259 _ => None,
260 }
261 }
262 pub fn as_tree(&self) -> Option<&TreeRef<'a>> {
264 match self {
265 ObjectRef::Tree(v) => Some(v),
266 _ => None,
267 }
268 }
269 pub fn into_tree(self) -> Option<TreeRef<'a>> {
271 match self {
272 ObjectRef::Tree(v) => Some(v),
273 _ => None,
274 }
275 }
276 pub fn as_tag(&self) -> Option<&TagRef<'a>> {
278 match self {
279 ObjectRef::Tag(v) => Some(v),
280 _ => None,
281 }
282 }
283 pub fn into_tag(self) -> Option<TagRef<'a>> {
285 match self {
286 ObjectRef::Tag(v) => Some(v),
287 _ => None,
288 }
289 }
290 pub fn kind(&self) -> Kind {
292 match self {
293 ObjectRef::Tree(_) => Kind::Tree,
294 ObjectRef::Blob(_) => Kind::Blob,
295 ObjectRef::Commit(_) => Kind::Commit,
296 ObjectRef::Tag(_) => Kind::Tag,
297 }
298 }
299}