use fnv::FnvHashMap;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct Context {
elements: FnvHashMap<String, String>,
}
impl Context {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
elements: FnvHashMap::with_capacity_and_hasher(
capacity,
Default::default(),
),
}
}
pub fn hash(&self) -> u64 {
let mut hasher = DefaultHasher::new();
for (key, value) in &self.elements {
key.hash(&mut hasher);
value.hash(&mut hasher);
}
hasher.finish()
}
pub fn set(&mut self, key: String, value: String) {
let _ = self.elements.insert(key, value);
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&String> {
self.elements.get(key)
}
pub fn get_mut(&mut self, key: &str) -> Option<&mut String> {
self.elements.get_mut(key)
}
pub fn remove(&mut self, key: &str) -> Option<String> {
self.elements.remove(key)
}
#[must_use]
pub fn len(&self) -> usize {
self.elements.len()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.elements.capacity()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
self.elements.iter()
}
pub fn clear(&mut self) {
self.elements.clear();
}
pub fn update<K, V>(&mut self, key: K, value: V)
where
K: Into<String>,
V: Into<String>,
{
let _ = self.elements.insert(key.into(), value.into());
}
}
impl FromIterator<(String, String)> for Context {
fn from_iter<I: IntoIterator<Item = (String, String)>>(
iter: I,
) -> Self {
let mut context = Context::new();
context.extend(iter);
context
}
}
impl Extend<(String, String)> for Context {
fn extend<T: IntoIterator<Item = (String, String)>>(
&mut self,
iter: T,
) {
for (key, value) in iter {
self.set(key, value);
}
}
}
impl Deref for Context {
type Target = FnvHashMap<String, String>;
fn deref(&self) -> &Self::Target {
&self.elements
}
}
impl DerefMut for Context {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.elements
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_context() {
let context = Context::new();
assert!(context.is_empty());
}
#[test]
fn test_with_capacity() {
let context = Context::with_capacity(10);
assert!(context.capacity() >= 10);
}
#[test]
fn test_set_and_get() {
let mut context = Context::new();
context.set("key".to_string(), "value".to_string());
assert_eq!(context.get("key"), Some(&"value".to_string()));
}
#[test]
fn test_get_mut() {
let mut context = Context::new();
context.set("key".to_string(), "value".to_string());
if let Some(value) = context.get_mut("key") {
*value = "new_value".to_string();
}
assert_eq!(context.get("key"), Some(&"new_value".to_string()));
}
#[test]
fn test_remove() {
let mut context = Context::new();
context.set("key".to_string(), "value".to_string());
assert_eq!(context.remove("key"), Some("value".to_string()));
assert_eq!(context.get("key"), None);
}
#[test]
fn test_hash() {
let mut context1 = Context::new();
context1.set("key1".to_string(), "value1".to_string());
let mut context2 = Context::new();
context2.set("key1".to_string(), "value1".to_string());
assert_eq!(context1.hash(), context2.hash());
context2.set("key2".to_string(), "value2".to_string());
assert_ne!(context1.hash(), context2.hash());
}
#[test]
fn test_from_iterator() {
let pairs = vec![
("key1".to_string(), "value1".to_string()),
("key2".to_string(), "value2".to_string()),
];
let context: Context = pairs.into_iter().collect();
assert_eq!(context.get("key1"), Some(&"value1".to_string()));
assert_eq!(context.get("key2"), Some(&"value2".to_string()));
}
#[test]
fn test_extend() {
let mut context = Context::new();
context.extend(vec![
("key1".to_string(), "value1".to_string()),
("key2".to_string(), "value2".to_string()),
]);
assert_eq!(context.get("key1"), Some(&"value1".to_string()));
assert_eq!(context.get("key2"), Some(&"value2".to_string()));
}
#[test]
fn test_iter() {
let mut context = Context::new();
context.set("key1".to_string(), "value1".to_string());
context.set("key2".to_string(), "value2".to_string());
let mut pairs: Vec<(&String, &String)> =
context.iter().collect();
pairs.sort_by(|a, b| a.0.cmp(b.0));
assert_eq!(
pairs,
vec![
(&"key1".to_string(), &"value1".to_string()),
(&"key2".to_string(), &"value2".to_string()),
]
);
}
#[test]
fn test_clear() {
let mut context = Context::new();
context.set("key1".to_string(), "value1".to_string());
context.set("key2".to_string(), "value2".to_string());
assert_eq!(context.len(), 2);
context.clear();
assert!(context.is_empty());
}
#[test]
fn test_deref() {
let mut context = Context::new();
context.set("key".to_string(), "value".to_string());
assert_eq!(context["key"], "value");
}
#[test]
fn test_deref_mut() {
let mut context = Context::new();
context.set("key".to_string(), "value".to_string());
let _ = context
.entry("key".to_string())
.and_modify(|val| *val = "new_value".to_string());
assert_eq!(context.get("key"), Some(&"new_value".to_string()));
}
#[test]
fn test_update() {
let mut context = Context::new();
context.set("key".to_string(), "value".to_string());
context.update("key", "new_value");
assert_eq!(context.get("key"), Some(&"new_value".to_string()));
}
}