Skip to content

Commit

Permalink
✨ Add ability to build SessionID object from rust
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurlm committed Nov 13, 2023
1 parent aae77d6 commit 39c439d
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 7 deletions.
3 changes: 3 additions & 0 deletions quickfix-bind/include/quickfix_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,14 @@ extern "C"
int FixSocketAcceptor_isStopped(const FixSocketAcceptor_t *obj);
void FixSocketAcceptor_delete(FixSocketAcceptor_t *obj);

FixSessionID_t *FixSessionID_new(const char *beginString, const char *senderCompID, const char *targetCompID, const char *sessionQualifier);
const char *FixSessionID_getBeginString(const FixSessionID_t *session);
const char *FixSessionID_getSenderCompID(const FixSessionID_t *session);
const char *FixSessionID_getTargetCompID(const FixSessionID_t *session);
const char *FixSessionID_getSessionQualifier(const FixSessionID_t *session);
int8_t FixSessionID_isFIXT(const FixSessionID_t *session);
const char *FixSessionID_toString(const FixSessionID *session);
void FixSessionID_delete(FixSessionID_t *session);

FixMessage_t *FixMessage_new();
int FixMessage_setField(const FixMessage_t *obj, int tag, const char *value);
Expand Down
45 changes: 42 additions & 3 deletions quickfix-bind/src/quickfix_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,24 @@ extern "C"
DELETE_OBJ(FIX::SocketAcceptor, obj);
}

FixSessionID_t *
FixSessionID_new(const char *beginString, const char *senderCompID, const char *targetCompID, const char *sessionQualifier)
{
RETURN_VAL_IF_NULL(beginString, NULL);
RETURN_VAL_IF_NULL(senderCompID, NULL);
RETURN_VAL_IF_NULL(targetCompID, NULL);
RETURN_VAL_IF_NULL(sessionQualifier, NULL);

try
{
return (FixSessionID_t *)(new FIX::SessionID(beginString, senderCompID, targetCompID, sessionQualifier));
}
catch (std::exception &ex)
{
return NULL;
}
}

