use std::ffi::CString;
use crate::correlation::CorrelationId;
use crate::errors::{BlpError, Result};
pub struct SubscriptionList {
ptr: *mut crate::ffi::blpapi_SubscriptionList_t,
}
impl SubscriptionList {
pub fn new() -> Self {
let ptr = unsafe { crate::ffi::blpapi_SubscriptionList_create() };
Self { ptr }
}
pub fn add(
&mut self,
topic: &str,
fields: &[&str],
options: &str,
cid: &CorrelationId,
) -> Result<()> {
if self.ptr.is_null() {
return Err(BlpError::Internal {
detail: "subscription list not initialized".into(),
});
}
let c_topic = CString::new(topic).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid topic: {}", e),
})?;
let c_fields: Vec<CString> = fields
.iter()
.map(|f| {
CString::new(*f).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid field: {}", e),
})
})
.collect::<Result<Vec<_>>>()?;
let field_ptrs: Vec<*const i8> = c_fields.iter().map(|s| s.as_ptr()).collect();
let options_vec: Vec<&str> = if options.is_empty() {
Vec::new()
} else {
options.split(',').map(|s| s.trim()).collect()
};
let c_options: Vec<CString> = options_vec
.iter()
.map(|o| {
CString::new(*o).map_err(|e| BlpError::InvalidArgument {
detail: format!("invalid option: {}", e),
})
})
.collect::<Result<Vec<_>>>()?;
let option_ptrs: Vec<*const i8> = c_options.iter().map(|s| s.as_ptr()).collect();
let cid_ffi = cid.to_ffi();
let rc = unsafe {
crate::ffi::blpapi_SubscriptionList_add(
self.ptr,
c_topic.as_ptr(),
&cid_ffi,
field_ptrs.as_ptr() as *mut *const i8,
option_ptrs.as_ptr() as *mut *const i8,
field_ptrs.len(),
option_ptrs.len(),
)
};
if rc != 0 {
return Err(BlpError::Internal {
detail: format!("blpapi_SubscriptionList_add failed with rc={}", rc),
});
}
Ok(())
}
pub(crate) fn as_ptr(&self) -> *mut crate::ffi::blpapi_SubscriptionList_t {
self.ptr
}
}
impl Default for SubscriptionList {
fn default() -> Self {
Self::new()
}
}
impl Drop for SubscriptionList {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe {
crate::ffi::blpapi_SubscriptionList_destroy(self.ptr);
}
self.ptr = std::ptr::null_mut();
}
}
}