irmin/
store.rs

1use crate::internal::*;
2
3/// Wrapper around Irmin.S
4pub struct Store<'a, T: Contents> {
5    pub ptr: *mut Irmin,
6    pub repo: &'a Repo<T>,
7}
8
9impl<'a, T: Contents> Store<'a, T> {
10    /// Open the main branch of a store
11    pub fn new(repo: &'a Repo<T>) -> Result<Store<'a, T>, Error> {
12        unsafe {
13            let ptr = irmin_main(repo.ptr);
14            check!(repo.ptr, ptr);
15            Ok(Store { ptr, repo })
16        }
17    }
18
19    /// Specify the branch to open
20    pub fn of_branch(repo: &'a Repo<T>, branch: impl AsRef<str>) -> Result<Store<'a, T>, Error> {
21        let branch = cstring(branch);
22        unsafe {
23            let ptr = irmin_of_branch(repo.ptr, branch.as_ptr() as *mut _);
24            check!(repo.ptr, ptr);
25            Ok(Store { ptr, repo })
26        }
27    }
28
29    /// Specify the commit to open
30    pub fn of_commit(repo: &'a Repo<T>, commit: &Commit) -> Result<Store<'a, T>, Error> {
31        unsafe {
32            let ptr = irmin_of_commit(repo.ptr, commit.ptr);
33            check!(repo.ptr, ptr);
34            Ok(Store { ptr, repo })
35        }
36    }
37
38    /// Set a value, creating a new commit
39    pub fn set(&mut self, path: &Path, value: &T, info: Info) -> Result<bool, Error> {
40        let value = value.to_value()?;
41        unsafe {
42            let r = irmin_set(self.ptr, path.ptr, value.ptr as *mut _, info.ptr);
43            check!(self.repo.ptr, r, false);
44            Ok(r)
45        }
46    }
47
48    /// Set a value if `old` matches the current value
49    pub fn test_and_set(
50        &mut self,
51        path: &Path,
52        old: Option<&T>,
53        value: Option<&T>,
54        info: Info,
55    ) -> Result<bool, Error> {
56        let old = match old {
57            Some(value) => Some(value.to_value()?),
58            None => None,
59        };
60        let value = match value {
61            Some(value) => Some(value.to_value()?),
62            None => None,
63        };
64        unsafe {
65            let r = irmin_test_and_set(
66                self.ptr,
67                path.ptr,
68                old.map(|x| x.ptr as *mut _)
69                    .unwrap_or_else(std::ptr::null_mut),
70                value
71                    .map(|x| x.ptr as *mut _)
72                    .unwrap_or_else(std::ptr::null_mut),
73                info.ptr,
74            );
75            check!(self.repo.ptr, r, false);
76            Ok(r)
77        }
78    }
79
80    /// Set a tree, creating a new commit
81    pub fn set_tree(&mut self, path: &Path, tree: &Tree<T>, info: Info) -> Result<bool, Error> {
82        unsafe {
83            let r = irmin_set_tree(self.ptr, path.ptr, tree.ptr, info.ptr);
84            check!(self.repo.ptr, r, false);
85            Ok(r)
86        }
87    }
88
89    /// Set a tree if `old` matches the current tree
90    pub fn test_and_set_tree(
91        &mut self,
92        path: &Path,
93        old: Option<&Tree<T>>,
94        tree: Option<&Tree<T>>,
95        info: Info,
96    ) -> Result<bool, Error> {
97        unsafe {
98            let r = irmin_test_and_set_tree(
99                self.ptr,
100                path.ptr,
101                old.map(|x| x.ptr).unwrap_or_else(std::ptr::null_mut),
102                tree.map(|x| x.ptr).unwrap_or_else(std::ptr::null_mut),
103                info.ptr,
104            );
105            check!(self.repo.ptr, r, false);
106            Ok(r)
107        }
108    }
109
110    /// Find the value associated with the given path
111    pub fn find(&self, path: &Path) -> Result<Option<T>, Error> {
112        let r = unsafe { irmin_find(self.ptr, path.ptr) };
113        check_opt!(self.repo.ptr, r);
114        let ty = T::ty()?;
115        let v = Value {
116            ptr: r as *mut _,
117            ty,
118        };
119        let v = T::from_value(&v)?;
120        Ok(Some(v))
121    }
122
123    /// Find the tree associated with the given path
124    pub fn find_tree(&self, path: &Path) -> Result<Option<Tree<T>>, Error> {
125        unsafe {
126            let ptr = irmin_find_tree(self.ptr, path.ptr);
127            check_opt!(self.repo.ptr, ptr);
128            let x = Tree {
129                ptr,
130                repo: UntypedRepo::new(self.repo),
131                _t: std::marker::PhantomData,
132            };
133            Ok(Some(x))
134        }
135    }
136
137    /// Check for the existence of a value at the given path
138    pub fn mem(&self, path: &Path) -> bool {
139        unsafe { irmin_mem(self.ptr, path.ptr) }
140    }
141
142    /// Check for the existence of a tree at the given path
143    pub fn mem_tree(&self, path: &Path) -> bool {
144        unsafe { irmin_mem_tree(self.ptr, path.ptr) }
145    }
146
147    /// Remove the tree or value associated with the given path
148    pub fn remove(&mut self, path: &Path, info: Info) -> bool {
149        unsafe { irmin_remove(self.ptr, path.ptr, info.ptr) }
150    }
151
152    /// Get current head commit
153    pub fn head(&self) -> Result<Option<Commit<'a>>, Error> {
154        let ptr = unsafe { irmin_get_head(self.ptr) };
155        check_opt!(self.repo.ptr, ptr);
156        Ok(Some(Commit {
157            ptr,
158            repo: UntypedRepo::new(self.repo),
159        }))
160    }
161
162    /// Set head commit
163    pub fn set_head(&mut self, c: &Commit) {
164        unsafe { irmin_set_head(self.ptr, c.ptr) }
165    }
166
167    /// Update current branch to the specified commit
168    pub fn fast_forward(&mut self, c: &Commit) -> bool {
169        unsafe { irmin_fast_forward(self.ptr, c.ptr) }
170    }
171
172    /// Merge with another branch
173    pub fn merge_with_branch(
174        &mut self,
175        branch: impl AsRef<str>,
176        info: Info,
177    ) -> Result<bool, Error> {
178        let branch = cstring(branch);
179        let r = unsafe { irmin_merge_with_branch(self.ptr, branch.as_ptr() as *mut _, info.ptr) };
180        check!(self.repo.ptr, r, false);
181        Ok(r)
182    }
183
184    /// Merge with another commit
185    pub fn merge_with_commit(&mut self, commit: &Commit, info: Info) -> Result<bool, Error> {
186        let r = unsafe { irmin_merge_with_commit(self.ptr, commit.ptr, info.ptr) };
187        check!(self.repo.ptr, r, false);
188        Ok(r)
189    }
190
191    /// Merge with another store
192    pub fn merge(&mut self, store: &Store<T>, info: Info) -> Result<bool, Error> {
193        let r = unsafe { irmin_merge_into(self.ptr, store.ptr, info.ptr) };
194        check!(self.repo.ptr, r, false);
195        Ok(r)
196    }
197
198    /// List paths
199    pub fn list(&self, path: &Path) -> Result<Vec<Path>, Error> {
200        let p = unsafe { irmin_list(self.ptr, path.ptr) };
201        check!(self.repo.ptr, p);
202        let len = unsafe { irmin_path_array_length(self.repo.ptr, p) };
203        let mut dest = Vec::new();
204        for i in 0..len {
205            let path = unsafe { irmin_path_array_get(self.repo.ptr, p, i) };
206            if path.is_null() {
207                continue;
208            }
209            dest.push(Path {
210                ptr: path,
211                repo: UntypedRepo::new(self.repo),
212            })
213        }
214
215        unsafe { irmin_path_array_free(p) }
216
217        Ok(dest)
218    }
219
220    /// Pull from a remote respository, if the `info` parameter is set then
221    /// a merge commit will be made
222    pub fn pull(
223        &mut self,
224        remote: &Remote,
225        depth: Option<i32>,
226        info: Option<&Info>,
227    ) -> Result<Commit, Error> {
228        let info = match info {
229            Some(i) => i.ptr as *mut _,
230            None => std::ptr::null_mut(),
231        };
232        let depth = depth.unwrap_or(-1);
233        let c = unsafe { irmin_pull(self.ptr, depth, remote.ptr, info) };
234        check!(self.repo.ptr, c);
235        Ok(Commit {
236            ptr: c,
237            repo: UntypedRepo::new(self.repo),
238        })
239    }
240
241    /// Fetch data from a remote repository
242    pub fn fetch(&mut self, remote: &Remote, depth: Option<i32>) -> Result<Commit, Error> {
243        let depth = depth.unwrap_or(-1);
244        let c = unsafe { irmin_fetch(self.ptr, depth, remote.ptr) };
245        check!(self.repo.ptr, c);
246        Ok(Commit {
247            ptr: c,
248            repo: UntypedRepo::new(self.repo),
249        })
250    }
251
252    /// Push to a remote repository
253    pub fn push(&mut self, remote: &Remote, depth: Option<i32>) -> Result<Commit, Error> {
254        let depth = depth.unwrap_or(-1);
255        let c = unsafe { irmin_push(self.ptr, depth, remote.ptr) };
256        check!(self.repo.ptr, c);
257        Ok(Commit {
258            ptr: c,
259            repo: UntypedRepo::new(self.repo),
260        })
261    }
262}
263
264impl<'a, T: Contents> Drop for Store<'a, T> {
265    fn drop(&mut self) {
266        unsafe { irmin_free(self.ptr) }
267    }
268}