2023-02-24 23:55:49 +08:00
|
|
|
use crate::wchar_ffi::WCharToFFI;
|
|
|
|
#[rustfmt::skip]
|
|
|
|
use ::std::pin::Pin;
|
|
|
|
#[rustfmt::skip]
|
|
|
|
use ::std::slice;
|
2023-06-20 03:03:46 +08:00
|
|
|
use crate::env::{EnvMode, EnvStackRef, EnvStackRefFFI};
|
2023-08-13 02:35:16 +08:00
|
|
|
use crate::job_group::JobGroup;
|
2023-03-14 10:23:31 +08:00
|
|
|
pub use crate::wait_handle::{
|
|
|
|
WaitHandleRef, WaitHandleRefFFI, WaitHandleStore, WaitHandleStoreFFI,
|
|
|
|
};
|
2023-08-09 06:16:04 +08:00
|
|
|
use crate::wchar::prelude::*;
|
2023-03-19 11:11:18 +08:00
|
|
|
use crate::wchar_ffi::WCharFromFFI;
|
2023-01-15 06:56:24 +08:00
|
|
|
use autocxx::prelude::*;
|
2023-01-16 11:52:08 +08:00
|
|
|
use cxx::SharedPtr;
|
2023-02-12 04:31:08 +08:00
|
|
|
use libc::pid_t;
|
2023-01-15 06:56:24 +08:00
|
|
|
|
|
|
|
// autocxx has been hacked up to know about this.
|
|
|
|
pub type wchar_t = u32;
|
|
|
|
|
|
|
|
include_cpp! {
|
2023-05-14 12:05:39 +08:00
|
|
|
#include "autoload.h"
|
2023-02-25 07:44:20 +08:00
|
|
|
#include "builtin.h"
|
2023-05-29 07:49:20 +08:00
|
|
|
#include "color.h"
|
2023-02-25 07:44:20 +08:00
|
|
|
#include "common.h"
|
2023-05-17 09:51:34 +08:00
|
|
|
#include "complete.h"
|
2023-02-24 23:55:49 +08:00
|
|
|
#include "env.h"
|
2023-04-30 10:58:51 +08:00
|
|
|
#include "env_universal_common.h"
|
2023-02-25 07:44:20 +08:00
|
|
|
#include "event.h"
|
2023-06-17 05:38:08 +08:00
|
|
|
#include "exec.h"
|
2023-02-25 07:44:20 +08:00
|
|
|
#include "fallback.h"
|
2023-01-15 06:56:24 +08:00
|
|
|
#include "fds.h"
|
Port AST to Rust
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
2023-04-02 22:42:59 +08:00
|
|
|
#include "fish_indent_common.h"
|
2023-01-15 06:56:24 +08:00
|
|
|
#include "flog.h"
|
2023-04-11 01:49:50 +08:00
|
|
|
#include "function.h"
|
|
|
|
#include "highlight.h"
|
2023-05-17 09:51:34 +08:00
|
|
|
#include "history.h"
|
2023-01-15 06:56:24 +08:00
|
|
|
#include "io.h"
|
2023-05-17 09:51:34 +08:00
|
|
|
#include "input_common.h"
|
2023-02-24 23:55:49 +08:00
|
|
|
#include "parse_constants.h"
|
2023-01-15 06:56:24 +08:00
|
|
|
#include "parser.h"
|
2023-02-25 07:44:20 +08:00
|
|
|
#include "parse_util.h"
|
2023-02-25 04:14:13 +08:00
|
|
|
#include "path.h"
|
2023-01-15 06:56:24 +08:00
|
|
|
#include "proc.h"
|
2023-04-30 10:58:51 +08:00
|
|
|
#include "reader.h"
|
2023-05-17 09:51:34 +08:00
|
|
|
#include "screen.h"
|
2023-02-25 07:44:20 +08:00
|
|
|
#include "tokenizer.h"
|
|
|
|
#include "wildcard.h"
|
|
|
|
#include "wutil.h"
|
2023-01-15 06:56:24 +08:00
|
|
|
|
2023-03-14 10:23:31 +08:00
|
|
|
// We need to block these types so when exposing C++ to Rust.
|
|
|
|
block!("WaitHandleStoreFFI")
|
|
|
|
block!("WaitHandleRefFFI")
|
|
|
|
|
2023-01-15 06:56:24 +08:00
|
|
|
safety!(unsafe_ffi)
|
|
|
|
|
|
|
|
generate_pod!("wcharz_t")
|
2023-04-11 03:19:36 +08:00
|
|
|
generate!("wcstring_list_ffi_t")
|
2023-01-15 06:56:24 +08:00
|
|
|
generate!("wperror")
|
|
|
|
|
|
|
|
generate_pod!("pipes_ffi_t")
|
2023-03-19 11:11:18 +08:00
|
|
|
generate!("environment_t")
|
2023-02-25 00:00:05 +08:00
|
|
|
generate!("env_stack_t")
|
2023-03-19 11:11:18 +08:00
|
|
|
generate!("env_var_t")
|
2023-04-30 10:58:51 +08:00
|
|
|
generate!("env_universal_t")
|
|
|
|
generate!("env_universal_sync_result_t")
|
|
|
|
generate!("callback_data_t")
|
|
|
|
generate!("universal_notifier_t")
|
|
|
|
generate!("var_table_ffi_t")
|
|
|
|
|
|
|
|
generate!("event_list_ffi_t")
|
|
|
|
|
2023-01-15 06:56:24 +08:00
|
|
|
generate!("make_pipes_ffi")
|
|
|
|
|
2023-03-28 23:59:51 +08:00
|
|
|
generate!("log_extra_to_flog_file")
|
2023-01-15 06:56:24 +08:00
|
|
|
|
2023-02-05 16:35:06 +08:00
|
|
|
generate!("fish_wcwidth")
|
|
|
|
generate!("fish_wcswidth")
|
|
|
|
|
2023-01-15 06:56:24 +08:00
|
|
|
generate!("wildcard_match")
|
2023-01-16 05:18:52 +08:00
|
|
|
generate!("wgettext_ptr")
|
2023-01-15 06:56:24 +08:00
|
|
|
|
2023-02-25 03:21:27 +08:00
|
|
|
generate!("block_t")
|
2023-01-16 11:52:08 +08:00
|
|
|
generate!("parser_t")
|
2023-03-14 10:23:31 +08:00
|
|
|
|
2023-01-16 11:52:08 +08:00
|
|
|
generate!("job_t")
|
2023-06-28 01:05:55 +08:00
|
|
|
generate!("job_control_t")
|
|
|
|
generate!("get_job_control_mode")
|
|
|
|
generate!("set_job_control_mode")
|
|
|
|
generate!("get_login")
|
2023-01-16 11:52:08 +08:00
|
|
|
generate!("process_t")
|
2023-02-19 00:13:58 +08:00
|
|
|
generate!("library_data_t")
|
2023-02-12 01:15:27 +08:00
|
|
|
generate_pod!("library_data_pod_t")
|
2023-01-16 11:52:08 +08:00
|
|
|
|
Port AST to Rust
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
2023-04-02 22:42:59 +08:00
|
|
|
generate!("highlighter_t")
|
|
|
|
|
2023-01-16 11:52:08 +08:00
|
|
|
generate!("proc_wait_any")
|
|
|
|
|
|
|
|
generate!("output_stream_t")
|
|
|
|
generate!("io_streams_t")
|
2023-05-21 11:04:26 +08:00
|
|
|
generate!("make_null_io_streams_ffi")
|
2023-06-20 10:28:35 +08:00
|
|
|
generate!("make_test_io_streams_ffi")
|
|
|
|
generate!("get_test_output_ffi")
|
2023-01-16 11:52:08 +08:00
|
|
|
|
|
|
|
generate_pod!("RustFFIJobList")
|
|
|
|
generate_pod!("RustFFIProcList")
|
|
|
|
generate_pod!("RustBuiltin")
|
|
|
|
|
2023-02-25 04:14:13 +08:00
|
|
|
generate!("builtin_exists")
|
2023-01-16 11:52:08 +08:00
|
|
|
generate!("builtin_missing_argument")
|
|
|
|
generate!("builtin_unknown_option")
|
|
|
|
generate!("builtin_print_help")
|
2023-02-19 00:13:58 +08:00
|
|
|
generate!("builtin_print_error_trailer")
|
2023-04-16 17:29:26 +08:00
|
|
|
generate!("builtin_get_names_ffi")
|
2023-01-16 11:52:08 +08:00
|
|
|
|
Port AST to Rust
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
2023-04-02 22:42:59 +08:00
|
|
|
generate!("pretty_printer_t")
|
|
|
|
|
2023-02-11 23:51:43 +08:00
|
|
|
generate!("escape_string")
|
2023-02-18 09:21:44 +08:00
|
|
|
|
|
|
|
generate!("fd_event_signaller_t")
|
2023-02-24 23:55:49 +08:00
|
|
|
|
2023-02-12 04:31:08 +08:00
|
|
|
generate!("block_t")
|
|
|
|
generate!("block_type_t")
|
|
|
|
generate!("statuses_t")
|
|
|
|
generate!("io_chain_t")
|
|
|
|
|
2023-03-01 13:05:27 +08:00
|
|
|
generate!("env_var_t")
|
2023-04-11 00:27:35 +08:00
|
|
|
|
2023-06-17 05:38:08 +08:00
|
|
|
generate!("exec_subshell_ffi")
|
|
|
|
|
2023-05-29 07:49:20 +08:00
|
|
|
generate!("rgb_color_t")
|
|
|
|
generate_pod!("color24_t")
|
2023-04-11 01:49:50 +08:00
|
|
|
generate!("colorize_shell")
|
2023-04-30 10:58:51 +08:00
|
|
|
generate!("reader_status_count")
|
|
|
|
|
|
|
|
generate!("get_history_variable_text_ffi")
|
2023-05-17 09:51:34 +08:00
|
|
|
|
|
|
|
generate!("is_interactive_session")
|
|
|
|
generate!("set_interactive_session")
|
|
|
|
generate!("screen_set_midnight_commander_hack")
|
|
|
|
generate!("screen_clear_layout_cache_ffi")
|
2023-06-20 10:28:35 +08:00
|
|
|
generate!("escape_code_length_ffi")
|
2023-05-17 09:51:34 +08:00
|
|
|
generate!("reader_schedule_prompt_repaint")
|
|
|
|
generate!("reader_change_history")
|
|
|
|
generate!("history_session_id")
|
|
|
|
generate!("reader_change_cursor_selection_mode")
|
|
|
|
generate!("reader_set_autosuggestion_enabled_ffi")
|
|
|
|
generate!("complete_invalidate_path")
|
2023-05-15 02:40:18 +08:00
|
|
|
generate!("complete_add_wrapper")
|
2023-05-17 09:51:34 +08:00
|
|
|
generate!("update_wait_on_escape_ms_ffi")
|
2023-08-31 05:12:22 +08:00
|
|
|
generate!("update_wait_on_sequence_key_ms_ffi")
|
2023-05-14 12:05:39 +08:00
|
|
|
generate!("autoload_t")
|
|
|
|
generate!("make_autoload_ffi")
|
|
|
|
generate!("perform_autoload_ffi")
|
|
|
|
generate!("complete_get_wrap_targets_ffi")
|
2023-08-13 02:35:16 +08:00
|
|
|
|
|
|
|
generate!("is_thompson_shell_script")
|
2023-01-16 11:52:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl parser_t {
|
2023-03-14 10:23:31 +08:00
|
|
|
pub fn get_wait_handles_mut(&mut self) -> &mut WaitHandleStore {
|
|
|
|
let ptr = self.get_wait_handles_void() as *mut Box<WaitHandleStoreFFI>;
|
|
|
|
assert!(!ptr.is_null());
|
|
|
|
unsafe { (*ptr).from_ffi_mut() }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_wait_handles(&self) -> &WaitHandleStore {
|
|
|
|
let ptr = self.get_wait_handles_void() as *const Box<WaitHandleStoreFFI>;
|
|
|
|
assert!(!ptr.is_null());
|
|
|
|
unsafe { (*ptr).from_ffi() }
|
|
|
|
}
|
|
|
|
|
2023-02-12 04:31:08 +08:00
|
|
|
pub fn get_block_at_index(&self, i: usize) -> Option<&block_t> {
|
|
|
|
let b = self.block_at_index(i);
|
|
|
|
unsafe { b.as_ref() }
|
|
|
|
}
|
|
|
|
|
2023-01-16 11:52:08 +08:00
|
|
|
pub fn get_jobs(&self) -> &[SharedPtr<job_t>] {
|
|
|
|
let ffi_jobs = self.ffi_jobs();
|
|
|
|
unsafe { slice::from_raw_parts(ffi_jobs.jobs, ffi_jobs.count) }
|
|
|
|
}
|
2023-02-12 01:15:27 +08:00
|
|
|
|
|
|
|
pub fn libdata_pod(&mut self) -> &mut library_data_pod_t {
|
|
|
|
let libdata = self.pin().ffi_libdata_pod();
|
|
|
|
|
|
|
|
unsafe { &mut *libdata }
|
|
|
|
}
|
2023-02-25 00:00:05 +08:00
|
|
|
|
|
|
|
pub fn remove_var(&mut self, var: &wstr, flags: c_int) -> c_int {
|
|
|
|
self.pin().remove_var_ffi(&var.to_ffi(), flags)
|
|
|
|
}
|
2023-02-12 04:31:08 +08:00
|
|
|
|
|
|
|
pub fn job_get_from_pid(&self, pid: pid_t) -> Option<&job_t> {
|
|
|
|
let job = self.ffi_job_get_from_pid(pid.into());
|
|
|
|
unsafe { job.as_ref() }
|
|
|
|
}
|
2023-03-19 11:11:18 +08:00
|
|
|
|
2023-06-20 03:03:46 +08:00
|
|
|
pub fn get_vars(&mut self) -> EnvStackRef {
|
|
|
|
self.pin().vars().from_ffi()
|
2023-03-19 11:11:18 +08:00
|
|
|
}
|
2023-06-17 05:38:08 +08:00
|
|
|
|
|
|
|
pub fn get_func_name(&mut self, level: i32) -> Option<WString> {
|
|
|
|
let name = self.pin().get_function_name_ffi(c_int(level));
|
|
|
|
name.as_ref()
|
|
|
|
.map(|s| s.from_ffi())
|
|
|
|
.filter(|s| !s.is_empty())
|
|
|
|
}
|
2023-03-19 11:11:18 +08:00
|
|
|
}
|
|
|
|
|
2023-04-30 10:58:51 +08:00
|
|
|
unsafe impl Send for env_universal_t {}
|
|
|
|
|
2023-06-20 03:03:46 +08:00
|
|
|
impl env_stack_t {
|
|
|
|
/// Access the underlying Rust environment stack.
|
|
|
|
#[allow(clippy::borrowed_box)]
|
|
|
|
pub fn from_ffi(&self) -> EnvStackRef {
|
|
|
|
// Safety: get_impl_ffi returns a pointer to a Box<EnvStackRefFFI>.
|
|
|
|
let envref = self.get_impl_ffi();
|
|
|
|
assert!(!envref.is_null());
|
|
|
|
let env: &Box<EnvStackRefFFI> = unsafe { &*(envref.cast()) };
|
|
|
|
env.0.clone()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-19 11:11:18 +08:00
|
|
|
impl environment_t {
|
|
|
|
/// Helper to get a variable as a string, using the default flags.
|
|
|
|
pub fn get_as_string(&self, name: &wstr) -> Option<WString> {
|
2023-08-06 08:00:16 +08:00
|
|
|
self.get_as_string_flags(name, EnvMode::default())
|
2023-03-19 11:11:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper to get a variable as a string, using the given flags.
|
|
|
|
pub fn get_as_string_flags(&self, name: &wstr, flags: EnvMode) -> Option<WString> {
|
|
|
|
self.get_or_null(&name.to_ffi(), flags.bits())
|
|
|
|
.as_ref()
|
|
|
|
.map(|s| s.as_string().from_ffi())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl env_stack_t {
|
|
|
|
/// Helper to get a variable as a string, using the default flags.
|
|
|
|
pub fn get_as_string(&self, name: &wstr) -> Option<WString> {
|
2023-08-06 08:00:16 +08:00
|
|
|
self.get_as_string_flags(name, EnvMode::default())
|
2023-03-19 11:11:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper to get a variable as a string, using the given flags.
|
|
|
|
pub fn get_as_string_flags(&self, name: &wstr, flags: EnvMode) -> Option<WString> {
|
|
|
|
self.get_or_null(&name.to_ffi(), flags.bits())
|
|
|
|
.as_ref()
|
|
|
|
.map(|s| s.as_string().from_ffi())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper to set a value.
|
2023-06-17 05:38:08 +08:00
|
|
|
pub fn set_var<T: AsRef<wstr>, U: AsRef<wstr>>(
|
|
|
|
&mut self,
|
|
|
|
name: T,
|
|
|
|
value: &[U],
|
|
|
|
flags: EnvMode,
|
|
|
|
) -> libc::c_int {
|
2023-03-19 11:11:18 +08:00
|
|
|
use crate::wchar_ffi::{wstr_to_u32string, W0String};
|
|
|
|
let strings: Vec<W0String> = value.iter().map(wstr_to_u32string).collect();
|
|
|
|
let ptrs: Vec<*const u32> = strings.iter().map(|s| s.as_ptr()).collect();
|
|
|
|
self.pin()
|
|
|
|
.set_ffi(
|
2023-06-17 05:38:08 +08:00
|
|
|
&name.as_ref().to_ffi(),
|
2023-03-19 11:11:18 +08:00
|
|
|
flags.bits(),
|
|
|
|
ptrs.as_ptr() as *const c_void,
|
|
|
|
ptrs.len(),
|
|
|
|
)
|
|
|
|
.into()
|
|
|
|
}
|
2023-01-16 11:52:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl job_t {
|
2023-02-06 04:52:21 +08:00
|
|
|
#[allow(clippy::mut_from_ref)]
|
2023-01-16 11:52:08 +08:00
|
|
|
pub fn get_procs(&self) -> &mut [UniquePtr<process_t>] {
|
|
|
|
let ffi_procs = self.ffi_processes();
|
|
|
|
unsafe { slice::from_raw_parts_mut(ffi_procs.procs, ffi_procs.count) }
|
|
|
|
}
|
2023-08-13 02:35:16 +08:00
|
|
|
|
|
|
|
pub fn get_job_group(&self) -> &JobGroup {
|
|
|
|
unsafe { ::std::mem::transmute::<&job_group_t, &JobGroup>(self.ffi_group()) }
|
|
|
|
}
|
2023-01-15 06:56:24 +08:00
|
|
|
}
|
|
|
|
|
2023-03-14 10:23:31 +08:00
|
|
|
impl process_t {
|
|
|
|
/// \return the wait handle for the process, if it exists.
|
|
|
|
pub fn get_wait_handle(&self) -> Option<WaitHandleRef> {
|
|
|
|
let handle_ptr = self.get_wait_handle_void() as *const Box<WaitHandleRefFFI>;
|
|
|
|
if handle_ptr.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let handle: &WaitHandleRefFFI = unsafe { &*handle_ptr };
|
|
|
|
Some(handle.from_ffi().clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \return the wait handle for the process, creating it if necessary.
|
|
|
|
pub fn make_wait_handle(&mut self, jid: u64) -> Option<WaitHandleRef> {
|
|
|
|
let handle_ref = self.pin().make_wait_handle_void(jid) as *const Box<WaitHandleRefFFI>;
|
|
|
|
if handle_ref.is_null() {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
let handle: &WaitHandleRefFFI = unsafe { &*handle_ref };
|
|
|
|
Some(handle.from_ffi().clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-15 06:56:24 +08:00
|
|
|
/// Allow wcharz_t to be "into" wstr.
|
2023-08-09 06:16:04 +08:00
|
|
|
impl From<wcharz_t> for &wstr {
|
2023-01-15 06:56:24 +08:00
|
|
|
fn from(w: wcharz_t) -> Self {
|
|
|
|
let len = w.length();
|
2023-08-06 08:00:16 +08:00
|
|
|
#[allow(clippy::unnecessary_cast)]
|
2023-01-15 06:56:24 +08:00
|
|
|
let v = unsafe { slice::from_raw_parts(w.str_ as *const u32, len) };
|
2023-08-09 06:16:04 +08:00
|
|
|
wstr::from_slice(v).expect("Invalid UTF-32")
|
2023-01-15 06:56:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allow wcharz_t to be "into" WString.
|
2023-08-09 06:16:04 +08:00
|
|
|
impl From<wcharz_t> for WString {
|
2023-01-15 06:56:24 +08:00
|
|
|
fn from(w: wcharz_t) -> Self {
|
2023-08-09 06:16:04 +08:00
|
|
|
let w: &wstr = w.into();
|
2023-08-06 08:00:16 +08:00
|
|
|
w.to_owned()
|
2023-01-15 06:56:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 11:52:08 +08:00
|
|
|
/// A bogus trait for turning &mut Foo into Pin<&mut Foo>.
|
|
|
|
/// autocxx enforces that non-const methods must be called through Pin,
|
|
|
|
/// but this means we can't pass around mutable references to types like parser_t.
|
|
|
|
/// We also don't want to assert that parser_t is Unpin.
|
|
|
|
/// So we just allow constructing a pin from a mutable reference; none of the C++ code.
|
|
|
|
/// It's worth considering disabling this in cxx; for now we use this trait.
|
|
|
|
/// Eventually parser_t and io_streams_t will not require Pin so we just unsafe-it away.
|
|
|
|
pub trait Repin {
|
|
|
|
fn pin(&mut self) -> Pin<&mut Self> {
|
|
|
|
unsafe { Pin::new_unchecked(self) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn unpin(self: Pin<&mut Self>) -> &mut Self {
|
|
|
|
unsafe { self.get_unchecked_mut() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implement Repin for our types.
|
2023-05-14 12:05:39 +08:00
|
|
|
impl Repin for autoload_t {}
|
2023-02-25 03:21:27 +08:00
|
|
|
impl Repin for block_t {}
|
2023-02-24 23:55:49 +08:00
|
|
|
impl Repin for env_stack_t {}
|
2023-04-30 10:58:51 +08:00
|
|
|
impl Repin for env_universal_t {}
|
2023-01-16 11:52:08 +08:00
|
|
|
impl Repin for io_streams_t {}
|
2023-02-25 07:44:20 +08:00
|
|
|
impl Repin for job_t {}
|
2023-01-16 11:52:08 +08:00
|
|
|
impl Repin for output_stream_t {}
|
2023-02-25 07:44:20 +08:00
|
|
|
impl Repin for parser_t {}
|
|
|
|
impl Repin for process_t {}
|
2023-04-17 04:17:57 +08:00
|
|
|
impl Repin for wcstring_list_ffi_t {}
|
2023-01-16 11:52:08 +08:00
|
|
|
|
2023-01-15 06:56:24 +08:00
|
|
|
pub use autocxx::c_int;
|
|
|
|
pub use ffi::*;
|
|
|
|
pub use libc::c_char;
|
2023-02-18 09:21:44 +08:00
|
|
|
|
|
|
|
/// A version of [`* const core::ffi::c_void`] (or [`* const libc::c_void`], if you prefer) that
|
|
|
|
/// implements `Copy` and `Clone`, because those two don't. Used to represent a `void *` ptr for ffi
|
|
|
|
/// purposes.
|
|
|
|
#[repr(transparent)]
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
pub struct void_ptr(pub *const core::ffi::c_void);
|
|
|
|
|
|
|
|
impl core::fmt::Debug for void_ptr {
|
|
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
|
|
write!(f, "{:p}", &self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for void_ptr {}
|
|
|
|
unsafe impl Sync for void_ptr {}
|
2023-02-19 02:52:58 +08:00
|
|
|
|
|
|
|
impl core::convert::From<*const core::ffi::c_void> for void_ptr {
|
|
|
|
fn from(value: *const core::ffi::c_void) -> Self {
|
|
|
|
Self(value as *const _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::convert::From<*const u8> for void_ptr {
|
|
|
|
fn from(value: *const u8) -> Self {
|
|
|
|
Self(value as *const _)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::convert::From<*const autocxx::c_void> for void_ptr {
|
|
|
|
fn from(value: *const autocxx::c_void) -> Self {
|
|
|
|
Self(value as *const _)
|
|
|
|
}
|
|
|
|
}
|
2023-04-26 23:29:38 +08:00
|
|
|
|
|
|
|
impl core::convert::From<void_ptr> for *const u8 {
|
|
|
|
fn from(value: void_ptr) -> Self {
|
|
|
|
value.0 as *const _
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::convert::From<void_ptr> for *const core::ffi::c_void {
|
|
|
|
fn from(value: void_ptr) -> Self {
|
|
|
|
value.0 as *const _
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl core::convert::From<void_ptr> for *const autocxx::c_void {
|
|
|
|
fn from(value: void_ptr) -> Self {
|
|
|
|
value.0 as *const _
|
|
|
|
}
|
|
|
|
}
|
2023-06-28 01:05:55 +08:00
|
|
|
|
2023-07-02 06:11:40 +08:00
|
|
|
impl TryFrom<&wstr> for job_control_t {
|
2023-06-28 01:05:55 +08:00
|
|
|
type Error = ();
|
|
|
|
|
2023-07-02 06:11:40 +08:00
|
|
|
fn try_from(value: &wstr) -> Result<Self, Self::Error> {
|
|
|
|
if value == "full" {
|
|
|
|
Ok(job_control_t::all)
|
|
|
|
} else if value == "interactive" {
|
|
|
|
Ok(job_control_t::interactive)
|
|
|
|
} else if value == "none" {
|
|
|
|
Ok(job_control_t::none)
|
|
|
|
} else {
|
|
|
|
Err(())
|
2023-06-28 01:05:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|