Skip to main content

clankerdiff_protocol/client/
document_cache.rs

1use 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}