1
0

feat: fix cstr ffi again

This commit is contained in:
2026-05-10 16:55:09 +08:00
parent 1a45b309e7
commit 7d92f9a4a0
2 changed files with 55 additions and 19 deletions

View File

@@ -9,21 +9,44 @@
//! The only thing that outer programs should note is that this string is volatile, //! The only thing that outer programs should note is that this string is volatile,
//! once they get it, they must dupliate it immediately before any futher calling to this dynamic library. //! once they get it, they must dupliate it immediately before any futher calling to this dynamic library.
use std::cell::RefCell; use std::cell::RefCell;
use std::ffi::{CString, CStr, c_char}; use std::ffi::{CStr, CString, c_char};
use thiserror::Error as TeError;
struct StringCache { // region: Error
/// Error occurs in this crate.
#[derive(Debug, TeError)]
pub enum Error {
#[error("unexpected NUL when parsing into C/C++ string")]
UnexpectedNul(#[from] std::ffi::NulError),
#[error("given string pointer is nullptr when parsing from C/C++ string")]
NullPtr,
#[error("invalid UTF8 sequence when parsing from C/C++ string")]
InvalidEncoding(#[from] std::str::Utf8Error),
}
/// Result type used in this crate.
type Result<T> = std::result::Result<T, Error>;
// endregion
// region: FFI String
struct FfiString {
msg: CString, msg: CString,
} }
impl StringCache { impl FfiString {
fn new() -> Self { fn new() -> Self {
Self { Self {
msg: CString::new("").expect("empty string must be valid for CString"), msg: CString::new("").expect("empty string must be valid for CString"),
} }
} }
pub fn set_msg(&mut self, msg: &str) { pub fn set_msg(&mut self, msg: &str) -> Result<()> {
self.msg = CString::new(msg).expect("unexpected blank in string push into string cache"); self.msg = CString::new(msg)?;
Ok(())
} }
pub fn get_msg(&self) -> *const c_char { pub fn get_msg(&self) -> *const c_char {
@@ -35,15 +58,19 @@ impl StringCache {
} }
} }
// endregion
// region: Exposed Functions
thread_local! { thread_local! {
static STRING_CACHE: RefCell<StringCache> = RefCell::new(StringCache::new()); static STRING_CACHE: RefCell<FfiString> = RefCell::new(FfiString::new());
} }
/// Set thread local string exposed for C code. /// Set thread local string exposed for C code.
pub fn set_ffi_string(msg: &str) { pub fn set_ffi_string(msg: &str) -> Result<()> {
STRING_CACHE.with(|e| { STRING_CACHE.with(|e| {
e.borrow_mut().set_msg(msg); e.borrow_mut().set_msg(msg)
}); })
} }
/// Get const pointer to thread local string exposed for C code. /// Get const pointer to thread local string exposed for C code.
@@ -61,6 +88,13 @@ pub fn clear_ffi_string() {
} }
/// Parse string given by C code into Rust string. /// Parse string given by C code into Rust string.
pub fn parse_ffi_string<'a>(ptr: *const c_char) -> &'a CStr { pub fn parse_ffi_string<'a>(ptr: *const c_char) -> Result<&'a str> {
unsafe { CStr::from_ptr(ptr) } if ptr.is_null() {
Err(Error::NullPtr)
} else {
let c_str = unsafe { CStr::from_ptr(ptr) };
Ok(c_str.to_str()?)
} }
}
// endregion

View File

@@ -12,6 +12,9 @@ mod wrapper;
/// Error occurs in this crate. /// Error occurs in this crate.
#[derive(Debug, TeError)] #[derive(Debug, TeError)]
enum Error { enum Error {
/// Error when operating Schema.
#[error("{0}")]
Schema(#[from] wfassoc::highlevel::SchemaError),
/// Error when parsing Schema into Program. /// Error when parsing Schema into Program.
#[error("{0}")] #[error("{0}")]
ParseProgram(#[from] wfassoc::highlevel::ParseProgramError), ParseProgram(#[from] wfassoc::highlevel::ParseProgramError),
@@ -19,10 +22,9 @@ enum Error {
#[error("{0}")] #[error("{0}")]
Program(#[from] wfassoc::highlevel::ProgramError), Program(#[from] wfassoc::highlevel::ProgramError),
#[error("error occurs when parsing into C/C++ string")] /// Error when manipulating with C-style string.
CastIntoCStr(#[from] std::ffi::NulError), #[error("{0}")]
#[error("error occurs when parsing from C/C++ string")] CStrFfi(#[from] cstr_ffi::Error),
CastFromCStr(#[from] std::ffi::IntoStringError),
} }
/// Result type used in this crate. /// Result type used in this crate.
@@ -37,12 +39,12 @@ type Result<T> = std::result::Result<T, Error>;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub extern "C" fn WFStartup() -> bool { pub extern "C" fn WFStartup() -> bool {
false true
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub extern "C" fn WFShutdown() -> bool { pub extern "C" fn WFShutdown() -> bool {
false true
} }
#[unsafe(no_mangle)] #[unsafe(no_mangle)]