mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
refactor: Introduce CacheKey
trait (#3323)
This PR introduces a new `CacheKey` trait for types that can be used as a cache key. I'm not entirely sure if this is worth the "overhead", but I was surprised to find `HashableHashSet` and got scared when I looked at the time complexity of the `hash` function. These implementations must be extremely slow in hashed collections. I then searched for usages and quickly realized that only the cache uses these `Hash` implementations, where performance is less sensitive. This PR introduces a new `CacheKey` trait to communicate the difference between a hash and computing a key for the cache. The new trait can be implemented for types that don't implement `Hash` for performance reasons, and we can define additional constraints on the implementation: For example, we'll want to enforce portability when we add remote caching support. Using a different trait further allows us not to implement it for types without stable identities (e.g. pointers) or use other implementations than the standard hash function.
This commit is contained in:
parent
d1288dc2b1
commit
cdbe2ee496
53 changed files with 842 additions and 331 deletions
108
crates/ruff_cache/tests/cache_key.rs
Normal file
108
crates/ruff_cache/tests/cache_key.rs
Normal file
|
@ -0,0 +1,108 @@
|
|||
use ruff_cache::{CacheKey, CacheKeyHasher};
|
||||
use ruff_macros::CacheKey;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
#[derive(CacheKey, Hash)]
|
||||
struct UnitStruct;
|
||||
|
||||
#[derive(CacheKey, Hash)]
|
||||
struct NamedFieldsStruct {
|
||||
a: String,
|
||||
b: String,
|
||||
}
|
||||
|
||||
#[derive(CacheKey, Hash)]
|
||||
struct UnnamedFieldsStruct(String, String);
|
||||
|
||||
#[derive(CacheKey, Hash)]
|
||||
enum Enum {
|
||||
Unit,
|
||||
UnnamedFields(String, String),
|
||||
NamedFields { a: String, b: String },
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_struct_cache_key() {
|
||||
let mut key = CacheKeyHasher::new();
|
||||
|
||||
UnitStruct.cache_key(&mut key);
|
||||
|
||||
let mut hash = DefaultHasher::new();
|
||||
UnitStruct.hash(&mut hash);
|
||||
|
||||
assert_eq!(hash.finish(), key.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_field_struct() {
|
||||
let mut key = CacheKeyHasher::new();
|
||||
|
||||
let named_fields = NamedFieldsStruct {
|
||||
a: "Hello".into(),
|
||||
b: "World".into(),
|
||||
};
|
||||
|
||||
named_fields.cache_key(&mut key);
|
||||
|
||||
let mut hash = DefaultHasher::new();
|
||||
named_fields.hash(&mut hash);
|
||||
|
||||
assert_eq!(hash.finish(), key.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unnamed_field_struct() {
|
||||
let mut key = CacheKeyHasher::new();
|
||||
|
||||
let unnamed_fields = UnnamedFieldsStruct("Hello".into(), "World".into());
|
||||
|
||||
unnamed_fields.cache_key(&mut key);
|
||||
|
||||
let mut hash = DefaultHasher::new();
|
||||
unnamed_fields.hash(&mut hash);
|
||||
|
||||
assert_eq!(hash.finish(), key.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_unit_variant() {
|
||||
let mut key = CacheKeyHasher::new();
|
||||
|
||||
let variant = Enum::Unit;
|
||||
variant.cache_key(&mut key);
|
||||
|
||||
let mut hash = DefaultHasher::new();
|
||||
variant.hash(&mut hash);
|
||||
|
||||
assert_eq!(hash.finish(), key.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_named_fields_variant() {
|
||||
let mut key = CacheKeyHasher::new();
|
||||
|
||||
let variant = Enum::NamedFields {
|
||||
a: "Hello".to_string(),
|
||||
b: "World".to_string(),
|
||||
};
|
||||
variant.cache_key(&mut key);
|
||||
|
||||
let mut hash = DefaultHasher::new();
|
||||
variant.hash(&mut hash);
|
||||
|
||||
assert_eq!(hash.finish(), key.finish());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_unnamed_fields_variant() {
|
||||
let mut key = CacheKeyHasher::new();
|
||||
|
||||
let variant = Enum::UnnamedFields("Hello".to_string(), "World".to_string());
|
||||
variant.cache_key(&mut key);
|
||||
|
||||
let mut hash = DefaultHasher::new();
|
||||
variant.hash(&mut hash);
|
||||
|
||||
assert_eq!(hash.finish(), key.finish());
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue