Skip to content

Commit 14c0ad2

Browse files
committed
IntoRef
1 parent 76c80e6 commit 14c0ad2

File tree

2 files changed

+94
-38
lines changed

2 files changed

+94
-38
lines changed

src/null_terminated.rs

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ use std::mem::transmute;
44
use std::iter;
55
use libc::c_char;
66

7+
pub trait IntoRef<'a, T: ?Sized> {
8+
type Target: 'a + AsRef<T>;
9+
10+
fn into_ref(self) -> Self::Target;
11+
}
12+
713
pub struct NullTerminatedSlice<T> {
814
inner: [Option<T>],
915
}
@@ -55,29 +61,80 @@ impl<T> DerefMut for NullTerminatedSlice<T> {
5561
}
5662
}
5763

58-
pub trait BorrowNullTerminatedSlice<T> {
59-
fn borrow_null_terminated_slice<R, F: FnOnce(&NullTerminatedSlice<&T>) -> R>(self, f: F) -> R;
64+
impl<T> AsRef<NullTerminatedSlice<T>> for NullTerminatedSlice<T> {
65+
fn as_ref(&self) -> &Self {
66+
self
67+
}
68+
}
69+
70+
pub struct NullTerminatedVec<T> {
71+
inner: Vec<Option<T>>,
72+
}
73+
74+
impl<T> NullTerminatedVec<T> {
75+
pub fn from_vec(vec: Vec<Option<T>>) -> Option<Self> {
76+
if vec.last().map(Option::is_none).unwrap_or(false) {
77+
Some(unsafe { Self::from_vec_unchecked(vec) })
78+
} else {
79+
None
80+
}
81+
}
82+
83+
pub unsafe fn from_vec_unchecked(vec: Vec<Option<T>>) -> Self {
84+
NullTerminatedVec {
85+
inner: vec,
86+
}
87+
}
88+
}
89+
90+
impl<T> Deref for NullTerminatedVec<T> {
91+
type Target = NullTerminatedSlice<T>;
92+
93+
fn deref(&self) -> &Self::Target {
94+
unsafe {
95+
NullTerminatedSlice::from_slice_unchecked(&self.inner)
96+
}
97+
}
98+
}
99+
100+
impl<T> DerefMut for NullTerminatedVec<T> {
101+
fn deref_mut(&mut self) -> &mut Self::Target {
102+
unsafe {
103+
NullTerminatedSlice::from_slice_mut_unchecked(&mut self.inner)
104+
}
105+
}
106+
}
107+
108+
impl<T> AsRef<NullTerminatedSlice<T>> for NullTerminatedVec<T> {
109+
fn as_ref(&self) -> &NullTerminatedSlice<T> {
110+
self
111+
}
60112
}
61113

62-
impl<T: AsRef<CStr>, I: IntoIterator<Item=T>> BorrowNullTerminatedSlice<c_char> for I {
63-
fn borrow_null_terminated_slice<R, F: FnOnce(&NullTerminatedSlice<&c_char>) -> R>(self, f: F) -> R {
114+
impl<'a, T: 'a> IntoRef<'a, NullTerminatedSlice<&'a T>> for &'a NullTerminatedSlice<&'a T> {
115+
type Target = &'a NullTerminatedSlice<&'a T>;
116+
117+
fn into_ref(self) -> Self::Target {
118+
self
119+
}
120+
}
121+
122+
impl<'a, T: AsRef<CStr> + 'a, I: IntoIterator<Item=T>> IntoRef<'a, NullTerminatedSlice<&'a c_char>> for I {
123+
type Target = NullTerminatedVec<&'a c_char>;
124+
125+
fn into_ref(self) -> Self::Target {
64126
fn cstr_char<'a, S: AsRef<CStr> + 'a>(s: S) -> &'a c_char {
65127
unsafe {
66128
&*s.as_ref().as_ptr()
67129
}
68130
}
69131

70-
let values: Vec<_> = self.into_iter()
132+
let terminated = self.into_iter()
71133
.map(cstr_char)
72134
.map(Some).chain(iter::once(None)).collect();
73-
let terminated = unsafe { NullTerminatedSlice::from_slice_unchecked(&values[..]) };
74135

75-
f(terminated)
76-
}
77-
}
78-
79-
impl<'a, T: 'a> BorrowNullTerminatedSlice<T> for &'a NullTerminatedSlice<&'a T> {
80-
fn borrow_null_terminated_slice<R, F: FnOnce(&NullTerminatedSlice<&T>) -> R>(self, f: F) -> R {
81-
f(self)
136+
unsafe {
137+
NullTerminatedVec::from_vec_unchecked(terminated)
138+
}
82139
}
83140
}

src/unistd.rs

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Standard symbolic constants and types
22
//!
33
use {Errno, Error, Result, NixPath};
4-
use null_terminated::BorrowNullTerminatedSlice;
4+
use null_terminated::{IntoRef, NullTerminatedSlice};
55
use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC};
66
use fcntl::FcntlArg::{F_SETFD, F_SETFL};
77
use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t};
@@ -123,38 +123,37 @@ pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<uid_t>, group: Option<
123123
}
124124

