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