diff --git a/lib/sdk/src/murmur/idstring32.rs b/lib/sdk/src/murmur/idstring32.rs new file mode 100644 index 0000000..99ea7aa --- /dev/null +++ b/lib/sdk/src/murmur/idstring32.rs @@ -0,0 +1,162 @@ +use std::fmt; + +use serde::{Deserializer, Serializer}; + +use super::Murmur32; + +// This type encodes the fact that when reading in a bundle, we don't always have a dictionary +// entry for every hash in there. So we do want to have the real string available when needed, +// but at the same time retain the original hash information for when we don't. +// This is especially important when wanting to write back the read bundle, as the hashes need to +// stay the same. +// The previous system of always turning hashes into strings worked well for the purpose of +// displaying hashes, but would have made it very hard to turn a stringyfied hash back into +// an actual hash. +#[derive(Clone, Debug, Eq)] +pub enum IdString32 { + Hash(Murmur32), + String(String), +} + +impl IdString32 { + pub fn to_murmur32(&self) -> Murmur32 { + match self { + Self::Hash(hash) => *hash, + Self::String(s) => Murmur32::hash(s.as_bytes()), + } + } + + pub fn display(&self) -> IdString32Display { + let s = match self { + IdString32::Hash(hash) => hash.to_string(), + IdString32::String(s) => s.clone(), + }; + + IdString32Display(s) + } + + pub fn is_string(&self) -> bool { + match self { + IdString32::Hash(_) => false, + IdString32::String(_) => true, + } + } + + pub fn is_hash(&self) -> bool { + match self { + IdString32::Hash(_) => true, + IdString32::String(_) => false, + } + } +} + +impl From for IdString32 { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From for IdString32 { + fn from(value: u32) -> Self { + Self::Hash(value.into()) + } +} + +impl From for u32 { + fn from(value: IdString32) -> Self { + value.to_murmur32().into() + } +} + +impl From for IdString32 { + fn from(value: Murmur32) -> Self { + Self::Hash(value) + } +} + +impl From for Murmur32 { + fn from(value: IdString32) -> Self { + value.to_murmur32() + } +} + +impl PartialEq for IdString32 { + fn eq(&self, other: &Self) -> bool { + self.to_murmur32() == other.to_murmur32() + } +} + +impl std::hash::Hash for IdString32 { + fn hash(&self, state: &mut H) { + state.write_u32(self.to_murmur32().into()); + } +} + +impl serde::Serialize for IdString32 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_u32(self.to_murmur32().into()) + } +} + +struct IdString32Visitor; + +impl<'de> serde::de::Visitor<'de> for IdString32Visitor { + type Value = IdString32; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an u32 or a string") + } + + fn visit_u32(self, value: u32) -> Result + where + E: serde::de::Error, + { + Ok(IdString32::Hash(value.into())) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(IdString32::String(v.to_string())) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(IdString32::String(v)) + } +} + +impl<'de> serde::Deserialize<'de> for IdString32 { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_u32(IdString32Visitor) + } +} + +pub struct IdString32Display(String); + +impl std::fmt::Display for IdString32Display { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::fmt::UpperHex for IdString32 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::UpperHex::fmt(&self.to_murmur32(), f) + } +} + +impl std::fmt::LowerHex for IdString32 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::LowerHex::fmt(&self.to_murmur32(), f) + } +} diff --git a/lib/sdk/src/murmur/idstring64.rs b/lib/sdk/src/murmur/idstring64.rs new file mode 100644 index 0000000..781a0cd --- /dev/null +++ b/lib/sdk/src/murmur/idstring64.rs @@ -0,0 +1,175 @@ +use std::{fmt, path::Path}; + +use path_slash::PathExt as _; +use serde::{Deserializer, Serializer}; + +use super::Murmur64; + +// This type encodes the fact that when reading in a bundle, we don't always have a dictionary +// entry for every hash in there. So we do want to have the real string available when needed, +// but at the same time retain the original hash information for when we don't. +// This is especially important when wanting to write back the read bundle, as the hashes need to +// stay the same. +// The previous system of always turning hashes into strings worked well for the purpose of +// displaying hashes, but would have made it very hard to turn a stringyfied hash back into +// an actual hash. +#[derive(Clone, Debug, Eq)] +pub enum IdString64 { + Hash(Murmur64), + String(String), +} + +impl IdString64 { + pub fn to_murmur64(&self) -> Murmur64 { + match self { + Self::Hash(hash) => *hash, + Self::String(s) => Murmur64::hash(s.as_bytes()), + } + } + + pub fn display(&self) -> IdString64Display { + let s = match self { + IdString64::Hash(hash) => hash.to_string(), + IdString64::String(s) => s.clone(), + }; + + IdString64Display(s) + } + + pub fn is_string(&self) -> bool { + match self { + IdString64::Hash(_) => false, + IdString64::String(_) => true, + } + } + + pub fn is_hash(&self) -> bool { + match self { + IdString64::Hash(_) => true, + IdString64::String(_) => false, + } + } + + // Would love to have this as a proper `impl From`, but + // rustc will complain that it overlaps with the `impl From>`. + pub fn from_path(p: impl AsRef) -> Self { + Self::String(p.as_ref().to_slash_lossy().to_string()) + } +} + +impl From for IdString64 { + fn from(value: String) -> Self { + Self::String(value) + } +} + +impl From for IdString64 { + fn from(value: u64) -> Self { + Self::Hash(value.into()) + } +} + +impl From for IdString64 { + fn from(value: Murmur64) -> Self { + Self::Hash(value) + } +} + +impl From for Murmur64 { + fn from(value: IdString64) -> Self { + value.to_murmur64() + } +} + +impl From for u64 { + fn from(value: IdString64) -> Self { + value.to_murmur64().into() + } +} + +impl Default for IdString64 { + fn default() -> Self { + Self::Hash(0.into()) + } +} + +impl PartialEq for IdString64 { + fn eq(&self, other: &Self) -> bool { + self.to_murmur64() == other.to_murmur64() + } +} + +impl std::hash::Hash for IdString64 { + fn hash(&self, state: &mut H) { + state.write_u64(self.to_murmur64().into()); + } +} + +impl serde::Serialize for IdString64 { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_u64(self.to_murmur64().into()) + } +} + +struct IdString64Visitor; + +impl<'de> serde::de::Visitor<'de> for IdString64Visitor { + type Value = IdString64; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an u64 or a string") + } + + fn visit_u64(self, value: u64) -> Result + where + E: serde::de::Error, + { + Ok(IdString64::Hash(value.into())) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(IdString64::String(v.to_string())) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(IdString64::String(v)) + } +} + +impl<'de> serde::Deserialize<'de> for IdString64 { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_u64(IdString64Visitor) + } +} + +pub struct IdString64Display(String); + +impl std::fmt::Display for IdString64Display { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::fmt::UpperHex for IdString64 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::UpperHex::fmt(&self.to_murmur64(), f) + } +} + +impl std::fmt::LowerHex for IdString64 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::LowerHex::fmt(&self.to_murmur64(), f) + } +} diff --git a/lib/sdk/src/murmur/mod.rs b/lib/sdk/src/murmur/mod.rs index 87a8473..6449d38 100644 --- a/lib/sdk/src/murmur/mod.rs +++ b/lib/sdk/src/murmur/mod.rs @@ -8,6 +8,8 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; mod dictionary; // Currently unused // mod murmurhash32; +mod idstring32; +mod idstring64; mod murmurhash64; mod types; mod util; @@ -15,6 +17,8 @@ mod util; pub const SEED: u32 = 0; pub use dictionary::{Dictionary, Entry, HashGroup}; +pub use idstring32::*; +pub use idstring64::*; pub use murmurhash64::hash; pub use murmurhash64::hash32; pub use murmurhash64::hash_inverse as inverse; diff --git a/lib/sdk/src/murmur/types.rs b/lib/sdk/src/murmur/types.rs index 20bf46a..c66e2cf 100644 --- a/lib/sdk/src/murmur/types.rs +++ b/lib/sdk/src/murmur/types.rs @@ -1,7 +1,3 @@ -use std::path::Path; - -use path_slash::PathExt; - use self::util::{parse_hex32, parse_hex64}; use super::*; @@ -154,6 +150,12 @@ impl fmt::UpperHex for Murmur32 { } } +impl fmt::LowerHex for Murmur32 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::LowerHex::fmt(&self.0, f) + } +} + impl fmt::Display for Murmur32 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:08X}", self) @@ -222,166 +224,3 @@ impl<'de> Deserialize<'de> for Murmur32 { deserializer.deserialize_any(Self(0)) } } - -// This type encodes the fact that when reading in a bundle, we don't always have a dictionary -// entry for every hash in there. So we do want to have the real string available when needed, -// but at the same time retain the original hash information for when we don't. -// This is especially important when wanting to write back the read bundle, as the hashes need to -// stay the same. -// The previous system of always turning hashes into strings worked well for the purpose of -// displaying hashes, but would have made it very hard to turn a stringyfied hash back into -// an actual hash. -#[derive(Clone, Debug, Eq)] -pub enum IdString64 { - Hash(Murmur64), - String(String), -} - -impl IdString64 { - pub fn to_murmur64(&self) -> Murmur64 { - match self { - Self::Hash(hash) => *hash, - Self::String(s) => Murmur64::hash(s.as_bytes()), - } - } - - pub fn display(&self) -> IdString64Display { - let s = match self { - IdString64::Hash(hash) => hash.to_string(), - IdString64::String(s) => s.clone(), - }; - - IdString64Display(s) - } - - pub fn is_string(&self) -> bool { - match self { - IdString64::Hash(_) => false, - IdString64::String(_) => true, - } - } - - pub fn is_hash(&self) -> bool { - match self { - IdString64::Hash(_) => true, - IdString64::String(_) => false, - } - } - - // Would love to have this as a proper `impl From`, but - // rustc will complain that it overlaps with the `impl From>`. - pub fn from_path(p: impl AsRef) -> Self { - Self::String(p.as_ref().to_slash_lossy().to_string()) - } -} - -impl From for IdString64 { - fn from(value: String) -> Self { - Self::String(value) - } -} - -impl From for IdString64 { - fn from(value: u64) -> Self { - Self::Hash(value.into()) - } -} - -impl From for IdString64 { - fn from(value: Murmur64) -> Self { - Self::Hash(value) - } -} - -impl From for Murmur64 { - fn from(value: IdString64) -> Self { - value.to_murmur64() - } -} - -impl Default for IdString64 { - fn default() -> Self { - Self::Hash(0.into()) - } -} - -impl PartialEq for IdString64 { - fn eq(&self, other: &Self) -> bool { - self.to_murmur64() == other.to_murmur64() - } -} - -impl std::hash::Hash for IdString64 { - fn hash(&self, state: &mut H) { - state.write_u64(self.to_murmur64().into()); - } -} - -impl serde::Serialize for IdString64 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_u64(self.to_murmur64().into()) - } -} - -struct IdString64Visitor; - -impl<'de> serde::de::Visitor<'de> for IdString64Visitor { - type Value = IdString64; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("an u64 or a string") - } - - fn visit_u64(self, value: u64) -> Result - where - E: serde::de::Error, - { - Ok(IdString64::Hash(value.into())) - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - Ok(IdString64::String(v.to_string())) - } - - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, - { - Ok(IdString64::String(v)) - } -} - -impl<'de> serde::Deserialize<'de> for IdString64 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_u64(IdString64Visitor) - } -} - -pub struct IdString64Display(String); - -impl std::fmt::Display for IdString64Display { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl std::fmt::UpperHex for IdString64 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::UpperHex::fmt(&self.to_murmur64(), f) - } -} - -impl std::fmt::LowerHex for IdString64 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - std::fmt::LowerHex::fmt(&self.to_murmur64(), f) - } -}