1 //! git_tag_foreach support
2 //! see original: <https://libgit2.org/libgit2/#HEAD/group/tag/git_tag_foreach>
3
4 use crate::{panic, raw, util::Binding, Oid};
5 use libc::{c_char, c_int};
6 use raw::git_oid;
7 use std::ffi::{c_void, CStr};
8
9 /// boxed callback type
10 pub(crate) type TagForeachCB<'a> = Box<dyn FnMut(Oid, &[u8]) -> bool + 'a>;
11
12 /// helper type to be able to pass callback to payload
13 pub(crate) struct TagForeachData<'a> {
14 /// callback
15 pub(crate) cb: TagForeachCB<'a>,
16 }
17
18 /// c callback forwarding to rust callback inside `TagForeachData`
19 /// see original: <https://libgit2.org/libgit2/#HEAD/group/callback/git_tag_foreach_cb>
tag_foreach_cb( name: *const c_char, oid: *mut git_oid, payload: *mut c_void, ) -> c_int20 pub(crate) extern "C" fn tag_foreach_cb(
21 name: *const c_char,
22 oid: *mut git_oid,
23 payload: *mut c_void,
24 ) -> c_int {
25 panic::wrap(|| unsafe {
26 let id: Oid = Binding::from_raw(oid as *const _);
27
28 let name = CStr::from_ptr(name);
29 let name = name.to_bytes();
30
31 let payload = &mut *(payload as *mut TagForeachData<'_>);
32 let cb = &mut payload.cb;
33
34 let res = cb(id, name);
35
36 if res {
37 0
38 } else {
39 -1
40 }
41 })
42 .unwrap_or(-1)
43 }
44
45 #[cfg(test)]
46 mod tests {
47
48 #[test]
smoke()49 fn smoke() {
50 let (_td, repo) = crate::test::repo_init();
51 let head = repo.head().unwrap();
52 let id = head.target().unwrap();
53 assert!(repo.find_tag(id).is_err());
54
55 let obj = repo.find_object(id, None).unwrap();
56 let sig = repo.signature().unwrap();
57 let tag_id = repo.tag("foo", &obj, &sig, "msg", false).unwrap();
58
59 let mut tags = Vec::new();
60 repo.tag_foreach(|id, name| {
61 tags.push((id, String::from_utf8(name.into()).unwrap()));
62 true
63 })
64 .unwrap();
65
66 assert_eq!(tags[0].0, tag_id);
67 assert_eq!(tags[0].1, "refs/tags/foo");
68 }
69 }
70