diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-12-21 21:29:59 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-21 21:29:59 +0000 |
commit | 4f7119c61da6ab3a11d5e52b5e6cf7105a66efb9 (patch) | |
tree | f0f4562bfd6f1296572078d08e46eab4e9185566 /src | |
parent | 1dcc582f8eba50f6233bc0bf398ada4032469c1f (diff) | |
parent | 644d36cf1fa5515dade300e42de6f9877c892204 (diff) | |
download | nix-4f7119c61da6ab3a11d5e52b5e6cf7105a66efb9.zip |
Merge #1583
1583: Remove unsafe in with_nix_path() for [u8] r=asomers a=rtzoeller
Remove use of `unsafe` in the implementation of `with_nix_path()` for `[u8]`. This also comes with a nice determinism win across input sizes, and is fairly performance neutral (slightly slower for small strings, much faster for large strings).
I suspect the performance degradation in the existing implementation is related to the following note in the `CStr::from_ptr()` documentation:
> Note: This operation is intended to be a 0-cost cast but it is currently implemented with an up-front calculation of the length of the string. This is not guaranteed to always be the case.
---
Tested with `cargo 1.57.0-nightly (7fbbf4e8f 2021-10-19)`, with variations of the following benchmarking code:
```rs
#[bench]
fn bench_with_nix_path_1024(b: &mut test::Bencher) {
let bytes = std::hint::black_box([70u8; 1024]);
b.iter(|| {
bytes.with_nix_path(|cstr| {
std::hint::black_box(&cstr);
}).unwrap();
})
}
```
| Length | Before Change | After Change |
|--------|-----------------------|-----------------------|
| 16 | 37 ns/iter (+/- 0) | 44 ns/iter (+/- 0) |
| 64 | 39 ns/iter (+/- 0) | 44 ns/iter (+/- 0) |
| 256 | 84 ns/iter (+/- 0) | 48 ns/iter (+/- 0) |
| 1024 | 232 ns/iter (+/- 1) | 50 ns/iter (+/- 1) |
| 4095 | 796 ns/iter (+/- 8) | 62 ns/iter (+/- 2) |
Co-authored-by: Ryan Zoeller <rtzoeller@rtzoeller.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 18 |
1 files changed, 6 insertions, 12 deletions
@@ -161,9 +161,9 @@ pub mod unistd; * */ -use libc::{c_char, PATH_MAX}; +use libc::PATH_MAX; -use std::{ptr, result}; +use std::result; use std::ffi::{CStr, OsStr}; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; @@ -267,16 +267,10 @@ impl NixPath for [u8] { return Err(Errno::ENAMETOOLONG) } - match self.iter().position(|b| *b == 0) { - Some(_) => Err(Errno::EINVAL), - None => { - unsafe { - // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028 - ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len()); - Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char))) - } - - } + buf[..self.len()].copy_from_slice(self); + match CStr::from_bytes_with_nul(&buf[..=self.len()]) { + Ok(s) => Ok(f(s)), + Err(_) => Err(Errno::EINVAL), } } } |