Make C++ env_var_t wrap Rust EnvVar

This reimplements C++'s env_var_t to reference a Rust EnvVar.
The C++ env_var_t is now just a thin wrapper.
This commit is contained in:
ridiculousfish
2023-04-29 19:58:45 -07:00
committed by Peter Ammon
parent 10ee87eb28
commit 0681b6b53a
8 changed files with 233 additions and 47 deletions

View File

@@ -25,6 +25,7 @@ fn main() -> miette::Result<()> {
let source_files = vec![
"src/abbrs.rs",
"src/ast.rs",
"src/env/env_ffi.rs",
"src/event.rs",
"src/common.rs",
"src/fd_monitor.rs",

119
fish-rust/src/env/env_ffi.rs vendored Normal file
View File

@@ -0,0 +1,119 @@
use super::var::{EnvVar, EnvVarFlags};
use crate::ffi::{wchar_t, wcharz_t, wcstring_list_ffi_t};
use crate::wchar_ffi::WCharToFFI;
use crate::wchar_ffi::{AsWstr, WCharFromFFI};
use cxx::{CxxWString, UniquePtr};
use std::pin::Pin;
#[allow(clippy::module_inception)]
#[cxx::bridge]
mod env_ffi {
/// Return values for `EnvStack::set()`.
#[repr(u8)]
#[cxx_name = "env_stack_set_result_t"]
enum EnvStackSetResult {
ENV_OK,
ENV_PERM,
ENV_SCOPE,
ENV_INVALID,
ENV_NOT_FOUND,
}
extern "C++" {
include!("wutil.h");
type wcstring_list_ffi_t = super::wcstring_list_ffi_t;
type wcharz_t = super::wcharz_t;
}
extern "Rust" {
type EnvVar;
fn is_empty(&self) -> bool;
fn exports(&self) -> bool;
fn is_read_only(&self) -> bool;
fn is_pathvar(&self) -> bool;
#[cxx_name = "equals"]
fn equals_ffi(&self, rhs: &EnvVar) -> bool;
#[cxx_name = "as_string"]
fn as_string_ffi(&self) -> UniquePtr<CxxWString>;
#[cxx_name = "as_list"]
fn as_list_ffi(&self) -> UniquePtr<wcstring_list_ffi_t>;
#[cxx_name = "to_list"]
fn to_list_ffi(&self, out: Pin<&mut wcstring_list_ffi_t>);
#[cxx_name = "get_delimiter"]
fn get_delimiter_ffi(&self) -> wchar_t;
#[cxx_name = "get_flags"]
fn get_flags_ffi(&self) -> u8;
#[cxx_name = "clone_box"]
fn clone_box_ffi(&self) -> Box<EnvVar>;
#[cxx_name = "env_var_create"]
fn env_var_create_ffi(vals: &wcstring_list_ffi_t, flags: u8) -> Box<EnvVar>;
#[cxx_name = "env_var_create_from_name"]
fn env_var_create_from_name_ffi(
name: wcharz_t,
values: &wcstring_list_ffi_t,
) -> Box<EnvVar>;
}
}
pub use env_ffi::EnvStackSetResult;
impl Default for EnvStackSetResult {
fn default() -> Self {
EnvStackSetResult::ENV_OK
}
}
/// FFI bits.
impl EnvVar {
pub fn equals_ffi(&self, rhs: &EnvVar) -> bool {
self == rhs
}
pub fn as_string_ffi(&self) -> UniquePtr<CxxWString> {
self.as_string().to_ffi()
}
pub fn as_list_ffi(&self) -> UniquePtr<wcstring_list_ffi_t> {
self.as_list().to_ffi()
}
pub fn to_list_ffi(&self, mut out: Pin<&mut wcstring_list_ffi_t>) {
out.as_mut().clear();
for val in self.as_list() {
out.as_mut().push(val);
}
}
pub fn clone_box_ffi(&self) -> Box<Self> {
Box::new(self.clone())
}
pub fn get_flags_ffi(&self) -> u8 {
self.get_flags().bits()
}
pub fn get_delimiter_ffi(self: &EnvVar) -> wchar_t {
self.get_delimiter().into()
}
}
fn env_var_create_ffi(vals: &wcstring_list_ffi_t, flags: u8) -> Box<EnvVar> {
Box::new(EnvVar::new_vec(
vals.from_ffi(),
EnvVarFlags::from_bits(flags).expect("invalid flags"),
))
}
pub fn env_var_create_from_name_ffi(name: wcharz_t, values: &wcstring_list_ffi_t) -> Box<EnvVar> {
Box::new(EnvVar::new_from_name_vec(name.as_wstr(), values.from_ffi()))
}

View File

@@ -1,3 +1,4 @@
mod env_ffi;
pub mod environment;
pub mod var;

View File

@@ -11,7 +11,6 @@
pub const PATH_ARRAY_SEP: char = ':';
pub const NONPATH_ARRAY_SEP: char = ' ';
// Flags that may be passed as the 'mode' in env_stack_t::set() / environment_t::get().
bitflags! {
/// Flags that may be passed as the 'mode' in env_stack_t::set() / environment_t::get().
#[repr(C)]
@@ -71,6 +70,12 @@ pub enum EnvStackSetResult {
ENV_NOT_FOUND,
}
impl Default for EnvStackSetResult {
fn default() -> Self {
EnvStackSetResult::ENV_OK
}
}
/// A struct of configuration directories, determined in main() that fish will optionally pass to
/// env_init.
pub struct ConfigPaths {
@@ -213,7 +218,7 @@ pub fn as_list(&self) -> &[WString] {
}
/// Returns the delimiter character used when converting from a list to a string.
fn get_delimiter(&self) -> char {
pub fn get_delimiter(&self) -> char {
if self.is_pathvar() {
PATH_ARRAY_SEP
} else {
@@ -250,7 +255,7 @@ pub fn setting_pathvar(&mut self, pathvar: bool) -> Self {
}
/// Returns flags for a variable with the given name.
fn flags_for(name: &wstr) -> EnvVarFlags {
pub fn flags_for(name: &wstr) -> EnvVarFlags {
let mut result = EnvVarFlags::empty();
if is_read_only(name) {
result.insert(EnvVarFlags::READ_ONLY);

View File

@@ -104,6 +104,18 @@ fn into_cpp(self) -> cxx::UniquePtr<cxx::CxxWString> {
}
}
impl ToCppWString for WString {
fn into_cpp(self) -> cxx::UniquePtr<cxx::CxxWString> {
self.to_ffi()
}
}
impl ToCppWString for &WString {
fn into_cpp(self) -> cxx::UniquePtr<cxx::CxxWString> {
self.to_ffi()
}
}
/// WString may be converted to CxxWString.
impl WCharToFFI for WString {
type Target = cxx::UniquePtr<cxx::CxxWString>;
@@ -213,6 +225,12 @@ fn as_wstr(&'a self) -> &'a wstr {
}
}
impl AsWstr<'_> for wcharz_t {
fn as_wstr(&self) -> &wstr {
wstr::from_char_slice(self.chars())
}
}
use crate::ffi_tests::add_test;
add_test!("test_wcstring_list_ffi_t", || {
let data: Vec<WString> = wcstring_list_ffi_t::get_test_data().from_ffi();