Skip to content

Commit

Permalink
Reorganize core Rust crates
Browse files Browse the repository at this point in the history
  • Loading branch information
cjdsellers committed Oct 18, 2023
1 parent 58cc388 commit 8adadb0
Show file tree
Hide file tree
Showing 38 changed files with 369 additions and 330 deletions.
5 changes: 4 additions & 1 deletion nautilus_core/common/src/clock_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ use std::{
ops::{Deref, DerefMut},
};

use nautilus_core::{ffi::cvec::CVec, string::cstr_to_string, time::UnixNanos};
use nautilus_core::{
ffi::{cvec::CVec, string::cstr_to_string},
time::UnixNanos,
};
use pyo3::{
ffi,
prelude::*,
Expand Down
2 changes: 1 addition & 1 deletion nautilus_core/common/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

use std::{ffi::c_char, fmt::Debug, str::FromStr};

use nautilus_core::string::{cstr_to_string, str_to_cstr};
use nautilus_core::ffi::string::{cstr_to_string, str_to_cstr};
use serde::{Deserialize, Serialize};
use strum::{Display, EnumIter, EnumString, FromRepr};

Expand Down
6 changes: 4 additions & 2 deletions nautilus_core/common/src/logging_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ use std::{
};

use nautilus_core::{
parsing::optional_bytes_to_json,
string::{cstr_to_string, optional_cstr_to_string, str_to_cstr},
ffi::{
parsing::optional_bytes_to_json,
string::{cstr_to_string, optional_cstr_to_string, str_to_cstr},
},
uuid::UUID4,
};
use nautilus_model::identifiers::trader_id::TraderId;
Expand Down
2 changes: 1 addition & 1 deletion nautilus_core/common/src/timer_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use std::ffi::c_char;

use nautilus_core::{
string::{cstr_to_string, str_to_cstr},
ffi::string::{cstr_to_string, str_to_cstr},
uuid::UUID4,
};

Expand Down
14 changes: 1 addition & 13 deletions nautilus_core/core/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,13 @@
// limitations under the License.
// -------------------------------------------------------------------------------------------------

use std::{
ffi::c_char,
time::{Duration, UNIX_EPOCH},
};
use std::time::{Duration, UNIX_EPOCH};

use chrono::{
prelude::{DateTime, Utc},
SecondsFormat,
};

use crate::string::str_to_cstr;

const MILLISECONDS_IN_SECOND: u64 = 1_000;
const NANOSECONDS_IN_SECOND: u64 = 1_000_000_000;
const NANOSECONDS_IN_MILLISECOND: u64 = 1_000_000;
Expand Down Expand Up @@ -87,13 +82,6 @@ pub fn unix_nanos_to_iso8601(timestamp_ns: u64) -> String {
dt.to_rfc3339_opts(SecondsFormat::Nanos, true)
}

/// Converts a UNIX nanoseconds timestamp to an ISO 8601 formatted C string pointer.
#[cfg(feature = "ffi")]
#[no_mangle]
pub extern "C" fn unix_nanos_to_iso8601_cstr(timestamp_ns: u64) -> *const c_char {
str_to_cstr(&unix_nanos_to_iso8601(timestamp_ns))
}

////////////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////////////
Expand Down
25 changes: 25 additions & 0 deletions nautilus_core/core/src/ffi/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// -------------------------------------------------------------------------------------------------
// Copyright (C) 2015-2023 Nautech Systems Pty Ltd. All rights reserved.
// https://nautechsystems.io
//
// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------

use std::ffi::c_char;

use crate::{datetime::unix_nanos_to_iso8601, ffi::string::str_to_cstr};

/// Converts a UNIX nanoseconds timestamp to an ISO 8601 formatted C string pointer.
#[cfg(feature = "ffi")]
#[no_mangle]
pub extern "C" fn unix_nanos_to_iso8601_cstr(timestamp_ns: u64) -> *const c_char {
str_to_cstr(&unix_nanos_to_iso8601(timestamp_ns))
}
3 changes: 3 additions & 0 deletions nautilus_core/core/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
// -------------------------------------------------------------------------------------------------

pub mod cvec;
pub mod datetime;
pub mod parsing;
pub mod string;
pub mod uuid;
261 changes: 261 additions & 0 deletions nautilus_core/core/src/ffi/parsing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
// -------------------------------------------------------------------------------------------------
// Copyright (C) 2015-2023 Nautech Systems Pty Ltd. All rights reserved.
// https://nautechsystems.io
//
// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -------------------------------------------------------------------------------------------------

use std::{
collections::HashMap,
ffi::{c_char, CStr, CString},
};

use serde_json::{Result, Value};
use ustr::Ustr;

use crate::{ffi::string::cstr_to_string, parsing::precision_from_str};

/// Convert a C bytes pointer into an owned `Vec<String>`.
///
/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
#[must_use]
pub unsafe fn bytes_to_string_vec(ptr: *const c_char) -> Vec<String> {
assert!(!ptr.is_null(), "`ptr` was NULL");

let c_str = CStr::from_ptr(ptr);
let bytes = c_str.to_bytes();
let json_string = std::str::from_utf8(bytes).unwrap();
let parsed_value: serde_json::Value = serde_json::from_str(json_string).unwrap();

match parsed_value {
serde_json::Value::Array(arr) => arr
.into_iter()
.filter_map(|value| match value {
serde_json::Value::String(string_value) => Some(string_value),
_ => None,
})
.collect(),
_ => Vec::new(),
}
}

#[must_use]
pub fn string_vec_to_bytes(strings: Vec<String>) -> *const c_char {
let json_string = serde_json::to_string(&strings).unwrap();
let c_string = CString::new(json_string).unwrap();
c_string.into_raw()
}

/// Convert a C bytes pointer into an owned `Option<HashMap<String, Value>>`.
///
/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
#[must_use]
pub unsafe fn optional_bytes_to_json(ptr: *const c_char) -> Option<HashMap<String, Value>> {
if ptr.is_null() {
None
} else {
let c_str = CStr::from_ptr(ptr);
let bytes = c_str.to_bytes();
let json_string = std::str::from_utf8(bytes).unwrap();
let result: Result<HashMap<String, Value>> = serde_json::from_str(json_string);
match result {
Ok(map) => Some(map),
Err(e) => {
eprintln!("Error parsing JSON: {e}");
None
}
}
}
}

/// Convert a C bytes pointer into an owned `Option<HashMap<Ustr, Ustr>>`.
///
/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
#[must_use]
pub unsafe fn optional_bytes_to_str_map(ptr: *const c_char) -> Option<HashMap<Ustr, Ustr>> {
if ptr.is_null() {
None
} else {
let c_str = CStr::from_ptr(ptr);
let bytes = c_str.to_bytes();
let json_string = std::str::from_utf8(bytes).unwrap();
let result: Result<HashMap<Ustr, Ustr>> = serde_json::from_str(json_string);
match result {
Ok(map) => Some(map),
Err(e) => {
eprintln!("Error parsing JSON: {e}");
None
}
}
}
}

/// Convert a C bytes pointer into an owned `Option<Vec<String>>`.
///
/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
#[must_use]
pub unsafe fn optional_bytes_to_str_vec(ptr: *const c_char) -> Option<Vec<String>> {
if ptr.is_null() {
None
} else {
let c_str = CStr::from_ptr(ptr);
let bytes = c_str.to_bytes();
let json_string = std::str::from_utf8(bytes).unwrap();
let result: Result<Vec<String>> = serde_json::from_str(json_string);
match result {
Ok(map) => Some(map),
Err(e) => {
eprintln!("Error parsing JSON: {e}");
None
}
}
}
}

/// Return the decimal precision inferred from the given C string.
///
/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
///
/// # Panics
///
/// - If `ptr` is null.
#[no_mangle]
pub unsafe extern "C" fn precision_from_cstr(ptr: *const c_char) -> u8 {
assert!(!ptr.is_null(), "`ptr` was NULL");
precision_from_str(&cstr_to_string(ptr))
}

/// Return a `bool` value from the given `u8`.
#[must_use]
pub fn u8_to_bool(value: u8) -> bool {
value != 0
}

////////////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////////////
#[cfg(test)]
mod tests {
use std::ffi::CString;

use rstest::rstest;

use super::*;

#[rstest]
fn test_optional_bytes_to_json_null() {
let ptr = std::ptr::null();
let result = unsafe { optional_bytes_to_json(ptr) };
assert_eq!(result, None);
}

#[rstest]
fn test_optional_bytes_to_json_empty() {
let json_str = CString::new("{}").unwrap();
let ptr = json_str.as_ptr() as *const c_char;
let result = unsafe { optional_bytes_to_json(ptr) };
assert_eq!(result, Some(HashMap::new()));
}

#[rstest]
fn test_string_vec_to_bytes_valid() {
let strings = vec!["value1", "value2", "value3"]
.into_iter()
.map(String::from)
.collect::<Vec<String>>();

let ptr = string_vec_to_bytes(strings.clone());

let result = unsafe { bytes_to_string_vec(ptr) };
assert_eq!(result, strings);
}

#[rstest]
fn test_string_vec_to_bytes_empty() {
let strings = Vec::new();
let ptr = string_vec_to_bytes(strings.clone());

let result = unsafe { bytes_to_string_vec(ptr) };
assert_eq!(result, strings);
}

#[rstest]
fn test_bytes_to_string_vec_valid() {
let json_str = CString::new(r#"["value1", "value2", "value3"]"#).unwrap();
let ptr = json_str.as_ptr() as *const c_char;
let result = unsafe { bytes_to_string_vec(ptr) };

let expected_vec = vec!["value1", "value2", "value3"]
.into_iter()
.map(String::from)
.collect::<Vec<String>>();

assert_eq!(result, expected_vec);
}

#[rstest]
fn test_bytes_to_string_vec_invalid() {
let json_str = CString::new(r#"["value1", 42, "value3"]"#).unwrap();
let ptr = json_str.as_ptr() as *const c_char;
let result = unsafe { bytes_to_string_vec(ptr) };

let expected_vec = vec!["value1", "value3"]
.into_iter()
.map(String::from)
.collect::<Vec<String>>();

assert_eq!(result, expected_vec);
}

#[rstest]
fn test_optional_bytes_to_json_valid() {
let json_str = CString::new(r#"{"key1": "value1", "key2": 2}"#).unwrap();
let ptr = json_str.as_ptr() as *const c_char;
let result = unsafe { optional_bytes_to_json(ptr) };
let mut expected_map = HashMap::new();
expected_map.insert("key1".to_owned(), Value::String("value1".to_owned()));
expected_map.insert(
"key2".to_owned(),
Value::Number(serde_json::Number::from(2)),
);
assert_eq!(result, Some(expected_map));
}

#[rstest]
fn test_optional_bytes_to_json_invalid() {
let json_str = CString::new(r#"{"key1": "value1", "key2": }"#).unwrap();
let ptr = json_str.as_ptr() as *const c_char;
let result = unsafe { optional_bytes_to_json(ptr) };
assert_eq!(result, None);
}

#[rstest]
#[case("1e8", 0)]
#[case("123", 0)]
#[case("123.45", 2)]
#[case("123.456789", 6)]
#[case("1.23456789e-2", 2)]
#[case("1.23456789e-12", 12)]
fn test_precision_from_cstr(#[case] input: &str, #[case] expected: u8) {
let c_str = CString::new(input).unwrap();
assert_eq!(unsafe { precision_from_cstr(c_str.as_ptr()) }, expected);
}
}
File renamed without changes.
1 change: 0 additions & 1 deletion nautilus_core/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ pub mod correctness;
pub mod datetime;
pub mod parsing;
pub mod serialization;
pub mod string;
pub mod time;
pub mod uuid;

Expand Down
Loading

0 comments on commit 8adadb0

Please sign in to comment.