From 3d1b37fcbb485a58e2f3a8ec98337362fdc8c543 Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Thu, 23 Apr 2026 17:43:24 +0200 Subject: [PATCH] oid: Make `Oid::SHA1_LEN` public The length of a SHA-1 object identifier is defined in various locations. Instead of this redundancy, make the definition in `radicle-oid` public, and use it in `radicle{-{core,protocol},}`. --- crates/radicle-core/src/repo.rs | 8 +++----- crates/radicle-oid/src/lib.rs | 2 +- crates/radicle-protocol/src/wire.rs | 22 +++++++++------------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/crates/radicle-core/src/repo.rs b/crates/radicle-core/src/repo.rs index 8b6391c7..7ec85721 100644 --- a/crates/radicle-core/src/repo.rs +++ b/crates/radicle-core/src/repo.rs @@ -14,8 +14,8 @@ pub const RAD_PREFIX: &str = "rad:"; pub enum IdError { #[error(transparent)] Multibase(#[from] multibase::Error), - #[error("invalid length: expected {expected} bytes, got {actual} bytes")] - Length { expected: usize, actual: usize }, + #[error("invalid length: expected {} bytes, got {actual} bytes", Oid::LEN_SHA1)] + Length { actual: usize }, #[error(fmt = fmt_mismatched_base_encoding)] MismatchedBaseEncoding { input: String, @@ -106,12 +106,10 @@ impl RepoId { /// /// [multibase]: https://github.com/multiformats/multibase?tab=readme-ov-file#multibase-table pub fn from_canonical(input: &str) -> Result { - const EXPECTED_LEN: usize = 20; let (base, bytes) = multibase::decode(input)?; Self::guard_base_encoding(input, base)?; - let bytes: [u8; EXPECTED_LEN] = + let bytes: [u8; Oid::LEN_SHA1] = bytes.try_into().map_err(|bytes: Vec| IdError::Length { - expected: EXPECTED_LEN, actual: bytes.len(), })?; Ok(Self(Oid::from_sha1(bytes))) diff --git a/crates/radicle-oid/src/lib.rs b/crates/radicle-oid/src/lib.rs index 35e21074..e4f66d9f 100644 --- a/crates/radicle-oid/src/lib.rs +++ b/crates/radicle-oid/src/lib.rs @@ -86,7 +86,7 @@ pub enum Oid { // length becomes popular? impl Oid { /// The length of a SHA-1 object identifier in bytes. - const SHA1_LEN: usize = 20; + pub const LEN_SHA1: usize = 20; /// A SHA-1 object identifier with all digest bytes set to zero. /// This is sometimes used as a sentinel value to indicate the absence of diff --git a/crates/radicle-protocol/src/wire.rs b/crates/radicle-protocol/src/wire.rs index 36b0499d..66cf57db 100644 --- a/crates/radicle-protocol/src/wire.rs +++ b/crates/radicle-protocol/src/wire.rs @@ -7,7 +7,6 @@ pub use message::{AddressType, MessageType}; use std::convert::TryFrom; use std::fmt::Debug; -use std::mem; use std::ops::Deref; use std::str::FromStr; use std::string::FromUtf8Error; @@ -45,8 +44,11 @@ pub type Size = u16; #[derive(thiserror::Error, Debug)] pub enum Invalid { - #[error("invalid Git object identifier size: expected {expected}, got {actual}")] - Oid { expected: usize, actual: usize }, + #[error( + "invalid Git object identifier size: expected {}, got {actual}", + git::Oid::LEN_SHA1 + )] + Oid { actual: usize }, #[error(transparent)] Bounded(#[from] crate::bounded::Error), #[error("invalid filter size: {actual}")] @@ -382,19 +384,13 @@ where impl Decode for git::Oid { fn decode(buf: &mut impl Buf) -> Result { - const LEN_EXPECTED: usize = mem::size_of::(); - let len = Size::decode(buf)? as usize; - if len != LEN_EXPECTED { - return Err(Invalid::Oid { - expected: LEN_EXPECTED, - actual: len, - } - .into()); + if len != git::Oid::LEN_SHA1 { + return Err(Invalid::Oid { actual: len }.into()); } - let buf: [u8; LEN_EXPECTED] = Decode::decode(buf)?; + let buf: [u8; git::Oid::SHA1_LEN] = Decode::decode(buf)?; let oid = raw::Oid::from_bytes(&buf).expect("the buffer is exactly the right size"); let oid = git::Oid::from(oid); @@ -633,7 +629,7 @@ mod tests { } #[quickcheck] - fn prop_oid(input: [u8; 20]) { + fn prop_oid(input: [u8; git::Oid::SHA1_LEN]) { roundtrip(git::Oid::from_sha1(input)); }