use std::{
ffi::c_char,
ops::{Deref, DerefMut},
};
use nautilus_core::{
UnixNanos,
ffi::{
cvec::CVec,
parsing::{bytes_to_string_vec, string_vec_to_bytes},
string::{cstr_as_str, str_to_cstr},
},
};
use crate::{
identifiers::{InstrumentId, Symbol},
instruments::synthetic::SyntheticInstrument,
types::{ERROR_PRICE, Price},
};
#[repr(C)]
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct SyntheticInstrument_API(Box<SyntheticInstrument>);
impl Deref for SyntheticInstrument_API {
type Target = SyntheticInstrument;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SyntheticInstrument_API {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn synthetic_instrument_new(
symbol: Symbol,
price_precision: u8,
components_ptr: *const c_char,
formula_ptr: *const c_char,
ts_event: u64,
ts_init: u64,
) -> SyntheticInstrument_API {
let components = unsafe { bytes_to_string_vec(components_ptr) }
.into_iter()
.map(InstrumentId::from)
.collect::<Vec<InstrumentId>>();
let formula = unsafe { cstr_as_str(formula_ptr) };
let synth = SyntheticInstrument::new(
symbol,
price_precision,
components,
formula,
ts_event.into(),
ts_init.into(),
);
SyntheticInstrument_API(Box::new(synth))
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_drop(synth: SyntheticInstrument_API) {
drop(synth); }
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_id(synth: &SyntheticInstrument_API) -> InstrumentId {
synth.id
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_price_precision(synth: &SyntheticInstrument_API) -> u8 {
synth.price_precision
}
#[unsafe(no_mangle)]
#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
pub extern "C" fn synthetic_instrument_price_increment(synth: &SyntheticInstrument_API) -> Price {
synth.price_increment
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_formula_to_cstr(
synth: &SyntheticInstrument_API,
) -> *const c_char {
str_to_cstr(&synth.formula)
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_components_to_cstr(
synth: &SyntheticInstrument_API,
) -> *const c_char {
let components_vec = synth
.components
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>();
string_vec_to_bytes(&components_vec)
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_components_count(synth: &SyntheticInstrument_API) -> usize {
synth.components.len()
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_ts_event(synth: &SyntheticInstrument_API) -> UnixNanos {
synth.ts_event
}
#[unsafe(no_mangle)]
pub extern "C" fn synthetic_instrument_ts_init(synth: &SyntheticInstrument_API) -> UnixNanos {
synth.ts_init
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn synthetic_instrument_is_valid_formula(
formula_ptr: *const c_char,
components_ptr: *const c_char,
) -> u8 {
if formula_ptr.is_null() || components_ptr.is_null() {
return 0;
}
let components = unsafe { bytes_to_string_vec(components_ptr) }
.into_iter()
.map(InstrumentId::from)
.collect::<Vec<InstrumentId>>();
let formula = unsafe { cstr_as_str(formula_ptr) };
u8::from(SyntheticInstrument::is_valid_formula_for_components(
formula,
&components,
))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn synthetic_instrument_change_formula(
synth: &mut SyntheticInstrument_API,
formula_ptr: *const c_char,
) {
let formula = unsafe { cstr_as_str(formula_ptr) };
synth.change_formula(formula).unwrap();
}
#[unsafe(no_mangle)]
#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
pub extern "C" fn synthetic_instrument_calculate(
synth: &mut SyntheticInstrument_API,
inputs_ptr: &CVec,
) -> Price {
let CVec { ptr, len, .. } = inputs_ptr;
let inputs: &[f64] = unsafe { std::slice::from_raw_parts((*ptr).cast::<f64>(), *len) };
match synth.calculate(inputs) {
Ok(price) => price,
Err(_) => ERROR_PRICE,
}
}