diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..dd5903a --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,41 @@ +name: CI + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + +env: + CARGO_TERM_COLOR: always + +jobs: + format: + name: rustfmt + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + components: rustfmt, clippy + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: -- --check + + test: + name: cargo test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + - uses: actions-rs/cargo@v1 + with: + command: test + args: --all-targets --all-features diff --git a/src/lib.rs b/src/lib.rs index e5ddaee..9c17825 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,21 +12,21 @@ //! ``` //! use std::thread::sleep; //! use std::time::Duration; -//! +//! //! use endorphin::policy::TTLPolicy; //! use endorphin::HashMap; -//! +//! //! fn main() { //! let mut cache = HashMap::new(TTLPolicy::new()); -//! +//! //! cache.insert("Still", "Alive", Duration::from_secs(3)); //! cache.insert("Gonna", "Die", Duration::from_secs(1)); -//! +//! //! sleep(Duration::from_secs(1)); -//! +//! //! assert_eq!(cache.get(&"Still"), Some(&"Alive")); //! assert_eq!(cache.get(&"Gonna"), None); -//!} +//! } //! ``` //! For more examples, visit [here] //! diff --git a/src/map.rs b/src/map.rs index bd50a67..32f0e05 100644 --- a/src/map.rs +++ b/src/map.rs @@ -143,7 +143,7 @@ where } if let Some(backlog) = self.exp_backlog.pop() { - for entry_id in backlog.into_iter().filter_map(|v| v) { + for entry_id in backlog.into_iter().flatten() { // bucket could already removed and its empty storage. if let Some(bucket) = self.exp_bucket_table.release_slot(entry_id) { unsafe { @@ -162,7 +162,7 @@ where ) -> Bucket<(K, V, Storage)> { let mut has_backlog = false; while let Some(backlog) = self.exp_backlog.pop() { - for entry_id in backlog.into_iter().filter_map(|v| v) { + for entry_id in backlog.into_iter().flatten() { // bucket could already removed and its empty storage. if let Some(bucket) = self.exp_bucket_table.release_slot(entry_id) { unsafe { @@ -208,7 +208,7 @@ where Command::Noop => return, } - removed.iter().cloned().filter_map(|v| v).for_each(|v| { + removed.iter().cloned().flatten().for_each(|v| { if let Some(bucket) = self.exp_bucket_table.get(v) { let (_, _, s) = unsafe { bucket.as_ref() }; @@ -266,7 +266,7 @@ where self.exp_bucket_table .set_bucket(s.entry_id, Some(bucket.clone())); - self.handle_status(self.exp_policy.on_insert(s.entry_id, &mut s.storage)); + self.handle_status(self.exp_policy.on_insert(s.entry_id, &s.storage)); (bucket, old_v) } @@ -298,7 +298,7 @@ where K: Borrow, Q: Hash + Eq, { - let hash = make_hash::(&self.hash_builder, &k); + let hash = make_hash::(&self.hash_builder, k); let bucket = match self.table.find(hash, equivalent_key(k)) { Some(bucket) => bucket, None => return None, @@ -306,10 +306,10 @@ where // fire on_insert event. let (_, v, s) = unsafe { bucket.as_mut() }; - self.handle_status(self.exp_policy.on_access(s.entry_id, &mut s.storage)); + self.handle_status(self.exp_policy.on_access(s.entry_id, &s.storage)); // don't give access to entry if entry expired. - if self.exp_policy.is_expired(s.entry_id, &mut s.storage) || unlikely(s.is_removed()) { + if self.exp_policy.is_expired(s.entry_id, &s.storage) || unlikely(s.is_removed()) { None } else { Some(v) @@ -344,7 +344,7 @@ where K: Borrow, Q: Hash + Eq, { - let hash = make_hash::(&self.hash_builder, &k); + let hash = make_hash::(&self.hash_builder, k); let bucket = match self.table.find(hash, equivalent_key(k)) { Some(bucket) => bucket, None => return None, @@ -352,10 +352,10 @@ where // fire on_insert event. let (k, v, s) = unsafe { bucket.as_mut() }; - self.handle_status(self.exp_policy.on_access(s.entry_id, &mut s.storage)); + self.handle_status(self.exp_policy.on_access(s.entry_id, &s.storage)); // don't give access to entry if entry expired. - if self.exp_policy.is_expired(s.entry_id, &mut s.storage) || unlikely(s.is_removed()) { + if self.exp_policy.is_expired(s.entry_id, &s.storage) || unlikely(s.is_removed()) { None } else { Some((k, v)) @@ -391,7 +391,7 @@ where K: Borrow, Q: Hash + Eq, { - let hash = make_hash::(&self.hash_builder, &k); + let hash = make_hash::(&self.hash_builder, k); let bucket = match self.table.find(hash, equivalent_key(k)) { Some(bucket) => bucket, None => return None, @@ -399,10 +399,10 @@ where // fire on_insert event. let (_, v, s) = unsafe { bucket.as_mut() }; - self.handle_status(self.exp_policy.on_access(s.entry_id, &mut s.storage)); + self.handle_status(self.exp_policy.on_access(s.entry_id, &s.storage)); // don't give access to entry if entry expired. - if self.exp_policy.is_expired(s.entry_id, &mut s.storage) || unlikely(s.is_removed()) { + if self.exp_policy.is_expired(s.entry_id, &s.storage) || unlikely(s.is_removed()) { None } else { Some(v) @@ -464,7 +464,7 @@ where pub fn insert(&mut self, k: K, v: V, init: P::Info) -> Option { let (_, old_v) = unsafe { self.raw_insert(k, v, init) }; - return old_v; + old_v } /// Removes a key from the `HashMap`, returning the value at the key if the key was previously in the `HashMap`. @@ -499,7 +499,7 @@ where self.process_single_backlog(); // Avoid `Option::map` because it bloats LLVM IR. - let hash = make_hash::(&self.hash_builder, &k); + let hash = make_hash::(&self.hash_builder, k); let entry = match self.table.remove_entry(hash, equivalent_key(k)) { Some((_, v, s)) => { self.exp_bucket_table.set_bucket(s.entry_id, None); @@ -513,7 +513,7 @@ where None => None, }; - return entry; + entry } /// Removes a key from the `HashMap`, returning the stored key and value if the key was previously in the `HashMap`. @@ -547,7 +547,7 @@ where self.process_single_backlog(); // Avoid `Option::map` because it bloats LLVM IR. - let hash = make_hash::(&self.hash_builder, &k); + let hash = make_hash::(&self.hash_builder, k); let entry = match self.table.remove_entry(hash, equivalent_key(k)) { Some((k, v, s)) => { self.exp_bucket_table.set_bucket(s.entry_id, None); @@ -561,7 +561,7 @@ where None => None, }; - return entry; + entry } #[inline] @@ -1553,7 +1553,7 @@ where pub fn get(&self) -> &V { let (_, v, s) = unsafe { self.elem.as_mut() }; self.table - .handle_status(self.table.exp_policy.on_access(s.entry_id, &mut s.storage)); + .handle_status(self.table.exp_policy.on_access(s.entry_id, &s.storage)); v } @@ -1587,7 +1587,7 @@ where pub fn get_mut(&mut self) -> &mut V { let (_, v, s) = unsafe { self.elem.as_mut() }; self.table - .handle_status(self.table.exp_policy.on_access(s.entry_id, &mut s.storage)); + .handle_status(self.table.exp_policy.on_access(s.entry_id, &s.storage)); v } @@ -1621,7 +1621,7 @@ where pub fn into_mut(self) -> &'a mut V { let (_, v, s) = unsafe { self.elem.as_mut() }; self.table - .handle_status(self.table.exp_policy.on_access(s.entry_id, &mut s.storage)); + .handle_status(self.table.exp_policy.on_access(s.entry_id, &s.storage)); v } @@ -1649,12 +1649,12 @@ where let k = unsafe { &self.elem.as_ref().0 }; let s = self.table.exp_policy.init_storage(init); - let mut storage = Storage::new(s, self.table.exp_bucket_table.acquire_slot()); + let storage = Storage::new(s, self.table.exp_bucket_table.acquire_slot()); self.table.handle_status( self.table .exp_policy - .on_insert(storage.entry_id, &mut storage.storage), + .on_insert(storage.entry_id, &storage.storage), ); let (_, old_v, old_s) = self @@ -1736,7 +1736,7 @@ where self.table.handle_status( self.table .exp_policy - .on_access(entry.2.entry_id, &mut entry.2.storage), + .on_access(entry.2.entry_id, &entry.2.storage), ); let old_key = mem::replace(&mut entry.0, self.key.unwrap()); @@ -1779,7 +1779,7 @@ where self.table.handle_status( self.table .exp_policy - .on_access(entry.2.entry_id, &mut entry.2.storage), + .on_access(entry.2.entry_id, &entry.2.storage), ); mem::replace(&mut entry.0, self.key.unwrap()) @@ -1857,7 +1857,7 @@ where .exp_bucket_table .set_bucket(s.entry_id, Some(elem.clone())); self.table - .handle_status(self.table.exp_policy.on_access(s.entry_id, &mut s.storage)); + .handle_status(self.table.exp_policy.on_access(s.entry_id, &s.storage)); if let Some(key) = spare_key { Entry::Vacant(VacantEntry { @@ -2110,34 +2110,34 @@ mod test_map { fn test_contains_key() { let mut map = HashMap::new(MockPolicy::new()); - assert_eq!(map.contains_key(&0), false); - assert_eq!(map.contains_key(&1), false); + assert!(!map.contains_key(&0)); + assert!(!map.contains_key(&1)); assert!(map.insert(0, 0, ()).is_none()); - assert_eq!(map.contains_key(&0), true); - assert_eq!(map.contains_key(&1), false); + assert!(map.contains_key(&0)); + assert!(!map.contains_key(&1)); assert!(map.remove(&0).is_some()); - assert_eq!(map.contains_key(&0), false); + assert!(!map.contains_key(&0)); } #[test] fn test_remove() { let mut map = HashMap::new(MockPolicy::new()); - assert_eq!(map.contains_key(&0), false); + assert!(!map.contains_key(&0)); assert!(map.insert(0, 1, ()).is_none()); - assert_eq!(map.contains_key(&0), true); + assert!(map.contains_key(&0)); assert_eq!(map.remove(&0).unwrap(), 1); - assert_eq!(map.contains_key(&0), false); + assert!(!map.contains_key(&0)); - assert_eq!(map.contains_key(&10), false); + assert!(!map.contains_key(&10)); assert_eq!(map.remove(&10), None); } @@ -2146,15 +2146,15 @@ mod test_map { fn test_remove_entry() { let mut map = HashMap::new(MockPolicy::new()); - assert_eq!(map.contains_key(&0), false); + assert!(!map.contains_key(&0)); assert!(map.insert(0, 1, ()).is_none()); - assert_eq!(map.contains_key(&0), true); + assert!(map.contains_key(&0)); assert_eq!(map.remove_entry(&0).unwrap(), (0, 1)); - assert_eq!(map.contains_key(&0), false); + assert!(!map.contains_key(&0)); } #[test] @@ -2278,13 +2278,13 @@ mod test_map { map.insert(0, 0, ()); match map.entry(0) { - Entry::Occupied(_) => assert!(true), + Entry::Occupied(_) => (), Entry::Vacant(_) => unreachable!(), } match map.entry(1) { Entry::Occupied(_) => unreachable!(), - Entry::Vacant(_) => assert!(true), + Entry::Vacant(_) => (), } } @@ -2352,8 +2352,8 @@ mod test_map { let now = map .entry(0) - .and_modify(|v| *v = *v + 5) - .and_modify(|v| *v = *v * 10); + .and_modify(|v| *v += 5) + .and_modify(|v| *v *= 10); assert_eq!(now.or_insert(0, ()), &50); assert_eq!(map.get(&0).unwrap(), &50); } @@ -2418,7 +2418,7 @@ mod test_map { assert_eq!(v, &10); *v += 10; - let v = entry.get_mut(); // not moved + let _v = entry.get_mut(); // not moved } Entry::Vacant(_) => unreachable!(), } diff --git a/src/policy/mixed_policy.rs b/src/policy/mixed_policy.rs index 84bc849..847b643 100644 --- a/src/policy/mixed_policy.rs +++ b/src/policy/mixed_policy.rs @@ -34,6 +34,12 @@ impl MixedPolicy { } } +impl Default for MixedPolicy { + fn default() -> Self { + Self::new() + } +} + impl ExpirePolicy for MixedPolicy { type Info = Expiration; type Storage = Storage; diff --git a/src/policy/tti_policy.rs b/src/policy/tti_policy.rs index 7f3dba4..62e83b6 100644 --- a/src/policy/tti_policy.rs +++ b/src/policy/tti_policy.rs @@ -32,7 +32,7 @@ impl TTIStorage { return false; } - return true; + true } } @@ -59,6 +59,12 @@ impl TTIPolicy { } } +impl Default for TTIPolicy { + fn default() -> Self { + Self::new() + } +} + impl ExpirePolicy for TTIPolicy { type Info = Duration; type Storage = TTIStorage; @@ -98,7 +104,7 @@ impl ExpirePolicy for TTIPolicy { for _ in 0..(records.len() >> 5 | 1) { let expires_at = if let Some(v) = records.keys().next() { - v.clone() + *v } else { break; }; @@ -152,7 +158,7 @@ impl ExpirePolicy for TTIPolicy { #[inline] fn align_instant(instant: Instant, by: Duration) -> Instant { use once_cell::sync::Lazy; - static BASE: Lazy = Lazy::new(|| Instant::now()); + static BASE: Lazy = Lazy::new(Instant::now); let v = *BASE; if likely(v < instant) { diff --git a/src/policy/ttl_policy.rs b/src/policy/ttl_policy.rs index 56a1954..3263e76 100644 --- a/src/policy/ttl_policy.rs +++ b/src/policy/ttl_policy.rs @@ -30,6 +30,12 @@ impl TTLPolicy { } } +impl Default for TTLPolicy { + fn default() -> Self { + Self::new() + } +} + impl ExpirePolicy for TTLPolicy { type Info = Duration; type Storage = Instant; @@ -68,7 +74,7 @@ impl ExpirePolicy for TTLPolicy { let mut expired_values = Vec::new(); for _ in 0..(records.len() >> 5 | 1) { let expires_at = if let Some(k) = records.keys().next() { - k.clone() + *k } else { break; }; @@ -109,7 +115,7 @@ impl ExpirePolicy for TTLPolicy { #[inline] fn align_instant(instant: Instant, by: Duration) -> Instant { use once_cell::sync::Lazy; - static BASE: Lazy = Lazy::new(|| Instant::now()); + static BASE: Lazy = Lazy::new(Instant::now); let v = *BASE; if likely(v < instant) { diff --git a/src/set.rs b/src/set.rs index e32cef7..fcf22ef 100644 --- a/src/set.rs +++ b/src/set.rs @@ -116,14 +116,7 @@ where #[inline] pub fn get_or_insert(&mut self, value: T, init: P::Info) -> &T { - match self.map.get_key_value(&value) { - Some((k, _v)) => k, - None => { - let (bucket, _) = unsafe { self.map.raw_insert(value, (), init) }; - - unsafe { &bucket.as_ref().0 } - } - } + todo!() } #[inline] @@ -132,14 +125,7 @@ where T: Borrow, Q: Hash + Eq + ToOwned, { - match self.map.get_key_value(value) { - Some((k, _v)) => k, - None => { - let (bucket, _) = unsafe { self.map.raw_insert(value.to_owned(), (), init) }; - - unsafe { &bucket.as_ref().0 } - } - } + todo!() } #[inline] @@ -149,14 +135,7 @@ where Q: Hash + Eq, F: FnOnce(&Q) -> T, { - match self.map.get_key_value(value) { - Some((k, _v)) => k, - None => { - let (bucket, _) = unsafe { self.map.raw_insert(f(value), (), init) }; - - unsafe { &bucket.as_ref().0 } - } - } + todo!() } pub fn is_disjoint(&self, other: &Self) -> bool { @@ -199,10 +178,7 @@ where T: Borrow, Q: Hash + Eq, { - match self.map.remove_entry(value) { - Some((k, _)) => Some(k), - None => None, - } + self.map.remove_entry(value).map(|(k, _)| k) } } @@ -276,10 +252,7 @@ where type Item = T; fn next(&mut self) -> Option { - match self.iter.next() { - Some((k, _)) => Some(k), - None => None, - } + self.iter.next().map(|(k, _)| k) } }