pub mod metrics {
use std::collections::HashMap;
pub trait Metrics {
fn record(&mut self, metric: &str, value: u64) -> anyhow::Result<()>;
}
pub struct MetricsCollector {
metrics: HashMap<String, u64>,
operations_since_flush: usize,
flush_interval: usize,
}
impl MetricsCollector {
pub fn new(flush_interval: usize) -> Self {
Self {
metrics: HashMap::new(),
operations_since_flush: 0,
flush_interval,
}
}
fn flush(&mut self) -> anyhow::Result<()> {
for (metric, value) in &self.metrics {
self.store_metric(metric, *value)?;
}
self.metrics.clear();
self.operations_since_flush = 0;
Ok(())
}
fn store_metric(&self, metric: &str, _value: u64) -> anyhow::Result<()> {
if metric.contains("error") {
anyhow::bail!("Metrics storage service unavailable");
}
Ok(())
}
}
impl Metrics for MetricsCollector {
fn record(&mut self, metric: &str, value: u64) -> anyhow::Result<()> {
*self.metrics.entry(metric.to_string()).or_insert(0) += value;
self.operations_since_flush += 1;
if self.operations_since_flush >= self.flush_interval {
self.flush()?;
}
Ok(())
}
}
}
pub mod kv_store {
use std::collections::HashMap;
use super::metrics::Metrics;
pub struct KVStore<M: Metrics> {
data: HashMap<String, String>,
metrics: M,
}
impl<M: Metrics> KVStore<M> {
pub fn new(metrics: M) -> Self {
Self {
data: HashMap::new(),
metrics,
}
}
pub fn get(&mut self, key: &str) -> anyhow::Result<Option<String>> {
self.metrics.record("kv.get", 1)?;
match self.data.get(key) {
Some(value) => {
self.metrics.record("kv.hit", 1)?;
Ok(Some(value.clone()))
}
None => {
self.metrics.record("kv.miss", 1)?;
Ok(None)
}
}
}
pub fn set(&mut self, key: String, value: String) -> anyhow::Result<()> {
if key.is_empty() {
anyhow::bail!("Key cannot be empty");
}
self.metrics.record("kv.set", 1)?;
self.data.insert(key, value);
Ok(())
}
pub fn delete(&mut self, key: &str) -> anyhow::Result<()> {
self.metrics.record("kv.delete", 1)?;
self.data.remove(key);
Ok(())
}
}
}
pub mod main {
use anyhow::Context;
use super::{kv_store::KVStore, metrics::MetricsCollector};
pub fn run() -> anyhow::Result<()> {
println!("Running v1: Pure anyhow");
let metrics = MetricsCollector::new(5);
let mut store = KVStore::new(metrics);
store
.set("user:123".to_string(), "Alice".to_string())
.context("Failed to store user")?;
store
.set("user:456".to_string(), "Bob".to_string())
.context("Failed to store user")?;
let name = store
.get("user:123")
.context("Failed to retrieve user")?
.context("User not found")?;
println!(" Retrieved user: {}", name);
match store.get("user:999")? {
Some(name) => println!(" Found: {}", name),
None => println!(" User 999 not found"),
}
Ok(())
}
}