From a3fc564dc3b1faf776a77cd2da717ee9360ddee5 Mon Sep 17 00:00:00 2001 From: Aurelien Clu Date: Thu, 4 Jan 2024 22:53:37 +0900 Subject: [PATCH] Implement std::hash::Hash for Ksuid structs. (#7) Co-authored-by: Aurelien Somename --- src/lib.rs | 13 +++++++++++ tests/integration.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index b91d3a3..635ad9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,6 +60,7 @@ //! All rights reserved to the [Svix webhooks service](https://www.svix.com). use core::fmt; +use std::hash::{Hash, Hasher}; use std::{error, str::FromStr}; use byteorder::{BigEndian, ByteOrder}; @@ -355,6 +356,12 @@ impl fmt::Display for Ksuid { } } +impl Hash for Ksuid { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + /// K-Sortable Unique ID (Ms accuracy) /// /// This one has Ms accuracy compared to the normal one that has second accuracy @@ -493,6 +500,12 @@ impl fmt::Display for KsuidMs { } } +impl Hash for KsuidMs { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } +} + #[cfg(feature = "serde")] impl Serialize for Ksuid { fn serialize(&self, serializer: S) -> Result diff --git a/tests/integration.rs b/tests/integration.rs index e962c0f..a109a9a 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,6 +1,8 @@ use serde::Deserialize; #[cfg(feature = "serde")] use serde::Serialize; +use std::collections::HashSet; +use std::hash::{Hash, Hasher}; use std::{ fs::File, io::{self, BufRead}, @@ -103,6 +105,58 @@ fn test_ordering() -> Result<(), String> { Ok(()) } +#[test] +fn test_hash() { + // given + let mut set = HashSet::new(); + let ksuid1 = Ksuid::new(None, None); + let ksuid2 = Ksuid::new(None, None); + // when + set.insert(ksuid1.clone()); + set.insert(ksuid2.clone()); + // then + assert_eq!(set.len(), 2); + assert!(set.contains(&ksuid1)); + assert!(set.contains(&ksuid2)); +} + +#[test] +fn test_hash_ms() { + // given + let mut set = HashSet::new(); + let ksuidms1 = KsuidMs::new(None, None); + let ksuidms2 = KsuidMs::new(None, None); + // when + set.insert(ksuidms1.clone()); + set.insert(ksuidms2.clone()); + // then + assert_eq!(set.len(), 2); + assert!(set.contains(&ksuidms1)); + assert!(set.contains(&ksuidms2)); +} + +#[test] +fn test_hash_are_deterministic() { + let cases: Vec<(&str, u64)> = vec![ + ("000000pryYUMiBILyxOCoroLz6w", 7055508431330265589), + ("02GY99XXwBHbeBundUPJoqYpvet", 3000553476947541532), + ("04X6IIDacKaayM4WWom0flpf3mY", 15766199744355542564), + ]; + + for case in cases { + // given + let id_as_str = case.0; + let expected_hash = case.1; + // when + let ksuid = Ksuid::from_str(id_as_str).expect("valid id"); + let mut hasher = std::collections::hash_map::DefaultHasher::new(); + ksuid.hash(&mut hasher); + let hashed = hasher.finish(); + // then + assert_eq!(hashed, expected_hash); + } +} + #[cfg(feature = "serde")] #[derive(Serialize, Deserialize)] struct TestKsuid {