Skip to content

Commit

Permalink
✨ Add ability to get / remove Message field
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurlm committed Nov 13, 2023
1 parent 7f769cf commit 6cf1305
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 34 deletions.
2 changes: 2 additions & 0 deletions quickfix-bind/include/quickfix_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ extern "C"

FixMessage_t *FixMessage_new();
int FixMessage_setField(const FixMessage_t *obj, int tag, const char *value);
const char *FixMessage_getField(const FixMessage_t *obj, int tag);
int FixMessage_removeField(const FixMessage_t *obj, int tag);
int FixMessage_toBuffer(const FixMessage_t *obj, char *buffer, size_t length);
void FixMessage_delete(FixMessage_t *obj);

Expand Down
39 changes: 37 additions & 2 deletions quickfix-bind/src/quickfix_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ extern "C"
}
}

int FixMessage_setField(const FixMessage_t *obj, int tag, const char *value)
int
FixMessage_setField(const FixMessage_t *obj, int tag, const char *value)
{
RETURN_VAL_IF_NULL(obj, ERRNO_INVAL);
RETURN_VAL_IF_NULL(value, ERRNO_INVAL);
Expand All @@ -396,7 +397,41 @@ extern "C"
return 0;
}

int FixMessage_toBuffer(const FixMessage_t *obj, char *buffer, size_t length)
const char *
FixMessage_getField(const FixMessage_t *obj, int tag)
{
RETURN_VAL_IF_NULL(obj, NULL);

auto fix_obj = (FIX::Message *)(obj);
try
{
return fix_obj->getField(tag).c_str();
}
catch (std::exception &ex)
{
return NULL;
}
}

int
FixMessage_removeField(const FixMessage_t *obj, int tag)
{
RETURN_VAL_IF_NULL(obj, ERRNO_INVAL);

auto fix_obj = (FIX::Message *)(obj);
try
{
fix_obj->removeField(tag);
}
catch (std::exception &ex)
{
return ERRNO_EXCEPTION;
}
return 0;
}

