use crate::error::{Error, Result};
use std::ffi::{CStr, CString};
pub struct ZoomConnection {
raw: crate::ZOOM_connection,
}
pub struct ZoomResultSet {
raw: crate::ZOOM_resultset,
}
impl ZoomConnection {
pub fn connect(target: &str) -> Result<Self> {
let c_target = CString::new(target)
.map_err(|_| Error::ConnectionError("Invalid target string".into()))?;
unsafe {
let connection = crate::ZOOM_connection_create(std::ptr::null_mut());
if connection.is_null() {
return Err(Error::ConnectionError("Failed to create ZOOM connection".into()));
}
crate::ZOOM_connection_connect(connection, c_target.as_ptr(), 0);
let err_code = crate::ZOOM_connection_errcode(connection);
if err_code != 0 {
let err_msg_ptr = crate::ZOOM_connection_errmsg(connection);
let err_msg = if !err_msg_ptr.is_null() {
CStr::from_ptr(err_msg_ptr).to_string_lossy().to_string()
} else {
format!("ZOOM connection error code: {}", err_code)
};
crate::ZOOM_connection_destroy(connection);
return Err(Error::ConnectionError(err_msg));
}
Ok(Self { raw: connection })
}
}
pub fn option_set(&mut self, key: &str, value: &str) -> Result<()> {
let c_key = CString::new(key).map_err(|_| Error::Other("Invalid option key".into()))?;
let c_value = CString::new(value).map_err(|_| Error::Other("Invalid option value".into()))?;
unsafe {
crate::ZOOM_connection_option_set(self.raw, c_key.as_ptr(), c_value.as_ptr());
}
Ok(())
}
pub fn option_get(&self, key: &str) -> Result<Option<String>> {
let c_key = CString::new(key).map_err(|_| Error::Other("Invalid option key".into()))?;
unsafe {
let ptr = crate::ZOOM_connection_option_get(self.raw, c_key.as_ptr());
if ptr.is_null() {
return Ok(None);
}
Ok(Some(CStr::from_ptr(ptr).to_string_lossy().to_string()))
}
}
pub fn search_pqf(&mut self, pqf: &str) -> Result<ZoomResultSet> {
let c_query = CString::new(pqf)
.map_err(|_| Error::SearchError("Invalid PQF query".into()))?;
unsafe {
let rs = crate::ZOOM_connection_search_pqf(self.raw, c_query.as_ptr());
if rs.is_null() {
return Err(Error::SearchError("Search failed".into()));
}
let err_code = crate::ZOOM_connection_errcode(self.raw);
if err_code != 0 {
let err_msg_ptr = crate::ZOOM_connection_errmsg(self.raw);
let err_msg = if !err_msg_ptr.is_null() {
CStr::from_ptr(err_msg_ptr).to_string_lossy().to_string()
} else {
format!("ZOOM search error code: {}", err_code)
};
crate::ZOOM_resultset_destroy(rs);
return Err(Error::SearchError(err_msg));
}
Ok(ZoomResultSet { raw: rs })
}
}
}
impl Drop for ZoomConnection {
fn drop(&mut self) {
unsafe {
if !self.raw.is_null() {
crate::ZOOM_connection_destroy(self.raw);
}
}
}
}
impl ZoomResultSet {
pub fn size(&self) -> usize {
unsafe { crate::ZOOM_resultset_size(self.raw) }
}
pub fn option_get(&self, key: &str) -> Result<Option<String>> {
let c_key = CString::new(key).map_err(|_| Error::Other("Invalid result set option key".into()))?;
unsafe {
let ptr = crate::ZOOM_resultset_option_get(self.raw, c_key.as_ptr());
if ptr.is_null() {
return Ok(None);
}
Ok(Some(CStr::from_ptr(ptr).to_string_lossy().to_string()))
}
}
pub fn fetch(&mut self, start: usize, count: usize) {
if count == 0 {
return;
}
unsafe {
crate::ZOOM_resultset_records(self.raw, std::ptr::null_mut(), start, count);
}
}
pub fn record_data(&self, position: usize, record_type: &str) -> Result<Option<Vec<u8>>> {
let c_type = CString::new(record_type).map_err(|_| Error::Other("Invalid record type".into()))?;
unsafe {
let record = crate::ZOOM_resultset_record(self.raw, position);
if record.is_null() {
return Ok(None);
}
let mut len: i32 = 0;
let data_ptr = crate::ZOOM_record_get(record, c_type.as_ptr(), &mut len);
if data_ptr.is_null() {
return Ok(None);
}
if len > 0 {
let bytes = std::slice::from_raw_parts(data_ptr as *const u8, len as usize).to_vec();
return Ok(Some(bytes));
}
let bytes = CStr::from_ptr(data_ptr).to_bytes().to_vec();
Ok(Some(bytes))
}
}
pub fn record_text(&self, position: usize, record_type: &str) -> Result<Option<String>> {
match self.record_data(position, record_type)? {
Some(bytes) => Ok(Some(String::from_utf8_lossy(&bytes).to_string())),
None => Ok(None),
}
}
}
impl Drop for ZoomResultSet {
fn drop(&mut self) {
unsafe {
if !self.raw.is_null() {
crate::ZOOM_resultset_destroy(self.raw);
}
}
}
}