That way both representations are optimal in memory for their intended usecase. - `TagRef` is decodable from a buffer refers to it with all of its fields. That way round-trips are cheapest. - `Tag` does not allocate for hashes as there is a more compact representation: `git_hash::ObjectId`.
Showing the changes to git-object/src (5 of 6 files). Show all
Unified · Split
| @@ -23,6 +23,10 @@ impl crate::WriteTo for Commit { · 22 unmodified lines | ||
| 23 | 23 | out.write_all(&self.message) |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | + fn kind(&self) -> Kind { | |
| 27 | + Kind::Commit | |
| 28 | + } | |
| 29 | + | |
| 26 | 30 | fn size(&self) -> usize { |
| 27 | 31 | let hash_in_hex = self.tree.kind().len_in_hex(); |
| 28 | 32 | b"tree".len() + 1 /*space*/ + hash_in_hex + 1 /* nl */ |
| @@ -45,10 +49,6 @@ impl crate::WriteTo for Commit { · 16 unmodified lines | ||
| 45 | 49 | + 1 /* nl */ |
| 46 | 50 | + self.message.len() |
| 47 | 51 | } |
| 48 | − | |
| 49 | − fn kind(&self) -> Kind { | |
| 50 | − Kind::Commit | |
| 51 | − } | |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | impl<'a> crate::WriteTo for CommitRef<'a> { |
| @@ -70,6 +70,10 @@ impl<'a> crate::WriteTo for CommitRef<'a> { · 15 unmodified lines | ||
| 70 | 70 | out.write_all(self.message) |
| 71 | 71 | } |
| 72 | 72 | |
| 73 | + fn kind(&self) -> Kind { | |
| 74 | + Kind::Commit | |
| 75 | + } | |
| 76 | + | |
| 73 | 77 | fn size(&self) -> usize { |
| 74 | 78 | let hash_in_hex = self.tree().kind().len_in_hex(); |
| 75 | 79 | b"tree".len() + 1 /* space */ + hash_in_hex + 1 /* nl */ |
| @@ -92,8 +96,4 @@ impl<'a> crate::WriteTo for CommitRef<'a> { · 16 unmodified lines | ||
| 92 | 96 | + 1 /* nl */ |
| 93 | 97 | + self.message.len() |
| 94 | 98 | } |
| 95 | − | |
| 96 | − fn kind(&self) -> Kind { | |
| 97 | − Kind::Commit | |
| 98 | − } | |
| 99 | 99 | } |
| @@ -136,7 +136,7 @@ pub struct TagRef<'a> { · 135 unmodified lines | ||
| 136 | 136 | #[cfg_attr(feature = "serde1", serde(borrow))] |
| 137 | 137 | pub target: &'a BStr, |
| 138 | 138 | /// The kind of object that `target` points to. |
| 139 | − pub target_kind: crate::Kind, | |
| 139 | + pub target_kind: Kind, | |
| 140 | 140 | /// The name of the tag, e.g. "v1.0". |
| 141 | 141 | pub name: &'a BStr, |
| 142 | 142 | /// The author of the tag. |
| @@ -159,9 +159,8 @@ pub struct TagRefIter<'a> { · 16 unmodified lines | ||
| 159 | 159 | #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] |
| 160 | 160 | #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] |
| 161 | 161 | pub struct Tag { |
| 162 | − /// The hash this tag is pointing to stored as hexadecimal representation from which an `ObjectId` | |
| 163 | − /// can be constructed. Use [`.target()`][Tag::target()] to access that `ObjectId`. | |
| 164 | − pub target: BString, | |
| 162 | + /// The hash this tag is pointing to. | |
| 163 | + pub target: git_hash::ObjectId, | |
| 165 | 164 | /// The kind of object this tag is pointing to. |
| 166 | 165 | pub target_kind: Kind, |
| 167 | 166 | /// The name of the tag, e.g. "v1.0". |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | use std::convert::TryFrom; |
| 2 | 2 | |
| 3 | −use crate::{bstr::BStr, tree, Blob, BlobRef, Commit, CommitRef, Object, ObjectRef, Tag, TagRef, Tree, TreeRef}; | |
| 3 | +use crate::{tree, Blob, BlobRef, Commit, CommitRef, Object, ObjectRef, Tag, TagRef, Tree, TreeRef}; | |
| 4 | 4 | |
| 5 | 5 | impl From<TagRef<'_>> for Tag { |
| 6 | 6 | fn from(other: TagRef<'_>) -> Tag { |
| @@ -13,7 +13,7 @@ impl From<TagRef<'_>> for Tag { · 6 unmodified lines | ||
| 13 | 13 | pgp_signature, |
| 14 | 14 | } = other; |
| 15 | 15 | Tag { |
| 16 | − target: target.to_owned(), | |
| 16 | + target: git_hash::ObjectId::from_hex(target).expect("prior parser validation"), | |
| 17 | 17 | name: name.to_owned(), |
| 18 | 18 | target_kind, |
| 19 | 19 | message: message.to_owned(), |
| @@ -23,27 +23,6 @@ impl From<TagRef<'_>> for Tag { · 3 unmodified lines | ||
| 23 | 23 | } |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | −impl<'a> From<&'a Tag> for TagRef<'a> { | |
| 27 | − fn from(other: &'a Tag) -> TagRef<'a> { | |
| 28 | − let Tag { | |
| 29 | − target, | |
| 30 | − target_kind, | |
| 31 | − name, | |
| 32 | − tagger, | |
| 33 | − message, | |
| 34 | − pgp_signature, | |
| 35 | − } = other; | |
| 36 | − TagRef { | |
| 37 | − target: target.as_ref(), | |
| 38 | − target_kind: *target_kind, | |
| 39 | − name: name.as_ref(), | |
| 40 | − tagger: tagger.as_ref().map(|s| s.to_ref()), | |
| 41 | − message: message.as_ref(), | |
| 42 | − pgp_signature: pgp_signature.as_deref().map(BStr::new), | |
| 43 | − } | |
| 44 | − } | |
| 45 | −} | |
| 46 | − | |
| 47 | 26 | impl From<CommitRef<'_>> for Commit { |
| 48 | 27 | fn from(other: CommitRef<'_>) -> Commit { |
| 49 | 28 | let CommitRef { |
| @@ -56,10 +35,10 @@ impl From<CommitRef<'_>> for Commit { · 6 unmodified lines | ||
| 56 | 35 | extra_headers, |
| 57 | 36 | } = other; |
| 58 | 37 | Commit { |
| 59 | − tree: git_hash::ObjectId::from_hex(tree).expect("40 bytes hex sha1"), | |
| 38 | + tree: git_hash::ObjectId::from_hex(tree).expect("prior parser validation"), | |
| 60 | 39 | parents: parents |
| 61 | 40 | .iter() |
| 62 | − .map(|parent| git_hash::ObjectId::from_hex(parent).expect("40 bytes hex sha1")) | |
| 41 | + .map(|parent| git_hash::ObjectId::from_hex(parent).expect("prior parser validation")) | |
| 63 | 42 | .collect(), |
| 64 | 43 | author: author.into(), |
| 65 | 44 | committer: committer.into(), |
| @@ -1,4 +1,4 @@ | ||
| 1 | −use crate::{Tag, TagRef}; | |
| 1 | +use crate::TagRef; | |
| 2 | 2 | |
| 3 | 3 | mod decode; |
| 4 | 4 | |
| @@ -20,11 +20,3 @@ impl<'a> TagRef<'a> { · 15 unmodified lines | ||
| 20 | 20 | git_hash::ObjectId::from_hex(self.target).expect("prior validation") |
| 21 | 21 | } |
| 22 | 22 | } |
| 23 | − | |
| 24 | −/// Access | |
| 25 | −impl Tag { | |
| 26 | − /// The hash this tag is pointing to. | |
| 27 | − pub fn target(&self) -> git_hash::ObjectId { | |
| 28 | − git_hash::ObjectId::from_hex(&self.target).expect("parser assured this is a valid hash") | |
| 29 | − } | |
| 30 | −} | |
| @@ -21,22 +21,46 @@ impl From<Error> for io::Error { · 20 unmodified lines | ||
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | impl crate::WriteTo for Tag { |
| 24 | − fn write_to(&self, out: impl io::Write) -> io::Result<()> { | |
| 25 | − TagRef::from(self).write_to(out) | |
| 26 | − } | |
| 24 | + fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { | |
| 25 | + encode::trusted_header_id(b"object", &self.target, &mut out)?; | |
| 26 | + encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?; | |
| 27 | + encode::header_field(b"tag", validated_name(self.name.as_ref())?, &mut out)?; | |
| 28 | + if let Some(tagger) = &self.tagger { | |
| 29 | + encode::trusted_header_signature(b"tagger", &tagger.to_ref(), &mut out)?; | |
| 30 | + } | |
| 27 | 31 | |
| 28 | − fn size(&self) -> usize { | |
| 29 | − TagRef::from(self).size() | |
| 32 | + out.write_all(NL)?; | |
| 33 | + if !self.message.is_empty() { | |
| 34 | + out.write_all(self.message.as_ref())?; | |
| 35 | + } | |
| 36 | + if let Some(message) = &self.pgp_signature { | |
| 37 | + out.write_all(NL)?; | |
| 38 | + out.write_all(message.as_ref())?; | |
| 39 | + } | |
| 40 | + Ok(()) | |
| 30 | 41 | } |
| 31 | 42 | |
| 32 | 43 | fn kind(&self) -> Kind { |
| 33 | 44 | Kind::Tag |
| 34 | 45 | } |
| 46 | + | |
| 47 | + fn size(&self) -> usize { | |
| 48 | + b"object".len() + 1 /* space */ + self.target.kind().len_in_hex() + 1 /* nl */ | |
| 49 | + + b"type".len() + 1 /* space */ + self.target_kind.as_bytes().len() + 1 /* nl */ | |
| 50 | + + b"tag".len() + 1 /* space */ + self.name.len() + 1 /* nl */ | |
| 51 | + + self | |
| 52 | + .tagger | |
| 53 | + .as_ref() | |
| 54 | + .map(|t| b"tagger".len() + 1 /* space */ + t.size() + 1 /* nl */) | |
| 55 | + .unwrap_or(0) | |
| 56 | + + 1 /* nl */ + self.message.len() | |
| 57 | + + self.pgp_signature.as_ref().map(|m| 1 /* nl */ + m.len()).unwrap_or(0) | |
| 58 | + } | |
| 35 | 59 | } |
| 36 | 60 | |
| 37 | 61 | impl<'a> crate::WriteTo for TagRef<'a> { |
| 38 | 62 | fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { |
| 39 | − encode::trusted_header_id(b"object", &self.target(), &mut out)?; | |
| 63 | + encode::trusted_header_field(b"object", &self.target, &mut out)?; | |
| 40 | 64 | encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?; |
| 41 | 65 | encode::header_field(b"tag", validated_name(self.name)?, &mut out)?; |
| 42 | 66 | if let Some(tagger) = &self.tagger { |