use std::collections::{HashMap, HashSet};
use crate::{MatchConfig, RouteSignature};
use super::activity_store::ActivityStore;
#[derive(Debug, Default)]
pub struct SignatureStore {
signatures: HashMap<String, RouteSignature>,
dirty: HashSet<String>,
newly_computed: HashSet<String>,
}
impl SignatureStore {
pub fn new() -> Self {
Self {
signatures: HashMap::new(),
dirty: HashSet::new(),
newly_computed: HashSet::new(),
}
}
pub fn mark_dirty(&mut self, id: &str) {
self.dirty.insert(id.to_string());
}
pub fn mark_many_dirty(&mut self, ids: impl IntoIterator<Item = String>) {
self.dirty.extend(ids);
}
pub fn mark_all_dirty(&mut self, ids: impl IntoIterator<Item = String>) {
self.signatures.clear();
self.newly_computed.clear();
self.dirty = ids.into_iter().collect();
}
pub fn remove(&mut self, id: &str) {
self.signatures.remove(id);
self.dirty.remove(id);
self.newly_computed.remove(id);
}
pub fn remove_many(&mut self, ids: &[String]) {
for id in ids {
self.remove(id);
}
}
pub fn clear(&mut self) {
self.signatures.clear();
self.dirty.clear();
self.newly_computed.clear();
}
pub fn clear_newly_computed(&mut self) {
self.newly_computed.clear();
}
pub fn has_dirty(&self) -> bool {
!self.dirty.is_empty()
}
pub fn has_newly_computed(&self) -> bool {
!self.newly_computed.is_empty()
}
pub fn dirty_count(&self) -> usize {
self.dirty.len()
}
pub fn newly_computed_count(&self) -> usize {
self.newly_computed.len()
}
pub fn is_dirty(&self, id: &str) -> bool {
self.dirty.contains(id)
}
pub fn ensure_computed(&mut self, store: &ActivityStore, config: &MatchConfig) {
if self.dirty.is_empty() {
return;
}
let dirty_ids: Vec<String> = self.dirty.drain().collect();
for id in dirty_ids {
if let Some(activity) = store.get(&id)
&& let Some(sig) =
RouteSignature::from_points(&activity.id, &activity.coords, config)
{
self.signatures.insert(id.clone(), sig);
self.newly_computed.insert(id);
}
}
}
pub fn get(
&mut self,
id: &str,
store: &ActivityStore,
config: &MatchConfig,
) -> Option<&RouteSignature> {
if self.dirty.contains(id) {
if let Some(activity) = store.get(id)
&& let Some(sig) =
RouteSignature::from_points(&activity.id, &activity.coords, config)
{
self.signatures.insert(id.to_string(), sig);
self.newly_computed.insert(id.to_string());
}
self.dirty.remove(id);
}
self.signatures.get(id)
}
pub fn get_cached(&self, id: &str) -> Option<&RouteSignature> {
if self.dirty.contains(id) {
None
} else {
self.signatures.get(id)
}
}
pub fn all(&self) -> impl Iterator<Item = &RouteSignature> {
self.signatures.values()
}
pub fn all_cloned(&self) -> Vec<RouteSignature> {
self.signatures.values().cloned().collect()
}
pub fn newly_computed(&self) -> Vec<RouteSignature> {
self.newly_computed
.iter()
.filter_map(|id| self.signatures.get(id).cloned())
.collect()
}
pub fn existing(&self) -> Vec<RouteSignature> {
self.signatures
.iter()
.filter(|(id, _)| !self.newly_computed.contains(*id))
.map(|(_, sig)| sig.clone())
.collect()
}
pub fn len(&self) -> usize {
self.signatures.len()
}
pub fn is_empty(&self) -> bool {
self.signatures.is_empty()
}
}