Skip to content

Commit 4194c59

Browse files
feat: add traits to represent the lowest common denominator for reference query and mutation.
This is in preparation for supporting reftables Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
1 parent dad2a82 commit 4194c59

6 files changed

Lines changed: 403 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-ref/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ gix-object = { version = "^0.57.0", path = "../gix-object" }
2929
gix-utils = { version = "^0.3.1", path = "../gix-utils" }
3030
gix-validate = { version = "^0.11.0", path = "../gix-validate" }
3131
gix-actor = { version = "^0.40.0", path = "../gix-actor" }
32+
gix-error = { version = "^0.2.0", path = "../gix-error" }
3233
gix-lock = { version = "^21.0.0", path = "../gix-lock" }
3334
gix-tempfile = { version = "^21.0.0", default-features = false, path = "../gix-tempfile" }
3435

gix-ref/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ pub mod transaction;
4141

4242
mod parse;
4343
mod raw;
44+
mod traits;
4445

4546
pub use raw::Reference;
47+
pub use traits::{StoreMutate, StoreRead, StoreReadExt};
4648

4749
mod target;
4850

gix-ref/src/traits.rs

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
use std::{rc::Rc, sync::Arc};
2+
3+
use gix_error::{ErrorExt, Exn};
4+
5+
/// Read capabilities of a reference store.
6+
pub trait StoreRead {
7+
/// Try to find a reference by `partial` name.
8+
///
9+
/// Returns `Ok(None)` if no matching reference exists.
10+
fn try_find(&self, partial: &crate::PartialNameRef) -> Result<Option<crate::Reference>, Exn>;
11+
12+
/// Return a platform to iterate references as loose-and-packed overlay.
13+
fn iter(&self) -> Result<crate::file::iter::Platform<'_>, Exn>;
14+
15+
/// Return `true` if a reflog exists for `name`.
16+
fn reflog_exists(&self, name: &crate::FullNameRef) -> Result<bool, Exn>;
17+
18+
/// Return a forward reflog iterator for `name`, or `None` if there is no reflog.
19+
fn reflog_iter<'a>(
20+
&self,
21+
name: &crate::FullNameRef,
22+
buf: &'a mut Vec<u8>,
23+
) -> Result<Option<crate::file::log::iter::Forward<'a>>, Exn>;
24+
25+
/// Return a reverse reflog iterator for `name`, or `None` if there is no reflog.
26+
fn reflog_iter_rev<'a>(
27+
&self,
28+
name: &crate::FullNameRef,
29+
buf: &'a mut [u8],
30+
) -> Result<Option<crate::file::log::iter::Reverse<'a, std::fs::File>>, Exn>;
31+
}
32+
33+
/// Convenience methods built on top of [`StoreRead`].
34+
pub trait StoreReadExt: StoreRead {
35+
/// Like [`StoreRead::try_find()`], but a missing reference is treated as error.
36+
fn find(&self, partial: &crate::PartialNameRef) -> Result<crate::Reference, Exn> {
37+
self.try_find(partial)?.ok_or_else(|| {
38+
crate::file::find::existing::Error::NotFound {
39+
name: partial.to_partial_path().to_owned(),
40+
}
41+
.raise_erased()
42+
})
43+
}
44+
}
45+
46+
impl<T: StoreRead + ?Sized> StoreReadExt for T {}
47+
48+
/// Mutation capabilities of a reference store.
49+
pub trait StoreMutate {
50+
/// Return a transaction platform for mutating references.
51+
fn transaction(&self) -> Result<crate::file::Transaction<'_, '_>, Exn>;
52+
}
53+
54+
impl StoreRead for crate::file::Store {
55+
fn try_find(&self, partial: &crate::PartialNameRef) -> Result<Option<crate::Reference>, Exn> {
56+
crate::file::Store::try_find(self, partial).map_err(|err| err.raise_erased())
57+
}
58+
59+
fn iter(&self) -> Result<crate::file::iter::Platform<'_>, Exn> {
60+
crate::file::Store::iter(self).map_err(|err| err.raise_erased())
61+
}
62+
63+
fn reflog_exists(&self, name: &crate::FullNameRef) -> Result<bool, Exn> {
64+
Ok(crate::file::Store::reflog_exists(self, name).expect("a FullNameRef is always valid"))
65+
}
66+
67+
fn reflog_iter<'a>(
68+
&self,
69+
name: &crate::FullNameRef,
70+
buf: &'a mut Vec<u8>,
71+
) -> Result<Option<crate::file::log::iter::Forward<'a>>, Exn> {
72+
crate::file::Store::reflog_iter(self, name, buf).map_err(|err| err.raise_erased())
73+
}
74+
75+
fn reflog_iter_rev<'a>(
76+
&self,
77+
name: &crate::FullNameRef,
78+
buf: &'a mut [u8],
79+
) -> Result<Option<crate::file::log::iter::Reverse<'a, std::fs::File>>, Exn> {
80+
crate::file::Store::reflog_iter_rev(self, name, buf).map_err(|err| err.raise_erased())
81+
}
82+
}
83+
84+
impl StoreMutate for crate::file::Store {
85+
fn transaction(&self) -> Result<crate::file::Transaction<'_, '_>, Exn> {
86+
Ok(crate::file::Store::transaction(self))
87+
}
88+
}
89+
90+
impl<T> StoreRead for &T
91+
where
92+
T: StoreRead + ?Sized,
93+
{
94+
fn try_find(&self, partial: &crate::PartialNameRef) -> Result<Option<crate::Reference>, Exn> {
95+
(*self).try_find(partial)
96+
}
97+
98+
fn iter(&self) -> Result<crate::file::iter::Platform<'_>, Exn> {
99+
(*self).iter()
100+
}
101+
102+
fn reflog_exists(&self, name: &crate::FullNameRef) -> Result<bool, Exn> {
103+
(*self).reflog_exists(name)
104+
}
105+
106+
fn reflog_iter<'a>(
107+
&self,
108+
name: &crate::FullNameRef,
109+
buf: &'a mut Vec<u8>,
110+
) -> Result<Option<crate::file::log::iter::Forward<'a>>, Exn> {
111+
(*self).reflog_iter(name, buf)
112+
}
113+
114+
fn reflog_iter_rev<'a>(
115+
&self,
116+
name: &crate::FullNameRef,
117+
buf: &'a mut [u8],
118+
) -> Result<Option<crate::file::log::iter::Reverse<'a, std::fs::File>>, Exn> {
119+
(*self).reflog_iter_rev(name, buf)
120+
}
121+
}
122+
123+
impl<T> StoreMutate for &T
124+
where
125+
T: StoreMutate + ?Sized,
126+
{
127+
fn transaction(&self) -> Result<crate::file::Transaction<'_, '_>, Exn> {
128+
(*self).transaction()
129+
}
130+
}
131+
132+
impl<T> StoreRead for Rc<T>
133+
where
134+
T: StoreRead + ?Sized,
135+
{
136+
fn try_find(&self, partial: &crate::PartialNameRef) -> Result<Option<crate::Reference>, Exn> {
137+
self.as_ref().try_find(partial)
138+
}
139+
140+
fn iter(&self) -> Result<crate::file::iter::Platform<'_>, Exn> {
141+
self.as_ref().iter()
142+
}
143+
144+
fn reflog_exists(&self, name: &crate::FullNameRef) -> Result<bool, Exn> {
145+
self.as_ref().reflog_exists(name)
146+
}
147+
148+
fn reflog_iter<'a>(
149+
&self,
150+
name: &crate::FullNameRef,
151+
buf: &'a mut Vec<u8>,
152+
) -> Result<Option<crate::file::log::iter::Forward<'a>>, Exn> {
153+
self.as_ref().reflog_iter(name, buf)
154+
}
155+
156+
fn reflog_iter_rev<'a>(
157+
&self,
158+
name: &crate::FullNameRef,
159+
buf: &'a mut [u8],
160+
) -> Result<Option<crate::file::log::iter::Reverse<'a, std::fs::File>>, Exn> {
161+
self.as_ref().reflog_iter_rev(name, buf)
162+
}
163+
}
164+
165+
impl<T> StoreMutate for Rc<T>
166+
where
167+
T: StoreMutate + ?Sized,
168+
{
169+
fn transaction(&self) -> Result<crate::file::Transaction<'_, '_>, Exn> {
170+
self.as_ref().transaction()
171+
}
172+
}
173+
174+
impl<T> StoreRead for Arc<T>
175+
where
176+
T: StoreRead + ?Sized,
177+
{
178+
fn try_find(&self, partial: &crate::PartialNameRef) -> Result<Option<crate::Reference>, Exn> {
179+
self.as_ref().try_find(partial)
180+
}
181+
182+
fn iter(&self) -> Result<crate::file::iter::Platform<'_>, Exn> {
183+
self.as_ref().iter()
184+
}
185+
186+
fn reflog_exists(&self, name: &crate::FullNameRef) -> Result<bool, Exn> {
187+
self.as_ref().reflog_exists(name)
188+
}
189+
190+
fn reflog_iter<'a>(
191+
&self,
192+
name: &crate::FullNameRef,
193+
buf: &'a mut Vec<u8>,
194+
) -> Result<Option<crate::file::log::iter::Forward<'a>>, Exn> {
195+
self.as_ref().reflog_iter(name, buf)
196+
}
197+
198+
fn reflog_iter_rev<'a>(
199+
&self,
200+
name: &crate::FullNameRef,
201+
buf: &'a mut [u8],
202+
) -> Result<Option<crate::file::log::iter::Reverse<'a, std::fs::File>>, Exn> {
203+
self.as_ref().reflog_iter_rev(name, buf)
204+
}
205+
}
206+
207+
impl<T> StoreMutate for Arc<T>
208+
where
209+
T: StoreMutate + ?Sized,
210+
{
211+
fn transaction(&self) -> Result<crate::file::Transaction<'_, '_>, Exn> {
212+
self.as_ref().transaction()
213+
}
214+
}
215+
216+
impl<T> StoreRead for Box<T>
217+
where
218+
T: StoreRead + ?Sized,
219+
{
220+
fn try_find(&self, partial: &crate::PartialNameRef) -> Result<Option<crate::Reference>, Exn> {
221+
self.as_ref().try_find(partial)
222+
}
223+
224+
fn iter(&self) -> Result<crate::file::iter::Platform<'_>, Exn> {
225+
self.as_ref().iter()
226+
}
227+
228+
fn reflog_exists(&self, name: &crate::FullNameRef) -> Result<bool, Exn> {
229+
self.as_ref().reflog_exists(name)
230+
}
231+
232+
fn reflog_iter<'a>(
233+
&self,
234+
name: &crate::FullNameRef,
235+
buf: &'a mut Vec<u8>,
236+
) -> Result<Option<crate::file::log::iter::Forward<'a>>, Exn> {
237+
self.as_ref().reflog_iter(name, buf)
238+
}
239+
240+
fn reflog_iter_rev<'a>(
241+
&self,
242+
name: &crate::FullNameRef,
243+
buf: &'a mut [u8],
244+
) -> Result<Option<crate::file::log::iter::Reverse<'a, std::fs::File>>, Exn> {
245+
self.as_ref().reflog_iter_rev(name, buf)
246+
}
247+
}
248+
249+
impl<T> StoreMutate for Box<T>
250+
where
251+
T: StoreMutate + ?Sized,
252+
{
253+
fn transaction(&self) -> Result<crate::file::Transaction<'_, '_>, Exn> {
254+
self.as_ref().transaction()
255+
}
256+
}

gix-ref/tests/refs/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,5 @@ mod namespace;
4444
mod packed;
4545
mod reference;
4646
mod store;
47+
mod traits;
4748
mod transaction;

0 commit comments

Comments
 (0)