use std::fmt::Debug;
use std::fmt::Display;
use std::hash::Hash;
use std::hash::Hasher;
use std::ops::Deref;
use allocative::Allocative;
use dupe::Dupe;
use equivalent::Equivalent;
#[cfg(feature = "pagable_dep")]
use pagable::Pagable;
use serde::Deserialize;
use serde::Serialize;
use strong_hash::StrongHash;
use crate::hash_value::StarlarkHashValue;
#[derive(
PartialEq,
Eq,
Debug,
Clone,
Copy,
Dupe,
Allocative,
Serialize,
Deserialize
)]
#[cfg_attr(feature = "pagable_dep", derive(Pagable))]
#[cfg_attr(feature = "pagable_dep", pagable(bound = "K: Pagable + 'static"))]
pub struct Hashed<K> {
hash: StarlarkHashValue,
key: K,
}
#[allow(clippy::derived_hash_with_manual_eq)]
impl<K> Hash for Hashed<K> {
fn hash<S: Hasher>(&self, state: &mut S) {
self.hash.hash(state)
}
}
impl<K: StrongHash> StrongHash for Hashed<K> {
fn strong_hash<S: Hasher>(&self, state: &mut S) {
self.key.strong_hash(state);
}
}
impl<K> Deref for Hashed<K> {
type Target = K;
fn deref(&self) -> &Self::Target {
&self.key
}
}
impl<K: Display> Display for Hashed<K> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.key.fmt(f)
}
}
impl<K: PartialOrd> PartialOrd for Hashed<K> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.key.partial_cmp(&other.key)
}
}
impl<K: Ord> Ord for Hashed<K> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.key.cmp(&other.key)
}
}
impl<K> Hashed<K> {
pub fn new(key: K) -> Self
where
K: Hash,
{
Hashed::new_unchecked(StarlarkHashValue::new(&key), key)
}
pub fn new_unchecked(hash: StarlarkHashValue, key: K) -> Self {
Hashed { hash, key }
}
pub fn key(&self) -> &K {
&self.key
}
pub fn key_mut(&mut self) -> &mut K {
&mut self.key
}
pub fn into_key(self) -> K {
self.key
}
pub fn hash(&self) -> StarlarkHashValue {
self.hash
}
pub fn as_ref(&self) -> Hashed<&K> {
Hashed::new_unchecked(self.hash, &self.key)
}
}
impl<K> Hashed<&K> {
pub fn copied(self) -> Hashed<K>
where
K: Copy,
{
Hashed::new_unchecked(self.hash, *self.key)
}
pub fn cloned(self) -> Hashed<K>
where
K: Clone,
{
Hashed::new_unchecked(self.hash, self.key.clone())
}
}
impl<K: ?Sized> Hashed<&K> {
pub fn owned<T>(self) -> Hashed<T>
where
K: Equivalent<T>,
K: ToOwned<Owned = T>,
{
Hashed::new_unchecked(self.hash, self.key.to_owned())
}
}