const char *FixSessionID_getBeginString(const FixSessionID_t *session)
{
RETURN_VAL_IF_NULL(session, NULL);
Expand All @@ -353,19 +371,40 @@ extern "C"

int8_t FixSessionID_isFIXT(const FixSessionID_t *session)
{
RETURN_VAL_IF_NULL(session, 0);
RETURN_VAL_IF_NULL(session, ERRNO_INVAL);

auto fix_obj = (FIX::SessionID *)(session);
try
{
return fix_obj->isFIXT();
return fix_obj->isFIXT() ? 1 : 0;
}
catch (std::exception &e)
{
return 0;
return ERRNO_EXCEPTION;
}
}

const char *FixSessionID_toString(const FixSessionID *session)
{
RETURN_VAL_IF_NULL(session, NULL);

auto fix_obj = (FIX::SessionID *)(session);
try
{
return fix_obj->toStringFrozen().c_str();
}
catch (std::exception &e)
{
return NULL;
}
}

void FixSessionID_delete(FixSessionID_t *session)
{
RETURN_IF_NULL(session);
DELETE_OBJ(FIX::SessionID, session);
}

FixMessage_t *
FixMessage_new()
{
Expand Down
8 changes: 8 additions & 0 deletions quickfix-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,19 @@ extern "C" {
pub fn FixSocketAcceptor_isStopped(obj: FixSocketAcceptor_t) -> ffi::c_int;
pub fn FixSocketAcceptor_delete(obj: FixSocketAcceptor_t);

pub fn FixSessionID_new(
beginString: *const ffi::c_char,
senderCompID: *const ffi::c_char,
targetCompID: *const ffi::c_char,
sessionQualifier: *const ffi::c_char,
) -> Option<FixSessionID_t>;
pub fn FixSessionID_getBeginString(obj: FixSessionID_t) -> Option<NonNull<ffi::c_char>>;
pub fn FixSessionID_getSenderCompID(obj: FixSessionID_t) -> Option<NonNull<ffi::c_char>>;
pub fn FixSessionID_getTargetCompID(obj: FixSessionID_t) -> Option<NonNull<ffi::c_char>>;
pub fn FixSessionID_getSessionQualifier(obj: FixSessionID_t) -> Option<NonNull<ffi::c_char>>;
pub fn FixSessionID_isFIXT(obj: FixSessionID_t) -> i8;
pub fn FixSessionID_toString(obj: FixSessionID_t) -> Option<NonNull<ffi::c_char>>;
pub fn FixSessionID_delete(obj: FixSessionID_t);

pub fn FixMessage_new() -> Option<FixMessage_t>;
#[must_use]
Expand Down
52 changes: 48 additions & 4 deletions quickfix/src/session_id.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
use std::{ffi::CString, fmt};

use quickfix_ffi::{
FixSessionID_getBeginString, FixSessionID_getSenderCompID, FixSessionID_getSessionQualifier,
FixSessionID_getTargetCompID, FixSessionID_isFIXT,
FixSessionID_delete, FixSessionID_getBeginString, FixSessionID_getSenderCompID,
FixSessionID_getSessionQualifier, FixSessionID_getTargetCompID, FixSessionID_isFIXT,
FixSessionID_toString,
};

use crate::utils::read_checked_cstr;
use crate::{utils::read_checked_cstr, QuickFixError};

#[derive(Debug)]
pub struct SessionId(pub(crate) quickfix_ffi::FixSessionID_t);

impl SessionId {
pub fn try_new(
begin_string: &str,
sender_comp_id: &str,
target_comp_id: &str,
session_qualifier: &str,
) -> Result<Self, QuickFixError> {
let ffi_begin_string = CString::new(begin_string)?;
let ffi_sender_comp_id = CString::new(sender_comp_id)?;
let ffi_target_comp_id = CString::new(target_comp_id)?;
let ffi_session_qualifier = CString::new(session_qualifier)?;

match unsafe {
quickfix_ffi::FixSessionID_new(
ffi_begin_string.as_ptr(),
ffi_sender_comp_id.as_ptr(),
ffi_target_comp_id.as_ptr(),
ffi_session_qualifier.as_ptr(),
)
} {
Some(val) => Ok(Self(val)),
None => Err(QuickFixError::InvalidFunctionReturn),
}
}

pub fn get_begin_string(&self) -> Option<String> {
unsafe { FixSessionID_getBeginString(self.0) }.map(read_checked_cstr)
}
Expand All @@ -29,4 +55,22 @@ impl SessionId {
let val = unsafe { FixSessionID_isFIXT(self.0) };
val != 0
}

pub fn as_string(&self) -> String {
unsafe { FixSessionID_toString(self.0) }
.map(read_checked_cstr)
.unwrap_or_default()
}
}

impl fmt::Debug for SessionId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("SessionId").field(&self.as_string()).finish()
}
}

impl Drop for SessionId {
fn drop(&mut self) {
unsafe { FixSessionID_delete(self.0) }
}
}
20 changes: 20 additions & 0 deletions quickfix/tests/test_session_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use quickfix::SessionId;

#[test]
fn test_new() {
let session = SessionId::try_new("FIX.4.1", "FOO", "BAR", "").unwrap();
assert_eq!(session.get_begin_string().as_deref(), Some("FIX.4.1"));
assert_eq!(session.get_sender_comp_id().as_deref(), Some("FOO"));
assert_eq!(session.get_target_comp_id().as_deref(), Some("BAR"));
assert_eq!(session.get_session_qualifier().as_deref(), Some(""));
assert_eq!(session.as_string(), "FIX.4.1:FOO->BAR");
}

#[test]
fn test_fixt() {
let session1 = SessionId::try_new("FIX.4.1", "FOO", "BAR", "").unwrap();
let session2 = SessionId::try_new("FIXT", "FOO", "BAR", "").unwrap();

assert!(!session1.is_fixt());
assert!(session2.is_fixt());
}

0 comments on commit 39c439d

Please sign in to comment.