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