clankerdiff_protocol/client/
document_cache.rs1use crate::{
2 server::{ServerEvent, ServerMessage},
3 shared::{DiffSnapshot, DocumentUpdate, FileEntry, ProtocolError},
4};
5use clankerdiff_core::{DiffDocument, RepoPath};
6use std::{collections::BTreeMap, sync::Arc};
7
8#[derive(Debug, Default)]
9pub struct DocumentCache {
10 document: Arc<DiffDocument>,
11 index: BTreeMap<RepoPath, usize>,
12}
13
14impl DocumentCache {
15 pub fn decode_event(&mut self, text: &str) -> Result<ServerEvent, ProtocolError> {
16 self.apply_event(ServerMessage::decode(text)?)
17 }
18
19 pub fn apply_event(&mut self, message: ServerMessage) -> Result<ServerEvent, ProtocolError> {
20 message.try_map(|update| Ok(Arc::new(self.apply(&update)?)))
21 }
22
23 pub fn apply(&mut self, update: &DocumentUpdate) -> Result<DiffSnapshot, ProtocolError> {
24 let mut files = Vec::with_capacity(update.files.len());
25 let mut index = BTreeMap::new();
26 for entry in &update.files {
27 let file = match entry {
28 FileEntry::Unchanged(path) => self
29 .index
30 .get(path)
31 .and_then(|index| self.document.files.get(*index))
32 .ok_or(ProtocolError::Files)?
33 .clone(),
34 FileEntry::Changed(file) => file.as_ref().clone(),
35 };
36 if index.insert(file.path.clone(), files.len()).is_some() {
37 return Err(ProtocolError::Files);
38 }
39 files.push(file);
40 }
41 self.document = Arc::new(DiffDocument {
42 repo_root: update.repo_root.clone(),
43 files,
44 });
45 self.index = index;
46 Ok(DiffSnapshot {
47 scope: update.scope,
48 document: Arc::clone(&self.document),
49 })
50 }
51}