Consolidate for_each implementation into Rust

This commit is contained in:
topjohnwu
2025-08-24 15:13:56 -07:00
committed by John Wu
parent 78f5cd55c7
commit e91fc75d86
12 changed files with 103 additions and 103 deletions

View File

@@ -1,15 +1,20 @@
// Functions in this file are only for exporting to C++, DO NOT USE IN RUST
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
use std::fs::File;
use std::io::BufReader;
use std::mem::ManuallyDrop;
use std::ops::DerefMut;
use std::os::fd::{BorrowedFd, FromRawFd, OwnedFd, RawFd};
use cfg_if::cfg_if;
use libc::{c_char, mode_t};
use libc::{O_RDONLY, c_char, mode_t};
use crate::ffi::{FnBoolStrStr, FnBoolString};
use crate::files::map_file_at;
pub(crate) use crate::xwrap::*;
use crate::{
CxxResultExt, Directory, OsResultStatic, Utf8CStr, clone_attr, cstr, fclone_attr, fd_path,
map_fd, map_file, slice_from_ptr,
BufReadExt, CxxResultExt, Directory, OsResultStatic, Utf8CStr, clone_attr, cstr, fclone_attr,
fd_path, map_fd, map_file, slice_from_ptr,
};
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
@@ -178,3 +183,14 @@ unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
this.len()
}
pub(crate) fn parse_prop_file_rs(name: &Utf8CStr, f: &FnBoolStrStr) {
if let Ok(file) = name.open(O_RDONLY) {
BufReader::new(file).for_each_prop(|key, value| f.call(key, value))
}
}
pub(crate) fn file_readline_rs(fd: RawFd, f: &FnBoolString) {
let mut fd = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
BufReader::new(fd.deref_mut()).for_each_line(|line| f.call(line));
}

View File

@@ -8,15 +8,6 @@
using namespace std;
int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
if (fd_path(dirfd, byte_data(path, size)) < 0)
return -1;
auto len = strlen(path);
path[len] = '/';
strscpy(path + len + 1, name, size - len - 1);
return 0;
}
void full_read(int fd, string &str) {
char buf[4096];
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)
@@ -52,53 +43,6 @@ void write_zero(int fd, size_t size) {
}
}
void file_readline(bool trim, FILE *fp, const function<bool(string_view)> &fn) {
size_t len = 1024;
char *buf = (char *) malloc(len);
char *start;
ssize_t read;
while ((read = getline(&buf, &len, fp)) >= 0) {
start = buf;
if (trim) {
while (read && "\n\r "sv.find(buf[read - 1]) != string::npos)
--read;
buf[read] = '\0';
while (*start == ' ')
++start;
}
if (!fn(start))
break;
}
free(buf);
}
void file_readline(bool trim, const char *file, const function<bool(string_view)> &fn) {
if (auto fp = open_file(file, "re"))
file_readline(trim, fp.get(), fn);
}
void file_readline(const char *file, const function<bool(string_view)> &fn) {
file_readline(false, file, fn);
}
void parse_prop_file(FILE *fp, const function<bool(string_view, string_view)> &fn) {
file_readline(true, fp, [&](string_view line_view) -> bool {
char *line = (char *) line_view.data();
if (line[0] == '#')
return true;
char *eql = strchr(line, '=');
if (eql == nullptr || eql == line)
return true;
*eql = '\0';
return fn(line, eql + 1);
});
}
void parse_prop_file(const char *file, const function<bool(string_view, string_view)> &fn) {
if (auto fp = open_file(file, "re"))
parse_prop_file(fp.get(), fn);
}
sDIR make_dir(DIR *dp) {
return sDIR(dp, [](DIR *dp){ return dp ? closedir(dp) : 1; });
}

View File

