ChatGPT Codex 5.2 xhigh refactored > 45min
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
use std::{
|
||||
collections::{HashMap, VecDeque},
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
use lanspread_proto::{GameSummary, LibraryDelta, LibrarySnapshot, LibrarySummary};
|
||||
|
||||
const MAX_DELTA_HISTORY: usize = 8;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LocalLibraryState {
|
||||
pub revision: u64,
|
||||
pub digest: u64,
|
||||
pub games: HashMap<String, GameSummary>,
|
||||
pub recent_deltas: VecDeque<LibraryDelta>,
|
||||
}
|
||||
|
||||
impl LocalLibraryState {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
revision: 0,
|
||||
digest: 0,
|
||||
games: HashMap::new(),
|
||||
recent_deltas: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_from_scan(
|
||||
&mut self,
|
||||
summaries: HashMap<String, GameSummary>,
|
||||
revision: u64,
|
||||
) -> Option<LibraryDelta> {
|
||||
let new_digest = compute_library_digest(&summaries);
|
||||
let changed =
|
||||
self.revision != revision || self.digest != new_digest || self.games != summaries;
|
||||
|
||||
if !changed {
|
||||
return None;
|
||||
}
|
||||
|
||||
let delta = compute_library_delta(self.revision, revision, &self.games, &summaries);
|
||||
self.revision = revision;
|
||||
self.digest = new_digest;
|
||||
self.games = summaries;
|
||||
self.recent_deltas.push_back(delta.clone());
|
||||
while self.recent_deltas.len() > MAX_DELTA_HISTORY {
|
||||
self.recent_deltas.pop_front();
|
||||
}
|
||||
Some(delta)
|
||||
}
|
||||
|
||||
pub fn delta_since(&self, from_rev: u64) -> Option<LibraryDelta> {
|
||||
self.recent_deltas
|
||||
.iter()
|
||||
.find(|delta| delta.from_rev == from_rev)
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_library_digest(games: &HashMap<String, GameSummary>) -> u64 {
|
||||
let mut entries: Vec<&GameSummary> = games.values().collect();
|
||||
entries.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
|
||||
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||
for summary in entries {
|
||||
summary.id.hash(&mut hasher);
|
||||
summary.name.hash(&mut hasher);
|
||||
summary.size.hash(&mut hasher);
|
||||
summary.downloaded.hash(&mut hasher);
|
||||
summary.installed.hash(&mut hasher);
|
||||
summary.eti_version.hash(&mut hasher);
|
||||
summary.manifest_hash.hash(&mut hasher);
|
||||
summary.availability.hash(&mut hasher);
|
||||
}
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
pub fn build_library_summary(state: &LocalLibraryState) -> LibrarySummary {
|
||||
LibrarySummary {
|
||||
library_rev: state.revision,
|
||||
library_digest: state.digest,
|
||||
game_count: state.games.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_library_snapshot(state: &LocalLibraryState) -> LibrarySnapshot {
|
||||
let mut games: Vec<GameSummary> = state.games.values().cloned().collect();
|
||||
games.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
LibrarySnapshot {
|
||||
library_rev: state.revision,
|
||||
games,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compute_library_delta(
|
||||
from_rev: u64,
|
||||
to_rev: u64,
|
||||
previous: &HashMap<String, GameSummary>,
|
||||
next: &HashMap<String, GameSummary>,
|
||||
) -> LibraryDelta {
|
||||
let mut added = Vec::new();
|
||||
let mut updated = Vec::new();
|
||||
let mut removed = Vec::new();
|
||||
|
||||
for (game_id, summary) in next {
|
||||
match previous.get(game_id) {
|
||||
None => added.push(summary.clone()),
|
||||
Some(existing) => {
|
||||
if existing != summary {
|
||||
updated.push(summary.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for game_id in previous.keys() {
|
||||
if !next.contains_key(game_id) {
|
||||
removed.push(game_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
LibraryDelta {
|
||||
from_rev,
|
||||
to_rev,
|
||||
added,
|
||||
updated,
|
||||
removed,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user