Skip to content

Commit b2ded12

Browse files
committed
fix!: remove panicking version of ObjectId::from() in favor of ObjectId::from_bytes_or_panic().
We also add an `&oid::try_from()` implementation for good measure, which is hard to call in practice but certainly not impossible.
1 parent 7ddf948 commit b2ded12

File tree

3 files changed

+47
-26
lines changed

3 files changed

+47
-26
lines changed

gix-hash/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#[path = "oid.rs"]
1313
mod borrowed;
14-
pub use borrowed::oid;
14+
pub use borrowed::{oid, Error};
1515

1616
mod object_id;
1717
pub use object_id::{decode, ObjectId};

gix-hash/src/object_id.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::{
22
borrow::Borrow,
3-
convert::TryInto,
43
hash::{Hash, Hasher},
54
ops::Deref,
65
};
@@ -152,6 +151,19 @@ impl ObjectId {
152151
}
153152
}
154153

154+
/// Lifecycle
155+
impl ObjectId {
156+
/// Convert `bytes` into an owned object Id or panic if the slice length doesn't indicate a supported hash.
157+
///
158+
/// Use `Self::try_from(bytes)` for a fallible version.
159+
pub fn from_bytes_or_panic(bytes: &[u8]) -> Self {
160+
match bytes.len() {
161+
20 => Self::Sha1(bytes.try_into().expect("prior length validation")),
162+
other => panic!("BUG: unsupported hash len: {other}"),
163+
}
164+
}
165+
}
166+
155167
/// Sha1 hash specific methods
156168
impl ObjectId {
157169
/// Instantiate an Digest from 20 bytes of a Sha1 digest.
@@ -195,15 +207,6 @@ impl From<[u8; SIZE_OF_SHA1_DIGEST]> for ObjectId {
195207
}
196208
}
197209

198-
impl From<&[u8]> for ObjectId {
199-
fn from(v: &[u8]) -> Self {
200-
match v.len() {
201-
20 => Self::Sha1(v.try_into().expect("prior length validation")),
202-
other => panic!("BUG: unsupported hash len: {other}"),
203-
}
204-
}
205-
}
206-
207210
impl From<&oid> for ObjectId {
208211
fn from(v: &oid) -> Self {
209212
match v.kind() {
@@ -212,6 +215,14 @@ impl From<&oid> for ObjectId {
212215
}
213216
}
214217

218+
impl TryFrom<&[u8]> for ObjectId {
219+
type Error = crate::Error;
220+
221+
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
222+
Ok(oid::try_from_bytes(bytes)?.into())
223+
}
224+
}
225+
215226
impl Deref for ObjectId {
216227
type Target = oid;
217228

gix-hash/src/oid.rs

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{convert::TryInto, fmt, hash};
1+
use std::{convert::TryInto, hash};
22

33
use crate::{Kind, ObjectId, SIZE_OF_SHA1_DIGEST};
44

@@ -41,28 +41,30 @@ pub struct HexDisplay<'a> {
4141
hex_len: usize,
4242
}
4343

44-
impl<'a> fmt::Display for HexDisplay<'a> {
45-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46-
let mut hex = crate::Kind::hex_buf();
44+
impl<'a> std::fmt::Display for HexDisplay<'a> {
45+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46+
let mut hex = Kind::hex_buf();
4747
let max_len = self.inner.hex_to_buf(hex.as_mut());
4848
let hex = std::str::from_utf8(&hex[..self.hex_len.min(max_len)]).expect("ascii only in hex");
4949
f.write_str(hex)
5050
}
5151
}
5252

53-
impl fmt::Debug for oid {
54-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
53+
impl std::fmt::Debug for oid {
54+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5555
write!(
5656
f,
5757
"{}({})",
5858
match self.kind() {
59-
crate::Kind::Sha1 => "Sha1",
59+
Kind::Sha1 => "Sha1",
6060
},
6161
self.to_hex(),
6262
)
6363
}
6464
}
6565

66+
/// The error returned when trying to convert a byte slice to an [`oid`] or [`ObjectId`]
67+
#[allow(missing_docs)]
6668
#[derive(Debug, thiserror::Error)]
6769
pub enum Error {
6870
#[error("Cannot instantiate git hash from a digest of length {0}")]
@@ -104,8 +106,8 @@ impl oid {
104106
impl oid {
105107
/// The kind of hash used for this instance.
106108
#[inline]
107-
pub fn kind(&self) -> crate::Kind {
108-
crate::Kind::from_len_in_bytes(self.bytes.len())
109+
pub fn kind(&self) -> Kind {
110+
Kind::from_len_in_bytes(self.bytes.len())
109111
}
110112

111113
/// The first byte of the hash, commonly used to partition a set of object ids.
@@ -164,7 +166,7 @@ impl oid {
164166
/// Write ourselves to `out` in hexadecimal notation.
165167
#[inline]
166168
pub fn write_hex_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> {
167-
let mut hex = crate::Kind::hex_buf();
169+
let mut hex = Kind::hex_buf();
168170
let hex_len = self.hex_to_buf(&mut hex);
169171
out.write_all(&hex[..hex_len])
170172
}
@@ -182,12 +184,20 @@ impl AsRef<oid> for &oid {
182184
}
183185
}
184186

187+
impl<'a> TryFrom<&'a [u8]> for &'a oid {
188+
type Error = Error;
189+
190+
fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
191+
oid::try_from_bytes(value)
192+
}
193+
}
194+
185195
impl ToOwned for oid {
186-
type Owned = crate::ObjectId;
196+
type Owned = ObjectId;
187197

188198
fn to_owned(&self) -> Self::Owned {
189199
match self.kind() {
190-
crate::Kind::Sha1 => crate::ObjectId::Sha1(self.bytes.try_into().expect("no bug in hash detection")),
200+
Kind::Sha1 => ObjectId::Sha1(self.bytes.try_into().expect("no bug in hash detection")),
191201
}
192202
}
193203
}
@@ -198,16 +208,16 @@ impl<'a> From<&'a [u8; SIZE_OF_SHA1_DIGEST]> for &'a oid {
198208
}
199209
}
200210

201-
impl fmt::Display for &oid {
202-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211+
impl std::fmt::Display for &oid {
212+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203213
for b in self.as_bytes() {
204214
write!(f, "{b:02x}")?;
205215
}
206216
Ok(())
207217
}
208218
}
209219

210-
impl PartialEq<crate::ObjectId> for &oid {
220+
impl PartialEq<ObjectId> for &oid {
211221
fn eq(&self, other: &ObjectId) -> bool {
212222
*self == other.as_ref()
213223
}

0 commit comments

Comments
 (0)