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::{
62         AutotagOption, DiffFormat, FetchPrune, FileFavor, SubmoduleIgnore, SubmoduleUpdate,
63     };
64 
65     impl<T: Copy> Convert<T> for T {
convert(&self) -> T66         fn convert(&self) -> T {
67             *self
68         }
69     }
70 
71     impl Convert<libc::c_int> for bool {
convert(&self) -> libc::c_int72         fn convert(&self) -> libc::c_int {
73             *self as libc::c_int
74         }
75     }
76     impl<'a, T> Convert<*const T> for &'a T {
convert(&self) -> *const T77         fn convert(&self) -> *const T {
78             *self as *const T
79         }
80     }
81     impl<'a, T> Convert<*mut T> for &'a mut T {
convert(&self) -> *mut T82         fn convert(&self) -> *mut T {
83             &**self as *const T as *mut T
84         }
85     }
86     impl<T> Convert<*const T> for *mut T {
convert(&self) -> *const T87         fn convert(&self) -> *const T {
88             *self as *const T
89         }
90     }
91 
92     impl Convert<*const libc::c_char> for CString {
convert(&self) -> *const libc::c_char93         fn convert(&self) -> *const libc::c_char {
94             self.as_ptr()
95         }
96     }
97 
98     impl<T, U: Convert<*const T>> Convert<*const T> for Option<U> {
convert(&self) -> *const T99         fn convert(&self) -> *const T {
100             self.as_ref().map(|s| s.convert()).unwrap_or(ptr::null())
101         }
102     }
103 
104     impl<T, U: Convert<*mut T>> Convert<*mut T> for Option<U> {
convert(&self) -> *mut T105         fn convert(&self) -> *mut T {
106             self.as_ref()
107                 .map(|s| s.convert())
108                 .unwrap_or(ptr::null_mut())
109         }
110     }
111 
112     impl Convert<raw::git_reset_t> for ResetType {
convert(&self) -> raw::git_reset_t113         fn convert(&self) -> raw::git_reset_t {
114             match *self {
115                 ResetType::Soft => raw::GIT_RESET_SOFT,
116                 ResetType::Hard => raw::GIT_RESET_HARD,
117                 ResetType::Mixed => raw::GIT_RESET_MIXED,
118             }
119         }
120     }
121 
122     impl Convert<raw::git_direction> for Direction {
convert(&self) -> raw::git_direction123         fn convert(&self) -> raw::git_direction {
124             match *self {
125                 Direction::Push => raw::GIT_DIRECTION_PUSH,
126                 Direction::Fetch => raw::GIT_DIRECTION_FETCH,
127             }
128         }
129     }
130 
131     impl Convert<raw::git_object_t> for ObjectType {
convert(&self) -> raw::git_object_t132         fn convert(&self) -> raw::git_object_t {
133             match *self {
134                 ObjectType::Any => raw::GIT_OBJECT_ANY,
135                 ObjectType::Commit => raw::GIT_OBJECT_COMMIT,
136                 ObjectType::Tree => raw::GIT_OBJECT_TREE,
137                 ObjectType::Blob => raw::GIT_OBJECT_BLOB,
138                 ObjectType::Tag => raw::GIT_OBJECT_TAG,
139             }
140         }
141     }
142 
143     impl Convert<raw::git_object_t> for Option<ObjectType> {
convert(&self) -> raw::git_object_t144         fn convert(&self) -> raw::git_object_t {
145             self.unwrap_or(ObjectType::Any).convert()
146         }
147     }
148 
149     impl Convert<raw::git_branch_t> for BranchType {
convert(&self) -> raw::git_branch_t150         fn convert(&self) -> raw::git_branch_t {
151             match *self {
152                 BranchType::Remote => raw::GIT_BRANCH_REMOTE,
153                 BranchType::Local => raw::GIT_BRANCH_LOCAL,
154             }
155         }
156     }
157 
158     impl Convert<raw::git_branch_t> for Option<BranchType> {
convert(&self) -> raw::git_branch_t159         fn convert(&self) -> raw::git_branch_t {
160             self.map(|s| s.convert()).unwrap_or(raw::GIT_BRANCH_ALL)
161         }
162     }
163 
164     impl Convert<raw::git_config_level_t> for ConfigLevel {
convert(&self) -> raw::git_config_level_t165         fn convert(&self) -> raw::git_config_level_t {
166             match *self {
167                 ConfigLevel::ProgramData => raw::GIT_CONFIG_LEVEL_PROGRAMDATA,
168                 ConfigLevel::System => raw::GIT_CONFIG_LEVEL_SYSTEM,
169                 ConfigLevel::XDG => raw::GIT_CONFIG_LEVEL_XDG,
170                 ConfigLevel::Global => raw::GIT_CONFIG_LEVEL_GLOBAL,
171                 ConfigLevel::Local => raw::GIT_CONFIG_LEVEL_LOCAL,
172                 ConfigLevel::App => raw::GIT_CONFIG_LEVEL_APP,
173                 ConfigLevel::Highest => raw::GIT_CONFIG_HIGHEST_LEVEL,
174             }
175         }
176     }
177 
178     impl Convert<raw::git_diff_format_t> for DiffFormat {
convert(&self) -> raw::git_diff_format_t179         fn convert(&self) -> raw::git_diff_format_t {
180             match *self {
181                 DiffFormat::Patch => raw::GIT_DIFF_FORMAT_PATCH,
182                 DiffFormat::PatchHeader => raw::GIT_DIFF_FORMAT_PATCH_HEADER,
183                 DiffFormat::Raw => raw::GIT_DIFF_FORMAT_RAW,
184                 DiffFormat::NameOnly => raw::GIT_DIFF_FORMAT_NAME_ONLY,
185                 DiffFormat::NameStatus => raw::GIT_DIFF_FORMAT_NAME_STATUS,
186                 DiffFormat::PatchId => raw::GIT_DIFF_FORMAT_PATCH_ID,
187             }
188         }
189     }
190 
191     impl Convert<raw::git_merge_file_favor_t> for FileFavor {
convert(&self) -> raw::git_merge_file_favor_t192         fn convert(&self) -> raw::git_merge_file_favor_t {
193             match *self {
194                 FileFavor::Normal => raw::GIT_MERGE_FILE_FAVOR_NORMAL,
195                 FileFavor::Ours => raw::GIT_MERGE_FILE_FAVOR_OURS,
196                 FileFavor::Theirs => raw::GIT_MERGE_FILE_FAVOR_THEIRS,
197                 FileFavor::Union => raw::GIT_MERGE_FILE_FAVOR_UNION,
198             }
199         }
200     }
201 
202     impl Convert<raw::git_submodule_ignore_t> for SubmoduleIgnore {
convert(&self) -> raw::git_submodule_ignore_t203         fn convert(&self) -> raw::git_submodule_ignore_t {
204             match *self {
205                 SubmoduleIgnore::Unspecified => raw::GIT_SUBMODULE_IGNORE_UNSPECIFIED,
206                 SubmoduleIgnore::None => raw::GIT_SUBMODULE_IGNORE_NONE,
207                 SubmoduleIgnore::Untracked => raw::GIT_SUBMODULE_IGNORE_UNTRACKED,
208                 SubmoduleIgnore::Dirty => raw::GIT_SUBMODULE_IGNORE_DIRTY,
209                 SubmoduleIgnore::All => raw::GIT_SUBMODULE_IGNORE_ALL,
210             }
211         }
212     }
213 
214     impl Convert<raw::git_submodule_update_t> for SubmoduleUpdate {
convert(&self) -> raw::git_submodule_update_t215         fn convert(&self) -> raw::git_submodule_update_t {
216             match *self {
217                 SubmoduleUpdate::Checkout => raw::GIT_SUBMODULE_UPDATE_CHECKOUT,
218                 SubmoduleUpdate::Rebase => raw::GIT_SUBMODULE_UPDATE_REBASE,
219                 SubmoduleUpdate::Merge => raw::GIT_SUBMODULE_UPDATE_MERGE,
220                 SubmoduleUpdate::None => raw::GIT_SUBMODULE_UPDATE_NONE,
221                 SubmoduleUpdate::Default => raw::GIT_SUBMODULE_UPDATE_DEFAULT,
222             }
223         }
224     }
225 
226     impl Convert<raw::git_remote_autotag_option_t> for AutotagOption {
convert(&self) -> raw::git_remote_autotag_option_t227         fn convert(&self) -> raw::git_remote_autotag_option_t {
228             match *self {
229                 AutotagOption::Unspecified => raw::GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED,
230                 AutotagOption::None => raw::GIT_REMOTE_DOWNLOAD_TAGS_NONE,
231                 AutotagOption::Auto => raw::GIT_REMOTE_DOWNLOAD_TAGS_AUTO,
232                 AutotagOption::All => raw::GIT_REMOTE_DOWNLOAD_TAGS_ALL,
233             }
234         }
235     }
236 
237     impl Convert<raw::git_fetch_prune_t> for FetchPrune {
convert(&self) -> raw::git_fetch_prune_t238         fn convert(&self) -> raw::git_fetch_prune_t {
239             match *self {
240                 FetchPrune::Unspecified => raw::GIT_FETCH_PRUNE_UNSPECIFIED,
241                 FetchPrune::On => raw::GIT_FETCH_PRUNE,
242                 FetchPrune::Off => raw::GIT_FETCH_NO_PRUNE,
243             }
244         }
245     }
246 }
247