use std::{ collections::{hash_map::Entry, HashMap}, fmt::Display, iter::IntoIterator, time::{Duration, SystemTime, UNIX_EPOCH}, }; use serde::{Deserialize, Serialize}; pub trait SessionSource { type Error; type Iter: IntoIterator; fn sessions(&self) -> Result; fn update( &self, mut hash_map: HashMap, ) -> Result, Self::Error> { for session in self.sessions()? { match hash_map.entry(session.name.to_owned()) { Entry::Occupied(mut o) if &session > o.get() => { o.insert(session); } Entry::Vacant(v) => { v.insert(session); } _ => {} } } Ok(hash_map) } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub enum State { Discovered, Connected, Updated, } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Session { pub state: State, #[serde(with = "epoch_timestamp")] pub timestamp: Duration, pub name: String, } mod epoch_timestamp { use std::time::Duration; use serde::{self, Deserialize, Deserializer, Serializer}; pub fn serialize(duration: &Duration, serializer: S) -> Result where S: Serializer, { serializer.serialize_u64(duration.as_secs()) } pub fn deserialize<'de, D>(d: D) -> Result where D: Deserializer<'de>, { u64::deserialize(d).map(Duration::from_secs) } } impl Display for Session { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name) } } impl From for Session { fn from(name: String) -> Self { let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("Current time is pre-epoch. (Time traveler?)"); Self { state: State::Discovered, timestamp, name, } } } impl From<(String, State)> for Session { fn from((name, state): (String, State)) -> Self { let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("Current time is pre-epoch. (Time traveler?)"); Self { state, timestamp, name, } } }