pub mod async_md_api;
pub mod async_trader_api;
pub mod md_api;
pub mod trader_api;
pub use async_md_api::AsyncMdApi;
pub use async_trader_api::AsyncTraderApi;
pub use md_api::{MdApi, MdSpiHandler};
pub use trader_api::{TraderApi, TraderSpiHandler};
use crate::error::{CtpError, CtpResult};
use std::ffi::CString;
pub trait CtpApi {
fn get_version() -> CtpResult<String>;
fn init(&mut self) -> CtpResult<()>;
fn release(&mut self);
fn get_trading_day(&self) -> CtpResult<String>;
fn register_front(&mut self, front_address: &str) -> CtpResult<()>;
fn join(&self) -> CtpResult<i32>;
}
pub(crate) fn to_cstring(s: &str) -> CtpResult<CString> {
CString::new(s).map_err(|e| CtpError::InvalidParameterError(format!("字符串转换失败: {}", e)))
}
#[allow(dead_code)]
pub(crate) fn check_null_ptr<T>(ptr: *const T, name: &str) -> CtpResult<()> {
if ptr.is_null() {
return Err(CtpError::FfiError(format!("{} 指针为空", name)));
}
Ok(())
}
pub(crate) fn safe_cstr_to_string(ptr: *const i8) -> CtpResult<String> {
if ptr.is_null() {
return Ok(String::new());
}
unsafe { crate::encoding::GbkConverter::cstring_to_utf8(ptr) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_cstring() {
let result = to_cstring("test");
assert!(result.is_ok());
let result = to_cstring("测试");
assert!(result.is_ok());
}
#[test]
fn test_check_null_ptr() {
let ptr: *const i32 = std::ptr::null();
assert!(check_null_ptr(ptr, "test").is_err());
let value = 42i32;
let ptr = &value as *const i32;
assert!(check_null_ptr(ptr, "test").is_ok());
}
}