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 acf6e8b commit 58cc388
Show file tree
Hide file tree
Showing 29 changed files with 423 additions and 252 deletions.
2 changes: 1 addition & 1 deletion nautilus_core/backtest/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use std::ops::{Deref, DerefMut};

use nautilus_common::{clock::TestClock, clock_api::TestClock_API, timer::TimeEventHandler};
use nautilus_core::{cvec::CVec, time::UnixNanos};
use nautilus_core::{ffi::cvec::CVec, time::UnixNanos};

/// Provides a means of accumulating and draining time event handlers.
pub struct TimeEventAccumulator {
Expand Down
2 changes: 1 addition & 1 deletion nautilus_core/common/src/clock_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::{
ops::{Deref, DerefMut},
};

use nautilus_core::{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
29 changes: 21 additions & 8 deletions nautilus_core/core/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,74 +13,87 @@
// limitations under the License.
// -------------------------------------------------------------------------------------------------

use std::time::{Duration, UNIX_EPOCH};
use std::{
ffi::c_char,
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;
const NANOSECONDS_IN_MICROSECOND: u64 = 1_000;

/// Converts seconds to nanoseconds (ns).
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn secs_to_nanos(secs: f64) -> u64 {
(secs * NANOSECONDS_IN_SECOND as f64) as u64
}

/// Converts seconds to milliseconds (ms).
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn secs_to_millis(secs: f64) -> u64 {
(secs * MILLISECONDS_IN_SECOND as f64) as u64
}

/// Converts milliseconds (ms) to nanoseconds (ns).
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn millis_to_nanos(millis: f64) -> u64 {
(millis * NANOSECONDS_IN_MILLISECOND as f64) as u64
}

/// Converts microseconds (μs) to nanoseconds (ns).
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn micros_to_nanos(micros: f64) -> u64 {
(micros * NANOSECONDS_IN_MICROSECOND as f64) as u64
}

/// Converts nanoseconds (ns) to seconds.
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn nanos_to_secs(nanos: u64) -> f64 {
nanos as f64 / NANOSECONDS_IN_SECOND as f64
}

/// Converts nanoseconds (ns) to milliseconds (ms).
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn nanos_to_millis(nanos: u64) -> u64 {
nanos / NANOSECONDS_IN_MILLISECOND
}

/// Converts nanoseconds (ns) to microseconds (μs).
#[no_mangle]
#[inline]
#[no_mangle]
pub extern "C" fn nanos_to_micros(nanos: u64) -> u64 {
nanos / NANOSECONDS_IN_MICROSECOND
}

/// Converts a UNIX nanoseconds timestamp to an ISO 8601 formatted string.
#[inline]
#[must_use]
pub fn unix_nanos_to_iso8601(timestamp_ns: u64) -> String {
let dt = DateTime::<Utc>::from(UNIX_EPOCH + Duration::from_nanos(timestamp_ns));
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
File renamed without changes.
17 changes: 17 additions & 0 deletions nautilus_core/core/src/ffi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// -------------------------------------------------------------------------------------------------
// 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.
// -------------------------------------------------------------------------------------------------

pub mod cvec;
pub mod uuid;
121 changes: 121 additions & 0 deletions nautilus_core/core/src/ffi/uuid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// -------------------------------------------------------------------------------------------------
// 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::hash_map::DefaultHasher,
ffi::{c_char, CStr},
hash::{Hash, Hasher},
};

use crate::uuid::UUID4;

#[no_mangle]
pub extern "C" fn uuid4_new() -> UUID4 {
UUID4::new()
}

/// Returns a [`UUID4`] from C string pointer.
///
/// # Safety
///
/// - Assumes `ptr` is a valid C string pointer.
///
/// # Panics
///
/// - If `ptr` cannot be cast to a valid C string.
#[no_mangle]
pub unsafe extern "C" fn uuid4_from_cstr(ptr: *const c_char) -> UUID4 {
assert!(!ptr.is_null(), "`ptr` was NULL");
UUID4::from(
CStr::from_ptr(ptr)
.to_str()
.unwrap_or_else(|_| panic!("CStr::from_ptr failed")),
)
}

#[no_mangle]
pub extern "C" fn uuid4_to_cstr(uuid: &UUID4) -> *const c_char {
uuid.to_cstr().as_ptr()
}

#[no_mangle]
pub extern "C" fn uuid4_eq(lhs: &UUID4, rhs: &UUID4) -> u8 {
u8::from(lhs == rhs)
}

#[no_mangle]
pub extern "C" fn uuid4_hash(uuid: &UUID4) -> u64 {
let mut h = DefaultHasher::new();
uuid.hash(&mut h);
h.finish()
}

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

use rstest::*;
use uuid::{self, Uuid};

use super::*;

#[rstest]
fn test_uuid4_new() {
let uuid = uuid4_new();
let uuid_string = uuid.to_string();
let uuid_parsed = Uuid::parse_str(&uuid_string).expect("Uuid::parse_str failed");
assert_eq!(uuid_parsed.get_version().unwrap(), uuid::Version::Random);
}

#[rstest]
fn test_uuid4_from_cstr() {
let uuid_string = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
let uuid_cstring = CString::new(uuid_string).expect("CString::new failed");
let uuid_ptr = uuid_cstring.as_ptr();
let uuid = unsafe { uuid4_from_cstr(uuid_ptr) };
assert_eq!(uuid_string, uuid.to_string());
}

#[rstest]
fn test_uuid4_to_cstr() {
let uuid_string = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
let uuid = UUID4::from(uuid_string);
let uuid_ptr = uuid4_to_cstr(&uuid);
let uuid_cstr = unsafe { CStr::from_ptr(uuid_ptr) };
let uuid_result_string = uuid_cstr.to_str().expect("CStr::to_str failed").to_string();
assert_eq!(uuid_string, uuid_result_string);
}

#[rstest]
fn test_uuid4_eq() {
let uuid1 = UUID4::from("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
let uuid2 = UUID4::from("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
let uuid3 = UUID4::from("6ba7b810-9dad-11d1-80b4-00c04fd430c9");
assert_eq!(uuid4_eq(&uuid1, &uuid2), 1);
assert_eq!(uuid4_eq(&uuid1, &uuid3), 0);
}

#[rstest]
fn test_uuid4_hash() {
let uuid1 = UUID4::from("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
let uuid2 = UUID4::from("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
let uuid3 = UUID4::from("6ba7b810-9dad-11d1-80b4-00c04fd430c9");
assert_eq!(uuid4_hash(&uuid1), uuid4_hash(&uuid2));
assert_ne!(uuid4_hash(&uuid1), uuid4_hash(&uuid3));
}
}
14 changes: 4 additions & 10 deletions nautilus_core/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,15 @@
// limitations under the License.
// -------------------------------------------------------------------------------------------------

use pyo3::{prelude::*, PyResult, Python};

pub mod correctness;
pub mod cvec;
pub mod datetime;
pub mod parsing;
pub mod python;
pub mod serialization;
pub mod string;
pub mod time;
pub mod uuid;

/// Loaded as nautilus_pyo3.core
#[pymodule]
pub fn core(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<uuid::UUID4>()?;
Ok(())
}
#[cfg(feature = "ffi")]
pub mod ffi;
#[cfg(feature = "python")]
pub mod python;
61 changes: 61 additions & 0 deletions nautilus_core/core/src/python/datetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// -------------------------------------------------------------------------------------------------
// 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 pyo3::prelude::*;

use crate::datetime::{
micros_to_nanos, millis_to_nanos, nanos_to_micros, nanos_to_millis, nanos_to_secs,
secs_to_millis, secs_to_nanos, unix_nanos_to_iso8601,
};

#[pyfunction(name = "secs_to_nanos")]
pub fn py_secs_to_nanos(secs: f64) -> u64 {
secs_to_nanos(secs)
}

#[pyfunction(name = "secs_to_millis")]
pub fn py_secs_to_millis(secs: f64) -> u64 {
secs_to_millis(secs)
}

#[pyfunction(name = "millis_to_nanos")]
pub fn py_millis_to_nanos(millis: f64) -> u64 {
millis_to_nanos(millis)
}

#[pyfunction(name = "micros_to_nanos")]
pub fn py_micros_to_nanos(micros: f64) -> u64 {
micros_to_nanos(micros)
}

#[pyfunction(name = "nanos_to_secs")]
pub fn py_nanos_to_secs(nanos: u64) -> f64 {
nanos_to_secs(nanos)
}

#[pyfunction(name = "nanos_to_millis")]
pub fn py_nanos_to_millis(nanos: u64) -> u64 {
nanos_to_millis(nanos)
}

#[pyfunction(name = "nanos_to_micros")]
pub fn py_nanos_to_micros(nanos: u64) -> u64 {
nanos_to_micros(nanos)
}

#[pyfunction(name = "unix_nanos_to_iso8601")]
pub fn py_unix_nanos_to_iso8601(timestamp_ns: u64) -> String {
unix_nanos_to_iso8601(timestamp_ns)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ use std::fmt;
use pyo3::{
exceptions::{PyRuntimeError, PyTypeError, PyValueError},
prelude::*,
wrap_pyfunction,
};

pub mod datetime;
pub mod serialization;
pub mod uuid;

/// Gets the type name for the given Python `obj`.
pub fn get_pytype_name<'p>(obj: &'p PyObject, py: Python<'p>) -> PyResult<&'p str> {
obj.as_ref(py).get_type().name()
Expand All @@ -39,3 +44,18 @@ pub fn to_pytype_err(e: impl fmt::Display) -> PyErr {
pub fn to_pyruntime_err(e: impl fmt::Display) -> PyErr {
PyRuntimeError::new_err(e.to_string())
}

/// Loaded as nautilus_pyo3.core
#[pymodule]
pub fn core(_: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<crate::uuid::UUID4>()?;
m.add_function(wrap_pyfunction!(datetime::py_secs_to_nanos, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_secs_to_millis, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_millis_to_nanos, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_micros_to_nanos, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_nanos_to_secs, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_nanos_to_millis, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_nanos_to_micros, m)?)?;
m.add_function(wrap_pyfunction!(datetime::py_unix_nanos_to_iso8601, m)?)?;
Ok(())
}
Loading

0 comments on commit 58cc388

Please sign in to comment.