Make sha1 optional in `gix-hash`
Unified · Split
| @@ -18,7 +18,7 @@ test = false · 17 unmodified lines | ||
| 18 | 18 | [features] |
| 19 | 19 | default = ["sha1"] |
| 20 | 20 | ## Support for SHA1 hashes and digests. |
| 21 | −sha1 = [] | |
| 21 | +sha1 = ["dep:sha1-checked"] | |
| 22 | 22 | ## Support for SHA256 hashes and digests. |
| 23 | 23 | sha256 = ["dep:sha2"] |
| 24 | 24 | ## Data structures implement `serde::Serialize` and `serde::Deserialize`. |
| @@ -30,7 +30,7 @@ gix-features = { version = "^0.45.1", path = "../gix-features", features = ["pro · 5 unmodified lines | ||
| 30 | 30 | thiserror = "2.0.17" |
| 31 | 31 | faster-hex = { version = "0.10.0", default-features = false, features = ["std"] } |
| 32 | 32 | serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] } |
| 33 | −sha1-checked = { version = "0.10.0", default-features = false } | |
| 33 | +sha1-checked = { version = "0.10.0", optional = true, default-features = false } | |
| 34 | 34 | sha2 = { version = "0.10.0", optional = true, default-features = false } |
| 35 | 35 | |
| 36 | 36 | document-features = { version = "0.2.0", optional = true } |
| @@ -7,8 +7,12 @@ pub enum Error { · 6 unmodified lines | ||
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | pub(super) mod _impl { |
| 10 | + #[cfg(feature = "sha1")] | |
| 10 | 11 | use sha1_checked::{CollisionResult, Digest}; |
| 11 | 12 | |
| 13 | + #[cfg(all(not(feature = "sha1"), feature = "sha256"))] | |
| 14 | + use sha2::Digest; | |
| 15 | + | |
| 12 | 16 | use crate::hasher::Error; |
| 13 | 17 | |
| 14 | 18 | /// Hash implementations that can be used once. |
| @@ -17,6 +21,7 @@ pub(super) mod _impl { · 2 unmodified lines | ||
| 17 | 21 | /// An implementation of the SHA1 hash. |
| 18 | 22 | /// |
| 19 | 23 | /// We use [`sha1_checked`] to implement the same collision detection algorithm as Git. |
| 24 | + #[cfg(feature = "sha1")] | |
| 20 | 25 | Sha1(sha1_checked::Sha1), |
| 21 | 26 | /// An implementation of the SHA256 hash. |
| 22 | 27 | #[cfg(feature = "sha256")] |
| @@ -25,6 +30,7 @@ pub(super) mod _impl { · 2 unmodified lines | ||
| 25 | 30 | |
| 26 | 31 | impl Hasher { |
| 27 | 32 | /// Let's not make this public to force people to go through [`hasher()`]. |
| 33 | + #[cfg(feature = "sha1")] | |
| 28 | 34 | fn new_sha1() -> Self { |
| 29 | 35 | // This matches the configuration used by Git, which only uses |
| 30 | 36 | // the collision detection to bail out, rather than computing |
| @@ -44,6 +50,7 @@ pub(super) mod _impl { · 13 unmodified lines | ||
| 44 | 50 | /// Digest the given `bytes`. |
| 45 | 51 | pub fn update(&mut self, bytes: &[u8]) { |
| 46 | 52 | match self { |
| 53 | + #[cfg(feature = "sha1")] | |
| 47 | 54 | Hasher::Sha1(sha1) => sha1.update(bytes), |
| 48 | 55 | #[cfg(feature = "sha256")] |
| 49 | 56 | Hasher::Sha256(sha256) => sha256.update(bytes), |
| @@ -59,6 +66,7 @@ pub(super) mod _impl { · 9 unmodified lines | ||
| 59 | 66 | #[inline] |
| 60 | 67 | pub fn try_finalize(self) -> Result<crate::ObjectId, Error> { |
| 61 | 68 | match self { |
| 69 | + #[cfg(feature = "sha1")] | |
| 62 | 70 | Hasher::Sha1(sha1) => match sha1.try_finalize() { |
| 63 | 71 | CollisionResult::Ok(digest) => Ok(crate::ObjectId::Sha1(digest.into())), |
| 64 | 72 | CollisionResult::Mitigated(_) => { |
| @@ -89,6 +97,7 @@ pub(super) mod _impl { · 24 unmodified lines | ||
| 89 | 97 | #[inline] |
| 90 | 98 | pub fn hasher(kind: crate::Kind) -> Hasher { |
| 91 | 99 | match kind { |
| 100 | + #[cfg(feature = "sha1")] | |
| 92 | 101 | crate::Kind::Sha1 => Hasher::new_sha1(), |
| 93 | 102 | #[cfg(feature = "sha256")] |
| 94 | 103 | crate::Kind::Sha256 => Hasher::new_sha256(), |
| @@ -114,6 +114,7 @@ pub(super) mod _impl { · 113 unmodified lines | ||
| 114 | 114 | /// Create a new hash writer which hashes all bytes written to `inner` with a hash of `kind`. |
| 115 | 115 | pub fn new(inner: T, object_hash: crate::Kind) -> Self { |
| 116 | 116 | match object_hash { |
| 117 | + #[cfg(feature = "sha1")] | |
| 117 | 118 | crate::Kind::Sha1 => Write { |
| 118 | 119 | inner, |
| 119 | 120 | hash: crate::hasher(object_hash), |
| @@ -1,6 +1,9 @@ | ||
| 1 | 1 | use std::str::FromStr; |
| 2 | 2 | |
| 3 | −use crate::{oid, Kind, ObjectId, SIZE_OF_SHA1_DIGEST, SIZE_OF_SHA1_HEX_DIGEST}; | |
| 3 | +use crate::{oid, Kind, ObjectId}; | |
| 4 | + | |
| 5 | +#[cfg(feature = "sha1")] | |
| 6 | +use crate::{SIZE_OF_SHA1_DIGEST, SIZE_OF_SHA1_HEX_DIGEST}; | |
| 4 | 7 | |
| 5 | 8 | #[cfg(feature = "sha256")] |
| 6 | 9 | use crate::{SIZE_OF_SHA256_DIGEST, SIZE_OF_SHA256_HEX_DIGEST}; |
| @@ -10,6 +13,7 @@ impl TryFrom<u8> for Kind { · 3 unmodified lines | ||
| 10 | 13 | |
| 11 | 14 | fn try_from(value: u8) -> Result<Self, Self::Error> { |
| 12 | 15 | Ok(match value { |
| 16 | + #[cfg(feature = "sha1")] | |
| 13 | 17 | 1 => Kind::Sha1, |
| 14 | 18 | #[cfg(feature = "sha256")] |
| 15 | 19 | 2 => Kind::Sha256, |
| @@ -23,6 +27,7 @@ impl FromStr for Kind { · 7 unmodified lines | ||
| 23 | 27 | |
| 24 | 28 | fn from_str(s: &str) -> Result<Self, Self::Err> { |
| 25 | 29 | Ok(match s { |
| 30 | + #[cfg(feature = "sha1")] | |
| 26 | 31 | "sha1" | "SHA1" | "SHA-1" => Kind::Sha1, |
| 27 | 32 | #[cfg(feature = "sha256")] |
| 28 | 33 | "sha256" | "SHA256" | "SHA-256" => Kind::Sha256, |
| @@ -34,6 +39,7 @@ impl FromStr for Kind { · 5 unmodified lines | ||
| 34 | 39 | impl std::fmt::Display for Kind { |
| 35 | 40 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 36 | 41 | match self { |
| 42 | + #[cfg(feature = "sha1")] | |
| 37 | 43 | Kind::Sha1 => f.write_str("sha1"), |
| 38 | 44 | #[cfg(feature = "sha256")] |
| 39 | 45 | Kind::Sha256 => f.write_str("sha256"), |
| @@ -84,6 +90,7 @@ impl Kind { · 44 unmodified lines | ||
| 84 | 90 | #[inline] |
| 85 | 91 | pub const fn len_in_hex(&self) -> usize { |
| 86 | 92 | match self { |
| 93 | + #[cfg(feature = "sha1")] | |
| 87 | 94 | Kind::Sha1 => SIZE_OF_SHA1_HEX_DIGEST, |
| 88 | 95 | #[cfg(feature = "sha256")] |
| 89 | 96 | Kind::Sha256 => SIZE_OF_SHA256_HEX_DIGEST, |
| @@ -94,6 +101,7 @@ impl Kind { · 4 unmodified lines | ||
| 94 | 101 | #[inline] |
| 95 | 102 | pub const fn len_in_bytes(&self) -> usize { |
| 96 | 103 | match self { |
| 104 | + #[cfg(feature = "sha1")] | |
| 97 | 105 | Kind::Sha1 => SIZE_OF_SHA1_DIGEST, |
| 98 | 106 | #[cfg(feature = "sha256")] |
| 99 | 107 | Kind::Sha256 => SIZE_OF_SHA256_DIGEST, |
| @@ -106,6 +114,7 @@ impl Kind { · 6 unmodified lines | ||
| 106 | 114 | #[inline] |
| 107 | 115 | pub const fn from_hex_len(hex_len: usize) -> Option<Self> { |
| 108 | 116 | Some(match hex_len { |
| 117 | + #[cfg(feature = "sha1")] | |
| 109 | 118 | 0..=SIZE_OF_SHA1_HEX_DIGEST => Kind::Sha1, |
| 110 | 119 | #[cfg(feature = "sha256")] |
| 111 | 120 | 0..=SIZE_OF_SHA256_HEX_DIGEST => Kind::Sha256, |
| @@ -124,6 +133,7 @@ impl Kind { · 12 unmodified lines | ||
| 124 | 133 | #[inline] |
| 125 | 134 | pub(crate) fn from_len_in_bytes(bytes: usize) -> Self { |
| 126 | 135 | match bytes { |
| 136 | + #[cfg(feature = "sha1")] | |
| 127 | 137 | SIZE_OF_SHA1_DIGEST => Kind::Sha1, |
| 128 | 138 | #[cfg(feature = "sha256")] |
| 129 | 139 | SIZE_OF_SHA256_DIGEST => Kind::Sha256, |
| @@ -135,6 +145,7 @@ impl Kind { · 5 unmodified lines | ||
| 135 | 145 | #[inline] |
| 136 | 146 | pub fn null_ref(&self) -> &'static oid { |
| 137 | 147 | match self { |
| 148 | + #[cfg(feature = "sha1")] | |
| 138 | 149 | Kind::Sha1 => oid::null_sha1(), |
| 139 | 150 | #[cfg(feature = "sha256")] |
| 140 | 151 | Kind::Sha256 => oid::null_sha256(), |
| @@ -145,6 +156,7 @@ impl Kind { · 4 unmodified lines | ||
| 145 | 156 | #[inline] |
| 146 | 157 | pub const fn null(&self) -> ObjectId { |
| 147 | 158 | match self { |
| 159 | + #[cfg(feature = "sha1")] | |
| 148 | 160 | Kind::Sha1 => ObjectId::null_sha1(), |
| 149 | 161 | #[cfg(feature = "sha256")] |
| 150 | 162 | Kind::Sha256 => ObjectId::null_sha256(), |
| @@ -9,10 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | #![cfg_attr(all(doc, feature = "document-features"), feature(doc_cfg))] |
| 10 | 10 | #![deny(missing_docs, rust_2018_idioms, unsafe_code)] |
| 11 | 11 | |
| 12 | −// Remove this once other hashes (e.g., SHA256, and potentially others) | |
| 13 | −// are supported, and this crate can build without [`ObjectId::Sha1`]. | |
| 14 | −#[cfg(not(feature = "sha1"))] | |
| 15 | −compile_error!("Please set the `sha1` feature flag"); | |
| 12 | +#[cfg(all(not(feature = "sha1"), not(feature = "sha256")))] | |
| 13 | +compile_error!("Please set either the `sha1` or the `sha256` feature flag"); | |
| 16 | 14 | |
| 17 | 15 | #[path = "oid.rs"] |
| 18 | 16 | mod borrowed; |
| @@ -47,8 +45,10 @@ pub struct Prefix { · 28 unmodified lines | ||
| 47 | 45 | } |
| 48 | 46 | |
| 49 | 47 | /// The size of a SHA1 hash digest in bytes. |
| 48 | +#[cfg(feature = "sha1")] | |
| 50 | 49 | const SIZE_OF_SHA1_DIGEST: usize = 20; |
| 51 | 50 | /// The size of a SHA1 hash digest in hex. |
| 51 | +#[cfg(feature = "sha1")] | |
| 52 | 52 | const SIZE_OF_SHA1_HEX_DIGEST: usize = 2 * SIZE_OF_SHA1_DIGEST; |
| 53 | 53 | |
| 54 | 54 | /// The size of a SHA256 hash digest in bytes. |
| @@ -58,8 +58,10 @@ const SIZE_OF_SHA256_DIGEST: usize = 32; · 3 unmodified lines | ||
| 58 | 58 | #[cfg(feature = "sha256")] |
| 59 | 59 | const SIZE_OF_SHA256_HEX_DIGEST: usize = 2 * SIZE_OF_SHA256_DIGEST; |
| 60 | 60 | |
| 61 | +#[cfg(feature = "sha1")] | |
| 61 | 62 | const EMPTY_BLOB_SHA1: &[u8; SIZE_OF_SHA1_DIGEST] = |
| 62 | 63 | b"\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"; |
| 64 | +#[cfg(feature = "sha1")] | |
| 63 | 65 | const EMPTY_TREE_SHA1: &[u8; SIZE_OF_SHA1_DIGEST] = |
| 64 | 66 | b"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"; |
| 65 | 67 | |
| @@ -74,9 +76,11 @@ const EMPTY_TREE_SHA256: &[u8; SIZE_OF_SHA256_DIGEST] = b"\x6e\xf1\x9b\x41\x22\x · 8 unmodified lines | ||
| 74 | 76 | #[non_exhaustive] |
| 75 | 77 | pub enum Kind { |
| 76 | 78 | /// The SHA1 hash with 160 bits. |
| 77 | − #[default] | |
| 79 | + #[cfg_attr(feature = "sha1", default)] | |
| 80 | + #[cfg(feature = "sha1")] | |
| 78 | 81 | Sha1 = 1, |
| 79 | 82 | /// The SHA256 hash with 256 bits. |
| 83 | + #[cfg_attr(all(not(feature = "sha1"), feature = "sha256"), default)] | |
| 80 | 84 | #[cfg(feature = "sha256")] |
| 81 | 85 | Sha256 = 2, |
| 82 | 86 | } |
| @@ -4,7 +4,10 @@ use std::{ · 3 unmodified lines | ||
| 4 | 4 | ops::Deref, |
| 5 | 5 | }; |
| 6 | 6 | |
| 7 | −use crate::{borrowed::oid, Kind, EMPTY_BLOB_SHA1, EMPTY_TREE_SHA1, SIZE_OF_SHA1_DIGEST}; | |
| 7 | +use crate::{borrowed::oid, Kind}; | |
| 8 | + | |
| 9 | +#[cfg(feature = "sha1")] | |
| 10 | +use crate::{EMPTY_BLOB_SHA1, EMPTY_TREE_SHA1, SIZE_OF_SHA1_DIGEST}; | |
| 8 | 11 | |
| 9 | 12 | #[cfg(feature = "sha256")] |
| 10 | 13 | use crate::{EMPTY_BLOB_SHA256, EMPTY_TREE_SHA256, SIZE_OF_SHA256_DIGEST}; |
| @@ -15,6 +18,7 @@ use crate::{EMPTY_BLOB_SHA256, EMPTY_TREE_SHA256, SIZE_OF_SHA256_DIGEST}; · 4 unmodified lines | ||
| 15 | 18 | #[non_exhaustive] |
| 16 | 19 | pub enum ObjectId { |
| 17 | 20 | /// A SHA1 hash digest |
| 21 | + #[cfg(feature = "sha1")] | |
| 18 | 22 | Sha1([u8; SIZE_OF_SHA1_DIGEST]), |
| 19 | 23 | /// A SHA256 hash digest |
| 20 | 24 | #[cfg(feature = "sha256")] |
| @@ -38,7 +42,10 @@ impl Hash for ObjectId { · 17 unmodified lines | ||
| 38 | 42 | pub mod decode { |
| 39 | 43 | use std::str::FromStr; |
| 40 | 44 | |
| 41 | − use crate::{object_id::ObjectId, SIZE_OF_SHA1_DIGEST, SIZE_OF_SHA1_HEX_DIGEST}; | |
| 45 | + use crate::object_id::ObjectId; | |
| 46 | + | |
| 47 | + #[cfg(feature = "sha1")] | |
| 48 | + use crate::{SIZE_OF_SHA1_DIGEST, SIZE_OF_SHA1_HEX_DIGEST}; | |
| 42 | 49 | |
| 43 | 50 | #[cfg(feature = "sha256")] |
| 44 | 51 | use crate::{SIZE_OF_SHA256_DIGEST, SIZE_OF_SHA256_HEX_DIGEST}; |
| @@ -62,6 +69,7 @@ pub mod decode { · 17 unmodified lines | ||
| 62 | 69 | /// Such a buffer can be obtained using [`oid::write_hex_to(buffer)`][super::oid::write_hex_to()] |
| 63 | 70 | pub fn from_hex(buffer: &[u8]) -> Result<ObjectId, Error> { |
| 64 | 71 | match buffer.len() { |
| 72 | + #[cfg(feature = "sha1")] | |
| 65 | 73 | SIZE_OF_SHA1_HEX_DIGEST => Ok({ |
| 66 | 74 | ObjectId::Sha1({ |
| 67 | 75 | let mut buf = [0; SIZE_OF_SHA1_DIGEST]; |
| @@ -107,6 +115,7 @@ impl ObjectId { · 39 unmodified lines | ||
| 107 | 115 | #[inline] |
| 108 | 116 | pub fn kind(&self) -> Kind { |
| 109 | 117 | match self { |
| 118 | + #[cfg(feature = "sha1")] | |
| 110 | 119 | ObjectId::Sha1(_) => Kind::Sha1, |
| 111 | 120 | #[cfg(feature = "sha256")] |
| 112 | 121 | ObjectId::Sha256(_) => Kind::Sha256, |
| @@ -116,6 +125,7 @@ impl ObjectId { · 3 unmodified lines | ||
| 116 | 125 | #[inline] |
| 117 | 126 | pub fn as_slice(&self) -> &[u8] { |
| 118 | 127 | match self { |
| 128 | + #[cfg(feature = "sha1")] | |
| 119 | 129 | Self::Sha1(b) => b.as_ref(), |
| 120 | 130 | #[cfg(feature = "sha256")] |
| 121 | 131 | Self::Sha256(b) => b.as_ref(), |
| @@ -125,6 +135,7 @@ impl ObjectId { · 3 unmodified lines | ||
| 125 | 135 | #[inline] |
| 126 | 136 | pub fn as_mut_slice(&mut self) -> &mut [u8] { |
| 127 | 137 | match self { |
| 138 | + #[cfg(feature = "sha1")] | |
| 128 | 139 | Self::Sha1(b) => b.as_mut(), |
| 129 | 140 | #[cfg(feature = "sha256")] |
| 130 | 141 | Self::Sha256(b) => b.as_mut(), |
| @@ -135,6 +146,7 @@ impl ObjectId { · 4 unmodified lines | ||
| 135 | 146 | #[inline] |
| 136 | 147 | pub const fn empty_blob(hash: Kind) -> ObjectId { |
| 137 | 148 | match hash { |
| 149 | + #[cfg(feature = "sha1")] | |
| 138 | 150 | Kind::Sha1 => ObjectId::Sha1(*EMPTY_BLOB_SHA1), |
| 139 | 151 | #[cfg(feature = "sha256")] |
| 140 | 152 | Kind::Sha256 => ObjectId::Sha256(*EMPTY_BLOB_SHA256), |
| @@ -145,6 +157,7 @@ impl ObjectId { · 4 unmodified lines | ||
| 145 | 157 | #[inline] |
| 146 | 158 | pub const fn empty_tree(hash: Kind) -> ObjectId { |
| 147 | 159 | match hash { |
| 160 | + #[cfg(feature = "sha1")] | |
| 148 | 161 | Kind::Sha1 => ObjectId::Sha1(*EMPTY_TREE_SHA1), |
| 149 | 162 | #[cfg(feature = "sha256")] |
| 150 | 163 | Kind::Sha256 => ObjectId::Sha256(*EMPTY_TREE_SHA256), |
| @@ -156,6 +169,7 @@ impl ObjectId { · 5 unmodified lines | ||
| 156 | 169 | #[doc(alias = "zero", alias = "git2")] |
| 157 | 170 | pub const fn null(kind: Kind) -> ObjectId { |
| 158 | 171 | match kind { |
| 172 | + #[cfg(feature = "sha1")] | |
| 159 | 173 | Kind::Sha1 => Self::null_sha1(), |
| 160 | 174 | #[cfg(feature = "sha256")] |
| 161 | 175 | Kind::Sha256 => Self::null_sha256(), |
| @@ -167,6 +181,7 @@ impl ObjectId { · 5 unmodified lines | ||
| 167 | 181 | #[doc(alias = "is_zero", alias = "git2")] |
| 168 | 182 | pub fn is_null(&self) -> bool { |
| 169 | 183 | match self { |
| 184 | + #[cfg(feature = "sha1")] | |
| 170 | 185 | ObjectId::Sha1(digest) => &digest[..] == oid::null_sha1().as_bytes(), |
| 171 | 186 | #[cfg(feature = "sha256")] |
| 172 | 187 | ObjectId::Sha256(digest) => &digest[..] == oid::null_sha256().as_bytes(), |
| @@ -193,6 +208,7 @@ impl ObjectId { · 20 unmodified lines | ||
| 193 | 208 | /// Use `Self::try_from(bytes)` for a fallible version. |
| 194 | 209 | pub fn from_bytes_or_panic(bytes: &[u8]) -> Self { |
| 195 | 210 | match bytes.len() { |
| 211 | + #[cfg(feature = "sha1")] | |
| 196 | 212 | SIZE_OF_SHA1_DIGEST => Self::Sha1(bytes.try_into().expect("prior length validation")), |
| 197 | 213 | #[cfg(feature = "sha256")] |
| 198 | 214 | SIZE_OF_SHA256_DIGEST => Self::Sha256(bytes.try_into().expect("prior length validation")), |
| @@ -205,6 +221,7 @@ impl ObjectId { · 6 unmodified lines | ||
| 205 | 221 | impl ObjectId { |
| 206 | 222 | /// Instantiate an `ObjectId` from a 20 bytes SHA1 digest. |
| 207 | 223 | #[inline] |
| 224 | + #[cfg(feature = "sha1")] | |
| 208 | 225 | fn new_sha1(id: [u8; SIZE_OF_SHA1_DIGEST]) -> Self { |
| 209 | 226 | ObjectId::Sha1(id) |
| 210 | 227 | } |
| @@ -220,6 +237,7 @@ impl ObjectId { · 9 unmodified lines | ||
| 220 | 237 | /// |
| 221 | 238 | /// Panics if the slice doesn't have a length of 20. |
| 222 | 239 | #[inline] |
| 240 | + #[cfg(feature = "sha1")] | |
| 223 | 241 | pub(crate) fn from_20_bytes(b: &[u8]) -> ObjectId { |
| 224 | 242 | let mut id = [0; SIZE_OF_SHA1_DIGEST]; |
| 225 | 243 | id.copy_from_slice(b); |
| @@ -239,6 +257,7 @@ impl ObjectId { · 13 unmodified lines | ||
| 239 | 257 | |
| 240 | 258 | /// Returns an `ObjectId` representing a SHA1 whose memory is zeroed. |
| 241 | 259 | #[inline] |
| 260 | + #[cfg(feature = "sha1")] | |
| 242 | 261 | pub(crate) const fn null_sha1() -> ObjectId { |
| 243 | 262 | ObjectId::Sha1([0u8; SIZE_OF_SHA1_DIGEST]) |
| 244 | 263 | } |
| @@ -254,6 +273,7 @@ impl ObjectId { · 9 unmodified lines | ||
| 254 | 273 | impl std::fmt::Debug for ObjectId { |
| 255 | 274 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 256 | 275 | match self { |
| 276 | + #[cfg(feature = "sha1")] | |
| 257 | 277 | ObjectId::Sha1(_hash) => f.write_str("Sha1(")?, |
| 258 | 278 | #[cfg(feature = "sha256")] |
| 259 | 279 | ObjectId::Sha256(_) => f.write_str("Sha256(")?, |
| @@ -265,6 +285,7 @@ impl std::fmt::Debug for ObjectId { · 5 unmodified lines | ||
| 265 | 285 | } |
| 266 | 286 | } |
| 267 | 287 | |
| 288 | +#[cfg(feature = "sha1")] | |
| 268 | 289 | impl From<[u8; SIZE_OF_SHA1_DIGEST]> for ObjectId { |
| 269 | 290 | fn from(v: [u8; SIZE_OF_SHA1_DIGEST]) -> Self { |
| 270 | 291 | Self::new_sha1(v) |
| @@ -281,6 +302,7 @@ impl From<[u8; SIZE_OF_SHA256_DIGEST]> for ObjectId { · 10 unmodified lines | ||
| 281 | 302 | impl From<&oid> for ObjectId { |
| 282 | 303 | fn from(v: &oid) -> Self { |
| 283 | 304 | match v.kind() { |
| 305 | + #[cfg(feature = "sha1")] | |
| 284 | 306 | Kind::Sha1 => ObjectId::from_20_bytes(v.as_bytes()), |
| 285 | 307 | #[cfg(feature = "sha256")] |
| 286 | 308 | Kind::Sha256 => ObjectId::from_32_bytes(v.as_bytes()), |
| @@ -1,6 +1,9 @@ | ||
| 1 | 1 | use std::hash; |
| 2 | 2 | |
| 3 | −use crate::{Kind, ObjectId, EMPTY_BLOB_SHA1, EMPTY_TREE_SHA1, SIZE_OF_SHA1_DIGEST}; | |
| 3 | +use crate::{Kind, ObjectId}; | |
| 4 | + | |
| 5 | +#[cfg(feature = "sha1")] | |
| 6 | +use crate::{EMPTY_BLOB_SHA1, EMPTY_TREE_SHA1, SIZE_OF_SHA1_DIGEST}; | |
| 4 | 7 | |
| 5 | 8 | #[cfg(feature = "sha256")] |
| 6 | 9 | use crate::{EMPTY_BLOB_SHA256, EMPTY_TREE_SHA256, SIZE_OF_SHA256_DIGEST}; |
| @@ -59,6 +62,7 @@ impl std::fmt::Debug for oid { · 52 unmodified lines | ||
| 59 | 62 | f, |
| 60 | 63 | "{}({})", |
| 61 | 64 | match self.kind() { |
| 65 | + #[cfg(feature = "sha1")] | |
| 62 | 66 | Kind::Sha1 => "Sha1", |
| 63 | 67 | #[cfg(feature = "sha256")] |
| 64 | 68 | Kind::Sha256 => "Sha256", |
| @@ -82,6 +86,7 @@ impl oid { · 17 unmodified lines | ||
| 82 | 86 | #[inline] |
| 83 | 87 | pub fn try_from_bytes(digest: &[u8]) -> Result<&Self, Error> { |
| 84 | 88 | match digest.len() { |
| 89 | + #[cfg(feature = "sha1")] | |
| 85 | 90 | SIZE_OF_SHA1_DIGEST => Ok( |
| 86 | 91 | #[allow(unsafe_code)] |
| 87 | 92 | unsafe { |
| @@ -178,6 +183,7 @@ impl oid { · 90 unmodified lines | ||
| 178 | 183 | #[doc(alias = "is_zero", alias = "git2")] |
| 179 | 184 | pub fn is_null(&self) -> bool { |
| 180 | 185 | match self.kind() { |
| 186 | + #[cfg(feature = "sha1")] | |
| 181 | 187 | Kind::Sha1 => &self.bytes == oid::null_sha1().as_bytes(), |
| 182 | 188 | #[cfg(feature = "sha256")] |
| 183 | 189 | Kind::Sha256 => &self.bytes == oid::null_sha256().as_bytes(), |
| @@ -188,6 +194,7 @@ impl oid { · 4 unmodified lines | ||
| 188 | 194 | #[inline] |
| 189 | 195 | pub fn is_empty_blob(&self) -> bool { |
| 190 | 196 | match self.kind() { |
| 197 | + #[cfg(feature = "sha1")] | |
| 191 | 198 | Kind::Sha1 => &self.bytes == oid::empty_blob_sha1().as_bytes(), |
| 192 | 199 | #[cfg(feature = "sha256")] |
| 193 | 200 | Kind::Sha256 => &self.bytes == oid::empty_blob_sha256().as_bytes(), |
| @@ -198,6 +205,7 @@ impl oid { · 4 unmodified lines | ||
| 198 | 205 | #[inline] |
| 199 | 206 | pub fn is_empty_tree(&self) -> bool { |
| 200 | 207 | match self.kind() { |
| 208 | + #[cfg(feature = "sha1")] | |
| 201 | 209 | Kind::Sha1 => &self.bytes == oid::empty_tree_sha1().as_bytes(), |
| 202 | 210 | #[cfg(feature = "sha256")] |
| 203 | 211 | Kind::Sha256 => &self.bytes == oid::empty_tree_sha256().as_bytes(), |
| @@ -209,6 +217,7 @@ impl oid { · 5 unmodified lines | ||
| 209 | 217 | impl oid { |
| 210 | 218 | /// Returns a SHA1 digest with all bytes being initialized to zero. |
| 211 | 219 | #[inline] |
| 220 | + #[cfg(feature = "sha1")] | |
| 212 | 221 | pub(crate) fn null_sha1() -> &'static Self { |
| 213 | 222 | oid::from_bytes([0u8; SIZE_OF_SHA1_DIGEST].as_ref()) |
| 214 | 223 | } |
| @@ -222,6 +231,7 @@ impl oid { · 7 unmodified lines | ||
| 222 | 231 | |
| 223 | 232 | /// Returns an `oid` representing the SHA1 hash of an empty blob. |
| 224 | 233 | #[inline] |
| 234 | + #[cfg(feature = "sha1")] | |
| 225 | 235 | pub(crate) fn empty_blob_sha1() -> &'static Self { |
| 226 | 236 | oid::from_bytes(EMPTY_BLOB_SHA1) |
| 227 | 237 | } |
| @@ -235,6 +245,7 @@ impl oid { · 7 unmodified lines | ||
| 235 | 245 | |
| 236 | 246 | /// Returns an `oid` representing the SHA1 hash of an empty tree. |
| 237 | 247 | #[inline] |
| 248 | + #[cfg(feature = "sha1")] | |
| 238 | 249 | pub(crate) fn empty_tree_sha1() -> &'static Self { |
| 239 | 250 | oid::from_bytes(EMPTY_TREE_SHA1) |
| 240 | 251 | } |
| @@ -266,6 +277,7 @@ impl ToOwned for oid { · 25 unmodified lines | ||
| 266 | 277 | |
| 267 | 278 | fn to_owned(&self) -> Self::Owned { |
| 268 | 279 | match self.kind() { |
| 280 | + #[cfg(feature = "sha1")] | |
| 269 | 281 | Kind::Sha1 => ObjectId::Sha1(self.bytes.try_into().expect("no bug in hash detection")), |
| 270 | 282 | #[cfg(feature = "sha256")] |
| 271 | 283 | Kind::Sha256 => ObjectId::Sha256(self.bytes.try_into().expect("no bug in hash detection")), |
| @@ -273,12 +285,20 @@ impl ToOwned for oid { · 1 unmodified line | ||
| 273 | 285 | } |
| 274 | 286 | } |
| 275 | 287 | |
| 288 | +#[cfg(feature = "sha1")] | |
| 276 | 289 | impl<'a> From<&'a [u8; SIZE_OF_SHA1_DIGEST]> for &'a oid { |
| 277 | 290 | fn from(v: &'a [u8; SIZE_OF_SHA1_DIGEST]) -> Self { |
| 278 | 291 | oid::from_bytes(v.as_ref()) |
| 279 | 292 | } |
| 280 | 293 | } |
| 281 | 294 | |
| 295 | +#[cfg(feature = "sha256")] | |
| 296 | +impl<'a> From<&'a [u8; SIZE_OF_SHA256_DIGEST]> for &'a oid { | |
| 297 | + fn from(v: &'a [u8; SIZE_OF_SHA256_DIGEST]) -> Self { | |
| 298 | + oid::from_bytes(v.as_ref()) | |
| 299 | + } | |
| 300 | +} | |
| 301 | + | |
| 282 | 302 | impl std::fmt::Display for &oid { |
| 283 | 303 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
| 284 | 304 | let mut buf = Kind::hex_buf(); |
| @@ -90,7 +90,6 @@ fn longest_sha1() { · 89 unmodified lines | ||
| 90 | 90 | assert_eq!(longest, Kind::Sha1); |
| 91 | 91 | } |
| 92 | 92 | |
| 93 | −// TODO: make sure to test all permutations once `sha1` is fully optional | |
| 94 | 93 | #[test] |
| 95 | 94 | #[cfg(all(not(feature = "sha1"), feature = "sha256"))] |
| 96 | 95 | fn longest_sha256() { |
| @@ -71,6 +71,7 @@ check: · 70 unmodified lines | ||
| 71 | 71 | cargo check -p gix-hash --all-features |
| 72 | 72 | cargo check -p gix-hash |
| 73 | 73 | cargo check -p gix-hash --features sha256 |
| 74 | + cargo check -p gix-hash --no-default-features --features sha256 | |
| 74 | 75 | cargo check -p gix-object --all-features |
| 75 | 76 | cargo check -p gix-object --features verbose-object-parsing-errors |
| 76 | 77 | cargo check -p gix-attributes --features serde |
| @@ -158,6 +159,7 @@ unit-tests: · 81 unmodified lines | ||
| 158 | 159 | cargo nextest run -p gix-worktree-tests --features gix-features-parallel --no-fail-fast |
| 159 | 160 | cargo nextest run -p gix-hash --no-fail-fast |
| 160 | 161 | cargo nextest run -p gix-hash --features sha256 --no-fail-fast |
| 162 | + cargo nextest run -p gix-hash --no-default-features --features sha256 --no-fail-fast # TODO: make this actually work by removing 'sha1' from default features. | |
| 161 | 163 | cargo nextest run -p gix-object --no-fail-fast |
| 162 | 164 | cargo nextest run -p gix-object --features verbose-object-parsing-errors --no-fail-fast |
| 163 | 165 | cargo nextest run -p gix-tempfile --features signals --no-fail-fast |