1use std::ffi::CString;
2use std::{mem, ptr};
3
4use crate::util::Binding;
5use crate::{raw, Buf, Commit, DiffFindOptions, DiffOptions, Error, IntoCString};
6use crate::{Diff, Oid, Signature};
7
8pub struct Email {
10 buf: Buf,
11}
12
13pub struct EmailCreateOptions {
15 diff_options: DiffOptions,
16 diff_find_options: DiffFindOptions,
17 subject_prefix: Option<CString>,
18 raw: raw::git_email_create_options,
19}
20
21impl Default for EmailCreateOptions {
22 fn default() -> Self {
23 let default_options = raw::git_email_create_options {
25 version: raw::GIT_EMAIL_CREATE_OPTIONS_VERSION,
26 flags: raw::GIT_EMAIL_CREATE_DEFAULT as u32,
27 diff_opts: unsafe { mem::zeroed() },
28 diff_find_opts: unsafe { mem::zeroed() },
29 subject_prefix: ptr::null(),
30 start_number: 1,
31 reroll_number: 0,
32 };
33 let mut diff_options = DiffOptions::new();
34 diff_options.show_binary(true).context_lines(3);
35 Self {
36 diff_options,
37 diff_find_options: DiffFindOptions::new(),
38 subject_prefix: None,
39 raw: default_options,
40 }
41 }
42}
43
44impl EmailCreateOptions {
45 pub fn new() -> Self {
50 Self::default()
51 }
52
53 fn flag(&mut self, opt: raw::git_email_create_flags_t, val: bool) -> &mut Self {
54 let opt = opt as u32;
55 if val {
56 self.raw.flags |= opt;
57 } else {
58 self.raw.flags &= !opt;
59 }
60 self
61 }
62
63 pub fn omit_numbers(&mut self, omit: bool) -> &mut Self {
65 self.flag(raw::GIT_EMAIL_CREATE_OMIT_NUMBERS, omit)
66 }
67
68 pub fn always_number(&mut self, always: bool) -> &mut Self {
71 self.flag(raw::GIT_EMAIL_CREATE_ALWAYS_NUMBER, always)
72 }
73
74 pub fn ignore_renames(&mut self, ignore: bool) -> &mut Self {
76 self.flag(raw::GIT_EMAIL_CREATE_NO_RENAMES, ignore)
77 }
78
79 pub fn diff_options(&mut self) -> &mut DiffOptions {
81 &mut self.diff_options
82 }
83
84 pub fn diff_find_options(&mut self) -> &mut DiffFindOptions {
87 &mut self.diff_find_options
88 }
89
90 pub fn subject_prefix<T: IntoCString>(&mut self, t: T) -> &mut Self {
97 self.subject_prefix = Some(t.into_c_string().unwrap());
98 self
99 }
100
101 pub fn start_number(&mut self, number: usize) -> &mut Self {
105 self.raw.start_number = number;
106 self
107 }
108
109 pub fn reroll_number(&mut self, number: usize) -> &mut Self {
113 self.raw.reroll_number = number;
114 self
115 }
116
117 unsafe fn raw(&mut self) -> *const raw::git_email_create_options {
122 self.raw.subject_prefix = self
123 .subject_prefix
124 .as_ref()
125 .map(|s| s.as_ptr())
126 .unwrap_or(ptr::null());
127 self.raw.diff_opts = ptr::read(self.diff_options.raw());
128 self.raw.diff_find_opts = ptr::read(self.diff_find_options.raw());
129 &self.raw as *const _
130 }
131}
132
133impl Email {
134 pub fn as_slice(&self) -> &[u8] {
137 &self.buf
138 }
139
140 pub fn from_diff<T: IntoCString>(
142 diff: &Diff<'_>,
143 patch_idx: usize,
144 patch_count: usize,
145 commit_id: &Oid,
146 summary: T,
147 body: T,
148 author: &Signature<'_>,
149 opts: &mut EmailCreateOptions,
150 ) -> Result<Self, Error> {
151 let buf = Buf::new();
152 let summary = summary.into_c_string()?;
153 let body = body.into_c_string()?;
154 unsafe {
155 try_call!(raw::git_email_create_from_diff(
156 buf.raw(),
157 Binding::raw(diff),
158 patch_idx,
159 patch_count,
160 Binding::raw(commit_id),
161 summary.as_ptr(),
162 body.as_ptr(),
163 Binding::raw(author),
164 opts.raw()
165 ));
166 Ok(Self { buf })
167 }
168 }
169
170 pub fn from_commit(commit: &Commit<'_>, opts: &mut EmailCreateOptions) -> Result<Self, Error> {
173 let buf = Buf::new();
174 unsafe {
175 try_call!(raw::git_email_create_from_commit(
176 buf.raw(),
177 commit.raw(),
178 opts.raw()
179 ));
180 Ok(Self { buf })
181 }
182 }
183}