@@ -45,7 +45,6 @@ bool fclone_attr(int src, int dest);
} // extern "C"
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
static inline ssize_t realpath(
const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz) {
return canonical_path(path, buf, bufsiz);
@@ -55,14 +54,27 @@ void full_read(const char *filename, std::string &str);
std::string full_read(int fd);
std::string full_read(const char *filename);
void write_zero(int fd, size_t size);
void file_readline(bool trim, FILE *fp, const std::function<bool(std::string_view)> &fn);
void file_readline(bool trim, const char *file, const std::function<bool(std::string_view)> &fn);
void file_readline(const char *file, const std::function<bool(std::string_view)> &fn);
void parse_prop_file(FILE *fp, const std::function<bool(std::string_view, std::string_view)> &fn);
void parse_prop_file(const char *file,
const std::function<bool(std::string_view, std::string_view)> &fn);
std::string resolve_preinit_dir(const char *base_dir);
// Functor = function<bool(string_view)>
template <typename Functor>
void file_readline(int fd, Functor &&fn) {
file_readline_rs(fd, [&](rust::String &line) -> bool {
return fn(std::string_view(line.c_str(), line.size()));
});
}
// Functor = function<bool(string_view, string_view)>
template <typename Functor>
void parse_prop_file(const char *file, Functor &&fn) {
parse_prop_file_rs(file, [&](rust::Str key, rust::Str val) -> bool {
// Null terminate all strings
*(const_cast<char *>(key.data()) + key.size()) = '\0';
*(const_cast<char *>(val.data()) + val.size()) = '\0';
return fn(std::string_view(key.data(), key.size()), std::string_view(val.data(), val.size()));
});
}
using sFILE = std::unique_ptr<FILE, decltype(&fclose)>;
using sDIR = std::unique_ptr<DIR, decltype(&closedir)>;
sDIR make_dir(DIR *dp);

View File

@@ -57,12 +57,12 @@ impl<T: Read + Seek> ReadSeekExt for T {
}
pub trait BufReadExt {
fn foreach_lines<F: FnMut(&mut String) -> bool>(&mut self, f: F);
fn foreach_props<F: FnMut(&str, &str) -> bool>(&mut self, f: F);
fn for_each_line<F: FnMut(&mut String) -> bool>(&mut self, f: F);
fn for_each_prop<F: FnMut(&str, &str) -> bool>(&mut self, f: F);
}
impl<T: BufRead> BufReadExt for T {
fn foreach_lines<F: FnMut(&mut String) -> bool>(&mut self, mut f: F) {
fn for_each_line<F: FnMut(&mut String) -> bool>(&mut self, mut f: F) {
let mut buf = String::new();
loop {
match self.read_line(&mut buf) {
@@ -81,8 +81,11 @@ impl<T: BufRead> BufReadExt for T {
}
}
fn foreach_props<F: FnMut(&str, &str) -> bool>(&mut self, mut f: F) {
self.foreach_lines(|line| {
fn for_each_prop<F: FnMut(&str, &str) -> bool>(&mut self, mut f: F) {
self.for_each_line(|line| {
// Reserve an additional byte, because this string will be manually
// null terminated on the C++ side, and it may need more space.
line.reserve(1);
let line = line.trim();
if line.starts_with('#') {
return true;
@@ -874,7 +877,7 @@ pub fn parse_mount_info(pid: &str) -> Vec<MountInfo> {
let mut res = vec![];
let mut path = format!("/proc/{pid}/mountinfo");
if let Ok(file) = Utf8CStr::from_string(&mut path).open(O_RDONLY | O_CLOEXEC) {
BufReader::new(file).foreach_lines(|line| {
BufReader::new(file).for_each_line(|line| {
parse_mount_info_line(line)
.map(|info| res.push(info))
.is_some()

View File

@@ -47,6 +47,12 @@ pub mod ffi {
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
fn fork_dont_care() -> i32;
type FnBoolStrStr;
fn call(self: &FnBoolStrStr, key: &str, value: &str) -> bool;
type FnBoolString;
fn call(self: &FnBoolString, key: &mut String) -> bool;
}
extern "Rust" {
@@ -56,6 +62,8 @@ pub mod ffi {
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
fn exit_on_error(b: bool);
fn cmdline_logging();
fn parse_prop_file_rs(name: Utf8CStrRef, f: &FnBoolStrStr);
fn file_readline_rs(fd: i32, f: &FnBoolString);
}
#[namespace = "rust"]

View File

@@ -283,7 +283,8 @@ struct Utf8CStr {
const char *c_str() const { return this->data(); }
size_t size() const { return this->length(); }
bool empty() const { return this->length() == 0 ; }
operator std::string_view() { return {data(), length()}; }
operator std::string_view() const { return {data(), length()}; }
bool operator==(std::string_view rhs) const { return std::string_view{data(), length()} == rhs; }
private:
#pragma clang diagnostic push
@@ -293,3 +294,18 @@ private:
};
} // namespace rust
// Bindings for std::function to be callable from Rust
struct FnBoolStrStr : public std::function<bool(rust::Str, rust::Str)> {
using std::function<bool(rust::Str, rust::Str)>::function;
bool call(rust::Str a, rust::Str b) const {
return operator()(a, b);
}
};
struct FnBoolString : public std::function<bool(rust::String&)> {
using std::function<bool(rust::String&)>::function;
bool call(rust::String &s) const {
return operator()(s);
}
};