History

Prefix now validates all constraints and errors on violation (#298)

That way, min and max lengths is assumed to be correct.

Sebastian Thiel committed 4 years ago

Commit 75efa791 parent 837db626 files · +63 −18Browse files

Unified · Split

6 files
  1. git-hash/src/lib.rs +1 −1
  2. git-hash/src/owned.rs +29 −6
  3. git-hash/tests/oid/mod.rs +16 −7
  4. git-pack/src/index/mod.rs +4 −0
  5. git-pack/src/multi_index/access.rs +2 −1
  6. git-pack/tests/pack/multi_index/mod.rs +11 −3
git-hash/src/lib.rs+1−1
@@ -11,7 +11,7 @@ use std::{convert::TryFrom, str::FromStr}; · 10 unmodified lines
11pub use borrowed::oid;11pub use borrowed::oid;
12 12
13mod owned;13mod owned;
14pub use owned::{ObjectId, Prefix};14pub use owned::{prefix, ObjectId, Prefix};
15 15
16#[allow(missing_docs)]16#[allow(missing_docs)]
17pub mod decode {17pub mod decode {
git-hash/src/owned.rs+29−6
@@ -11,17 +11,40 @@ pub struct Prefix { · 10 unmodified lines
11 hex_len: usize,11 hex_len: usize,
12}12}
13 13
14///
15pub mod prefix {
16 use quick_error::quick_error;
17
18 quick_error! {
19 /// TODO:
20 #[derive(Debug)]
21 #[allow(missing_docs)]
22 pub enum Error {
23 TooShort { hex_len: usize } {
24 display("The minimum hex length of a short object id is 4, got {}", hex_len)
25 }
26 TooLong { object_kind: crate::Kind, hex_len: usize } {
27 display("An object of kind {} cannot be larger than {} in hex, but {} was requested", object_kind, object_kind.len_in_hex(), hex_len)
28 }
29 }
30 }
31}
32
14impl Prefix {33impl Prefix {
15 /// Create a new instance by taking a full `id` as input and truncating it to `hex_len`.34 /// Create a new instance by taking a full `id` as input and truncating it to `hex_len`.
16 ///35 ///
17 /// For instance, with `hex_len` of 7 the resulting prefix is 3.5 bytes, or 3 bytes and 4 bits36 /// For instance, with `hex_len` of 7 the resulting prefix is 3.5 bytes, or 3 bytes and 4 bits
18 /// wide, with all other bytes and bits set to zero.37 /// wide, with all other bytes and bits set to zero.
19 pub fn from_id(id: impl AsRef<oid>, hex_len: usize) -> Self {38 pub fn try_from_id(id: impl AsRef<oid>, hex_len: usize) -> Result<Self, prefix::Error> {
20 let id = id.as_ref();39 let id = id.as_ref();
21 assert!(40 if hex_len > id.kind().len_in_hex() {
22 hex_len <= id.kind().len_in_hex(),41 return Err(prefix::Error::TooLong {
23 "hex_len must not be larger than the maximum hex len of the input id"42 object_kind: id.kind(),
24 );43 hex_len,
44 });
45 } else if hex_len < 4 {
46 return Err(prefix::Error::TooShort { hex_len });
47 }
25 48
26 let mut prefix = ObjectId::null(id.kind());49 let mut prefix = ObjectId::null(id.kind());
27 let b = prefix.as_mut_slice();50 let b = prefix.as_mut_slice();
@@ -31,7 +54,7 @@ impl Prefix { · 3 unmodified lines
31 b[hex_len / 2] &= 0xf0;54 b[hex_len / 2] &= 0xf0;
32 }55 }
33 56
34 Prefix { bytes: prefix, hex_len }57 Ok(Prefix { bytes: prefix, hex_len })
35 }58 }
36 59
37 /// Returns the prefix as object id.60 /// Returns the prefix as object id.
git-hash/tests/oid/mod.rs+16−7
@@ -8,23 +8,32 @@ mod prefix { · 7 unmodified lines
8 let oid_hex = "abcdefabcdefabcdefabcdefabcdefabcdefabcd";8 let oid_hex = "abcdefabcdefabcdefabcdefabcdefabcdefabcd";
9 let oid = hex_to_id(oid_hex);9 let oid = hex_to_id(oid_hex);
10 10
11 assert_eq!(git_hash::Prefix::from_id(oid, 0).as_oid(), ObjectId::null(oid.kind()));11 for hex_len in 4..oid.kind().len_in_hex() {
12
13 for hex_len in 1..oid.kind().len_in_hex() {
14 let mut expected = String::from(&oid_hex[..hex_len]);12 let mut expected = String::from(&oid_hex[..hex_len]);
15 let num_of_zeros = oid.kind().len_in_hex() - hex_len;13 let num_of_zeros = oid.kind().len_in_hex() - hex_len;
16 expected.extend(std::iter::repeat('0').take(num_of_zeros));14 expected.extend(std::iter::repeat('0').take(num_of_zeros));
17 let prefix = git_hash::Prefix::from_id(oid, hex_len);15 let prefix = git_hash::Prefix::try_from_id(oid, hex_len).unwrap();
18 assert_eq!(prefix.as_oid().to_hex().to_string(), expected, "{}", hex_len);16 assert_eq!(prefix.as_oid().to_hex().to_string(), expected, "{}", hex_len);
19 assert_eq!(prefix.hex_len(), hex_len);17 assert_eq!(prefix.hex_len(), hex_len);
20 }18 }
21 }19 }
22 20
23 #[test]21 #[test]
24 #[should_panic]22 fn errors_if_hex_len_is_longer_than_oid_len_in_hex() {
25 fn panics_if_hex_len_is_longer_than_oid_len_in_hex() {23 let kind = Kind::Sha1;
24 assert!(matches!(
25 git_hash::Prefix::try_from_id(ObjectId::null(kind), kind.len_in_hex() + 1),
26 Err(git_hash::prefix::Error::TooLong { .. })
27 ));
28 }
29
30 #[test]
31 fn errors_if_hex_len_is_too_short() {
26 let kind = Kind::Sha1;32 let kind = Kind::Sha1;
27 git_hash::Prefix::from_id(ObjectId::null(kind), kind.len_in_hex() + 1);33 assert!(matches!(
34 git_hash::Prefix::try_from_id(ObjectId::null(kind), 3),
35 Err(git_hash::prefix::Error::TooShort { .. })
36 ));
28 }37 }
29 }38 }
30}39}
git-pack/src/index/mod.rs+4−0
@@ -99,6 +99,10 @@ impl Version { · 98 unmodified lines
99 }99 }
100}100}
101 101
102/// A way to indicate if a lookup, despite successful, was ambiguous or yielded exactly
103/// one result in the particular index.
104pub type PrefixLookupResult = Result<EntryIndex, ()>;
105
102/// The type for referring to indices of an entry within the index file.106/// The type for referring to indices of an entry within the index file.
103pub type EntryIndex = u32;107pub type EntryIndex = u32;
104 108
git-pack/src/multi_index/access.rs+2−1
@@ -1,5 +1,6 @@
1use std::path::{Path, PathBuf};1use std::path::{Path, PathBuf};
2 2
3use crate::index::PrefixLookupResult;
3use crate::{4use crate::{
4 data,5 data,
5 multi_index::{EntryIndex, File, PackIndex, Version},6 multi_index::{EntryIndex, File, PackIndex, Version},
@@ -67,7 +68,7 @@ impl File { · 61 unmodified lines
67 }68 }
68 69
69 /// TODO70 /// TODO
70 pub fn lookup_prefix(&self, _id: impl AsRef<git_hash::oid>, _hex_len: usize) -> Option<EntryIndex> {71 pub fn lookup_prefix(&self, prefix: git_hash::Prefix) -> Option<PrefixLookupResult> {
71 todo!()72 todo!()
72 }73 }
73 74
git-pack/tests/pack/multi_index/mod.rs+11−3
@@ -16,15 +16,23 @@ mod access { · 15 unmodified lines
16 use std::path::PathBuf;16 use std::path::PathBuf;
17 17
18 #[test]18 #[test]
19 fn lookup_abbrev() {19 #[ignore]
20 fn lookup_with_ambiguity() {}
21
22 #[test]
23 fn lookup_prefix() {
20 let (file, _path) = multi_index();24 let (file, _path) = multi_index();
21 25
22 for (idx, entry) in file.iter().enumerate() {26 for (idx, entry) in file.iter().enumerate() {
23 let hex_len = (idx % file.object_hash().len_in_hex()).min(7);27 let hex_len = (idx % file.object_hash().len_in_hex()).min(7);
24 let hex_oid = entry.oid.to_hex_with_len(hex_len).to_string();28 let hex_oid = entry.oid.to_hex_with_len(hex_len).to_string();
25 assert_eq!(hex_oid.len(), hex_len);29 assert_eq!(hex_oid.len(), hex_len);
26 let _oid_prefix = git_hash::Prefix::from_id(&entry.oid, hex_len);30 let oid_prefix = git_hash::Prefix::try_from_id(&entry.oid, hex_len);
27 // file.lookup_prefix(oid_prefix, hex_len).expect("non-ambiguous")31 let entry_index = file
32 .lookup_prefix(oid_prefix)
33 .expect("object found")
34 .expect("non-ambiguous");
35 assert_eq!(file.oid_at_index(entry_index), entry.oid);
28 }36 }
29 }37 }
30 38

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t