Skip to content

Commit 007d9f8

Browse files
committed
Nits
1 parent 0786a85 commit 007d9f8

File tree

3 files changed

+216
-9
lines changed

3 files changed

+216
-9
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,16 +205,16 @@ If you only need specific implementations, you can select just the features you
205205

206206
```toml
207207
# Only use the core implementation
208-
sieve-cache = { version = "1.0.0", default-features = false }
208+
sieve-cache = { version = "1", default-features = false }
209209

210210
# Only use the core and sync implementations
211-
sieve-cache = { version = "1.0.0", default-features = false, features = ["sync"] }
211+
sieve-cache = { version = "1", default-features = false, features = ["sync"] }
212212

213213
# Only use the core and sharded implementations
214-
sieve-cache = { version = "1.0.0", default-features = false, features = ["sharded"] }
214+
sieve-cache = { version = "1", default-features = false, features = ["sharded"] }
215215

216216
# For documentation tests to work correctly
217-
sieve-cache = { version = "1.0.0", features = ["doctest"] }
217+
sieve-cache = { version = "1", features = ["doctest"] }
218218
```
219219

220220
## Performance Considerations

src/sharded.rs

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::SieveCache;
22
use std::borrow::Borrow;
33
use std::collections::hash_map::DefaultHasher;
4+
use std::fmt;
45
use std::hash::{Hash, Hasher};
56
use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
67

@@ -60,7 +61,114 @@ unsafe impl<K, V> Sync for ShardedSieveCache<K, V>
6061
where
6162
K: Eq + Hash + Clone + Send + Sync,
6263
V: Send + Sync,
63-
{}
64+
{
65+
}
66+
67+
impl<K, V> Default for ShardedSieveCache<K, V>
68+
where
69+
K: Eq + Hash + Clone + Send + Sync,
70+
V: Send + Sync,
71+
{
72+
/// Creates a new sharded cache with a default capacity of 100 entries and default number of shards.
73+
///
74+
/// # Panics
75+
///
76+
/// Panics if the underlying `ShardedSieveCache::new()` returns an error, which should never
77+
/// happen for a non-zero capacity.
78+
///
79+
/// # Examples
80+
///
81+
/// ```
82+
/// # use sieve_cache::ShardedSieveCache;
83+
/// # use std::default::Default;
84+
/// let cache: ShardedSieveCache<String, u32> = Default::default();
85+
/// assert!(cache.capacity() >= 100); // Due to shard distribution, might be slightly larger
86+
/// assert_eq!(cache.num_shards(), 16); // Default shard count
87+
/// ```
88+
fn default() -> Self {
89+
Self::new(100).expect("Failed to create cache with default capacity")
90+
}
91+
}
92+
93+
impl<K, V> fmt::Debug for ShardedSieveCache<K, V>
94+
where
95+
K: Eq + Hash + Clone + Send + Sync + fmt::Debug,
96+
V: Send + Sync + fmt::Debug,
97+
{
98+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99+
f.debug_struct("ShardedSieveCache")
100+
.field("capacity", &self.capacity())
101+
.field("len", &self.len())
102+
.field("num_shards", &self.num_shards)
103+
.finish()
104+
}
105+
}
106+
107+
impl<K, V> IntoIterator for ShardedSieveCache<K, V>
108+
where
109+
K: Eq + Hash + Clone + Send + Sync,
110+
V: Clone + Send + Sync,
111+
{
112+
type Item = (K, V);
113+
type IntoIter = std::vec::IntoIter<(K, V)>;
114+
115+
/// Converts the cache into an iterator over its key-value pairs.
116+
///
117+
/// This collects all entries into a Vec and returns an iterator over that Vec.
118+
///
119+
/// # Examples
120+
///
121+
/// ```
122+
/// # use sieve_cache::ShardedSieveCache;
123+
/// # use std::collections::HashMap;
124+
/// let cache = ShardedSieveCache::new(100).unwrap();
125+
/// cache.insert("key1".to_string(), "value1".to_string());
126+
/// cache.insert("key2".to_string(), "value2".to_string());
127+
///
128+
/// // Collect into a HashMap
129+
/// let map: HashMap<_, _> = cache.into_iter().collect();
130+
/// assert_eq!(map.len(), 2);
131+
/// assert_eq!(map.get("key1"), Some(&"value1".to_string()));
132+
/// ```
133+
fn into_iter(self) -> Self::IntoIter {
134+
self.entries().into_iter()
135+
}
136+
}
137+
138+
#[cfg(feature = "sync")]
139+
impl<K, V> From<crate::SyncSieveCache<K, V>> for ShardedSieveCache<K, V>
140+
where
141+
K: Eq + Hash + Clone + Send + Sync,
142+
V: Clone + Send + Sync,
143+
{
144+
/// Creates a new sharded cache from an existing `SyncSieveCache`.
145+
///
146+
/// This allows for upgrading a standard thread-safe cache to a more scalable sharded version.
147+
///
148+
/// # Examples
149+
///
150+
/// ```
151+
/// # use sieve_cache::{SyncSieveCache, ShardedSieveCache};
152+
/// let sync_cache = SyncSieveCache::new(100).unwrap();
153+
/// sync_cache.insert("key".to_string(), "value".to_string());
154+
///
155+
/// // Convert to sharded version with default sharding
156+
/// let sharded_cache = ShardedSieveCache::from(sync_cache);
157+
/// assert_eq!(sharded_cache.get(&"key".to_string()), Some("value".to_string()));
158+
/// ```
159+
fn from(sync_cache: crate::SyncSieveCache<K, V>) -> Self {
160+
// Create a new sharded cache with the same capacity
161+
let capacity = sync_cache.capacity();
162+
let sharded = Self::new(capacity).expect("Failed to create sharded cache");
163+
164+
// Transfer all entries
165+
for (key, value) in sync_cache.entries() {
166+
sharded.insert(key, value);
167+
}
168+
169+
sharded
170+
}
171+
}
64172

