1use crate::{Blob, Commit, Object, Tag, Tree};
2use gix_error::ExnMessageResult;
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::{ErrorExt, ResultExt, validation};
191
192impl<'a> ObjectRef<'a> {
193 pub fn from_loose(data: &'a [u8], hash_kind: gix_hash::Kind) -> ExnMessageResult<ObjectRef<'a>> {
195 let (kind, size, offset) = loose_header(data)?;
196
197 let size = usize::try_from(size).or_raise(|| {
198 validation(format!(
199 "Object sized {size} does not fit into memory - this can happen on 32 bit systems"
200 ))
201 })?;
202 let body = &data[offset..]
203 .get(..size)
204 .ok_or_else(|| validation("object data was shorter than its size declared in the header").raise())?;
205
206 Self::from_bytes(body, kind, hash_kind)
207 }
208
209 pub fn from_bytes(data: &'a [u8], kind: Kind, hash_kind: gix_hash::Kind) -> ExnMessageResult<ObjectRef<'a>> {
211 Ok(match kind {
212 Kind::Tree => ObjectRef::Tree(TreeRef::from_bytes(data, hash_kind)?),
213 Kind::Blob => ObjectRef::Blob(BlobRef { data }),
214 Kind::Commit => ObjectRef::Commit(CommitRef::from_bytes(data, hash_kind)?),
215 Kind::Tag => ObjectRef::Tag(TagRef::from_bytes(data, hash_kind)?),
216 })
217 }
218
219 pub fn into_owned(self) -> ExnMessageResult<Object> {
223 self.try_into()
224 }
225
226 pub fn to_owned(&self) -> ExnMessageResult<Object> {
230 self.clone().try_into()
231 }
232}
233
234impl<'a> ObjectRef<'a> {
236 pub fn as_blob(&self) -> Option<&BlobRef<'a>> {
238 match self {
239 ObjectRef::Blob(v) => Some(v),
240 _ => None,
241 }
242 }
243 pub fn into_blob(self) -> Option<BlobRef<'a>> {
245 match self {
246 ObjectRef::Blob(v) => Some(v),
247 _ => None,
248 }
249 }
250 pub fn as_commit(&self) -> Option<&CommitRef<'a>> {
252 match self {
253 ObjectRef::Commit(v) => Some(v),
254 _ => None,
255 }
256 }
257 pub fn into_commit(self) -> Option<CommitRef<'a>> {
259 match self {
260 ObjectRef::Commit(v) => Some(v),
261 _ => None,
262 }
263 }
264 pub fn as_tree(&self) -> Option<&TreeRef<'a>> {
266 match self {
267 ObjectRef::Tree(v) => Some(v),
268 _ => None,
269 }
270 }
271 pub fn into_tree(self) -> Option<TreeRef<'a>> {
273 match self {
274 ObjectRef::Tree(v) => Some(v),
275 _ => None,
276 }
277 }
278 pub fn as_tag(&self) -> Option<&TagRef<'a>> {
280 match self {
281 ObjectRef::Tag(v) => Some(v),
282 _ => None,
283 }
284 }
285 pub fn into_tag(self) -> Option<TagRef<'a>> {
287 match self {
288 ObjectRef::Tag(v) => Some(v),
289 _ => None,
290 }
291 }
292 pub fn kind(&self) -> Kind {
294 match self {
295 ObjectRef::Tree(_) => Kind::Tree,
296 ObjectRef::Blob(_) => Kind::Blob,
297 ObjectRef::Commit(_) => Kind::Commit,
298 ObjectRef::Tag(_) => Kind::Tag,
299 }
300 }
301}