rust连接ctp的数据交互处理
生成绑定
rust调用ctp的步骤:
- 利用python自动生成
wrapper.cpp和wrapper.hpp文件; - 用rust的bindgen 生成rust可调用的接口;
- 引入生成后的文件,引入的方式有两种:
pub use crate::ctp::generated::*;导入和
include!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/ctp/generated/mod.rs"
));include 模式,vscode代码导航只能到引入的文件,所以本人更推荐用use的形式ctp生成rust绑定可以参考这个开源项目:ctp-rs
c的char类型与rust的i8类型
ctp头文件中所有定义为char类型的,通过rust的bindgen将自动转为i8类型,比如下图的登录参数中的MacAddress在CTP头文件定义为char的21个字节定长类型,转为rust则变成[i8;21]定长数组:


rust 调用ctp时定长数据的处理
rust与ctp进行交互比较不好处理的是大量参数必须转换成[i8;N]定长数组类型。
在rust中,字符串转bytes后就是 &[u8]类型,通过map就可以很容易就转成 Vec<i8>类型:
let b: Vec<i8> = "Hello, world!"
.as_bytes()
.iter()
.map(|x| *x as i8)
.collect();Vec<i8>类型作为引用参数传入时,系统将自动转换为&[i8]类型。如下代码:
fn main() {
let b: Vec<i8> = "Hello, world!"
.as_bytes()
.iter()
.map(|x| *x as i8)
.collect();
print_sice(&b)
}
fn print_sice(s: &[i8]) {
println!("{:?}", s)
}输出:
================ STANDARD OUTPUT ================
[72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]因此不管是[u8]还是[i8],slice类型的数据都很容易转换获得。但是如果大量的定长数组就比较不好处理。有人可能觉得写一个方法将 String转[i8;N]即可。要知道在rust中[i8;1],[i8;2]...[i8;N]都是不同的类型。因此必须实现一个 String -> [i8;N]的转换函数。在rust1.51之前基本不可能实现这个功能,除非你从String->[i8;1]到String->[i8;N]每个手写一遍。rust的Default::default()看提示应该是用宏实现了数组,数组的最大长度为32(截止rustc 1.57.0),不信试试let b: [i8; 33] = Default::default();:
rust1.51的版本引入了很重要的一个特性:const泛型,相关的知识点可以通过Rust语言圣经了解:const泛型
下列给出&str -> [i8;N]的转换函数:
/// 将给定的字符串转换为定长的cstr
/// 注意:如果长度超过将被截断,不足部分用`�`补足
pub fn str_to_cstr<const N: usize>(text: &str) -> [i8; N] {
if N < 1 {
panic!("数组长度必须大于0!")
}
let buffer = &mut [0u8; N];
for (place, data) in buffer[..N - 1].iter_mut().zip(text.as_bytes().iter()) {
*place = *data;
}
let d: Vec<i8> = (*buffer).iter().map(|x| *x as i8).collect();
let mut arr: [i8; N] = [0i8; N];
arr.copy_from_slice(&d);
arr
}Example:
// "password" -> [i8;41]
let cs = to_cstr::<41>("password");
println!("{:?}",cs);其中 to_cstr::<41>尖括号中的数字代表转换后的数组长度
ctp返回数据处理
rust默认采用的是utf-8字符,特别对于非windows平台一般不使用gbk相关的字符集。
但是,ctp返回的是gbk字符集,如果不进行处理,将出现乱码。下列提供rust版本的gbk->utf-8
use encoding::{all::GB18030, DecoderTrap, Encoding};
/// ctp发送过来的中文信息是gbk格式的,这里需要转换为utf-8格式
/// rust的字符串是存储为`[u8]`格式,但是ctp包装后,接口过来的数据是 `[i8]`格式,因此
/// 在数据转换之前需先将 `[u8]`转为`[i8]`
/// 如果数据转换错误,将直接返回 `""` 空字符串`String`
pub fn gbk_cstr_to_str(v: &[i8]) -> String {
let vi: Vec<u8> = v.iter().map(|x| *x as u8).collect();
let slice = vi.split(|c| *c == 0u8).next().unwrap();
if slice.is_ascii() {
unsafe {
return std::str::from_utf8_unchecked(slice).to_owned();
};
}
match GB18030.decode(slice, DecoderTrap::Replace) {
Ok(s) => s,
Err(e) => {
log::error!("GBK转UTF-8错误:{}", e.to_string());
return "".to_owned();
}
}
}调用方法前须先引入依赖包
[dependencies]
encoding = "0.2"
说点什么
博主