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 | out.write_all(&self.message) | 23 | out.write_all(&self.message) |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | fn kind(&self) -> Kind { | ||
| 27 | Kind::Commit | ||
| 28 | } | ||
| 29 | |||
| 26 | fn size(&self) -> usize { | 30 | fn size(&self) -> usize { |
| 27 | let hash_in_hex = self.tree.kind().len_in_hex(); | 31 | let hash_in_hex = self.tree.kind().len_in_hex(); |
| 28 | b"tree".len() + 1 /*space*/ + hash_in_hex + 1 /* nl */ | 32 | b"tree".len() + 1 /*space*/ + hash_in_hex + 1 /* nl */ |
| @@ -45,10 +49,6 @@ impl crate::WriteTo for Commit { · 16 unmodified lines | |||
| 45 | + 1 /* nl */ | 49 | + 1 /* nl */ |
| 46 | + self.message.len() | 50 | + self.message.len() |
| 47 | } | 51 | } |
| 48 | |||
| 49 | fn kind(&self) -> Kind { | ||
| 50 | Kind::Commit | ||
| 51 | } | ||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | impl<'a> crate::WriteTo for CommitRef<'a> { | 54 | impl<'a> crate::WriteTo for CommitRef<'a> { |
| @@ -70,6 +70,10 @@ impl<'a> crate::WriteTo for CommitRef<'a> { · 15 unmodified lines | |||
| 70 | out.write_all(self.message) | 70 | out.write_all(self.message) |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | fn kind(&self) -> Kind { | ||
| 74 | Kind::Commit | ||
| 75 | } | ||
| 76 | |||
| 73 | fn size(&self) -> usize { | 77 | fn size(&self) -> usize { |
| 74 | let hash_in_hex = self.tree().kind().len_in_hex(); | 78 | let hash_in_hex = self.tree().kind().len_in_hex(); |
| 75 | b"tree".len() + 1 /* space */ + hash_in_hex + 1 /* nl */ | 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 | + 1 /* nl */ | 96 | + 1 /* nl */ |
| 93 | + self.message.len() | 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 | #[cfg_attr(feature = "serde1", serde(borrow))] | 136 | #[cfg_attr(feature = "serde1", serde(borrow))] |
| 137 | pub target: &'a BStr, | 137 | pub target: &'a BStr, |
| 138 | /// The kind of object that `target` points to. | 138 | /// The kind of object that `target` points to. |
| 139 | pub target_kind: crate::Kind, | 139 | pub target_kind: Kind, |
| 140 | /// The name of the tag, e.g. "v1.0". | 140 | /// The name of the tag, e.g. "v1.0". |
| 141 | pub name: &'a BStr, | 141 | pub name: &'a BStr, |
| 142 | /// The author of the tag. | 142 | /// The author of the tag. |
| @@ -159,9 +159,8 @@ pub struct TagRefIter<'a> { · 16 unmodified lines | |||
| 159 | #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] | 159 | #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] |
| 160 | #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] | 160 | #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] |
| 161 | pub struct Tag { | 161 | pub struct Tag { |
| 162 | /// The hash this tag is pointing to stored as hexadecimal representation from which an `ObjectId` | 162 | /// The hash this tag is pointing to. |
| 163 | /// can be constructed. Use [`.target()`][Tag::target()] to access that `ObjectId`. | 163 | pub target: git_hash::ObjectId, |
| 164 | pub target: BString, | ||
| 165 | /// The kind of object this tag is pointing to. | 164 | /// The kind of object this tag is pointing to. |
| 166 | pub target_kind: Kind, | 165 | pub target_kind: Kind, |
| 167 | /// The name of the tag, e.g. "v1.0". | 166 | /// The name of the tag, e.g. "v1.0". |
| @@ -1,6 +1,6 @@ | |||
| 1 | use std::convert::TryFrom; | 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 | impl From<TagRef<'_>> for Tag { | 5 | impl From<TagRef<'_>> for Tag { |
| 6 | fn from(other: TagRef<'_>) -> Tag { | 6 | fn from(other: TagRef<'_>) -> Tag { |
| @@ -13,7 +13,7 @@ impl From<TagRef<'_>> for Tag { · 6 unmodified lines | |||
| 13 | pgp_signature, | 13 | pgp_signature, |
| 14 | } = other; | 14 | } = other; |
| 15 | Tag { | 15 | Tag { |
| 16 | target: target.to_owned(), | 16 | target: git_hash::ObjectId::from_hex(target).expect("prior parser validation"), |
| 17 | name: name.to_owned(), | 17 | name: name.to_owned(), |
| 18 | target_kind, | 18 | target_kind, |
| 19 | message: message.to_owned(), | 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 | impl From<CommitRef<'_>> for Commit { | 26 | impl From<CommitRef<'_>> for Commit { |
| 48 | fn from(other: CommitRef<'_>) -> Commit { | 27 | fn from(other: CommitRef<'_>) -> Commit { |
| 49 | let CommitRef { | 28 | let CommitRef { |
| @@ -56,10 +35,10 @@ impl From<CommitRef<'_>> for Commit { · 6 unmodified lines | |||
| 56 | extra_headers, | 35 | extra_headers, |
| 57 | } = other; | 36 | } = other; |
| 58 | Commit { | 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 | parents: parents | 39 | parents: parents |
| 61 | .iter() | 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 | .collect(), | 42 | .collect(), |
| 64 | author: author.into(), | 43 | author: author.into(), |
| 65 | committer: committer.into(), | 44 | committer: committer.into(), |
| @@ -1,4 +1,4 @@ | |||
| 1 | use crate::{Tag, TagRef}; | 1 | use crate::TagRef; |
| 2 | 2 | ||
| 3 | mod decode; | 3 | mod decode; |
| 4 | 4 | ||
| @@ -20,11 +20,3 @@ impl<'a> TagRef<'a> { · 15 unmodified lines | |||
| 20 | git_hash::ObjectId::from_hex(self.target).expect("prior validation") | 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 | impl crate::WriteTo for Tag { | 23 | impl crate::WriteTo for Tag { |
| 24 | fn write_to(&self, out: impl io::Write) -> io::Result<()> { | 24 | fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { |
| 25 | TagRef::from(self).write_to(out) | 25 | encode::trusted_header_id(b"object", &self.target, &mut out)?; |
| 26 | } | 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 { | 32 | out.write_all(NL)?; |
| 29 | TagRef::from(self).size() | 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 | fn kind(&self) -> Kind { | 43 | fn kind(&self) -> Kind { |
| 33 | Kind::Tag | 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 | impl<'a> crate::WriteTo for TagRef<'a> { | 61 | impl<'a> crate::WriteTo for TagRef<'a> { |
| 38 | fn write_to(&self, mut out: impl io::Write) -> io::Result<()> { | 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 | encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?; | 64 | encode::trusted_header_field(b"type", self.target_kind.as_bytes(), &mut out)?; |
| 41 | encode::header_field(b"tag", validated_name(self.name)?, &mut out)?; | 65 | encode::header_field(b"tag", validated_name(self.name)?, &mut out)?; |
| 42 | if let Some(tagger) = &self.tagger { | 66 | if let Some(tagger) = &self.tagger { |