int
FixMessage_toBuffer(const FixMessage_t *obj, char *buffer, size_t length)
{
if (length == 0)
return 0;
Expand Down
4 changes: 4 additions & 0 deletions quickfix-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ extern "C" {
value: *const ffi::c_char,
) -> ffi::c_int;
#[must_use]
pub fn FixMessage_getField(obj: FixMessage_t, tag: ffi::c_int) -> Option<NonNull<ffi::c_char>>;
#[must_use]
pub fn FixMessage_removeField(obj: FixMessage_t, tag: ffi::c_int) -> ffi::c_int;
#[must_use]
pub fn FixMessage_toBuffer(
obj: FixMessage_t,
buffer: *mut ffi::c_char,
Expand Down
21 changes: 19 additions & 2 deletions quickfix/src/message.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
use std::ffi::CString;

use quickfix_ffi::{FixMessage_delete, FixMessage_new, FixMessage_setField, FixMessage_toBuffer};
use quickfix_ffi::{
FixMessage_delete, FixMessage_getField, FixMessage_new, FixMessage_removeField,
FixMessage_setField, FixMessage_toBuffer,
};

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

#[derive(Debug)]
pub struct Message(pub(crate) quickfix_ffi::FixMessage_t);
Expand All @@ -24,6 +30,17 @@ impl Message {
}
}

pub fn get_field(&self, tag: i32) -> Option<String> {
unsafe { FixMessage_getField(self.0, tag) }.map(read_checked_cstr)
}

pub fn remove_field(&self, tag: i32) -> Result<(), QuickFixError> {
match unsafe { FixMessage_removeField(self.0, tag) } {
0 => Ok(()),
code => Err(QuickFixError::InvalidFunctionReturnCode(code)),
}
}

pub fn as_string(&self) -> Result<String, QuickFixError> {
self.as_string_with_len(4096 /* 1 page */)
}
Expand Down
36 changes: 6 additions & 30 deletions quickfix/src/session_id.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,28 @@
use std::ffi::CStr;

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

use crate::utils::read_checked_cstr;

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

impl SessionId {
pub fn get_begin_string(&self) -> Option<String> {
match unsafe { FixSessionID_getBeginString(self.0) } {
Some(val) => {
let cstr = unsafe { CStr::from_ptr(val.as_ptr()) };
Some(String::from_utf8_lossy(cstr.to_bytes()).to_string())
}
None => None,
}
unsafe { FixSessionID_getBeginString(self.0) }.map(read_checked_cstr)
}

pub fn get_sender_comp_id(&self) -> Option<String> {
match unsafe { FixSessionID_getSenderCompID(self.0) } {
Some(val) => {
let cstr = unsafe { CStr::from_ptr(val.as_ptr()) };
Some(String::from_utf8_lossy(cstr.to_bytes()).to_string())
}
None => None,
}
unsafe { FixSessionID_getSenderCompID(self.0) }.map(read_checked_cstr)
}

pub fn get_target_comp_id(&self) -> Option<String> {
match unsafe { FixSessionID_getTargetCompID(self.0) } {
Some(val) => {
let cstr = unsafe { CStr::from_ptr(val.as_ptr()) };
Some(String::from_utf8_lossy(cstr.to_bytes()).to_string())
}
None => None,
}
unsafe { FixSessionID_getTargetCompID(self.0) }.map(read_checked_cstr)
}

pub fn get_session_qualifier(&self) -> Option<String> {
match unsafe { FixSessionID_getSessionQualifier(self.0) } {
Some(val) => {
let cstr = unsafe { CStr::from_ptr(val.as_ptr()) };
Some(String::from_utf8_lossy(cstr.to_bytes()).to_string())
}
None => None,
}
unsafe { FixSessionID_getSessionQualifier(self.0) }.map(read_checked_cstr)
}

pub fn is_fixt(&self) -> bool {
Expand Down
10 changes: 10 additions & 0 deletions quickfix/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
use std::{
ffi::{self, CStr},
ptr::NonNull,
};

pub fn read_buffer_to_string(buffer: &[u8]) -> String {
let null_index = buffer.iter().position(|x| *x == 0).unwrap_or(buffer.len());
String::from_utf8_lossy(&buffer[..null_index]).to_string()
}

pub fn read_checked_cstr(val: NonNull<ffi::c_char>) -> String {
let cstr = unsafe { CStr::from_ptr(val.as_ptr()) };
String::from_utf8_lossy(cstr.to_bytes()).to_string()
}
41 changes: 41 additions & 0 deletions quickfix/tests/test_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,44 @@ fn test_set_field() {
Ok("9=14\u{1}42=foo\u{1}56=bar\u{1}10=162\u{1}")
);
}

#[test]
fn test_set_field_twice() {
let mut msg = Message::try_new().unwrap();

msg.set_field(42, "foo").unwrap();
assert_eq!(
msg.as_string().as_deref(),
Ok("9=7\u{1}42=foo\u{1}10=150\u{1}")
);

msg.set_field(42, "bar").unwrap();
assert_eq!(
msg.as_string().as_deref(),
Ok("9=7\u{1}42=bar\u{1}10=135\u{1}")
);
}

#[test]
fn test_get_field() {
let mut msg = Message::try_new().unwrap();
assert_eq!(msg.get_field(42), None);

msg.set_field(42, "hello world").unwrap();
assert_eq!(msg.get_field(42).as_deref(), Some("hello world"));
}

#[test]
fn test_remove_field() {
let mut msg = Message::try_new().unwrap();
assert_eq!(msg.get_field(42), None);

msg.remove_field(42).unwrap();
assert_eq!(msg.get_field(42), None);

msg.set_field(42, "hello world").unwrap();
assert_eq!(msg.get_field(42).as_deref(), Some("hello world"));

msg.remove_field(42).unwrap();
assert_eq!(msg.get_field(42), None);
}

0 comments on commit 6cf1305

Please sign in to comment.