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
1111 pub use borrowed::oid;
1212
1313 mod owned;
14−pub use owned::{ObjectId, Prefix};
14+pub use owned::{prefix, ObjectId, Prefix};
1515
1616 #[allow(missing_docs)]
1717 pub mod decode {
git-hash/src/owned.rs+29−6
@@ -11,17 +11,40 @@ pub struct Prefix { · 10 unmodified lines
1111 hex_len: usize,
1212 }
1313
14+///
15+pub 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+
1433 impl Prefix {
1534 /// Create a new instance by taking a full `id` as input and truncating it to `hex_len`.
1635 ///
1736 /// For instance, with `hex_len` of 7 the resulting prefix is 3.5 bytes, or 3 bytes and 4 bits
1837 /// 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> {
2039 let id = id.as_ref();
21− assert!(
22− hex_len <= id.kind().len_in_hex(),
23− "hex_len must not be larger than the maximum hex len of the input id"
24− );
40+ if hex_len > id.kind().len_in_hex() {
41+ return Err(prefix::Error::TooLong {
42+ object_kind: id.kind(),
43+ hex_len,
44+ });
45+ } else if hex_len < 4 {
46+ return Err(prefix::Error::TooShort { hex_len });
47+ }
2548
2649 let mut prefix = ObjectId::null(id.kind());
2750 let b = prefix.as_mut_slice();
@@ -31,7 +54,7 @@ impl Prefix { · 3 unmodified lines
3154 b[hex_len / 2] &= 0xf0;
3255 }
3356
34− Prefix { bytes: prefix, hex_len }
57+ Ok(Prefix { bytes: prefix, hex_len })
3558 }
3659
3760 /// Returns the prefix as object id.
git-hash/tests/oid/mod.rs+16−7
@@ -8,23 +8,32 @@ mod prefix { · 7 unmodified lines
88 let oid_hex = "abcdefabcdefabcdefabcdefabcdefabcdefabcd";
99 let oid = hex_to_id(oid_hex);
1010
11− assert_eq!(git_hash::Prefix::from_id(oid, 0).as_oid(), ObjectId::null(oid.kind()));
12−
13− for hex_len in 1..oid.kind().len_in_hex() {
11+ for hex_len in 4..oid.kind().len_in_hex() {
1412 let mut expected = String::from(&oid_hex[..hex_len]);
1513 let num_of_zeros = oid.kind().len_in_hex() - hex_len;
1614 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();
1816 assert_eq!(prefix.as_oid().to_hex().to_string(), expected, "{}", hex_len);
1917 assert_eq!(prefix.hex_len(), hex_len);
2018 }
2119 }
2220
2321 #[test]
24− #[should_panic]
25− fn panics_if_hex_len_is_longer_than_oid_len_in_hex() {
22+ fn errors_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() {
2632 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+ ));
2837 }
2938 }
3039 }
git-pack/src/index/mod.rs+4−0
@@ -99,6 +99,10 @@ impl Version { · 98 unmodified lines
9999 }
100100 }
101101
102+/// A way to indicate if a lookup, despite successful, was ambiguous or yielded exactly
103+/// one result in the particular index.
104+pub type PrefixLookupResult = Result<EntryIndex, ()>;
105+
102106 /// The type for referring to indices of an entry within the index file.
103107 pub type EntryIndex = u32;
104108
git-pack/src/multi_index/access.rs+2−1
@@ -1,5 +1,6 @@
11 use std::path::{Path, PathBuf};
22
3+use crate::index::PrefixLookupResult;
34 use crate::{
45 data,
56 multi_index::{EntryIndex, File, PackIndex, Version},
@@ -67,7 +68,7 @@ impl File { · 61 unmodified lines
6768 }
6869
6970 /// 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> {
7172 todo!()
7273 }
7374
git-pack/tests/pack/multi_index/mod.rs+11−3
@@ -16,15 +16,23 @@ mod access { · 15 unmodified lines
1616 use std::path::PathBuf;
1717
1818 #[test]
19− fn lookup_abbrev() {
19+ #[ignore]
20+ fn lookup_with_ambiguity() {}
21+
22+ #[test]
23+ fn lookup_prefix() {
2024 let (file, _path) = multi_index();
2125
2226 for (idx, entry) in file.iter().enumerate() {
2327 let hex_len = (idx % file.object_hash().len_in_hex()).min(7);
2428 let hex_oid = entry.oid.to_hex_with_len(hex_len).to_string();
2529 assert_eq!(hex_oid.len(), hex_len);
26− let _oid_prefix = git_hash::Prefix::from_id(&entry.oid, hex_len);
27− // file.lookup_prefix(oid_prefix, hex_len).expect("non-ambiguous")
30+ let oid_prefix = git_hash::Prefix::try_from_id(&entry.oid, hex_len);
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);
2836 }
2937 }
3038

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