tiny-counter 0.1.0

Track event counts across time windows with fixed memory and fast queries
Documentation
//! Track event counts across multiple time windows with fixed memory and fast queries.
//!
//! This library solves the problem of tracking events (like user actions, API calls, or system
//! events) when you need to answer questions like "how many times did this happen in the last
//! week?" without storing every individual timestamp.
//!
//! # Key Features
//!
//! - **Fixed memory**: Each event uses ~2KB regardless of event count
//! - **Multiple time windows**: Query at different granularities (minutes, hours, days, weeks, months, years)
//! - **Fast queries**: All queries run in O(buckets) time, independent of event count
//! - **Persistence**: Save to SQLite, JSON, or custom storage backends
//! - **Merge-friendly**: Combine event data from multiple sources for distributed systems
//!
//! # Quick Start
//!
//! ```
//! use tiny_counter::EventStore;
//! use chrono::Duration;
//!
//! let mut store = EventStore::new();
//!
//! // Record events
//! store.record("app_launch");
//! store.record("app_launch");
//!
//! // Query last 7 days
//! let launches = store
//!     .query("app_launch")
//!     .last_days(7)
//!     .sum()
//!     .unwrap_or(0);
//!
//! assert_eq!(launches, 2);
//! ```
//!
//! # Recording Events
//!
//! Record events that just happened:
//!
//! ```
//! # use tiny_counter::EventStore;
//! let mut store = EventStore::new();
//! store.record("button_click");
//! store.record_count("api_call", 5);
//! ```
//!
//! Record events from the past:
//!
//! ```
//! # use tiny_counter::EventStore;
//! # use chrono::{Duration, Utc};
//! let mut store = EventStore::new();
//! let timestamp = Utc::now() - Duration::days(2);
//! store.record_at("feature_used", timestamp).unwrap();
//! store.record_ago("sync", Duration::hours(3));
//! ```
//!
//! # Querying Events
//!
//! Query event counts across different time ranges:
//!
//! ```
//! # use tiny_counter::EventStore;
//! let mut store = EventStore::new();
//! store.record("app_launch");
//!
//! // Different time granularities
//! let last_hour = store.query("app_launch").last_minutes(60).sum().unwrap();
//! let last_day = store.query("app_launch").last_hours(24).sum().unwrap();
//! let last_week = store.query("app_launch").last_days(7).sum().unwrap();
//! ```
//!
//! # Rate Limiting
//!
//! Enforce rate limits with multiple constraints:
//!
//! ```
//! # use tiny_counter::{EventStore, TimeUnit};
//! let mut store = EventStore::new();
//!
//! let result = store
//!     .limit()
//!     .at_most("api_call", 10, TimeUnit::Minutes)
//!     .at_most("api_call", 100, TimeUnit::Hours)
//!     .check_and_record("api_call");
//!
//! assert!(result.is_ok());
//! ```
//!
//! # Persistence
//!
//! Save and load event data (requires `serde` feature with a storage backend like `storage-fs`):
//!
#![cfg_attr(
    feature = "serde",
    doc = r#"
```
# use tiny_counter::EventStore;
# use tiny_counter::storage::MemoryStorage;
let mut store = EventStore::builder()
    .with_storage(MemoryStorage::new())
    .build()
    .unwrap();

store.record("event");
store.persist().unwrap();
```
"#
)]
#![cfg_attr(
    not(feature = "serde"),
    doc = r#"
```text
See examples/persistence.rs for usage with serde feature enabled.
```
"#
)]
//!

mod clock;
#[doc(hidden)]
pub mod config_converter;
mod count_ring;
mod counter;
mod error;
pub mod formatter;
mod interval;
pub mod storage;
mod store;
mod sync_time;
mod time_unit;
mod traits;

pub use formatter::Formatter;

pub use clock::{SystemClock, TestClock};
pub use error::{Error, LimitExceeded, Result};
pub use store::builder::EventStoreBuilder;
pub use store::limiter::{Constraint, LimitUsage, Limiter, Reservation, Schedule};
pub use store::query::{
    DeltaQuery, DeltaRangeQuery, MultiQuery, MultiRangeQuery, Query, RangeQuery, RatioQuery,
};
pub use store::{EventId, EventStore};
pub use time_unit::{TimeUnit, TimeWindow};
pub use traits::{Clock, Storage};

/// Internal APIs exposed for benchmarking only.
///
/// **WARNING:** These APIs have no stability guarantees and may change
/// or be removed without notice. Do not use in production code.
///
/// This module exists to support performance benchmarking while clearly
/// signaling that these are internal implementation details.
#[doc(hidden)]
pub mod internal {
    pub use crate::config_converter;
    pub use crate::counter::config::EventCounterConfig;
    pub use crate::counter::SingleEventCounter;
    pub use crate::interval::config::IntervalConfig;
    pub use crate::sync_time::synchronized_start;
}

// Internal re-exports for crate use
pub(crate) use count_ring::CountRing;
pub(crate) use counter::config::EventCounterConfig;
pub(crate) use counter::SingleEventCounter;
pub(crate) use interval::config::IntervalConfig;
pub(crate) use interval::IntervalCounter;
pub(crate) use store::inner::EventStoreInner;