use crate::collection::CollectionEventCallback;
use crate::errors::NitriteResult;
use crate::nitrite_config::NitriteConfig;
use anyhow::Error;
use basu::error::BasuError;
use basu::event::Event;
use basu::Handle;
use std::fmt::Debug;
use std::sync::Arc;
#[derive(Debug, PartialEq, Clone)]
pub enum StoreEvents {
Open,
Commit,
Closing,
Closed,
}
#[derive(Clone)]
pub struct StoreEventInfo {
event: StoreEvents,
nitrite_config: NitriteConfig,
}
impl StoreEventInfo {
pub fn new(event: StoreEvents, nitrite_config: NitriteConfig) -> Self {
StoreEventInfo {
event,
nitrite_config,
}
}
pub fn event(&self) -> StoreEvents {
self.event.clone()
}
pub(crate) fn nitrite_config(&self) -> &NitriteConfig {
&self.nitrite_config
}
}
impl Debug for StoreEventInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StoreEventInfo")
.field("event", &self.event)
.finish()
}
}
pub trait StoreEventCallback: Send + Sync + Fn(StoreEventInfo) -> NitriteResult<()> {}
impl<F> StoreEventCallback for F
where
F: Send + Sync + Fn(StoreEventInfo) -> NitriteResult<()>,
{
}
#[derive(Clone)]
pub struct StoreEventListener {
on_event: Arc<dyn StoreEventCallback>,
}
impl StoreEventListener {
pub fn new(on_event: impl StoreEventCallback + 'static) -> Self {
StoreEventListener {
on_event: Arc::new(on_event),
}
}
}
impl Handle<StoreEventInfo> for StoreEventListener {
fn handle(&self, event: &Event<StoreEventInfo>) -> Result<(), BasuError> {
match (self.on_event)(event.data.clone()) {
Ok(_) => Ok(()),
Err(e) => Err(BasuError::HandlerError(Error::from(e))),
}
}
}
impl Debug for StoreEventListener {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StoreEventListener")
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::errors::{ErrorKind, NitriteError};
use crate::nitrite_config::NitriteConfig;
use basu::event::Event;
use std::sync::Arc;
#[test]
fn test_store_event_listener_new() {
let listener = StoreEventListener::new(|_| Ok(()));
assert!(Arc::strong_count(&listener.on_event) > 0);
}
#[test]
fn test_store_event_listener_handle_success() {
let listener = StoreEventListener::new(|_| Ok(()));
let nitrite_config = NitriteConfig::default();
let store_event_info = StoreEventInfo::new(StoreEvents::Open, nitrite_config);
let event = Event::new(store_event_info);
assert!(listener.handle(&event).is_ok());
}
#[test]
fn test_store_event_listener_handle_failure() {
let listener = StoreEventListener::new(|_| {
Err(NitriteError::new("Test error", ErrorKind::InvalidOperation))
});
let nitrite_config = NitriteConfig::default();
let store_event_info = StoreEventInfo::new(StoreEvents::Open, nitrite_config);
let event = Event::new(store_event_info);
assert!(listener.handle(&event).is_err());
}
#[test]
fn test_store_event_info_new() {
let nitrite_config = NitriteConfig::default();
let store_event_info = StoreEventInfo::new(StoreEvents::Commit, nitrite_config.clone());
assert_eq!(store_event_info.event, StoreEvents::Commit);
}
#[test]
fn test_store_event_info_debug() {
let nitrite_config = NitriteConfig::default();
let store_event_info = StoreEventInfo::new(StoreEvents::Closing, nitrite_config);
let debug_str = format!("{:?}", store_event_info);
assert!(debug_str.contains("StoreEventInfo"));
}
#[test]
fn test_store_event_listener_debug() {
let listener = StoreEventListener::new(|_| Ok(()));
let debug_str = format!("{:?}", listener);
assert!(debug_str.contains("StoreEventListener"));
}
#[test]
fn test_store_event_listener_clone_efficiency() {
let listener = StoreEventListener::new(|_| Ok(()));
let initial_count = Arc::strong_count(&listener.on_event);
let listener2 = listener.clone();
let new_count = Arc::strong_count(&listener2.on_event);
assert_eq!(new_count, initial_count + 1);
}
#[test]
fn test_store_event_info_clone_efficiency() {
let config1 = NitriteConfig::default();
let info1 = StoreEventInfo::new(StoreEvents::Commit, config1);
let info2 = info1.clone();
assert_eq!(info2.event, StoreEvents::Commit);
}
#[test]
fn test_multiple_listeners_efficiency() {
let listeners: Vec<_> = (0..10)
.map(|_| StoreEventListener::new(|_| Ok(())))
.collect();
assert_eq!(listeners.len(), 10);
}
#[test]
fn test_store_event_info_events_immutable() {
let config = NitriteConfig::default();
let events = vec![
StoreEvents::Open,
StoreEvents::Commit,
StoreEvents::Closing,
StoreEvents::Closed,
];
for event in events {
let info = StoreEventInfo::new(event.clone(), config.clone());
assert_eq!(info.event(), event);
}
}
#[test]
fn test_handle_with_multiple_events() {
let listener = StoreEventListener::new(|_| Ok(()));
let events = vec![
StoreEvents::Open,
StoreEvents::Commit,
StoreEvents::Closing,
];
let config = NitriteConfig::default();
for event in events {
let info = StoreEventInfo::new(event, config.clone());
let event_wrapper = Event::new(info);
assert!(listener.handle(&event_wrapper).is_ok());
}
}
#[test]
fn test_listener_callback_capture_efficiency() {
let counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
let counter_clone = counter.clone();
let listener = StoreEventListener::new(move |_| {
counter_clone.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Ok(())
});
let config = NitriteConfig::default();
let info = StoreEventInfo::new(StoreEvents::Open, config);
let event = Event::new(info);
listener.handle(&event).unwrap();
assert_eq!(counter.load(std::sync::atomic::Ordering::Relaxed), 1);
}
}