Skip to content

Commit 9e79cfe

Browse files
committed
Make try_raw_entries stack allocated
1 parent 7381f93 commit 9e79cfe

File tree

1 file changed

+60
-58
lines changed

1 file changed

+60
-58
lines changed

src/index.rs

+60-58
Original file line numberDiff line numberDiff line change
@@ -89,68 +89,70 @@ pub struct IndexEntry {
8989
// a CString which is owned by the function. To make the pointer to the CString
9090
// valid during usage of raw::git_index_entry, we supply the index entry in a
9191
// callback where pointers to the CString are valid.
92-
fn try_raw_entries(
93-
entries: &[Option<&IndexEntry>],
94-
cb: impl FnOnce(&[*const raw::git_index_entry]) -> Result<(), Error>,
92+
fn try_raw_entries<const N: usize>(
93+
entries: &[Option<&IndexEntry>; N],
94+
cb: impl FnOnce(&[*const raw::git_index_entry; N]) -> Result<(), Error>,
9595
) -> Result<(), Error> {
96-
let paths = entries
97-
.iter()
98-
.map(|entry| {
99-
if let Some(entry) = entry {
100-
CString::new(&entry.path[..]).map(|ok| Some(ok))
96+
let mut paths: [Option<CString>; N] = unsafe {
97+
std::mem::MaybeUninit::uninit().assume_init()
98+
};
99+
for (idx, entry) in entries.iter().enumerate() {
100+
paths[idx] = if let Some(entry) = entry {
101+
Some(CString::new(&entry.path[..])?)
102+
} else {
103+
None
104+
}
105+
}
106+
107+
let mut raw_entries: [Option<raw::git_index_entry>; N] = unsafe {
108+
std::mem::MaybeUninit::uninit().assume_init()
109+
};
110+
for (idx, (entry, path)) in entries.iter().zip(&paths).enumerate() {
111+
raw_entries[idx] = if let Some(entry) = entry {
112+
// libgit2 encodes the length of the path in the lower bits of the
113+
// `flags` entry, so mask those out and recalculate here to ensure we
114+
// don't corrupt anything.
115+
let mut flags = entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
116+
117+
if entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
118+
flags |= entry.path.len() as u16;
101119
} else {
102-
Ok(None)
120+
flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
103121
}
104-
})
105-
.collect::<Result<Vec<Option<CString>>, std::ffi::NulError>>()?;
106-
107-
let raw_entries = entries
108-
.iter()
109-
.zip(&paths)
110-
.map(|(entry, path)| {
111-
if let Some(entry) = entry {
112-
// libgit2 encodes the length of the path in the lower bits of the
113-
// `flags` entry, so mask those out and recalculate here to ensure we
114-
// don't corrupt anything.
115-
let mut flags = entry.flags & !raw::GIT_INDEX_ENTRY_NAMEMASK;
116-
117-
if entry.path.len() < raw::GIT_INDEX_ENTRY_NAMEMASK as usize {
118-
flags |= entry.path.len() as u16;
119-
} else {
120-
flags |= raw::GIT_INDEX_ENTRY_NAMEMASK;
121-
}
122-
123-
unsafe {
124-
Some(raw::git_index_entry {
125-
dev: entry.dev,
126-
ino: entry.ino,
127-
mode: entry.mode,
128-
uid: entry.uid,
129-
gid: entry.gid,
130-
file_size: entry.file_size,
131-
id: *entry.id.raw(),
132-
flags,
133-
flags_extended: entry.flags_extended,
134-
path: path.as_ref().unwrap().as_ptr(),
135-
mtime: raw::git_index_time {
136-
seconds: entry.mtime.seconds(),
137-
nanoseconds: entry.mtime.nanoseconds(),
138-
},
139-
ctime: raw::git_index_time {
140-
seconds: entry.ctime.seconds(),
141-
nanoseconds: entry.ctime.nanoseconds(),
142-
},
143-
})
144-
}
145-
} else {
146-
None
122+
123+
unsafe {
124+
Some(raw::git_index_entry {
125+
dev: entry.dev,
126+
ino: entry.ino,
127+
mode: entry.mode,
128+
uid: entry.uid,
129+
gid: entry.gid,
130+
file_size: entry.file_size,
131+
id: *entry.id.raw(),
132+
flags,
133+
flags_extended: entry.flags_extended,
134+
path: path.as_ref().unwrap().as_ptr(),
135+
mtime: raw::git_index_time {
136+
seconds: entry.mtime.seconds(),
137+
nanoseconds: entry.mtime.nanoseconds(),
138+
},
139+
ctime: raw::git_index_time {
140+
seconds: entry.ctime.seconds(),
141+
nanoseconds: entry.ctime.nanoseconds(),
142+
},
143+
})
147144
}
148-
})
149-
.collect::<Vec<_>>();
150-
let raw_entry_ptrs = raw_entries
151-
.iter()
152-
.map(|opt| opt.as_ref().map_or_else(std::ptr::null, |ptr| ptr))
153-
.collect::<Vec<_>>();
145+
} else {
146+
None
147+
}
148+
}
149+
150+
let mut raw_entry_ptrs: [*const raw::git_index_entry; N] = unsafe {
151+
std::mem::MaybeUninit::uninit().assume_init()
152+
};
153+
for (idx, entry) in raw_entries.iter().enumerate() {
154+
raw_entry_ptrs[idx] = entry.as_ref().map_or_else(std::ptr::null, |ptr| ptr);
155+
}
154156

155157
cb(&raw_entry_ptrs)
156158
}

0 commit comments

Comments
 (0)