65173
impl<K, V> ShardedSieveCache<K, V>
66174
where
@@ -605,7 +713,7 @@ where
605713
{
606714
for shard in &self.shards {
607715
let mut guard = shard.lock().unwrap_or_else(PoisonError::into_inner);
608-
guard.iter_mut().for_each(|entry| f(entry));
716+
guard.iter_mut().for_each(&mut f);
609717
}
610718
}
611719

src/sync.rs

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::SieveCache;
22
use std::borrow::Borrow;
3+
use std::fmt;
34
use std::hash::Hash;
45
use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
56

@@ -39,7 +40,105 @@ unsafe impl<K, V> Sync for SyncSieveCache<K, V>
3940
where
4041
K: Eq + Hash + Clone + Send + Sync,
4142
V: Send + Sync,
42-
{}
43+
{
44+
}
45+
46+
impl<K, V> Default for SyncSieveCache<K, V>
47+
where
48+
K: Eq + Hash + Clone + Send + Sync,
49+
V: Send + Sync,
50+
{
51+
/// Creates a new cache with a default capacity of 100 entries.
52+
///
53+
/// # Panics
54+
///
55+
/// Panics if the underlying `SieveCache::new()` returns an error, which should never
56+
/// happen for a non-zero capacity.
57+
///
58+
/// # Examples
59+
///
60+
/// ```
61+
/// # use sieve_cache::SyncSieveCache;
62+
/// # use std::default::Default;
63+
/// let cache: SyncSieveCache<String, u32> = Default::default();
64+
/// assert_eq!(cache.capacity(), 100);
65+
/// ```
66+
fn default() -> Self {
67+
Self::new(100).expect("Failed to create cache with default capacity")
68+
}
69+
}
70+
71+
impl<K, V> fmt::Debug for SyncSieveCache<K, V>
72+
where
73+
K: Eq + Hash + Clone + Send + Sync + fmt::Debug,
74+
V: Send + Sync + fmt::Debug,
75+
{
76+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77+
let guard = self.locked_cache();
78+
f.debug_struct("SyncSieveCache")
79+
.field("capacity", &guard.capacity())
80+
.field("len", &guard.len())
81+
.finish()
82+
}
83+
}
84+
85+
impl<K, V> From<SieveCache<K, V>> for SyncSieveCache<K, V>
86+
where
87+
K: Eq + Hash + Clone + Send + Sync,
88+
V: Send + Sync,
89+
{
90+
/// Creates a new thread-safe cache from an existing `SieveCache`.
91+
///
92+
/// This allows for easily converting a single-threaded cache to a thread-safe version.
93+
///
94+
/// # Examples
95+
///
96+
/// ```
97+
/// # use sieve_cache::{SieveCache, SyncSieveCache};
98+
/// let mut single_threaded = SieveCache::new(100).unwrap();
99+
/// single_threaded.insert("key".to_string(), "value".to_string());
100+
///
101+
/// // Convert to thread-safe version
102+
/// let thread_safe = SyncSieveCache::from(single_threaded);
103+
/// assert_eq!(thread_safe.get(&"key".to_string()), Some("value".to_string()));
104+
/// ```
105+
fn from(cache: SieveCache<K, V>) -> Self {
106+
Self {
107+
inner: Arc::new(Mutex::new(cache)),
108+
}
109+
}
110+
}
111+
112+
impl<K, V> IntoIterator for SyncSieveCache<K, V>
113+
where
114+
K: Eq + Hash + Clone + Send + Sync,
115+
V: Clone + Send + Sync,
116+
{
117+
type Item = (K, V);
118+
type IntoIter = std::vec::IntoIter<(K, V)>;
119+
120+
/// Converts the cache into an iterator over its key-value pairs.
121+
///
122+
/// This collects all entries into a Vec and returns an iterator over that Vec.
123+
///
124+
/// # Examples
125+
///
126+
/// ```
127+
/// # use sieve_cache::SyncSieveCache;
128+
/// # use std::collections::HashMap;
129+
/// let cache = SyncSieveCache::new(100).unwrap();
130+
/// cache.insert("key1".to_string(), "value1".to_string());
131+
/// cache.insert("key2".to_string(), "value2".to_string());
132+
///
133+
/// // Collect into a HashMap
134+
/// let map: HashMap<_, _> = cache.into_iter().collect();
135+
/// assert_eq!(map.len(), 2);
136+
/// assert_eq!(map.get("key1"), Some(&"value1".to_string()));
137+
/// ```
138+
fn into_iter(self) -> Self::IntoIter {
139+
self.entries().into_iter()
140+
}
141+
}
43142

44143
impl<K, V> SyncSieveCache<K, V>
45144
where
@@ -431,12 +530,12 @@ where
431530
/// assert_eq!(cache.get(&"key1".to_string()), Some("value1_special".to_string()));
432531
/// assert_eq!(cache.get(&"key2".to_string()), Some("value2".to_string()));
433532
/// ```
434-
pub fn for_each_entry<F>(&self, mut f: F)
533+
pub fn for_each_entry<F>(&self, f: F)
435534
where
436535
F: FnMut((&K, &mut V)),
437536
{
438537
let mut guard = self.locked_cache();
439-
guard.iter_mut().for_each(|entry| f(entry));
538+
guard.iter_mut().for_each(f);
440539
}
441540

442541
/// Gets exclusive access to the underlying cache to perform multiple operations atomically.

0 commit comments

Comments
 (0)