1 #![macro_use]
2 use libc;
3 
4 use crate::Error;
5 
6 macro_rules! call {
7     (raw::$p:ident ($($e:expr),*)) => (
8         raw::$p($(crate::call::convert(&$e)),*)
9     )
10 }
11 
12 macro_rules! try_call {
13     (raw::$p:ident ($($e:expr),*)) => ({
14         match crate::call::c_try(raw::$p($(crate::call::convert(&$e)),*)) {
15             Ok(o) => o,
16             Err(e) => { crate::panic::check(); return Err(e) }
17         }
18     })
19 }
20 
21 macro_rules! try_call_iter {
22     ($($f:tt)*) => {
23         match call!($($f)*) {
24             0 => {}
25             raw::GIT_ITEROVER => return None,
26             e => return Some(Err(crate::call::last_error(e)))
27         }
28     }
29 }
30 
31 #[doc(hidden)]
32 pub trait Convert<T> {
convert(&self) -> T33     fn convert(&self) -> T;
34 }
35 
convert<T, U: Convert<T>>(u: &U) -> T36 pub fn convert<T, U: Convert<T>>(u: &U) -> T {
37     u.convert()
38 }
39 
c_try(ret: libc::c_int) -> Result<libc::c_int, Error>40 pub fn c_try(ret: libc::c_int) -> Result<libc::c_int, Error> {
41     match ret {
42         n if n < 0 => Err(last_error(n)),
43         n => Ok(n),
44     }
45 }
46 
last_error(code: libc::c_int) -> Error47 pub fn last_error(code: libc::c_int) -> Error {
48     // nowadays this unwrap is safe as `Error::last_error` always returns
49     // `Some`.
50     Error::last_error(code).unwrap()
51 }
52 
53 mod impls {
54     use std::ffi::CString;
55     use std::ptr;
56 
57     use libc;
58 
59     use crate::call::Convert;
60     use crate::{raw, BranchType, ConfigLevel, Direction, ObjectType, ResetType};
61     use crate::{AutotagOption, DiffFormat, FetchPrune, FileFavor, SubmoduleIgnore};
62 
63     impl<T: Copy> Convert<T> for T {
convert(&self) -> T64         fn convert(&self) -> T {
65             *self
66         }
67     }
68 
69     impl Convert<libc::c_int> for bool {
convert(&self) -> libc::c_int70         fn convert(&self) -> libc::c_int {
71             *self as libc::c_int
72         }
73     }
74     impl<'a, T> Convert<*const T> for &'a T {
convert(&self) -> *const T75         fn convert(&self) -> *const T {
76             *self as *const T
77         }
78     }
79     impl<'a, T> Convert<*mut T> for &'a mut T {
convert(&self) -> *mut T80         fn convert(&self) -> *mut T {
81             &**self as *const T as *mut T
82         }
83     }
84     impl<T> Convert<*const T> for *mut T {
convert(&self) -> *const T85         fn convert(&self) -> *const T {
86             *self as *const T
87         }
88     }
89 
90     impl Convert<*const libc::c_char> for CString {
convert(&self) -> *const libc::c_char91         fn convert(&self) -> *const libc::c_char {
92             self.as_ptr()
93         }
94     }
95 
96     impl<T, U: Convert<*const T>> Convert<*const T> for Option<U> {
convert(&self) -> *const T97         fn convert(&self) -> *const T {
98             self.as_ref().map(|s| s.convert()).unwrap_or(ptr::null())
99         }
100     }
101 
102     impl<T, U: Convert<*mut T>> Convert<*mut T> for Option<U> {
convert(&self) -> *mut T103         fn convert(&self) -> *mut T {
104             self.as_ref()
105                 .map(|s| s.convert())
106                 .unwrap_or(ptr::null_mut())
107         }
108     }
109 
110     impl Convert<raw::git_reset_t> for ResetType {
convert(&self) -> raw::git_reset_t111         fn convert(&self) -> raw::git_reset_t {
112             match *self {
113                 ResetType::Soft => raw::GIT_RESET_SOFT,
114                 ResetType::Hard => raw::GIT_RESET_HARD,
115                 ResetType::Mixed => raw::GIT_RESET_MIXED,
116             }
117         }
118     }
119 
120     impl Convert<raw::git_direction> for Direction {
convert(&self) -> raw::git_direction121         fn convert(&self) -> raw::git_direction {
122             match *self {
123                 Direction::Push => raw::GIT_DIRECTION_PUSH,
124                 Direction::Fetch => raw::GIT_DIRECTION_FETCH,
125             }
126         }
127     }
128 
129     impl Convert<raw::git_object_t> for ObjectType {
convert(&self) -> raw::git_object_t130         fn convert(&self) -> raw::git_object_t {
131             match *self {
132                 ObjectType::Any => raw::GIT_OBJECT_ANY,
133                 ObjectType::Commit => raw::GIT_OBJECT_COMMIT,
134                 ObjectType::Tree => raw::GIT_OBJECT_TREE,
135                 ObjectType::Blob => raw::GIT_OBJECT_BLOB,
136                 ObjectType::Tag => raw::GIT_OBJECT_TAG,
137             }
138         }
139     }
140 
141     impl Convert<raw::git_object_t> for Option<ObjectType> {
convert(&self) -> raw::git_object_t142         fn convert(&self) -> raw::git_object_t {
143             self.unwrap_or(ObjectType::Any).convert()
144         }
145     }
146 
147     impl Convert<raw::git_branch_t> for BranchType {
convert(&self) -> raw::git_branch_t148         fn convert(&self) -> raw::git_branch_t {
149             match *self {
150                 BranchType::Remote => raw::GIT_BRANCH_REMOTE,
151                 BranchType::Local => raw::GIT_BRANCH_LOCAL,
152             }
153         }
154     }
155 
156     impl Convert<raw::git_branch_t> for Option<BranchType> {
convert(&self) -> raw::git_branch_t157         fn convert(&self) -> raw::git_branch_t {
158             self.map(|s| s.convert()).unwrap_or(raw::GIT_BRANCH_ALL)
159         }
160     }
161 
162     impl Convert<raw::git_config_level_t> for ConfigLevel {
convert(&self) -> raw::git_config_level_t163         fn convert(&self) -> raw::git_config_level_t {
164             match *self {
165                 ConfigLevel::ProgramData => raw::GIT_CONFIG_LEVEL_PROGRAMDATA,
166                 ConfigLevel::System => raw::GIT_CONFIG_LEVEL_SYSTEM,
167                 ConfigLevel::XDG => raw::GIT_CONFIG_LEVEL_XDG,
168                 ConfigLevel::Global => raw::GIT_CONFIG_LEVEL_GLOBAL,
169                 ConfigLevel::Local => raw::GIT_CONFIG_LEVEL_LOCAL,
170                 ConfigLevel::App => raw::GIT_CONFIG_LEVEL_APP,
171                 ConfigLevel::Highest => raw::GIT_CONFIG_HIGHEST_LEVEL,
172             }
173         }
174     }
175 
176     impl Convert<raw::git_diff_format_t> for DiffFormat {
convert(&self) -> raw::git_diff_format_t177         fn convert(&self) -> raw::git_diff_format_t {
178             match *self {
179                 DiffFormat::Patch => raw::GIT_DIFF_FORMAT_PATCH,
180                 DiffFormat::PatchHeader => raw::GIT_DIFF_FORMAT_PATCH_HEADER,
181                 DiffFormat::Raw => raw::GIT_DIFF_FORMAT_RAW,
182                 DiffFormat::NameOnly => raw::GIT_DIFF_FORMAT_NAME_ONLY,
183                 DiffFormat::NameStatus => raw::GIT_DIFF_FORMAT_NAME_STATUS,
184             }
185         }
186     }
187 
188     impl Convert<raw::git_merge_file_favor_t> for FileFavor {
convert(&self) -> raw::git_merge_file_favor_t189         fn convert(&self) -> raw::git_merge_file_favor_t {
190             match *self {
191                 FileFavor::Normal => raw::GIT_MERGE_FILE_FAVOR_NORMAL,
192                 FileFavor::Ours => raw::GIT_MERGE_FILE_FAVOR_OURS,
193                 FileFavor::Theirs => raw::GIT_MERGE_FILE_FAVOR_THEIRS,
194                 FileFavor::Union => raw::GIT_MERGE_FILE_FAVOR_UNION,
195             }
196         }
197     }
198 
199     impl Convert<raw::git_submodule_ignore_t> for SubmoduleIgnore {
convert(&self) -> raw::git_submodule_ignore_t200         fn convert(&self) -> raw::git_submodule_ignore_t {
201             match *self {
202                 SubmoduleIgnore::Unspecified => raw::GIT_SUBMODULE_IGNORE_UNSPECIFIED,
203                 SubmoduleIgnore::None => raw::GIT_SUBMODULE_IGNORE_NONE,
204                 SubmoduleIgnore::Untracked => raw::GIT_SUBMODULE_IGNORE_UNTRACKED,
205                 SubmoduleIgnore::Dirty => raw::GIT_SUBMODULE_IGNORE_DIRTY,
206                 SubmoduleIgnore::All => raw::GIT_SUBMODULE_IGNORE_ALL,
207             }
208         }
209     }
210 
211     impl Convert<raw::git_remote_autotag_option_t> for AutotagOption {
convert(&self) -> raw::git_remote_autotag_option_t212         fn convert(&self) -> raw::git_remote_autotag_option_t {
213             match *self {
214                 AutotagOption::Unspecified => raw::GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED,
215                 AutotagOption::None => raw::GIT_REMOTE_DOWNLOAD_TAGS_NONE,
216                 AutotagOption::Auto => raw::GIT_REMOTE_DOWNLOAD_TAGS_AUTO,
217                 AutotagOption::All => raw::GIT_REMOTE_DOWNLOAD_TAGS_ALL,
218             }
219         }
220     }
221 
222     impl Convert<raw::git_fetch_prune_t> for FetchPrune {
convert(&self) -> raw::git_fetch_prune_t223         fn convert(&self) -> raw::git_fetch_prune_t {
224             match *self {
225                 FetchPrune::Unspecified => raw::GIT_FETCH_PRUNE_UNSPECIFIED,
226                 FetchPrune::On => raw::GIT_FETCH_PRUNE,
227                 FetchPrune::Off => raw::GIT_FETCH_NO_PRUNE,
228             }
229         }
230     }
231 }
232