125125
#[inline]
126-
pub fn execv<A: BorrowNullTerminatedSlice<c_char>>(path: &CStr, argv: A) -> Result<Void> {
127-
argv.borrow_null_terminated_slice(|args_p| {
128-
unsafe {
129-
libc::execv(path.as_ptr(), args_p.as_ptr())
130-
};
126+
pub fn execv<'a, A: IntoRef<'a, NullTerminatedSlice<&'a c_char>>>(path: &CStr, argv: A) -> Result<Void> {
127+
let argv = argv.into_ref();
131128

132-
Err(Error::Sys(Errno::last()))
133-
})
129+
unsafe {
130+
libc::execv(path.as_ptr(), argv.as_ref().as_ptr())
131+
};
132+
133+
Err(Error::Sys(Errno::last()))
134134
}
135135

136136
#[inline]
137-
pub fn execve<A: BorrowNullTerminatedSlice<c_char>, E: BorrowNullTerminatedSlice<c_char>>(path: &CStr, args: A, env: E) -> Result<Void> {
138-
args.borrow_null_terminated_slice(|args_p| {
139-
env.borrow_null_terminated_slice(|env_p| {
140-
unsafe {
141-
libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
142-
};
143-
144-
Err(Error::Sys(Errno::last()))
145-
})
146-
})
137+
pub fn execve<'a, 'e, A: IntoRef<'a, NullTerminatedSlice<&'a c_char>>, E: IntoRef<'e, NullTerminatedSlice<&'e c_char>>>(path: &CStr, args: A, env: E) -> Result<Void> {
138+
let args = args.into_ref();
139+
let env = env.into_ref();
140+
141+
unsafe {
142+
libc::execve(path.as_ptr(), args.as_ref().as_ptr(), env.as_ref().as_ptr())
143+
};
144+
145+
Err(Error::Sys(Errno::last()))
147146
}
148147

149148
#[inline]
150-
pub fn execvp<A: BorrowNullTerminatedSlice<c_char>>(filename: &CStr, args: A) -> Result<Void> {
151-
args.borrow_null_terminated_slice(|args_p| {
152-
unsafe {
153-
libc::execvp(filename.as_ptr(), args_p.as_ptr())
154-
};
149+
pub fn execvp<'a, A: IntoRef<'a, NullTerminatedSlice<&'a c_char>>>(filename: &CStr, args: A) -> Result<Void> {
150+
let args = args.into_ref();
155151

156-
Err(Error::Sys(Errno::last()))
157-
})
152+
unsafe {
153+
libc::execvp(filename.as_ptr(), args.as_ref().as_ptr())
154+
};
155+
156+
Err(Error::Sys(Errno::last()))
158157
}
159158

160159
pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {

0 commit comments

Comments
 (0)