ctp_dyn/
ffi.rs

1use std::ptr;
2
3use encoding_rs::GB18030;
4use std::borrow::Cow;
5
6pub fn copy_str_to_i8_array(dst: &mut [i8], src: &str) {
7    // 确保目标数组至少有一个元素用于放置 '\0'
8    if dst.is_empty() {
9        return;
10    }
11
12    // 获取源字符串的字节表示
13    let bytes = src.as_bytes();
14
15    // 计算要复制的长度,取源字符串长度和目标缓冲区长度减一的最小值
16    let len = usize::min(bytes.len(), dst.len() - 1);
17
18    unsafe {
19        ptr::copy_nonoverlapping(bytes.as_ptr(), dst.as_mut_ptr() as *mut u8, len);
20    }
21
22    // 使用 '\0' 截断
23    dst[len] = 0;
24
25    // 如果目标缓冲区比源字符串长,则剩余部分保持未初始化或保持原值。
26}
27
28#[macro_export]
29macro_rules! print_rsp_info {
30    ($p:expr) => {
31        if let Some(p) = $p {
32            println!(
33                "ErrorID[{}] Message[{}]",
34                p.ErrorID,
35                gb18030_cstr_i8_to_str(&p.ErrorMsg).unwrap().to_string()
36            );
37        }
38    };
39}
40
41/// 将 `&[std::os::raw::c_char]` 转换为 `Cow<str>`
42/// - 如果输入为 ASCII,返回 `Cow::Borrowed`。
43/// - 如果输入为 GB18030,解码后返回 `Cow::Owned`。
44/// - 如果解码失败,返回 `Err`。
45pub fn gb18030_cstr_i8_to_str<'a>(
46    c_chars: &'a [std::os::raw::c_char],
47) -> Result<Cow<'a, str>, String> {
48    // 找到 '\0' 的位置以截断
49    let len = c_chars
50        .iter()
51        .position(|&c| c == 0)
52        .unwrap_or(c_chars.len());
53    let bytes = &c_chars[..len];
54
55    // 转换为 &[u8]
56    let bytes = unsafe { &*(bytes as *const [std::os::raw::c_char] as *const [u8]) };
57
58    // 快速路径:检测是否是 ASCII
59    if bytes.is_ascii() {
60        return std::str::from_utf8(bytes)
61            .map(Cow::Borrowed)
62            .map_err(|e| format!("Invalid UTF-8: {}", e));
63    }
64
65    // 非 ASCII 的情况:使用 GB18030 解码
66    let (decoded, _, had_errors) = GB18030.decode(bytes);
67    if had_errors {
68        return Err("Failed to decode GB18030 string".to_string());
69    }
70
71    Ok(Cow::Owned(decoded.into_owned()))
72}
73
74pub trait AssignFromString {
75    /// 将 `&str` 的内容写入到 `[i8; N]` 数组中
76    /// 超出数组大小的部分将被截断,未被覆盖的部分保留原值或清零。
77    fn assign_from_str(&mut self, s: &str);
78}
79
80impl<const N: usize> AssignFromString for [i8; N] {
81    fn assign_from_str(&mut self, s: &str) {
82        copy_str_to_i8_array(self, s);
83    }
84}
85
86impl<const N: usize> AssignFromString for &mut [i8; N] {
87    fn assign_from_str(&mut self, s: &str) {
88        copy_str_to_i8_array(*self, s);
89    }
90}
91
92pub trait SetString {
93    /// 将 `&str` 的内容写入到 `[i8; N]` 数组中
94    /// 超出数组大小的部分将被截断,未被覆盖的部分保留原值或清零。
95    fn set_str(&mut self, s: &str);
96}
97
98impl<const N: usize> SetString for [i8; N] {
99    fn set_str(&mut self, s: &str) {
100        copy_str_to_i8_array(self, s);
101    }
102}
103
104impl<const N: usize> SetString for &mut [i8; N] {
105    fn set_str(&mut self, s: &str) {
106        copy_str_to_i8_array(*self, s);
107    }
108}
109
110pub trait WrapToString {
111    fn to_string(&self) -> String;
112}
113
114impl<const N: usize> WrapToString for [i8; N] {
115    fn to_string(&self) -> String {
116        let str_ = gb18030_cstr_i8_to_str(self);
117        str_.unwrap().to_string()
118    }
119}
120
121impl<const N: usize> WrapToString for &[i8; N] {
122    fn to_string(&self) -> String {
123        let str_ = gb18030_cstr_i8_to_str(*self);
124        str_.unwrap().to_string()
125    }
126}
127
128#[derive(Debug, Clone)]
129pub struct WrapString(pub String); // 包装 String
130
131impl<const N: usize> From<[i8; N]> for WrapString {
132    fn from(value: [i8; N]) -> Self {
133        let str_ = gb18030_cstr_i8_to_str(&value).expect("failed to decode");
134        WrapString(str_.into())
135    }
136}
137
138impl<const N: usize> From<&[i8; N]> for WrapString {
139    fn from(value: &[i8; N]) -> Self {
140        let str_ = gb18030_cstr_i8_to_str(value).expect("failed to decode");
141        WrapString(str_.into())
142    }
143}
144
145pub trait WrapFrom<T> {
146    fn wrap_from(value: T) -> Self;
147}
148
149// 自定义 MyInto trait
150pub trait WrapInto<T>: Sized {
151    fn wrap_into(self) -> T;
152}
153
154// 为 MyFrom 创建对应的 MyInto 实现
155impl<T, U> WrapInto<U> for T
156where
157    U: WrapFrom<T>,
158{
159    fn wrap_into(self) -> U {
160        U::wrap_from(self)
161    }
162}
163
164impl WrapFrom<&[i8]> for String {
165    fn wrap_from(bytes: &[i8]) -> Self {
166        let u8_bytes: Vec<u8> = bytes.iter().map(|&b| b as u8).collect();
167        String::from_utf8(u8_bytes).expect("Invalid UTF-8 sequence")
168    }
169}
170
171impl<const N: usize> WrapFrom<[i8; N]> for String {
172    fn wrap_from(value: [i8; N]) -> Self {
173        let str_ = gb18030_cstr_i8_to_str(&value).expect("failed to decode");
174        str_.into()
175    }
176}
177
178impl<const N: usize> WrapFrom<&[i8; N]> for String {
179    fn wrap_from(value: &[i8; N]) -> Self {
180        let str_ = gb18030_cstr_i8_to_str(value).expect("failed to decode");
181        str_.into()
182    }
183}