use crate::guardian::error::GuardianError;
use crate::log::{Log, entry::Entry};
use crate::traits::StoreIndex;
use parking_lot::RwLock;
use std::sync::Arc;
pub struct EventIndex {
entries_cache: Arc<RwLock<Vec<Entry>>>,
}
impl Default for EventIndex {
fn default() -> Self {
Self::new()
}
}
impl EventIndex {
pub fn new() -> Self {
EventIndex {
entries_cache: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn len(&self) -> usize {
let cache = self.entries_cache.read();
cache.len()
}
pub fn is_empty(&self) -> bool {
let cache = self.entries_cache.read();
cache.is_empty()
}
pub fn get_all_entries(&self) -> Vec<Entry> {
let cache = self.entries_cache.read();
cache.clone()
}
pub fn get_entry_at(&self, index: usize) -> Option<Entry> {
let cache = self.entries_cache.read();
cache.get(index).cloned()
}
pub fn get_last_entries(&self, count: usize) -> Vec<Entry> {
let cache = self.entries_cache.read();
let start = cache.len().saturating_sub(count);
cache[start..].to_vec()
}
}
impl StoreIndex for EventIndex {
type Error = GuardianError;
fn contains_key(&self, key: &str) -> std::result::Result<bool, Self::Error> {
if let Ok(index) = key.parse::<usize>() {
let cache = self.entries_cache.read();
Ok(index < cache.len())
} else {
Ok(false)
}
}
fn get_bytes(&self, key: &str) -> std::result::Result<Option<Vec<u8>>, Self::Error> {
if let Ok(index) = key.parse::<usize>() {
let cache = self.entries_cache.read();
if let Some(entry) = cache.get(index) {
Ok(Some(entry.payload().to_vec()))
} else {
Ok(None)
}
} else {
Ok(None)
}
}
fn keys(&self) -> std::result::Result<Vec<String>, GuardianError> {
let cache = self.entries_cache.read();
let keys: Vec<String> = (0..cache.len()).map(|i| i.to_string()).collect();
Ok(keys)
}
fn len(&self) -> std::result::Result<usize, Self::Error> {
let cache = self.entries_cache.read();
Ok(cache.len())
}
fn is_empty(&self) -> std::result::Result<bool, Self::Error> {
let cache = self.entries_cache.read();
Ok(cache.is_empty())
}
fn update_index(
&mut self,
_log: &Log,
entries: &[Entry],
) -> std::result::Result<(), Self::Error> {
{
let mut cache = self.entries_cache.write();
cache.clear();
cache.extend_from_slice(entries);
}
Ok(())
}
fn clear(&mut self) -> std::result::Result<(), Self::Error> {
let mut cache = self.entries_cache.write();
cache.clear();
Ok(())
}
fn get_entries_range(&self, start: usize, end: usize) -> Option<Vec<Entry>> {
let cache = self.entries_cache.read();
if start > end || start >= cache.len() {
return None;
}
let actual_end = end.min(cache.len());
Some(cache[start..actual_end].to_vec())
}
fn get_last_entries(&self, count: usize) -> Option<Vec<Entry>> {
let cache = self.entries_cache.read();
if cache.is_empty() || count == 0 {
return Some(Vec::new());
}
let start = cache.len().saturating_sub(count);
Some(cache[start..].to_vec())
}
fn get_entry_by_hash(&self, hash: &iroh_blobs::Hash) -> Option<Entry> {
let cache = self.entries_cache.read();
cache.iter().find(|entry| entry.hash() == hash).cloned()
}
fn supports_entry_queries(&self) -> bool {
true
}
}
pub fn new_event_index(_params: &[u8]) -> Box<dyn StoreIndex<Error = GuardianError>> {
Box::new(EventIndex::new())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::log::{
entry::Entry,
identity::{Identity, Signatures},
};
use std::sync::Arc;
fn create_test_identity() -> Arc<Identity> {
Arc::new(Identity::new(
"test_id",
"test_public_key",
Signatures::new("id_signature", "public_signature"),
))
}
fn create_test_entry(payload: &str) -> Entry {
let identity = (*create_test_identity()).clone();
Entry::new(
identity,
"test_log", payload.as_bytes(), &[], None, )
}
#[test]
fn test_event_index_creation() {
let index = EventIndex::new();
assert!(index.is_empty());
assert_eq!(index.len(), 0);
}
#[test]
fn test_event_index_basic_operations() {
let index = EventIndex::new();
assert!(index.is_empty());
assert_eq!(index.len(), 0);
assert!(index.get_all_entries().is_empty());
assert!(index.get_entry_at(0).is_none());
assert!(index.get_last_entries(5).is_empty());
}
#[test]
fn test_entries_cache_functionality() {
let index = EventIndex::new();
{
let mut cache = index.entries_cache.write();
cache.push(create_test_entry("test1"));
cache.push(create_test_entry("test2"));
cache.push(create_test_entry("test3"));
}
assert_eq!(index.len(), 3);
assert!(!index.is_empty());
let all_entries = index.get_all_entries();
assert_eq!(all_entries.len(), 3);
let entry_at_1 = index.get_entry_at(1);
assert!(entry_at_1.is_some());
assert_eq!(entry_at_1.unwrap().payload(), b"test2");
let last_2 = index.get_last_entries(2);
assert_eq!(last_2.len(), 2);
assert_eq!(last_2[0].payload(), b"test2");
assert_eq!(last_2[1].payload(), b"test3");
}
#[test]
fn test_new_event_index_factory() {
let params = b"test_params";
let index_box = new_event_index(params);
assert!(index_box.is_empty().unwrap()); assert_eq!(index_box.len().unwrap(), 0); }
#[test]
fn test_store_index_trait_implementation() {
let mut index = EventIndex::new();
assert!(index.is_empty());
assert_eq!(index.len(), 0);
assert!(index.get_all_entries().is_empty());
assert!(
(&index as &dyn StoreIndex<Error = GuardianError>)
.is_empty()
.unwrap()
);
assert_eq!(
(&index as &dyn StoreIndex<Error = GuardianError>)
.len()
.unwrap(),
0
);
assert!(
(&index as &dyn StoreIndex<Error = GuardianError>)
.keys()
.unwrap()
.is_empty()
);
assert!(
!(&index as &dyn StoreIndex<Error = GuardianError>)
.contains_key("0")
.unwrap()
);
assert!(
(&index as &dyn StoreIndex<Error = GuardianError>)
.get_bytes("0")
.unwrap()
.is_none()
);
{
let mut cache = index.entries_cache.write();
cache.push(create_test_entry("test1"));
cache.push(create_test_entry("test2"));
}
let store_index = &index as &dyn StoreIndex<Error = GuardianError>;
assert!(!store_index.is_empty().unwrap());
assert_eq!(store_index.len().unwrap(), 2);
assert_eq!(store_index.keys().unwrap(), vec!["0", "1"]);
assert!(store_index.contains_key("0").unwrap());
assert!(store_index.contains_key("1").unwrap());
assert!(!store_index.contains_key("2").unwrap());
let bytes_0 = store_index.get_bytes("0").unwrap();
assert!(bytes_0.is_some());
assert_eq!(bytes_0.unwrap(), b"test1".to_vec());
let bytes_1 = store_index.get_bytes("1").unwrap();
assert!(bytes_1.is_some());
assert_eq!(bytes_1.unwrap(), b"test2".to_vec());
index.clear().unwrap();
assert!(index.is_empty());
assert_eq!(index.len(), 0);
}
}