use std::collections::BTreeMap;
use super::types::SnapshotItem;
pub trait SnapshotItemSource {
fn items_for_source(&self, source_id: &str) -> Vec<SnapshotItem>;
}
pub fn extract_item_id(composite: &str) -> String {
if let Some(rest) = composite.strip_prefix("mem_src:") {
if let Some(pos) = rest.find(':') {
return rest[pos + 1..].to_string();
}
}
if let Some(pos) = composite.find(':') {
return composite[pos + 1..].to_string();
}
composite.to_string()
}
#[derive(Debug, Clone, Default)]
pub struct InMemoryItemSource {
rows: BTreeMap<String, Vec<(String, String)>>,
}
impl InMemoryItemSource {
pub fn new() -> Self {
Self::default()
}
pub fn push_chunk(
&mut self,
source_id: impl Into<String>,
composite_source_id: impl Into<String>,
content: impl Into<String>,
) {
self.rows
.entry(source_id.into())
.or_default()
.push((composite_source_id.into(), content.into()));
}
pub fn push_item(
&mut self,
source_id: impl Into<String>,
item_id: impl Into<String>,
content: impl Into<String>,
) {
let source_id = source_id.into();
let item_id = item_id.into();
let composite = format!("mem_src:{source_id}:{item_id}");
self.push_chunk(source_id, composite, content);
}
pub fn set_source(&mut self, source_id: impl Into<String>, items: &[(&str, &str)]) {
let source_id = source_id.into();
let rows = items
.iter()
.map(|(item, content)| (format!("mem_src:{source_id}:{item}"), content.to_string()))
.collect();
self.rows.insert(source_id, rows);
}
}
impl SnapshotItemSource for InMemoryItemSource {
fn items_for_source(&self, source_id: &str) -> Vec<SnapshotItem> {
let Some(rows) = self.rows.get(source_id) else {
return Vec::new();
};
let mut groups: BTreeMap<String, String> = BTreeMap::new();
for (composite, content) in rows {
let item_id = extract_item_id(composite);
groups.entry(item_id).or_default().push_str(content);
}
groups
.into_iter()
.map(|(item_id, content)| SnapshotItem { item_id, content })
.collect()
}
}
#[cfg(test)]
#[path = "source_tests.rs"]
mod tests;