Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 69 additions & 9 deletions src/stable_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,103 @@ use std::hash::Hasher;
#[cfg(test)]
mod tests;

/// Trait for retrieving the result of the stable hashing operation.
pub trait StableHasherResult: Sized {
fn finish(hash: [u64; 2]) -> Self;
}

/// A Stable Hasher adapted for cross-platform independent hash.
///
/// When hashing something that ends up affecting properties like symbol names,
/// we want these symbol names to be calculated independently of other factors
/// like what architecture you're compiling *from*.
///
/// To that end we always convert integers to little-endian format before
/// hashing and the architecture dependent `isize` and `usize` types are
/// extended to 64 bits if needed.
///
/// # Example
///
/// ```
/// use rustc_stable_hash::{StableHasher, StableHasherResult};
/// use std::hash::Hasher;
///
/// struct Hash128([u64; 2]);
/// impl StableHasherResult for Hash128 {
/// fn finish(hash: [u64; 2]) -> Hash128 {
/// Hash128(hash)
/// }
/// }
///
/// let mut hasher = StableHasher::new();
/// hasher.write_usize(0xFA);
///
/// let hash: Hash128 = hasher.finish();
/// ```
#[must_use]
pub struct StableHasher {
state: SipHasher128,
}

impl fmt::Debug for StableHasher {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.state)
}
/// Trait for retrieving the result of the stable hashing operation.
///
/// # Example
///
/// ```
/// use rustc_stable_hash::{StableHasher, StableHasherResult};
///
/// struct Hash128(u128);
///
/// impl StableHasherResult for Hash128 {
/// fn finish(hash: [u64; 2]) -> Hash128 {
/// let upper: u128 = hash[0] as u128;
/// let lower: u128 = hash[1] as u128;
///
/// Hash128((upper << 64) | lower)
/// }
/// }
/// ```
pub trait StableHasherResult: Sized {
/// Retrieving the finalized state of the [`StableHasher`] and construct
/// an [`Self`] containing the hash.
fn finish(hasher: [u64; 2]) -> Self;
}

impl StableHasher {
/// Creates a new [`StableHasher`].
///
/// To be used with the [`Hasher`] implementation and [`StableHasher::finish`].
#[inline]
#[must_use]
pub fn new() -> Self {
StableHasher {
state: SipHasher128::new_with_keys(0, 0),
}
}

/// Returns the typed-hash value for the values written.
///
/// The resulting typed-hash value is constructed from an
/// [`StableHasherResult`] implemenation.
///
/// To be used in-place of [`Hasher::finish`].
#[inline]
#[must_use]
pub fn finish<W: StableHasherResult>(self) -> W {
W::finish(self.state.finish128())
}
}

impl fmt::Debug for StableHasher {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.state)
}
}

impl Hasher for StableHasher {
/// <div class="warning">
///
/// Do not use this function, it will unconditionnaly panic.
///
/// Use instead [`StableHasher::finish`] which returns a
/// `[u64; 2]` for greater precision.
///
/// </div>
fn finish(&self) -> u64 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does deprecated work on implementations? If so, you could add it here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately no,

error: this `#[deprecated]` annotation has no effect
   --> src/stable_hasher.rs:118:5
    |
118 |     #[deprecated = "use StableHasher::finalize instead"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the unnecessary deprecation attribute
    |
    = note: `#[deny(useless_deprecated)]` on by default

error: could not compile `rustc-stable-hash` (lib) due to 1 previous error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaik, the panic is from a time when there was no StableHashResult yet. It should be fine to just return one half of the hash or do something like Fingerprint::combine.

panic!("use StableHasher::finalize instead");
}
Expand Down