mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-28 13:53:10 +00:00
Reimplement owning_null_terminated_array in Rust
owning_null_terminated_array is used for environment variables, where we need to provide envp for child processes. This switches the implementation from C++ to Rust. We retain the C++ owning_null_terminated_array_t; it simply wraps the Rust version now.
This commit is contained in:
parent
d4c3c77318
commit
10ee87eb28
5 changed files with 72 additions and 10 deletions
|
@ -36,6 +36,7 @@ fn main() -> miette::Result<()> {
|
||||||
"src/future_feature_flags.rs",
|
"src/future_feature_flags.rs",
|
||||||
"src/highlight.rs",
|
"src/highlight.rs",
|
||||||
"src/job_group.rs",
|
"src/job_group.rs",
|
||||||
|
"src/null_terminated_array.rs",
|
||||||
"src/parse_constants.rs",
|
"src/parse_constants.rs",
|
||||||
"src/parse_tree.rs",
|
"src/parse_tree.rs",
|
||||||
"src/parse_util.rs",
|
"src/parse_util.rs",
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::ffi::{c_char, CStr, CString};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub trait NulTerminatedString {
|
pub trait NulTerminatedString {
|
||||||
type CharType: Copy;
|
type CharType: Copy;
|
||||||
|
@ -21,9 +22,6 @@ impl NulTerminatedString for CStr {
|
||||||
/// This supports the null-terminated array of NUL-terminated strings consumed by exec.
|
/// This supports the null-terminated array of NUL-terminated strings consumed by exec.
|
||||||
/// Given a list of strings, construct a vector of pointers to those strings contents.
|
/// Given a list of strings, construct a vector of pointers to those strings contents.
|
||||||
/// This is used for building null-terminated arrays of null-terminated strings.
|
/// This is used for building null-terminated arrays of null-terminated strings.
|
||||||
/// *Important*: the vector stores pointers into the interior of the input strings, which may be
|
|
||||||
/// subject to the small-string optimization. This means that pointers will be left dangling if any
|
|
||||||
/// input string is deallocated *or moved*. This class should only be used in transient calls.
|
|
||||||
pub struct NullTerminatedArray<'p, T: NulTerminatedString + ?Sized> {
|
pub struct NullTerminatedArray<'p, T: NulTerminatedString + ?Sized> {
|
||||||
pointers: Vec<*const T::CharType>,
|
pointers: Vec<*const T::CharType>,
|
||||||
_phantom: PhantomData<&'p T>,
|
_phantom: PhantomData<&'p T>,
|
||||||
|
@ -100,6 +98,53 @@ pub fn null_terminated_array_length<T>(mut arr: *const *const T) -> usize {
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// FFI bits.
|
||||||
|
/// We often work in Arc<OwningNullTerminatedArray>.
|
||||||
|
/// Expose this to C++.
|
||||||
|
pub struct OwningNullTerminatedArrayRefFFI(pub Arc<OwningNullTerminatedArray>);
|
||||||
|
impl OwningNullTerminatedArrayRefFFI {
|
||||||
|
fn get(&self) -> *mut *const c_char {
|
||||||
|
self.0.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl cxx::ExternType for OwningNullTerminatedArrayRefFFI {
|
||||||
|
type Id = cxx::type_id!("OwningNullTerminatedArrayRefFFI");
|
||||||
|
type Kind = cxx::kind::Opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a CxxString to a CString, truncating at the first NUL.
|
||||||
|
use cxx::{CxxString, CxxVector};
|
||||||
|
fn cxxstring_to_cstring(s: &CxxString) -> CString {
|
||||||
|
let bytes: &[u8] = s.as_bytes();
|
||||||
|
let nul_pos = bytes.iter().position(|&b| b == 0);
|
||||||
|
let slice = &bytes[..nul_pos.unwrap_or(bytes.len())];
|
||||||
|
CString::new(slice).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_owning_null_terminated_array_ffi(
|
||||||
|
strs: &CxxVector<CxxString>,
|
||||||
|
) -> Box<OwningNullTerminatedArrayRefFFI> {
|
||||||
|
let cstrs = strs.iter().map(cxxstring_to_cstring).collect();
|
||||||
|
Box::new(OwningNullTerminatedArrayRefFFI(Arc::new(
|
||||||
|
OwningNullTerminatedArray::new(cstrs),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cxx::bridge]
|
||||||
|
mod null_terminated_array_ffi {
|
||||||
|
extern "Rust" {
|
||||||
|
type OwningNullTerminatedArrayRefFFI;
|
||||||
|
|
||||||
|
fn get(&self) -> *mut *const c_char;
|
||||||
|
|
||||||
|
#[cxx_name = "new_owning_null_terminated_array"]
|
||||||
|
fn new_owning_null_terminated_array_ffi(
|
||||||
|
strs: &CxxVector<CxxString>,
|
||||||
|
) -> Box<OwningNullTerminatedArrayRefFFI>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_null_terminated_array_length() {
|
fn test_null_terminated_array_length() {
|
||||||
let arr = [&1, &2, &3, std::ptr::null()];
|
let arr = [&1, &2, &3, std::ptr::null()];
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "cxx.h"
|
#include "cxx.h"
|
||||||
#include "maybe.h"
|
#include "maybe.h"
|
||||||
|
|
||||||
class owning_null_terminated_array_t;
|
struct owning_null_terminated_array_t;
|
||||||
|
|
||||||
extern size_t read_byte_limit;
|
extern size_t read_byte_limit;
|
||||||
extern bool curses_initialized;
|
extern bool curses_initialized;
|
||||||
|
|
|
@ -8,3 +8,12 @@ std::vector<std::string> wide_string_list_to_narrow(const std::vector<wcstring>
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char **owning_null_terminated_array_t::get() { return impl_->get(); }
|
||||||
|
|
||||||
|
owning_null_terminated_array_t::owning_null_terminated_array_t(std::vector<std::string> &&strings)
|
||||||
|
: impl_(new_owning_null_terminated_array(strings)) {}
|
||||||
|
|
||||||
|
owning_null_terminated_array_t::owning_null_terminated_array_t(
|
||||||
|
rust::Box<OwningNullTerminatedArrayRefFFI> impl)
|
||||||
|
: impl_(std::move(impl)) {}
|
||||||
|
|
|
@ -10,6 +10,12 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "cxx.h"
|
||||||
|
|
||||||
|
struct OwningNullTerminatedArrayRefFFI;
|
||||||
|
#if INCLUDE_RUST_HEADERS
|
||||||
|
#include "null_terminated_array.rs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/// This supports the null-terminated array of NUL-terminated strings consumed by exec.
|
/// This supports the null-terminated array of NUL-terminated strings consumed by exec.
|
||||||
/// Given a list of strings, construct a vector of pointers to those strings contents.
|
/// Given a list of strings, construct a vector of pointers to those strings contents.
|
||||||
|
@ -46,18 +52,19 @@ class null_terminated_array_t : noncopyable_t, nonmovable_t {
|
||||||
/// This is useful for persisted null-terminated arrays, e.g. the exported environment variable
|
/// This is useful for persisted null-terminated arrays, e.g. the exported environment variable
|
||||||
/// list. This assumes char, since we don't need this for wchar_t.
|
/// list. This assumes char, since we don't need this for wchar_t.
|
||||||
/// Note this class is not movable or copyable as it embeds a null_terminated_array_t.
|
/// Note this class is not movable or copyable as it embeds a null_terminated_array_t.
|
||||||
class owning_null_terminated_array_t {
|
struct owning_null_terminated_array_t {
|
||||||
public:
|
public:
|
||||||
// Access the null-terminated array of nul-terminated strings, appropriate for execv().
|
// Access the null-terminated array of nul-terminated strings, appropriate for execv().
|
||||||
const char **get() { return pointers_.get(); }
|
const char **get();
|
||||||
|
|
||||||
// Construct, taking ownership of a list of strings.
|
// Construct, taking ownership of a list of strings.
|
||||||
explicit owning_null_terminated_array_t(std::vector<std::string> &&strings)
|
explicit owning_null_terminated_array_t(std::vector<std::string> &&strings);
|
||||||
: strings_(std::move(strings)), pointers_(strings_) {}
|
|
||||||
|
// Construct from the FFI side.
|
||||||
|
explicit owning_null_terminated_array_t(rust::Box<OwningNullTerminatedArrayRefFFI> impl);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<std::string> strings_;
|
const rust::Box<OwningNullTerminatedArrayRefFFI> impl_;
|
||||||
null_terminated_array_t<char> pointers_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Helper to convert a list of wcstring to a list of std::string.
|
/// Helper to convert a list of wcstring to a list of std::string.
|
||||||
|
|
Loading…
Reference in a new issue