Skip to main content

pijul_core/changestore/
mod.rs

1//! A change store is a trait for change storage facilities. Even though
2//! changes are normally stored on disk, there are situations (such as
3//! an embedded Pijul) where one might want changes in-memory, in a
4//! database, or something else.
5use crate::pristine::{ChangeId, Hash, InodeMetadata, Position, Vertex};
6use crate::{
7    change::{Change, ChangeError, ChangeHeader},
8    text_encoding::Encoding,
9};
10
11#[cfg(feature = "ondisk-repos")]
12/// If this crate is compiled with the `ondisk-repos` feature (the
13/// default), this module stores changes on the file system, under
14/// `.pijul/changes`.
15pub mod filesystem;
16
17/// A change store entirely in memory.
18pub mod memory;
19
20/// A trait for storing changes and reading from them.
21pub trait ChangeStore {
22    type Error: std::error::Error
23        + std::fmt::Debug
24        + Send
25        + Sync
26        + From<std::str::Utf8Error>
27        + From<crate::change::ChangeError>
28        + 'static;
29    fn has_contents(&self, hash: Hash, change_id: Option<ChangeId>) -> bool;
30    fn get_contents<F: Fn(ChangeId) -> Option<Hash>>(
31        &self,
32        hash: F,
33        key: Vertex<ChangeId>,
34        buf: &mut [u8],
35    ) -> Result<usize, Self::Error>;
36    fn get_header(&self, h: &Hash) -> Result<ChangeHeader, Self::Error> {
37        Ok(self.get_change(h)?.hashed.header)
38    }
39    fn get_contents_ext(
40        &self,
41        key: Vertex<Option<Hash>>,
42        buf: &mut [u8],
43    ) -> Result<usize, Self::Error>;
44    fn get_dependencies(&self, hash: &Hash) -> Result<Vec<Hash>, Self::Error> {
45        Ok(self.get_change(hash)?.hashed.dependencies)
46    }
47    fn get_extra_known(&self, hash: &Hash) -> Result<Vec<Hash>, Self::Error> {
48        Ok(self.get_change(hash)?.hashed.extra_known)
49    }
50    fn get_changes(
51        &self,
52        hash: &Hash,
53    ) -> Result<Vec<crate::change::Hunk<Option<Hash>, crate::change::Local>>, Self::Error> {
54        Ok(self.get_change(hash)?.hashed.changes)
55    }
56    fn knows(&self, hash0: &Hash, hash1: &Hash) -> Result<bool, Self::Error> {
57        debug!("knows: {:?} {:?}", hash0, hash1);
58        Ok(self.get_change(hash0)?.knows(hash1))
59    }
60    fn has_edge(
61        &self,
62        change: Hash,
63        from: Position<Option<Hash>>,
64        to: Position<Option<Hash>>,
65        flags: crate::pristine::EdgeFlags,
66    ) -> Result<bool, Self::Error> {
67        let change_ = self.get_change(&change)?;
68        Ok(change_.has_edge(change, from, to, flags))
69    }
70    fn change_deletes_position<F: Fn(ChangeId) -> Option<Hash>>(
71        &self,
72        hash: F,
73        change: ChangeId,
74        pos: Position<Option<Hash>>,
75    ) -> Result<Vec<Hash>, Self::Error>;
76    fn save_change<
77        E: From<Self::Error> + From<ChangeError>,
78        F: FnOnce(&mut Change, &Hash) -> Result<(), E>,
79    >(
80        &self,
81        p: &mut Change,
82        f: F,
83    ) -> Result<Hash, E>;
84    fn del_change(&self, h: &Hash) -> Result<bool, Self::Error>;
85    fn get_change(&self, h: &Hash) -> Result<Change, Self::Error>;
86    fn get_file_meta<'a, F: Fn(ChangeId) -> Option<Hash>>(
87        &self,
88        hash: F,
89        vertex: Vertex<ChangeId>,
90        buf: &'a mut [u8],
91    ) -> Result<FileMetadata<'a>, Self::Error> {
92        self.get_contents(hash, vertex, buf)?;
93        Ok(FileMetadata::read(buf))
94    }
95}
96
97#[derive(Serialize, Deserialize)]
98pub struct FileMetadata<'a> {
99    pub metadata: InodeMetadata,
100    pub basename: &'a str,
101    pub encoding: Option<Encoding>,
102}
103
104impl<'a> FileMetadata<'a> {
105    pub fn read(buf: &'a [u8]) -> FileMetadata<'a> {
106        // FIXME use ? by adding the From trait somehow
107        trace!("filemetadata read: {:?}", buf);
108        if let Ok(m) = bincode::deserialize(buf) {
109            m
110        } else {
111            let (a, b) = buf.split_at(2);
112            FileMetadata {
113                metadata: InodeMetadata::from_basename(a),
114                basename: std::str::from_utf8(b).unwrap(),
115                encoding: None,
116            }
117        }
118    }
119
120    pub fn write(&self, mut w: &mut Vec<u8>) {
121        // FIXME use ? by adding the From trait somehow
122        let l = w.len();
123        bincode::serialize_into(&mut w, self).unwrap();
124        trace!("filemetadata write: {:?}", &w[l..]);
125    }
126}
127
128impl crate::change::Atom<Option<Hash>> {
129    pub fn deletes_pos(&self, pos: Position<Option<Hash>>) -> Vec<Hash> {
130        let mut h = Vec::new();
131        if let crate::change::Atom::EdgeMap(n) = self {
132            for edge in n.edges.iter() {
133                if edge.to.change == pos.change
134                    && edge.to.start <= pos.pos
135                    && pos.pos < edge.to.end
136                    && let Some(c) = edge.introduced_by
137                {
138                    h.push(c)
139                }
140            }
141        }
142        h
143    }
144}